生成的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 密钥协商示例代码。请告诉我你使用的语言和具体需求。
解决 无用评论 打赏 举报