C++国密SM2算法加解密的使用

        OpenSSL和GmSSL都提供了SM2加解密的实现,GmSSL自带例子很简单就能跑起来,网上大部分代码都是基于OpenSSL。还有一些自己实现的代码,需要测试可靠性。

        GmSSL加密串长度限制为255(SM2_MAX_PLAINTEXT_SIZE),不适合长文本的加解密。尝试分段加密方案,但测试时加密结果的长度不固定导致没法分段解密,没调通。转而使用OpenSSL库。

        使用OpenSSL新版本,因OpenSSL 早先版本存在BUG。编译OpenSSL-1.1.1w,\openssl-1.1.1w\test\sm2_internal_test.c中有SM2测试代码,直接使用是不行的,链接时会提示“未定义的引用”,只找到了一个评论有关于它的解释“对于OpenSSL 1.1.1系列,sm2.h 是一个内部的头文件,其中定义的函数不对外公开”这里有原文

        CSDN里找了一个基于OpenSSL的代码实现,联系这位作者

        关于SM2加密调用要注意:

一、明确明文和密文的编码。

二、密码散列函数,默认使用国密SM3。

三、密文顺序,有C1||C2||C3 和 C1||C3||C2的区别。

四、公钥、私钥格式。一般为Hex字符串格式,也可以用PEM格式。公钥为65字节,第一个字节要注意。公钥是将0x4、公钥的X坐标(32字节长)、公钥的Y坐标(32字节长)三部分拼在一起构成的。其中0x4是一个特殊指示符字节,表示未对椭圆曲线上的点坐标表示进行过压缩处理。

代码分为加密、解密两个接口,参数为std::string。

//sInput:明文,shexPublicKey:Hex格式公钥,shexEnc:Hex格式密文
int SM2Encrypt_hex(const std::string& sInput, const std::string& shexPublicKey, std::string& shexEnc)
{
	int error_code;
	size_t msg_len = sInput.size();
	SM2_KEY_PAIR key_pair;
	unsigned char c1[65], c3[32];
	unsigned char* c2;

	long len;
	unsigned char* pPubKey = OPENSSL_hexstr2buf(shexPublicKey.c_str(), &len);
	memcpy(key_pair.pub_key, pPubKey, PUBLIC_KEY_SIZE);

	//if (error_code = sm2_create_key_pair(&key_pair))
	//{
	//	qDebug() << "Create SM2 key pair failed!\n";
	//	return (-1);
	//}
	//qDebug() << "Create SM2 key pair succeeded!\n";

	qDebug() << "Public key:\n";

	char* pub_key_str = OPENSSL_buf2hexstr(key_pair.pub_key, PUBLIC_KEY_SIZE);
	QString sOut = QString("%1\n\n").arg(pub_key_str);
	qDebug() << sOut;

	qDebug() << "/*********************************************************/\n";
	if (!(c2 = (unsigned char*)malloc(msg_len)))
	{
		qDebug() << "c2 Memory allocation failed!\n";
		return ALLOCATION_MEMORY_FAIL;
	}
	if (error_code = sm2_encrypt((const unsigned char*)sInput.c_str(),
		msg_len,
		key_pair.pub_key,
		c1,
		c3,
		c2))
	{
		qDebug() << "Create SM2 ciphertext failed!\n";
		free(c2);
		return error_code;
	}

	qDebug() << "Create SM2 ciphertext succeeded!\n";
	qDebug() << "SM2 ciphertext:\n\n";
	qDebug() << "C1 component:\n";

	char* c1str = OPENSSL_buf2hexstr(c1, 65);
	sOut = QString("%1\n").arg(c1str);
	qDebug() << sOut;

	qDebug() << "C3 component:\n";
	char* c3str = OPENSSL_buf2hexstr(c3, 32);
	sOut = QString("%1\n").arg(c3str);
	qDebug() << sOut;

	qDebug() << "C2 component:\n";
	char* c2str = OPENSSL_buf2hexstr(c2, msg_len);
	sOut = QString("%1\n").arg(c2str);
	qDebug() << sOut;
	std::stringstream ss;
	ss << c1str << c3str << c2str;
	shexEnc = ss.str();

	free(c2);
	return 0;
}

int SM2Decrypt_hex(const std::string& shexEnc, const std::string& shexPrivateKey, std::string& sOutput)
{
	int error_code;
	SM2_KEY_PAIR key_pair;
	unsigned char c1[65], c3[32];
	unsigned char* c2, * plaintext;

	long len;
	unsigned char* pPriKey = OPENSSL_hexstr2buf(shexPrivateKey.c_str(), &len);
	memcpy(key_pair.pri_key, pPriKey, PRIVATE_KEY_SIZE);

	unsigned char* pEnc = OPENSSL_hexstr2buf(shexEnc.c_str(), &len);
	qDebug() << "C1 component:\n";
	c2 = (unsigned char*)malloc(len - 97);
	for (size_t i = 0; i < len; i++)
	{
		if (i < 65)
			c1[i] = pEnc[i];
		else if (i < 97)
			c3[i - 65] = pEnc[i];
		else
			c2[i - 97] = pEnc[i];
	}
	free(pEnc);

	size_t msg_len = len - 97;
	if (!(plaintext = (unsigned char*)malloc(msg_len)))
	{
		free(c2);
		qDebug() << "Memory allocation failed!\n";
		return ALLOCATION_MEMORY_FAIL;
	}

	if (error_code = sm2_decrypt(c1,
		c3,
		c2,
		msg_len,
		key_pair.pri_key,
		plaintext))
	{
		free(plaintext);
		free(c2);
		printf("Decrypt SM2 ciphertext failed!\n");
		return error_code;
	}

	for (size_t i = 0; i < msg_len; i++)
		sOutput.push_back(plaintext[i]);

	free(plaintext);
	free(c2);
	return 0;
}

测试代码:

//密钥可以用sm2_create_key_pair生成
//这里私钥和公钥为Hex格式,明文为utf-8编码
int main(void)
{
	QString sInput, sOutput;
	QString sPrivateKey, sPublicKey;
	sPrivateKey	= QString(u8"4F:8A:65:8B:D7:9A:04:C1:52:18:A1:03:D2:78:EF:CE:EE:C2:BF:A1:3E:66:F9:2F:76:CA:96:65:50:77:56:D7");
	sPublicKey	= QString(u8"04:14:77:50:9F:72:AA:41:B8:2C:35:25:79:7D:2B:40:BB:FD:1F:5F:60:5D:BD:32:6F:1F:21:DE:86:1E:98:AA:9A6D:18:81:99:9F:FD:89:66:2E:4D:34:2C:84:7F:FA:DD:F9:E8:D6:E1:08:AE:58:26:DD:36:B7:D7:B5:18:E9:5A");
	sInput = QString(u8"哈喽哈喽X23223414341SDss000999090dweimnfkhinbdmnbxh321314512341sdkfjiwejkngjkaWDFSFSDFW3245234154120587854wwdsfEWRW000999090324332dsfsfwefsedgdfgwefsdfweX23223414341SDss000999090dweimnfkhinbdmnbxh321314512341sdkfjiwejkngjkaWDFSFSDFW3245234154120587854wwdsfEWRW000999090324332dsfsfwefsedgdfgwefsdfweX23223414341SDss000999090dweimnfkhinbdmnbxh321314512341sdkfjiwejkngjkaWDFSFSDFW3245234154120587854wwdsfEWRW000999090324332dsfsfwefsedgdfgwefsdfweX23223414341SDss000999090dweimnfkhinbdmnbxh321314512341sdkfjiwejkngjkaWDFSFSDFW3245234154120587854wwdsfEWRW000999090324332dsfsfwefsedgdfgwefsdfweX23223414341SDss000999090dweimnfkhinbdmnbxh321314512341sdkfjiwejkngjkaWDFSFSDFW3245234154120587854wwdsfEWRW000999090324332dsfsfwefsedgdfgwefsdfweX23223414341SDss000999090dweimnfkhinbdmnbxh321314512341sdkfjiwejkngjkaWDFSFSDFW3245234154120587854wwdsfEWRW000999090324332dsfsfwefsedgdfgwefsdfwe哈喽哈喽");

	std::string strEnc;
	SM2Encrypt(sInput.toStdString(), sPublicKey.toStdString(), strEnc);

	std::string strOutput;
	SM2Decrypt(strEnc, sPrivateKey.toStdString(), strOutput);

	sOutput = QString::fromStdString(strOutput);
	if (0 != sOutput.compare(sInput, Qt::CaseInsensitive))
	{
		qDebug() << "Enc not justify Dec";
		return -1;
	}

	return 0;
}

SM2在线测试工具

适配测试结果:

java使用Hutool(底层bouncycastle)SM2加密(解密),C++解密(加密)成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值