一、前提描述

库地址:https://github.com/guanzhi/GmSSL/releases/tag/v3.1.1
设备环境:STM32F407裸机
公钥类型:非压缩公钥( 0x04 || x || y );
密文长度:96+明文长度:C1(64字节(x:32B + y:32B)) + C3(32字节) + C2(明文长度nB);

二、粗略描述加密过程:

(1)获得公钥x和y

1.如果是非压缩公钥04开头,那么接着64字节分别是公钥x与y,直接使用即可;
2.如果是base64格式,需要先decode得到十六进制公钥,再判断是否为非压缩公钥;
3.如果不是非压缩公钥,那么不需要继续往后看了,本文只描述非压缩公钥加密;

(2)加密数据C1

使用随机数计算得到,固定64字节(C1_x:32B + C1_y:32B)。如果每次加密得到C1数据都是一样的,那么产生随机数函数有误;

(3)加密数据C2和C3

1.继续使用随机数K与公钥P获得派生x2/y2(跟公钥x/y不一样);(K*P=(x2,y2),没看懂源码如何计算);
2.t = KDF(x2 || y2, inlen),也是没看懂源码如何计算。应该是用派生公钥x2y2,与明文长度inlen经过一系列计算,初步得到暂时的C2密文t。并且密文不能全是0;
3.C2 = M xor t,也是没看懂源码如何计算。最终得到C2加密数据,C2数据长度与明文长度一致;
4.C3 = Hash(x2 || M || y2),用hash算法将派生公钥和明文计算得到C3,这更看不懂hash算法的源码;

(4)密文编码

经过上面步骤,已经完整得到C1 C2 C3的密文。最后需要将这三部分数据拼接起来(拼接顺序本文只阐述新标准C1C3C2),其中有两种密文的编码方式:

ASN.1

序列码0x30 + 接着的数据长度值 + C1_x(序列码0x02 + 接着的数据长度值 + C1_x数据) + C1_y(序列码0x02 + 接着的数据长度值 + C1_y数据) + C3(序列码0x04 + 接着的数据长度值 + C3数据) + C2(序列码0x04 + 接着的数据长度值 + C2数据);
注意:拼接C1_的时候,如果遇到第一字节最高位为1的时候,要在前面加0,实际密文长度+1(源码就是这样做的,没看懂为啥要这样做)

plain

序列码0x04 + C1数据 + C3数据 + C2数据;
注意:只是前面加了0x04序列码,后面数据全是原始密文拼接

三、代码实现

(1)密钥对

测试公钥:043DF5A2FD63FE9B9ACEEED91F7908B684E0568B0ADF3AA9E847EE1F877501049CD8DDB764CD34A71CC127675117CA9C0B59DF3DD072DF88089DEA4511A8ABA039
测试私钥:5408B17606AF7594F9C13113B432CD824D889C8250CF5E7EF2341FBC6D1726A5
加密数据:o5bi5n6zr3zkyhyb
格式说明:测试使用的公钥和私钥都是十六进制的;加密数据类型是字符串,长度16字节;

(2)SM2加密代码

void SM2EncryptData(uint8_t* src, uint8_t* dst)
{
	uint8_t u8Temp = 0;
	uint8_t dIndex = 0;
	uint8_t encodeBuf[153] = {0};
	uint8_t base64Buf[144] = {0};
	uint8_t sm2Buf[144] = {0};
	SM2_KEY sm2_key;
	size_t clen = 0;
	size_t mlen = 153;
	int err = 0;
	
	// 初始化密钥
	memset(&sm2_key, 0, sizeof(SM2_KEY));
	memcpy(sm2_key.public_key.x, param.nvparam.value.encryptInfo.SM2encryptKey_x, 32);
	memcpy(sm2_key.public_key.y, param.nvparam.value.encryptInfo.SM2encryptKey_y, 32);
//	memcpy(sm2_key.private_key, key_private, 32);

	// SM2加密
	err = sm2_encrypt(&sm2_key, src, strlen((char*)src), sm2Buf, &clen);
	
//	// SM2解密测试
//	err = sm2_decrypt(&sm2_key, sm2Buf, clen, mbuf, &mlen);

#if 1
	/* 
		处理加密数据ASN.1 -> plain:
		1.ASN.1序列头0x30 与 剩余长度
		2.C1数据0x02 (0x20/0x21), C1固定32+32字节
		3.C3数据0x04 0x20, 固定32字节
		4.C2数据0x04 0x??, 长度与明文长度一致
	*/
	base64Buf[0] = 0x04;	// plain编码 序列头
	if( sm2Buf[dIndex] == 0x30 )
	{
		// C1_x
		dIndex += 3;
		if( sm2Buf[dIndex] == 0x20 ) 
		{
			dIndex++;
			memcpy(&base64Buf[1], &sm2Buf[dIndex], 32);	
		} 
		else if( sm2Buf[dIndex] == 0x21 && sm2Buf[dIndex+1] == 0x00 ) 
		{
			dIndex += 2;
			memcpy(&base64Buf[1], &sm2Buf[dIndex], 32);
		}
		dIndex += 32;

		// C1_y
		dIndex++;
		if( sm2Buf[dIndex] == 0x20 ) 
		{
			dIndex++;
			memcpy(&base64Buf[33], &sm2Buf[dIndex], 32);
		} 
		else if( sm2Buf[dIndex] == 0x21 && sm2Buf[dIndex+1] == 0x00 ) 
		{
			dIndex += 2;
			memcpy(&base64Buf[33], &sm2Buf[dIndex], 32);
		}
		dIndex += 32;

		// C3
		dIndex += 2;
		memcpy(&base64Buf[65], &sm2Buf[dIndex], 32);
		dIndex += 32;

		// C2
		dIndex++;
		u8Temp = sm2Buf[dIndex++];
		memcpy(&base64Buf[97], &sm2Buf[dIndex], u8Temp);
	}
#endif

	// 加密数据转 base64
	err = base64_encode(encodeBuf, &mlen, base64Buf, 97+u8Temp);

	memcpy(dst, encodeBuf, mlen);
}
	

(3)密文输出

ASN.1:30 79 02 20 5F A6 54 03 91 76 3C 8D 7A 0B E8 87 29 D5 6C 24 CC 65 84 F2 4A 01 3B A9 15 04 DA 7A 3D 10 D4 32 02 21 00 FA A4 37 A5 3F 89 A0 0F 17 C2 F2 77 18 11 FF 3A 8D 9F D0 89 96 CF AC 84 FA 6B 27 37 5F 36 C6 C9 04 20 C7 60 E0 3E 1C D8 D1 8C 93 CE AD 60 C5 91 BC 25 3B 7E 97 F2 D0 98 11 F5 A0 25 1A 88 DE 83 5A 20 04 10 63 19 7A 72 8A 5A 41 B5 7F AC 39 12 C2 94 D4 B9
plain: 04 5F A6 54 03 91 76 3C 8D 7A 0B E8 87 29 D5 6C 24 CC 65 84 F2 4A 01 3B A9 15 04 DA 7A 3D 10 D4 32 FA A4 37 A5 3F 89 A0 0F 17 C2 F2 77 18 11 FF 3A 8D 9F D0 89 96 CF AC 84 FA 6B 27 37 5F 36 C6 C9 C7 60 E0 3E 1C D8 D1 8C 93 CE AD 60 C5 91 BC 25 3B 7E 97 F2 D0 98 11 F5 A0 25 1A 88 DE 83 5A 20 63 19 7A 72 8A 5A 41 B5 7F AC 39 12 C2 94 D4 B9
数据说明:该加密库将以ASN.1编码格式返回密文(十六进制),根据实际需要是否转为plain编码
代码注意:加密数据存放数组sm2Buf要根据实际明文长度定义;上面代码sm2Buf保存的是ASN.1编码的密文;base64Buf保存的是plain编码的密文;encodeBuf是将密文转为base64格式

(4)验证密文

解密工具:https://tool.hiofd.com/sm2-decrypt-online/
如下图,解密成功:

在这里插入图片描述

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐