2401_84287747 2026-04-14 09:43 采纳率: 0%
浏览 3

openssl sm2的密钥协商报错,如何解决?

生成的sm密钥对,调用EVP_PKEY_derive_init时报错,operation not supported for this keytype 密钥的keytype是408,openssl3.4

  • 写回答

2条回答 默认 最新

  • 檀越@新空间 2026-04-14 09:44
    关注

    上午好☀️☀️☀️️
    本答案参考通义千问

    你遇到的问题是使用 OpenSSL 的 SM2(国密算法)进行密钥协商时,调用 EVP_PKEY_derive_init 时报错:operation not supported for this keytype,并且发现密钥的 keytype 是 408。这表明当前使用的密钥类型不支持密钥协商操作。


    ✅ 问题分析

    在 OpenSSL 中,某些加密算法并不支持密钥协商(key agreement),例如 SM2 在某些版本或配置下可能不支持直接通过 EVP_PKEY_derive_* 接口进行密钥派生。特别是当你使用的是 EVP_PKEY 类型为 408(即 SM2 密钥)时,OpenSSL 可能没有实现相应的密钥协商功能。

    📌 关键点:

    • SM2 算法本身是基于 ECC 的公钥算法,理论上应该支持密钥协商。
    • 但在 OpenSSL 3.4 版本中,SM2 的密钥协商功能可能未完全实现或未启用
    • 错误信息 “operation not supported for this keytype” 表示该密钥类型不支持 EVP_PKEY_derive 操作。

    🔧 解决方案

    1. 确认是否支持 SM2 密钥协商

    你可以先检查当前 OpenSSL 是否支持 SM2 密钥协商:

    #include <openssl/evp.h>
    #include <openssl/sm2.h>
    
    int main() {
        EVP_PKEY *pkey = EVP_PKEY_new();
        // 生成 SM2 密钥对
        // ... (省略生成代码)
    
        int ret = EVP_PKEY_derive_init(pkey);
        if (ret != 1) {
            fprintf(stderr, "Error: %s\n", ERR_error_string(ERR_get_error(), NULL));
        } else {
            printf("Supported.\n");
        }
    
        EVP_PKEY_free(pkey);
        return 0;
    }
    

    如果返回值为 0 或错误信息提示不支持,则说明当前环境不支持 SM2 密钥协商。


    2. 确保 OpenSSL 编译时启用了 SM2 支持

    如果你使用的是自定义编译的 OpenSSL,需要确保以下配置已启用:

    ./Configure --prefix=/usr/local/ssl --openssldir=/usr/local/ssl enable-sm2
    

    然后重新编译并安装 OpenSSL。


    3. 使用 EVP_PKEY_CTX 进行密钥协商(如果支持)

    如果 SM2 支持密钥协商,可以尝试如下方式:

    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
    if (!ctx) {
        // handle error
    }
    
    if (EVP_PKEY_derive_init(ctx) <= 0) {
        // handle error
    }
    
    // 设置对方公钥
    EVP_PKEY *peer_pkey = ...; // 对方 SM2 公钥
    if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
        // handle error
    }
    
    unsigned char *shared_key = malloc(32); // SM2 使用 32 字节共享密钥
    size_t shared_key_len;
    
    if (EVP_PKEY_derive(ctx, shared_key, &shared_key_len) <= 0) {
        // handle error
    }
    
    // 使用 shared_key...
    free(shared_key);
    EVP_PKEY_CTX_free(ctx);
    

    4. 使用 EC_KEY 替代 EVP_PKEY(如果可行)

    由于 SM2 实际上是基于 EC 的,你可以尝试使用 EC_KEY 代替 EVP_PKEY 来执行密钥协商,这通常更稳定。

    示例代码:

    #include <openssl/ec.h>
    #include <openssl/sm2.h>
    
    int main() {
        const EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_sm2);
        EC_KEY *eckey = EC_KEY_new_group(group);
        EC_KEY_generate_key(eckey);
    
        EC_KEY *peer_eckey = ...; // 对方 SM2 公钥
    
        unsigned char shared_key[32];
        size_t shared_key_len;
    
        if (EC_DH_compute_key(shared_key, EC_KEY_get_public_key(peer_eckey), eckey) <= 0) {
            // handle error
        }
    
        // 使用 shared_key...
        EC_KEY_free(eckey);
        EC_KEY_free(peer_eckey);
        EC_GROUP_free(group);
        return 0;
    }
    

    ⚠️ 注意:EC_DH_compute_key 在 OpenSSL 中用于 ECDH 协商,但 SM2 的密钥协商可能需要特定处理,如签名或加解密。


    5. 升级 OpenSSL 或使用兼容库

    如果你使用的是较旧版本的 OpenSSL(如 3.4),建议考虑:

    • 升级到更高版本(如 3.7 或以上),因为新版本可能已经修复了 SM2 相关的 bug。
    • 使用其他支持 SM2 的库,如 Bouncy Castle(Java)、Go 标准库等。

    📝 总结

    | 步骤 | 内容 | |------|------| | 1 | 确认 SM2 是否支持密钥协商 | | 2 | 确保 OpenSSL 编译时启用了 SM2 支持 | | 3 | 使用 EVP_PKEY_CTX 进行密钥协商(如支持) | | 4 | 尝试使用 EC_KEY 替代 EVP_PKEY | | 5 | 升级 OpenSSL 或使用其他兼容库 |


    💡 建议

    • 如果你只是做 SM2 密钥协商,建议使用 EC_KEY 而不是 EVP_PKEY
    • 如果仍然无法解决,建议查看 OpenSSL 官方文档或提交 issue 到 OpenSSL GitHub

    如有需要,我可以提供完整的 SM2 密钥协商示例代码。请告诉我你使用的语言和具体需求。

    评论

报告相同问题?

问题事件

  • 创建了问题 4月14日