C语言加载OpenSSL生成的secp256k1 ECIES公钥时EC_POINT_hex2point返回NULL问题求助
解决EC_POINT_hex2point返回NULL的问题
你踩了一个OpenSSL ECC开发里的常见误区——直接把PEM公钥文件转成十六进制,根本不是EC_POINT_hex2point需要的格式。让我帮你一步步理清问题、解决问题:
问题根源
PEM格式的公钥是ASN.1 DER编码后,再套上Base64和页眉页脚的结构化数据,里面包含了椭圆曲线参数、公钥点的包装信息;而EC_POINT_hex2point只认原始的椭圆曲线点十六进制串(要么是压缩格式:开头02/03+32字节X坐标;要么是非压缩格式:开头04+32字节X+32字节Y)。直接转PEM的十六进制会带上ASN.1的结构头,自然无法被解析成有效点。
正确提取公钥点的十六进制数据
先从PEM公钥里导出原始的EC点数据,再转成十六进制:
方法1:用OpenSSL命令直接提取
执行这条命令,就能得到可直接用的非压缩格式公钥点十六进制串:
openssl ec -in alice_pub_key.pem -pubin -text -noout | grep -A 2 "pub:" | tail -n 2 | tr -d '\n :'
输出会是类似这样的字符串(开头04是格式标识,后面是X+Y坐标的十六进制):
04ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890
方法2:导出DER格式后截取有效部分
先导出不含PEM包装的DER格式公钥,再转十六进制,然后截取最后65字节(非压缩)或33字节(压缩)的内容:
openssl ec -in alice_pub_key.pem -pubin -outform DER | hexdump -v -e '/1 "%02X"'
输出的长串里,从04开始的后续65字节就是你需要的原始点数据。
修正后的代码示例
拿到正确的十六进制点串后,用以下代码加载(记得加上错误检查,避免内存泄漏):
#include <openssl/ec.h> #include <openssl/obj_mac.h> #include <stdio.h> int main() { // 替换成你提取到的正确公钥点十六进制串 const char* pub_hex = "04ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890"; EC_KEY* key = EC_KEY_new_by_curve_name(NID_secp256k1); if (!key) { fprintf(stderr, "Failed to create EC_KEY\n"); return 1; } const EC_GROUP* group = EC_KEY_get0_group(key); if (!group) { fprintf(stderr, "Failed to get EC_GROUP\n"); EC_KEY_free(key); return 1; } EC_POINT* pub_key = EC_POINT_new(group); if (!pub_key) { fprintf(stderr, "Failed to create EC_POINT\n"); EC_KEY_free(key); return 1; } // 解析十六进制点 if (!EC_POINT_hex2point(group, pub_hex, pub_key, NULL)) { fprintf(stderr, "EC_POINT_hex2point failed\n"); EC_POINT_free(pub_key); EC_KEY_free(key); return 1; } // 将公钥点关联到EC_KEY if (EC_KEY_set_public_key(key, pub_key) != 1) { fprintf(stderr, "Failed to set public key to EC_KEY\n"); EC_POINT_free(pub_key); EC_KEY_free(key); return 1; } printf("Successfully loaded public key\n"); // 资源释放 EC_POINT_free(pub_key); EC_KEY_free(key); return 0; }
更简便的替代方案:直接加载PEM公钥
其实你完全不需要手动处理十六进制点,OpenSSL提供了直接从PEM文件加载公钥的API,更可靠还省事儿:
#include <openssl/ec.h> #include <openssl/pem.h> #include <stdio.h> int main() { FILE* pub_file = fopen("alice_pub_key.pem", "r"); if (!pub_file) { fprintf(stderr, "Failed to open public key file\n"); return 1; } EC_KEY* key = PEM_read_EC_PUBKEY(pub_file, NULL, NULL, NULL); fclose(pub_file); if (!key) { fprintf(stderr, "Failed to load PEM public key\n"); return 1; } printf("Successfully loaded PEM public key\n"); EC_KEY_free(key); return 0; }
内容的提问来源于stack exchange,提问作者Baboo Patel
相关产品推荐
相关产品推荐

