山东大学软件工程应用与实践——GMSSL开源库(七)——SM9密钥交换的源代码分析
2021SC@SDUSC
文章目录
- int SM9_generate_key_exchange
- SM9_compute_share_key_A
- int SM9_compute_share_key_B
- 小结
把密钥交换流程图重新放到这里,供下文代码分析时更好理解。
以下代码在\GmSSL-master\crypto\sm9\sm9_exch.c中
int SM9_generate_key_exchange

进行密钥交换前的一系列准备工作
1、 生成[1,n-1]的随机数r
do {if (!BN_rand_range(r, n)) {SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_BN_LIB);goto end;}} while (BN_is_zero(r));
2、hash1函数使用的是哪种密码杂凑函数,给md赋上不同的值
switch (OBJ_obj2nid(sk->hash1)) {case NID_sm9hash1_with_sm3:md = EVP_sm3();break;case NID_sm9hash1_with_sha256:md = EVP_sha256();break;default:SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);goto end;}
3、从sk中计算出Ppub-e来
if (!EC_POINT_oct2point(group, Ppube, ASN1_STRING_get0_data(sk->pointPpub),ASN1_STRING_length(sk->pointPpub), bn_ctx)) {SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);goto end;}
4、计算Q和R
/*计算H1(peer_id)*/
if (!SM9_hash1(md, &h, peer_id, peer_idlen, SM9_HID_EXCH, n, bn_ctx)) {SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);goto end;}
if (!EC_POINT_mul(group, Q, h, NULL, NULL, bn_ctx)/* Q = H1(peer_id) * P1 + Ppube */|| !EC_POINT_add(group, Q, Q, Ppube, bn_ctx)/* R = r * Q */|| !EC_POINT_mul(group, Q, NULL, Q, r, bn_ctx)|| (len = EC_POINT_point2oct(group, Q, point_form, R, *Rlen, bn_ctx)) <= 0) {SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);goto end;}
5、计算g和g’
if (!rate_pairing(g, NULL, Ppube, bn_ctx)) {SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);goto end;}
if (!fp12_pow(g, g, r, p, bn_ctx) || !fp12_to_bin(g, gr)) {SM9err(SM9_F_SM9_GENERATE_KEY_EXCHANGE, ERR_R_SM9_LIB);goto end;}
SM9_compute_share_key_A

1、首先给md赋值,函数KDF使用不同的哈希函数给md赋不同的值。
switch (type) {case NID_sm9kdf_with_sm3:md = EVP_sm3();break;case NID_sm9kdf_with_sha256:md = EVP_sha256();break;default:goto end;}
2、计算deA、Rb
if (ASN1_STRING_length(skA->privatePoint) != 129|| !point_from_octets(&deA, ASN1_STRING_get0_data(skA->privatePoint), p, bn_ctx)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);goto end;}
if (!EC_POINT_oct2point(group, P, RB, 65, bn_ctx)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);goto end;}
3、计算g2’和g3’
if (!rate_pairing(g, &deA, P, bn_ctx) || !fp12_to_bin(g, buf)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);goto end;}if (!fp12_pow(g, g, rA, p, bn_ctx) || !fp12_to_bin(g, buf + 384)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_SM9_LIB);goto end;}
4、计算SKA
while (SKAlen > 0) {unsigned char key[64];unsigned int len;if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)|| !EVP_DigestUpdate(md_ctx, g1, 384)|| !EVP_DigestUpdate(md_ctx, buf, sizeof(buf))|| !EVP_DigestUpdate(md_ctx, counter, 4)|| !EVP_DigestFinal_ex(md_ctx, key, &len)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);goto end;}if (len > SKAlen)len = SKAlen;memcpy(SKA, key, len);SKA += len;SKAlen -= len;counter[3]++;}
5、选项部分,进行S1的计算,并进行验证
if (SA) {unsigned char S1[32];/* dgst = H(g2 || g3 || ID_A || ID_B || R_A || R_B) */if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, buf, sizeof(buf))|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)|| !EVP_DigestFinal_ex(md_ctx, dgst, &dgstlen)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);goto end;}/* S1 = H(0x82 || g1' || dgst) */if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, x82, 1)|| !EVP_DigestUpdate(md_ctx, g1, 384)|| !EVP_DigestUpdate(md_ctx, dgst, dgstlen)|| !EVP_DigestFinal_ex(md_ctx, S1, &dgstlen)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_A, ERR_R_EVP_LIB);goto end;}
int SM9_compute_share_key_B

与int SM9_compute_share_key_A的实现差不多,不再次进行说明,仅把源代码粘贴到这里,以供分析:
int SM9_compute_share_key_B(int type,unsigned char *SKB, size_t SKBlen,unsigned char SB[32], /* optional, send to A */unsigned char S2[32], /* optional, to be compared with recved SA */const BIGNUM *rB,const unsigned char RB[65],const unsigned char RA[65],const unsigned char g2[384],const char *IDA, size_t IDAlen,SM9PrivateKey *skB)
{int ret = 0;const EVP_MD *md = EVP_sm3();const char *IDB;int IDBlen;EC_GROUP *group = NULL;EC_POINT *P = NULL;EVP_MD_CTX *md_ctx = NULL;BN_CTX *bn_ctx = NULL;fp12_t g;point_t deB;const BIGNUM *p = SM9_get0_prime();unsigned char x82[1] = {0x82};unsigned char x83[1] = {0x83};unsigned char g1[384];unsigned char g3[384];unsigned char counter[4] = {0, 0, 0, 1};unsigned char key[EVP_MAX_MD_SIZE];unsigned int len;switch (type) {case NID_sm9kdf_with_sm3:md = EVP_sm3();break;case NID_sm9kdf_with_sha256:md = EVP_sha256();break;default:goto end;}/* get IDB */IDB = (char *)ASN1_STRING_get0_data(skB->identity);IDBlen = ASN1_STRING_length(skB->identity);/* malloc */if (!(group = EC_GROUP_new_by_curve_name(NID_sm9bn256v1))|| !(P = EC_POINT_new(group))|| !(md_ctx = EVP_MD_CTX_new())|| !(bn_ctx = BN_CTX_new())) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_MALLOC_FAILURE);goto end;}BN_CTX_start(bn_ctx);if (!point_init(&deB, bn_ctx)|| !fp12_init(g, bn_ctx)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_MALLOC_FAILURE);goto end;}/* parse deB */if (ASN1_STRING_length(skB->privatePoint) != 129|| !point_from_octets(&deB, ASN1_STRING_get0_data(skB->privatePoint), p, bn_ctx)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);goto end;}/* parse RA */if (!EC_POINT_oct2point(group, P, RA, 65, bn_ctx)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);goto end;}/* g1 = e(RA, deB) */if (!rate_pairing(g, &deB, P, bn_ctx) || !fp12_to_bin(g, g1)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);goto end;}/* g3 = (g1)^r_B */if (!fp12_pow(g, g, rB, p, bn_ctx) || !fp12_to_bin(g, g3)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_SM9_LIB);goto end;}/* SKB = KDF(ID_A || ID_B || R_A || R_B || g1 || g2 || g3, Klen) */while (SKBlen > 0) {if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)|| !EVP_DigestUpdate(md_ctx, g1, 384)|| !EVP_DigestUpdate(md_ctx, g2, 384)|| !EVP_DigestUpdate(md_ctx, g3, 384)|| !EVP_DigestUpdate(md_ctx, counter, 4)|| !EVP_DigestFinal_ex(md_ctx, key, &len)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);goto end;}if (len > SKBlen)len = SKBlen;memcpy(SKB, key, len);SKB += len;SKBlen -= len;counter[3]++;}/* compute optional S1 */if (S2 && SB) {/* dgst = H(g2 || g3 || ID_A || ID_B || R_A || R_B) */if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, g2, 384)|| !EVP_DigestUpdate(md_ctx, g3, 384)|| !EVP_DigestUpdate(md_ctx, IDA, IDAlen)|| !EVP_DigestUpdate(md_ctx, IDB, IDBlen)|| !EVP_DigestUpdate(md_ctx, RA + 1, 64)|| !EVP_DigestUpdate(md_ctx, RB + 1, 64)|| !EVP_DigestFinal_ex(md_ctx, key, &len)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);goto end;}/* SB = H(0x82 || g1 || dgst) */if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, x82, 1)|| !EVP_DigestUpdate(md_ctx, g1, 384)|| !EVP_DigestUpdate(md_ctx, key, len)|| !EVP_DigestFinal_ex(md_ctx, SB, &len)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);goto end;}/* S2 = H(0x83 || g1 || dgst) */if (!EVP_DigestInit_ex(md_ctx, md, NULL)|| !EVP_DigestUpdate(md_ctx, x83, 1)|| !EVP_DigestUpdate(md_ctx, g1, 384)|| !EVP_DigestUpdate(md_ctx, key, len)|| !EVP_DigestFinal_ex(md_ctx, S2, &len)) {SM9err(SM9_F_SM9_COMPUTE_SHARE_KEY_B, ERR_R_EVP_LIB);goto end;}}ret = 1;end:EC_GROUP_free(group);EC_POINT_free(P);EVP_MD_CTX_free(md_ctx);fp12_cleanup(g);point_cleanup(&deB);if (bn_ctx) {BN_CTX_end(bn_ctx);}BN_CTX_free(bn_ctx);OPENSSL_cleanse(key, sizeof(key));return ret;
}
小结
随着我对源代码的一步步阅读与分析,更加能体会到GMSSL在整体架构上的完善性。结构体封装的比较好,使我一开始阅读起来没有那么顺利。慢慢的针对有关密码学内容的进一步学习以及对GMSSL变量参数的进一步熟悉,代码的阅读渐渐地没有那么困难了。
密钥交换是公钥密码体制的一大功能。根据国家发布的GMT 0044.3-2016 SM9 标识密码算法 第3部分:密钥交换协议中描述的SM9密钥交换协议的具体流程图内容,sm9_exch.c文件按照流程一步步编写代码内容,结合文章开始的流程图以及代码中少量的注释来阅读代码,可读性较强,理解起来问题不大。
SM9的密钥交换的主体较为底层的内容都在上述的代码中已经实现,上层可以通过GMSSL已经封装好的接口直接进行调用。
如有不足或错误,欢迎指正。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
