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

把密钥交换流程图重新放到这里,供下文代码分析时更好理解。
以下代码在\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已经封装好的接口直接进行调用。
如有不足或错误,欢迎指正。

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)