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已经封装好的接口直接进行调用。

如有不足或错误,欢迎指正。

Logo

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

更多推荐