使用OpenSSL在C语言中将unsigned char[]类型哈希值转换为BIGNUM时输出为0的问题排查及转换方法咨询
问题分析与解决
你遇到的问题根源在于对BN_hex2bn的参数理解有误:这个函数要求输入的是十六进制编码的ASCII字符串,但你传入的hash是二进制原始哈希数据(比如SHA-256哈希是32字节的二进制值),不是ASCII格式的十六进制字符串,所以函数无法正确解析,最终得到的BIGNUM自然是0。
最优解决方案:直接用BN_bin2bn转换
OpenSSL提供了专门的函数BN_bin2bn,可以直接将二进制数据转换为BIGNUM,完全不需要先转成十六进制字符串,这是最高效、最直接的方法,函数定义如下:
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
s:二进制数据的指针(也就是你的hash数组)len:二进制数据的长度(你的hash_size)ret:要写入的BIGNUM指针(如果传NULL会自动创建新的BIGNUM)
修改后的代码片段:
BIGNUM *h; h = BN_new(); unsigned char hash[EVP_MAX_MD_SIZE]; unsigned hash_size = EVP_MAX_MD_SIZE; EVP_DigestFinal_ex(hash_ctx, hash, &hash_size); EVP_MD_CTX_free(hash_ctx); // 打印哈希值 for (unsigned n = 0; n < hash_size; n++) { printf("%02hhx", hash[n]); } printf("\n"); // 直接将二进制哈希转换为BIGNUM BN_bin2bn(hash, hash_size, h); BN_print(bio_out, h);
如果你坚持用BN_hex2bn的转换方法
如果一定要通过十六进制字符串中转,那需要先把二进制hash数组转换成对应的ASCII十六进制字符串,再传给BN_hex2bn。步骤如下:
- 分配足够的字符串空间:每个字节对应2个十六进制字符,所以字符串长度是
hash_size * 2 + 1(+1是为了存储字符串终止符\0) - 遍历二进制数组,将每个字节转换为两个十六进制字符
- 调用
BN_hex2bn,之后记得释放字符串内存
示例代码:
// ... 前面的哈希计算代码不变 ... // 转换二进制哈希为十六进制字符串 char *hex_str = malloc(hash_size * 2 + 1); if (!hex_str) { // 处理内存分配失败 BN_free(h); return -1; } for (unsigned n = 0; n < hash_size; n++) { sprintf(hex_str + n*2, "%02x", hash[n]); } hex_str[hash_size * 2] = '\0'; // 用十六进制字符串初始化BIGNUM BN_hex2bn(&h, hex_str); BN_print(bio_out, h); // 别忘了释放字符串 free(hex_str);
注意:这种方法多了一次字符串转换的开销,性能不如直接用BN_bin2bn,所以更推荐第一种方案。
内容的提问来源于stack exchange,提问作者CipherX
相关产品推荐
相关产品推荐

