当前位置: 首页 > news >正文

【加密算法】SM2密钥生成与转换详解:从原理到代码实现

一、前言

在国密算法体系中,SM2是基于椭圆曲线密码(ECC)的非对称加密算法,广泛应用于数字签名、密钥交换等领域。在前文中,我们实现了SM2的加解密、签名与验签功能,但缺少密钥生成模块。本文将深入探讨SM2密钥的生成原理,并提供完整的C++实现代码,涵盖密钥生成公私钥转换十六进制编码等核心功能。


二、SM2密钥生成原理

1. 私钥的本质

SM2私钥是一个随机整数 d,需满足:

d∈[1, n−1]

其中 n 是椭圆曲线生成元 G 的阶,对应SM2标准中预定义的256位大数。

2. 公钥的生成

公钥是椭圆曲线上的一个点 Q,由私钥 d 与生成元 G 通过点乘运算得到:

Q=d⋅G

Q 的坐标 (x, y) 以64字节大端序存储。


三、核心代码实现

1. 密钥对生成函数 GenerateKey

void GenerateKey(SM2_KEY& key) {SM2_BN d;SM2_JACOBIAN_POINT Q;// 生成私钥d,确保范围合法do {if (fn_rand(d) != 1) {throw std::runtime_error("Private key generation failed");}} while (bn_is_zero(d) || bn_cmp(d, SM2_N) >= 0);// 计算公钥Q = d*Gjacobian_point_mul_generator(&Q, d);// 转换私钥为字节bn_to_bytes(d, key.private_key);// 将公钥坐标转为字节存储jacobian_point_to_bytes(&Q, (uint8_t*)&key.public_key);
}

关键点:
循环生成:确保私钥不为零且小于 n
点乘优化:使用雅可比坐标提升计算效率。
内存安全:敏感数据在栈中自动清理。

无效
有效
开始
生成随机数d
fn_rand成功?
检查 1< d < n-1
抛出异常
计算公钥 Q = d·G
转换私钥为字节数组
转换公钥坐标到字节
结束

2. 私钥转公钥函数 CalcPubKey

void CalcPubKey(const char pri_key[64], char pub_key[128]) {char bin_key[32] = {0};size_t out_len = 32;// 十六进制转二进制SM2::Hex2Bin(pri_key, 64, bin_key, out_len);SM2_BN d;bn_from_bytes(d, (uint8_t*)bin_key);// 计算公钥Q = d*GSM2_JACOBIAN_POINT Q;jacobian_point_mul_generator(&Q, d);// 转换坐标并输出十六进制SM2_POINT point;jacobian_point_to_bytes(&Q, (uint8_t*)&point);out_len = 128;SM2::Bin2Hex((char*)&point, 64, pub_key, out_len);
}

流程解析:

  1. 解码私钥:将64字符十六进制字符串转为32字节二进制。
  2. 重建公钥:通过点乘运算生成公钥点。
  3. 编码输出:将坐标转为128字符十六进制字符串。
密钥转换
密钥生成
输出
输出
输出
输出
密钥转HEX
私钥推导公钥
key
GenerateKey
私钥:64字符
公钥:128字符
推导公钥

3. 密钥转十六进制 Key2Hex

void Key2Hex(const SM2_KEY& key, char pri_key[64], char pub_key[128]) {// 私钥转HEXsize_t out_len = 64;SM2::Bin2Hex((char*)key.private_key, 32, pri_key, out_len);// 公钥转HEXout_len = 128;SM2::Bin2Hex((char*)&key.public_key, 64, pub_key, out_len);
}

输出格式:
私钥:64字符,如 "81EB26E941BB5AF16DF116495F90695272AE2CD63D6C4AE1678418E33730E700"
公钥:128字符,包含 xy 坐标,如 "55B40D0660A35C53..."


四、使用示例

int main() 
{SM2 sm2;// 生成密钥SM2_KEY key;char pPriKey[200] = { 0 };char pPubKey[200] = { 0 };sm2.GenerateKey(key);sm2.Key2Hex(key, pPriKey, pPubKey);std::cout << "密钥生成成功:\n私钥:" << pPriKey << "\n公钥:" << pPubKey << std::endl;memset(pPubKey, 0, sizeof(pPubKey));sm2.CalcPubKey(pPriKey, pPubKey);std::cout << "私钥计算公钥成功:\n私钥:" << pPriKey << "\n公钥:" << pPubKey << std::endl;if (!sm2.InitKey(priKey, pubKey)){std::cout << "初始化SM2密钥失败" << std::endl;return;}std::cout << "测试数据:" << strlen(pMsg) << "," << pMsg << std::endl;
}

输出示例:

密钥生成成功:
私钥:f24b1939308a8e235cdecb742a9aae924fa9983c58dbc96ae66eba37c634cb8a
公钥:81d02cff7051b8183a4a2adaddf555f10f7aad5f93eb4b5b3bb1c00247201dda2755ac0329bc8aadcab2498473538a85d9d860094e0e9b1f5b9579fc84c118a4
私钥计算公钥成功:
私钥:f24b1939308a8e235cdecb742a9aae924fa9983c58dbc96ae66eba37c634cb8a
公钥:81d02cff7051b8183a4a2adaddf555f10f7aad5f93eb4b5b3bb1c00247201dda2755ac0329bc8aadcab2498473538a85d9d860094e0e9b1f5b9579fc84c118a4

五、安全注意事项

  1. 私钥保护:生成后应立即加密存储,避免内存泄漏。
  2. 随机数质量:使用符合国密标准的密码学安全随机数生成器(如 /dev/urandom)。
  3. 输入校验:在 CalcPubKey 中需验证私钥的合法性。

六、总结

本文完善了SM2算法的密钥管理模块,通过底层椭圆曲线运算实现了密钥生成、转换和推导功能。这些函数为构建完整的SM2应用(如数字证书、安全通信)奠定了基础。在实际应用中,需结合具体场景强化密钥生命周期管理,确保符合国密合规要求。

相关文章:

  • ecovadis分为哪些类别,要进行ecovadis认证有什么要求
  • 榕壹云场馆预定系统:基于ThinkPHP+MySQL+UniApp打造的全能运动馆智慧运营解决方案
  • 解锁Grok-3的极致潜能:高阶应用与创新实践
  • 多模态大模型文字识别 vs OCR识别模型
  • 【Python进阶】断言(assert)的十大核心应用场景解析
  • RelativeLayout(相对布局)
  • Mac电脑交叉编译iphone设备可以运行的redsocks, openssl, libsevent
  • Rust + WebAssembly 性能剖析指南
  • 辛格迪客户案例 | 厦门三维丝实施SAP系统
  • js ES6箭头函数的作用
  • 0415-批量删除操作
  • ERR_PNPM_DLX_NO_BIN No binaries found in tailwindcss
  • ClickHouse 数据库中的 “超时”
  • 游戏引擎学习第227天
  • Java微服务线程隔离技术对比:线程池隔离 vs 信号量隔离
  • union all 关联查询
  • OpenAI发布GPT-4.1:开发者专属模型的深度解析 [特殊字符]
  • 无服务器架构(Serverless)在Web开发与云原生中的应用研究
  • 外接键盘与笔记本命令键键位不同解决方案(MacOS)
  • 蓝桥杯 1.路径之谜
  • 美国土安全部长餐厅遇窃,重要证件被盗走
  • 用8年还原曹操墓鉴定过程,探寻曹操墓新书创作分享会举行
  • 韩国新一届总统选举将于6月3日举行,民调显示李在明继续领跑
  • 国安部:机关工作人员用软件扫描涉密文件备份网盘致重大泄密
  • 瑞士成第15届北影节主宾国,6部佳作闪耀“瑞士电影周”
  • 中国船协发布关于美对华造船业实施限制措施的严正声明