You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 18:09:10