基于OpenSSL,实现RSA签名使用的hash的ASN1编码转换

本文介绍了如何基于OpenSSL库,实现RSA签名过程中哈希值的ASN1编码转换,这对于在不同接口间进行数据格式转换至关重要。在非对称加密的签名操作中,通常是对数据哈希进行签名。文中提供了二进制到ASN1编码以及ASN1编码回二进制的转换方法,并提到了实用的在线ASN1编码转换工具。
摘要由CSDN通过智能技术生成

基于OpenSSL, 实现算法的 Engine专栏

本专栏订阅后可查看以下文章

1、基于OpenSSL,实现RSA签名使用的hash的ASN1编码转换

2、基于OpenSSL,实现RSA公钥的ASN1编码转换

3、实现SM2公私钥的格式转换

4、基于OpenSSL,实现SM2签名数据的ASN1编码转换​​​​​​

5、基于OpenSSL,实现SM2密文数据的ASN1编码转换 

在非对称密钥算法运算中,因为公私钥的特殊使用,会产生签名的场景,在做签名时,只是为了证明身份,而非保护数据,所以在签名时,是对数据的哈希进行签名。

在实际应用场景中会遇到ASN1数据的编码转换,如,在硬件密码库中使用的API接口和在OpenSSL中使用的接口,很有可能是两种格式数据的表现形式,因此,本文提供以下方式进行数据格式的转换。

ASN1在线编码转换工具

二进制转为ASN1编码

// hash[in] : 源数据
// hashlen[in] : 源数据长度
// der[out] : 编码后的数据,传入NULL时,可以获得编码后的数据长度
// derlen[out] : 编码后的数据长度
// type[in] : 声明哈希的算法ID,NID_sha256
int RSA_sig_to_der(const unsigned char *hash, unsigned int hashlen, unsigned char *der, unsigned int *derlen, int type) {
	int ret = -1;
	X509_SIG *xsig;
	X509_ALGOR *algor;
	ASN1_OCTET_STRING *pdigest;
	do{
        // 不同于SM2算法的签名转换,此定义已在OpenSSL中声明
        // SM2的签名数据需要自己做声明
		xsig = X509_SIG_new();
		if (!xsig){
			break;
		}
        // 获得algor和pdigest在xsig中的地址,从而设置xsig的值
		X509_SIG_getm(xsig, &algor, &pdigest);
		if (!X509_ALGOR_set0(algor, OBJ_nid2obj(type), V_ASN1_NULL, NULL)){
			break;
		}
		if (!ASN1_OCTET_STRING_set(pdigest, hash, hashlen)) {
			break;
		}
		if (der) {
			*derlen = i2d_X509_SIG(xsig, &der);
		}
		else {
			*derlen = i2d_X509_SIG(xsig, NULL);
		}
		ret = 0;
	} while (0);

	if (xsig) {
		X509_SIG_free(xsig);
	}
	return ret;
}

ASN1编码转为二进制

// pbDer[in] : ASN1编码数据
// uiDerLen[in] : ASN1编码数据长度
// hash[out] : 哈希数据
// hashlen[out] : 哈希数据长度
int RSA_sig_to_hash(const unsigned char *pbDer, unsigned int uiDerLen, unsigned char *hash, unsigned int *hashlen) {
	int ret = -1;
	X509_SIG *xsig = NULL;
	const ASN1_OCTET_STRING *doct = NULL;
	const unsigned char *data = NULL;
	int datalen = 0;

	do{
		xsig = d2i_X509_SIG(NULL, &pbDer, uiDerLen);
		if (!xsig) {
			break;
		}
        // 这里没有对哈希算法进行解析,如需解析,把NULL变为变量再解析
		X509_SIG_get0(xsig, NULL, &doct);

		datalen = ASN1_STRING_length(doct);
		if (datalen <= 0) {
			break;
		}
		data = ASN1_STRING_get0_data(doct);
		if (!data) {
			break;
		}
		memcpy(hash, data, datalen);
		*hashlen = datalen;
		ret = 0;
	} while (0);
	
	if (xsig) {
		X509_SIG_free(xsig);
	}
	return ret;
}

具体调用如下:

int main(int argc, char *argv[]) {
	//unsigned char derB64[] = "MDEwDQYJYIZIAWUDBAIBBQAEILVRJqOfmxFwoy5vYeSmlMRSNeWsEcBezW/2OV3moRGH";
	unsigned char der[] = {
		0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
		0x00, 0x04, 0x20, 0xB5, 0x51, 0x26, 0xA3, 0x9F, 0x9B, 0x11, 0x70, 0xA3, 0x2E, 0x6F, 0x61, 0xE4,
		0xA6, 0x94, 0xC4, 0x52, 0x35, 0xE5, 0xAC, 0x11, 0xC0, 0x5E, 0xCD, 0x6F, 0xF6, 0x39, 0x5D, 0xE6,
		0xA1, 0x11, 0x87
	};
	unsigned int derlen = sizeof(der);

	unsigned char hash[64] = { 0 };
	unsigned int hashlen = 0;

	unsigned char out[128] = { 0 };
	unsigned int outlen = 0;

	int ret = RSA_sig_to_hash(der, derlen, hash, &hashlen);
	if (ret != 0){
		return -1;
	}

	ret = RSA_sig_to_der(hash, hashlen, out, &outlen, 672); // NID_sha256
	if (ret != 0){
		return -1;
	}
	if(derlen != outlen || memcmp(der, out, outlen) != 0) {
		return -1;
	}
	printf("exchange success!!!\n");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蜡笔小新1849

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值