Bootstrap

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

基于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在线编码转换工具


/****************************************************************
 * FileName:    SM2_sig.c
 * Author:      labixiaoxin1849
 * Date:        2022-08-27
 * Description: call of OpenSSL,SM2 key format conversion 
 ****************************************************************/

#include <string.h>
#include <openssl/ec.h>

// SM2算法,而非ECC

// SM2签名数据结构转为ASN1编码
// sig_r[in] : 签名的r部分
// sig_s[in] : 签名的s部分
// pbDer[out] : 转换后的ASN1编码数据
// uiDerLen[out] : 转换后的ASN1编码数据长度
int SM2_Signature_Struct_to_Der(const unsigned char *sig_r, const unsigned char *sig_s, unsigned char *pbDer, unsigned int *uiDerLen) 
{
    ECDSA_SIG *xsig;
    BIGNUM *r, *s;
    int ret = -1;
    do {
        r = s = NULL;
        xsig = ECDSA_SIG_new();
		
        r = BN_bin2bn(sig_r, 32, NULL);
        s = BN_bin2bn(sig_s, 32, NULL);
        if (!xsig || !r || !s) {
            break;
        }

        if (!ECDSA_SIG_set0(xsig, r, s)) {
            break;
        }

        r = s = NULL;

        if (pbDer) {
            *uiDerLen = i2d_ECDSA_SIG(xsig, &pbDer);
        } else {
            *uiDerLen = i2d_ECDSA_SIG(xsig, NULL);
        }
        
        if ((int)*uiDerLen < 1) {
            break;
        }

        ret = 0;
    } while (0);

    if (xsig) {
        ECDSA_SIG_free(xsig);
    }
    if (r) {
        BN_free(r);
    }
    if (s) {
        BN_free(s);
    }

    return ret;
}

// SM2签名数据的ASN1编码转结构
// pbDer[in] : 转换后的ASN1编码数据
// uiDerLen[in] : 转换后的ASN1编码数据长度
// sig_r[out] : 签名的r部分
// sig_s[out] : 签名的s部分
int SM2_Signature_Der_to_Struct(const unsigned char *pbDer, unsigned int uiDerLen, unsigned char *sig_r, unsigned char *sig_s)
{
	unsigned char pbTmp[64] = { 0 };
	int len;
	ECDSA_SIG *xsig;
	int ret = -1;

	do {
		xsig = d2i_ECDSA_SIG(NULL, &pbDer, uiDerLen);
		if (!xsig) {
			break;
		}

		memset(pbTmp, 0x00, sizeof(pbTmp));
		len = BN_bn2bin(ECDSA_SIG_get0_r(xsig), pbTmp);
		if (len > 32) {
			break;
		}
		memcpy(&sig_r[32 - len], pbTmp, len);

		memset(pbTmp, 0x00, sizeof(pbTmp));
		len = BN_bn2bin(ECDSA_SIG_get0_s(xsig), pbTmp);
		if (len > 32) {
			break;
		}
		memcpy(&sig_s[32 - len], pbTmp, len);
		ret = 0;
	} while (0);

	if (xsig) {
		ECDSA_SIG_free(xsig);
	}

	return ret;
}

int main(int argc, char *argv[]){
	unsigned char r[32] = {
		0x37, 0x1B, 0xAE, 0xC3, 0xC2, 0x32, 0x20, 0xEC, 0xF7, 0x91, 0xE3, 0x6B, 0x47, 0x26, 0x04, 0x64,
		0x5A, 0x69, 0xE1, 0x86, 0x9E, 0x6D, 0x51, 0xC9, 0x85, 0x4E, 0xA1, 0xDD, 0x07, 0xD3, 0x57, 0x9F
	};
	unsigned char s[32] = {
		0xDF, 0xAE, 0xE5, 0x73, 0xE6, 0x3E, 0x9C, 0xB3, 0xA4, 0x64, 0xDA, 0xB2, 0xEA, 0x83, 0x4F, 0xEB,
		0x00, 0xF5, 0xD2, 0x64, 0xE1, 0xD6, 0x3F, 0xF0, 0x70, 0x60, 0xC0, 0x61, 0xF4, 0xDE, 0x2E, 0x30
	};
	// 经过编码后的长度大于64
	unsigned char der[128] = {0};
	unsigned int derlen = 0;

	unsigned char r2[32] = {0};
	unsigned char s2[32] = {0};

	// der_out 设置为NULL可以获得结构长度
	int rv = SM2_Signature_Struct_to_Der(r, s, der, &derlen);
	if(rv != 0){
		return rv;
	}
	
	rv = SM2_Signature_Der_to_Struct(der, derlen, r2, s2);
	if(rv != 0){
		return rv;
	}
	
	if(memcmp(r, r2, 32) != 0 || memcmp(s, s2, 32) != 0) {
		return -1;
	}
	printf("SM2 signature exchange success!!!\n");
	return 0;
}

;