如何在 C 中使用 openssl bignum 将字符串转换为 long?

How to convert a string to a long with openssl bignum in C?

我正在尝试将此函数从 Python 移植到 C:

import binascii
from Crypto.Util.number import bytes_to_long

# converts from a string to a long
def _strtoLong(s):
    s = bytes("".join(s.split()), "UTF-8")
    s = binascii.a2b_hex(s)
    return bytes_to_long(s)

字符串很长。我相信生成的数字是 2048 位。我正在尝试使用 openssl bn 结构将其移植到 C,但我似乎无法获得正确的输出。这是 python 函数每一步的输出,打印为字符串表示形式:

bytes: b'B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371'

a2b_hex: b'\xb1\x0b\x8f\x96\xa0\x80\xe0\x1d\xde\x92\xde^\xae]T\xecR\xc9\x9f\xbc\xfb\x06\xa3\xc6\x9aj\x9d\xcaR\xd2;a`s\xe2\x86u\xa2=\x18\x988\xef\x1e.\xe6R\xc0\x13\xec\xb4\xae\xa9\x06\x11#$\x97\<\xd4\x9b\x83\xbf\xac\xcb\xdd}\x90\xc4\xbdp\x98H\x8e\x9c!\x9asrN\xff\xd6\xfa\xe5dG8\xfa\xa3\x1aO\xf5[\xcc\xc0\xa1Q\xaf_\r\xc8\xb4\xbdE\xbf7\xdf6\\x1ae\xe6\x8c\xfd\xa7mM\xa7\x08\xdf\x1f\xb2\xbc.JCq'

bytes_to_long: 124325339146889384540494091085456630009856882741872806181731279018491820800119460022367403769795008250021191767583423221479185609066059226301250167164084041279837566626881119772675984258163062926954046545485368458404445166682380071370274810671501916789361956272226105723317679562001235501455748016154805420913

在 C 中我正在做:

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
#include <openssl/bn.h>

int char2int(unsigned char input)
{
    if(input >= '0' && input <= '9')
        return input - '0';
    if(input >= 'A' && input <= 'F')
        return input - 'A' + 10;
    if(input >= 'a' && input <= 'f')
        return input - 'a' + 10;
    return -1;
}

// This function assumes src to be a zero terminated sanitized string with
// an even number of [0-9a-f] characters, and target to be sufficiently large
void hex2bin(const unsigned char* src, unsigned char* target)
{
    while(*src && src[1])
    {
        *(target++) = char2int(*src)*16 + char2int(src[1]);
        src += 2;
    }
}


int main()
{
    unsigned char buf[512] = "B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C6"
                    "9A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C0"
                    "13ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD70"
                    "98488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0"
                    "A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708"
                    "DF1FB2BC2E4A4371";
    unsigned char P[2049], val[256];
    int i;
    int len = 256;
    for(i=0; i<len; i++){
        P[i] = buf[i];
    }

    fprintf(stderr, "\nbytes=%s\n", P);

    hex2bin(P, val);
    fprintf(stderr, "\nhex2bin= ");
    for(i=0; i<len/2; i++)
        fprintf(stderr, "%02x", val[i]);
    fprintf(stderr, "\n");

    BIGNUM *bn = BN_new();    
    BN_bin2bn(val, (int)len/2, bn);


    fprintf(stderr, "\nbn=");
    BN_print_fp(stdout, bn);

    char *str = BN_bn2hex(bn);
    printf("\n\nbn2hex: %s\n", str);
    free(str);
    BN_free(bn);

    return 0;
}

这是它打印出来的内容:

matthew@matthew-HP-15-Notebook-PC:~/Desktop/crypto/prog$ make
clang -Wall -I../tomsfastmath/src/headers/ -I../openssl/include main.c ../tomsfastmath/libtfm.a ../openssl/libcrypto.a -o bignum
matthew@matthew-HP-15-Notebook-PC:~/Desktop/crypto/prog$ ./bignum 

bytes=B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371

hex2bin= b10b8f96a080e01dde92de5eae5d54ec52c99fbcfb06a3c69a6a9dca52d23b616073e28675a23d189838ef1e2ee652c013ecb4aea906112324975c3cd49b83bfaccbdd7d90c4bd7098488e9c219a73724effd6fae5644738faa31a4ff55bccc0a151af5f0dc8b4bd45bf37df365c1a65e68cfda76d4da708df1fb2bc2e4a4371

bn=B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371

bn2hex: B10B8F96A080E01DDE92DE5EAE5D54EC52C99FBCFB06A3C69A6A9DCA52D23B616073E28675A23D189838EF1E2EE652C013ECB4AEA906112324975C3CD49B83BFACCBDD7D90C4BD7098488E9C219A73724EFFD6FAE5644738FAA31A4FF55BCCC0A151AF5F0DC8B4BD45BF37DF365C1A65E68CFDA76D4DA708DF1FB2BC2E4A4371

关于如何将 bn 转换为与 python 相同的 long 的任何想法?

创建一个整数值 0。查看字符串最左边的字符,然后将一个值添加到 运行-total 整数中,该值等于该字符所代表的十进制值 (0 - 15)。然后将 运行 总数乘以 16,然后移至下一个字母/数字。继续这样做,直到十六进制字符串的最后一个位置,之后您不乘以 16。

我不太清楚这是否是您的代码正在尝试执行的操作。

根据 OpenSSL 手册:

int BN_print_fp(FILE *fp, const BIGNUM *a);

BN_print() and BN_print_fp() write the hexadecimal encoding of a, with a leading '-' for negative numbers, to the BIO or FILE fp.

您需要的是:

char *BN_bn2dec(const BIGNUM *a);

BN_bn2hex() and BN_bn2dec() return printable strings containing the hexadecimal and decimal encoding of a respectively. For negative numbers, the string is prefaced with a leading '-'. The string must be freed later using OPENSSL_free().

您可以使用 OpenSSL Bignum 函数:

int BN_bn2bin(const BIGNUM *a, unsigned char *to);

BN_bn2bin将a的绝对值转换成大端形式存入to。 to 必须指向 BN_num_bytes(a) 字节的内存。

char *BN_bn2hex(const BIGNUM *a);
char *BN_bn2dec(const BIGNUM *a);

BN_bn2hex() 和 BN_bn2dec() return 分别包含 a 的十六进制和十进制编码的可打印字符串。对于负数,字符串以前导“-”开头。稍后必须使用 OPENSSL_free().

释放该字符串

这些函数的反之亦然(将 char * 转换为 BIGNUM 数据结构):

BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
int BN_hex2bn(BIGNUM **a, const char *str);
int BN_dec2bn(BIGNUM **a, const char *str);