本专栏订阅后可查看以下文章
1、基于OpenSSL,实现RSA使用的hash的ASN1编码转换
4、基于OpenSSL,实现SM2签名数据的ASN1编码转换
5、基于OpenSSL,实现SM2密文数据的ASN1编码转换
在实际应用场景中会遇到ASN1数据的编码转换,如,在硬件密码库中使用的API接口和在OpenSSL中使用的接口,很有可能是两种格式数据的表现形式,因此,本文提供以下方式进行数据格式的转换。
由于SM2密文格式分为C1C3C2和C1C2C3两种格式,所以在OpenSSL中并没有提供定义的ASN1编码结构和相关函数的定义,因为,需要用户自己定义ASN1编码的结构体。具体如下:
/****************************************************************
* FileName: SM2_cipher.c
* Author: labixiaoxin1849
* Date: 2022-08-27
* Description: call of OpenSSL,RSA key format conversion
****************************************************************/
#include <string.h>
#include <openssl/ec.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
// 自定义ASN1编码结构
typedef struct SM2_Ciphertext_st SM2_Ciphertext;
DECLARE_ASN1_FUNCTIONS(SM2_Ciphertext)
struct SM2_Ciphertext_st {
BIGNUM *C1x;
BIGNUM *C1y;
ASN1_OCTET_STRING *C3;
ASN1_OCTET_STRING *C2;
};
// SM2密文转ASN1编码(ASN1编码格式由上述SM2_Ciphertext_st定义)
// cipher_x[in] : 密文C1的x分量,长度为32,不是公钥的x坐标
// cipher_y[in] : 密文C1的y分量,长度为32,不是公钥的y坐标
// cipher_m[in] : 密文C3,长度为32,原文的哈希值
// cipher_c[in] : 密文C2
// cipher_l[in] : 密文C2的长度
// pbDer[out] : ASN1编码的SM2密文
// uiDerLen[out] : ASN1编码的SM2密文长度
int SM2_Cipher_Struct_to_Der(unsigned char *cipher_x, unsigned char *cipher_y, unsigned char *cipher_m, unsigned char *cipher_c, unsigned int cipher_l, unsigned char *pbDer, unsigned int *uiDerLen)
{
SM2_Ciphertext *xcipher;
BIGNUM *x, *y;
int ret = 1;
do {
x = y = NULL;
xcipher = SM2_Ciphertext_new();
x = BN_bin2bn(cipher_x, 32, NULL);
y = BN_bin2bn(cipher_y, 32, NULL);
if (!xcipher || !x || !y) {
break;
}
if (xcipher->C1x) {
BN_free(xcipher->C1x);
}
xcipher->C1x = x;
if (xcipher->C1y) {
BN_free(xcipher->C1y);
}
xcipher->C1y = y;
x = y = NULL;
if (!ASN1_OCTET_STRING_set(xcipher->C3, cipher_m, 32)) {
break;
}
if (!ASN1_OCTET_STRING_set(xcipher->C2, cipher_c, cipher_l)) {
break;
}
if (pbDer) {
*uiDerLen = i2d_SM2_Ciphertext(xcipher, &pbDer);
}
else {
*uiDerLen = i2d_SM2_Ciphertext(xcipher, NULL);
}
if ((int)*uiDerLen < 1) {
break;
}
ret = 0;
} while (0);
if (xcipher) {
SM2_Ciphertext_free(xcipher);
}
if (x) {
BN_free(y);
}
if (x) {
BN_free(y);
}
return ret;
}
// SM2密文ASN1编码转结构(ASN1编码格式由上述SM2_Ciphertext_st定义)
// pbDer[in] : ASN1编码的SM2密文
// uiDerLen[in] : ASN1编码的SM2密文长度
// cipher_x[out] : 密文C1的x分量,长度为32,不是公钥的x坐标
// cipher_y[out] : 密文C1的y分量,长度为32,不是公钥的y坐标
// cipher_m[out] : 密文C3,长度为32,原文的哈希值
// cipher_c[out] : 密文C2
// cipher_l[out] : 密文C2的长度
int SM2_Cipher_Der_to_Struct(const unsigned char *pbDer, unsigned int uiDerLen, unsigned char *cipher_x, unsigned char *cipher_y, unsigned char *cipher_m, unsigned char *cipher_c, unsigned int *cipher_l)
{
unsigned char pbTmp[8192] = { 0 };
const unsigned char *data;
int len;
SM2_Ciphertext *xcipher;
int ret = 1;
do {
xcipher = d2i_SM2_Ciphertext(NULL, &pbDer, uiDerLen);
if (!xcipher) {
break;
}
len = BN_bn2bin(xcipher->C1x, pbTmp);
if (len > 32) {
break;
}
memcpy(cipher_x, pbTmp, len);
memset(pbTmp, 0, sizeof(pbTmp));
len = BN_bn2bin(xcipher->C1y, pbTmp);
if (len > 32) {
break;
}
memcpy(cipher_y, pbTmp, len);
len = ASN1_STRING_length(xcipher->C3);
if (len > 32) {
break;
}
data = ASN1_STRING_get0_data(xcipher->C3);
if (!data) {
break;
}
memcpy(cipher_m, data, len);
*cipher_l = ASN1_STRING_length(xcipher->C2);
if (*cipher_l > 512) {
break;
}
data = ASN1_STRING_get0_data(xcipher->C2);
if (!data) {
break;
}
memcpy(cipher_c, data, *cipher_l);
ret = 0;
} while (0);
SM2_Ciphertext_free(xcipher);
return ret;
}
ASN1_SEQUENCE(SM2_Ciphertext) = {
ASN1_SIMPLE(SM2_Ciphertext, C1x, BIGNUM),
ASN1_SIMPLE(SM2_Ciphertext, C1y, BIGNUM),
ASN1_SIMPLE(SM2_Ciphertext, C3, ASN1_OCTET_STRING),
ASN1_SIMPLE(SM2_Ciphertext, C2, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(SM2_Ciphertext)
// 由OpenSSL提供的宏,实现自定义的ASN1编码
// 调用此宏,便定义了函数: SM2_Ciphertext_new、SM2_Ciphertext_free、d2i_SM2_Ciphertext、i2d_SM2_Ciphertext
IMPLEMENT_ASN1_FUNCTIONS(SM2_Ciphertext)
int main(int argc, char *argv[]){
unsigned char c1x[] = {
0x57, 0xE9, 0x62, 0x22, 0xAB, 0x0A, 0x75, 0x43, 0x81, 0xA8, 0x43, 0x6A, 0xD9, 0x5F, 0xCC, 0xDD,
0x6B, 0x0D, 0xD4, 0xF6, 0x24, 0x1D, 0x13, 0xA0, 0x80, 0x2D, 0xE5, 0xD7, 0x09, 0x82, 0xF0, 0xF0
};
unsigned char c1y[] = {
0x97, 0xD3, 0x79, 0x5C, 0x79, 0x50, 0xF2, 0x78, 0x63, 0x50, 0x03, 0xA7, 0x08, 0xD5, 0x6C, 0x4F,
0xCB, 0x42, 0x44, 0xE4, 0xE2, 0x8C, 0xAA, 0x4F, 0x74, 0x4E, 0xF9, 0xE7, 0xA6, 0x82, 0x62, 0xE4
};
unsigned char c3[] = {
0xE7, 0x1B, 0x12, 0x51, 0x61, 0x40, 0xD3, 0xAC, 0x0C, 0x74, 0x84, 0x91, 0xBF, 0xE3, 0xEC, 0x0E,
0x60, 0x58, 0x24, 0xAA, 0xD5, 0x66, 0xC4, 0x48, 0x84, 0x10, 0xF4, 0x3C, 0x69, 0x29, 0xD0, 0x6C
};
unsigned char c2[] = {
0xB5, 0x92, 0xBF, 0x02, 0xD0, 0x53, 0xC2, 0x1A, 0x8A, 0x4A, 0xF1, 0x56, 0x21, 0x2E, 0xBD, 0x37
};
unsigned char der[256] = {0};
unsigned int derlen = 0;
unsigned char c1x2[32] = {0};
unsigned char c1y2[32] = {0};
unsigned char c32[32] = {0};
unsigned char c22[32] = {0};
unsigned int c22len = 0;
// der 设置为NULL可以获得结构长度
int rv = SM2_Cipher_Struct_to_Der(c1x, c1y, c3, c2, sizeof(c2), der, &derlen);
if (rv != 0){
return rv;
}
rv = SM2_Cipher_Der_to_Struct(der, derlen, c1x2, c1y2, c32, c22, &c22len);
if (rv != 0){
return rv;
}
if(memcmp(c1x, c1x2, 32) != 0 || memcmp(c1y, c1y2, 32) != 0 || memcmp(c3, c32, 32) != 0 ||
sizeof(c2) != c22len || memcmp(c2, c22, c22len) != 0) {
return -1;
}
printf("SM2 cipher exchange success!!!\n");
return 0;
}