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

OpenSSL 1.1.1下X25519 ECDH实现:密钥导出与导入求助

X25519 ECDH公钥导出与导入解决方案

你提到用EC_KEY_new_by_curve_name(NID_X25519)失败是正常的——OpenSSL里X25519属于EVP_PKEY框架下的密钥类型,EC_KEY这套API并不支持它,所以你用EVP_PKEY生成密钥的路子完全正确。下面直接给你公钥导出、导入的具体实现,附完整代码示例:

一、导出无压缩二进制公钥

X25519的公钥本身就是固定32字节的无压缩格式,不需要额外处理,直接用EVP_PKEY_get_raw_public_key就能提取原始二进制数据:

#include <openssl/evp.h>
#include <stdio.h>
#include <stdlib.h>

// 导出X25519公钥为32字节二进制
int export_x25519_public_key(EVP_PKEY *pkey, unsigned char **out_pub, size_t *out_len) {
    if (!pkey || !out_pub || !out_len) return 0;

    // X25519公钥固定32字节,直接分配内存
    *out_len = 32;
    *out_pub = malloc(*out_len);
    if (!*out_pub) return 0;

    // 提取原始公钥
    if (EVP_PKEY_get_raw_public_key(pkey, *out_pub, out_len) != 1) {
        free(*out_pub);
        *out_pub = NULL;
        return 0;
    }

    // 校验公钥长度(确保没有异常)
    if (*out_len != 32) {
        free(*out_pub);
        *out_pub = NULL;
        return 0;
    }

    return 1;
}

调用时把你生成的pkey传进去就行,拿到的out_pub就是32字节的无压缩公钥二进制,记得用完要手动free释放内存。

二、导入对方的32字节二进制公钥

导入同样用EVP_PKEY框架,通过EVP_PKEY_fromdata加载原始公钥数据:

// 从32字节二进制导入X25519公钥
EVP_PKEY *import_x25519_public_key(const unsigned char *pub_data, size_t pub_len) {
    if (!pub_data || pub_len != 32) return NULL;

    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(NID_X25519, NULL);
    if (!ctx) return NULL;

    EVP_PKEY *pkey = NULL;
    // 初始化公钥导入上下文
    if (EVP_PKEY_fromdata_init(ctx) != 1) {
        EVP_PKEY_CTX_free(ctx);
        return NULL;
    }

    // 设置导入类型为公钥
    if (EVP_PKEY_CTX_set_type(ctx, EVP_PKEY_PUBLIC_KEY) != 1) {
        EVP_PKEY_CTX_free(ctx);
        return NULL;
    }

    // 从原始二进制数据加载公钥
    if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, pub_data, pub_len) != 1) {
        EVP_PKEY_CTX_free(ctx);
        return NULL;
    }

    EVP_PKEY_CTX_free(ctx);
    return pkey;
}

注意:传入的公钥必须是严格32字节的X25519公钥,否则导入会失败。拿到返回的EVP_PKEY后,用完要调用EVP_PKEY_free释放资源。

三、补充:完成ECDH密钥交换(生成共享密钥)

既然你在做ECDH,顺便给你加个生成共享密钥的示例,把导入的对方公钥和自己的私钥结合起来:

// 生成X25519共享密钥
int generate_shared_secret(EVP_PKEY *my_privkey, EVP_PKEY *peer_pubkey, unsigned char **shared_secret, size_t *secret_len) {
    if (!my_privkey || !peer_pubkey || !shared_secret || !secret_len) return 0;

    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(my_privkey, NULL);
    if (!ctx) return 0;

    int ret = 0;
    // 初始化密钥派生上下文
    if (EVP_PKEY_derive_init(ctx) != 1) goto cleanup;

    // 设置对方的公钥
    if (EVP_PKEY_derive_set_peer(ctx, peer_pubkey) != 1) goto cleanup;

    // 先获取共享密钥的长度
    if (EVP_PKEY_derive(ctx, NULL, secret_len) != 1) goto cleanup;

    // 分配内存存储共享密钥
    *shared_secret = malloc(*secret_len);
    if (!*shared_secret) goto cleanup;

    // 生成共享密钥
    if (EVP_PKEY_derive(ctx, *shared_secret, secret_len) != 1) {
        free(*shared_secret);
        *shared_secret = NULL;
        goto cleanup;
    }

    ret = 1;

cleanup:
    EVP_PKEY_CTX_free(ctx);
    return ret;
}

X25519的共享密钥也是固定32字节,所以secret_len最终会是32。

注意事项

  • 所有OpenSSL函数调用都要检查返回值(我上面的代码都加了基本的错误处理),避免内存泄漏或逻辑错误;
  • 编译的时候要链接OpenSSL库,比如用gcc your_code.c -o your_code -lcrypto;
  • 确保你的OpenSSL版本是1.1.0及以上——X25519支持是从这个版本开始加入的。

内容的提问来源于stack exchange,提问作者Anton Vainer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:01:07