使转换类似于BN_hex2bn + BN_bn2bin,但在C

时间:2018-12-13 22:07:32

标签: c encryption openssl

我目前使用openSSL将值从加密的字符串转换为我认为是二进制数组的值。然后,我解密此“数组”(传递给EVP_DecryptUpdate)。我这样进行转换:

    BIGNUM *bnEncr = BN_new();
    if (0 == BN_hex2bn(&bnEncr, encrypted)) { // from hex to big number
        printf("ERROR\n");
    }
    unsigned int numOfBytesEncr = BN_num_bytes(bnEncr);
    unsigned char encrBin[numOfBytesEncr];
    if (0 == BN_bn2bin(bnEncr, encrBin)) { // from big number to binary
        printf("ERROR\n");
    }

然后我将encrBin传递给EVP_DecryptUpdate,解密工作正常。

我在代码的很多地方都这样做,现在想编写自己的C函数,将十六进制转换为二进制数组,然后将其传递给EVP_DecryptUpdate。我对此进行了尝试,并将加密的十六进制字符串转换为0和1的数组,但事实证明EVP_DecryptUpdate不适用于该数组。根据我在网上可以找到的信息,BN_bn2bin“创建了一个真正的二进制表示形式(即,一个位序列)。更具体地说,它创建了一个数字的大端表示。”所以这不只是0和1的数组,对吧?

有人可以解释我如何用C自己进行hex->(真正)二进制转换,这样我就可以得到EVP_DecryptUpdate期望的格式?这很复杂吗?

2 个答案:

答案 0 :(得分:0)

尚不清楚您为什么要这样做,并且绝对不建议您自己实施转换函数的实现(它们可能会停止对OpenSSL进行任何内部更改),但是如果您对它感兴趣,{{ 3}}:

static int bn2binpad(const BIGNUM *a, unsigned char *to, int tolen)
{
    int n;
    size_t i, lasti, j, atop, mask;
    BN_ULONG l;

    /*
     * In case |a| is fixed-top, BN_num_bytes can return bogus length,
     * but it's assumed that fixed-top inputs ought to be "nominated"
     * even for padded output, so it works out...
     */
    n = BN_num_bytes(a);
    if (tolen == -1) {
        tolen = n;
    } else if (tolen < n) {     /* uncommon/unlike case */
        BIGNUM temp = *a;

        bn_correct_top(&temp);
        n = BN_num_bytes(&temp);
        if (tolen < n)
            return -1;
    }

    /* Swipe through whole available data and don't give away padded zero. */
    atop = a->dmax * BN_BYTES;
    if (atop == 0) {
        OPENSSL_cleanse(to, tolen);
        return tolen;
    }

    lasti = atop - 1;
    atop = a->top * BN_BYTES;
    for (i = 0, j = 0, to += tolen; j < (size_t)tolen; j++) {
        l = a->d[i / BN_BYTES];
        mask = 0 - ((j - atop) >> (8 * sizeof(i) - 1));
        *--to = (unsigned char)(l >> (8 * (i % BN_BYTES)) & mask);
        i += (i - lasti) >> (8 * sizeof(i) - 1); /* stay on last limb */
    }

    return tolen;
}

答案 1 :(得分:0)

  

BN_bn2bin“创建一个真正的二进制表示形式(即   位序列)。更具体地说,它创建了一个大端   数字的表示形式。”因此,这不只是0和   1s,对吧?

此处提到的位序列表示为字节数组。每个字节包含8位,这可以解释为“ 0和1的数组”。如果您要问的话,它不是“具有0或1的整数数组”。

由于您不清楚BN_bn2bin()的工作原理,因此仅分析代码段的最终结果会有所帮助。您可以这样做(忽略任何错误检查):

#include <stdio.h>
#include <openssl/bn.h>

int main(
    int argc,
    char **argv)
{
    const char *hexString = argv[1];

    BIGNUM *bnEncr = BN_new();
    BN_hex2bn(&bnEncr, hexString);
    unsigned int numOfBytesEncr = BN_num_bytes(bnEncr);
    unsigned char encrBin[numOfBytesEncr];
    BN_bn2bin(bnEncr, encrBin);
    fwrite(encrBin, 1, numOfBytesEncr, stdout);
}

这会将encrBin的内容输出到标准输出,这从来都不是一件容易的事,但是您可以通过hexdump之类的工具将其传输,或将其重定向到文件中用十六进制编辑器进行分析。看起来像这样:

$ ./bntest 74162ac74759e85654e0e7762c2cdd26 | hexdump -C
00000000  74 16 2a c7 47 59 e8 56  54 e0 e7 76 2c 2c dd 26 |t.*.GY.VT..v,,.&|
00000010

或者,如果您确实希望看到这些0和1:

$ ./bntest  74162ac74759e85654e0e7762c2cdd26 | xxd -b -c 4
00000000: 01110100 00010110 00101010 11000111  t.*.
00000004: 01000111 01011001 11101000 01010110  GY.V
00000008: 01010100 11100000 11100111 01110110  T..v
0000000c: 00101100 00101100 11011101 00100110  ,,.&

这表明您的问题

  

有人可以解释我如何进行hex->(真正)二进制转换   我自己使用C语言,所以我会得到EVP_DecryptUpdate期望的格式吗?   这很复杂吗?

本质上与SO问题How to turn a hex string into an unsigned char array?相同,就像我commented一样。