SM2 algorithm encryption signature message syntax specification (four) how to construct envelopedData

The previous article has introduced the digital envelope data envelopedData type in the National Secret Specification. Next, let’s talk about how to construct this type of data~~\( ̄︶ ̄)/ 

1. Construction process

According to the RFC specification, in conjunction with the requirements of the GM/T 0010 specification, the process of constructing digital envelope data is as follows:    
    a. Generate a content encryption key (ie, session key or symmetric key) corresponding to a specific encryption algorithm;
    b. The content encryption key is encrypted with the public key of each recipient. (Algorithm: sm2-3 public key encryption algorithm OID: 1.2.156.10197.1.301.3)
    c. For each recipient, put the encrypted content encryption key and other information of the recipient into the RecipientInfo value.
    d. Encrypt the content with the content encryption key.
    e. Put the RecipientInfo value and encrypted content of all recipients into the EnvelopedData value.      

2. Coding implementation

Compared with the RFC specification, the digital envelope structure defined in the National Secret Specification has two new fields for storing negotiated shared information. But it is optional, I don't need these two fields here. Therefore, the PKCS7_ENVELOPE structure defined in gmssl can be used directly.

Then use the ASN.1 library to customize the oid type as envelopedData (1.2.156.10197.6.1.4.2.3) to implement DER encoding. For custom ASN structure schemes , please refer to the previous article of the editor. I won't repeat it here.

/*******************************************************

(=゚ω゚)ノ---===≡≡≡ The operation is as fierce as a tiger...

OK editor has customized the structure for digital envelope data ( SM2EnvelopedData );

Then according to the construction process, the relevant algorithm is called to calculate the session key ciphertext (encrypted by the recipient's public key) and the content ciphertext encrypted by the session key; and the ciphertext structure data are all DER encoded.

*******************************************************/

The main code of the construction part is as follows:

封装pkcs7数字信封///
	if ((p7 = SM2EnvelopedData_new()) == NULL)
	{
		//TODO. 错误处理
		goto end;
	}
	//------------设置类型为NID_pkcs7_enveloped
	if (!SM2_EnvelopedData_set_type(p7, OID_SM2_Enveloped)) {
		//TODO. 错误处理
		goto end;
	}

	//------------构造recipientinfo
	PKCS7_RECIP_INFO *ri = NULL;
	if ((ri = PKCS7_RECIP_INFO_new()) == NULL)
	{
		//TODO. 错误处理
		goto end;
	}
	//设置版本信息
	if (!ASN1_INTEGER_set(ri->version, 0))
	{
		//TODO. 错误处理
		goto end;
	}
	//填充issuer_and_serial 颁发者信息
	if (!X509_NAME_set(&ri->issuer_and_serial->issuer, X509_get_issuer_name(enc_cert)))
	{
		//TODO. 错误处理
		goto end;
	}
	ASN1_INTEGER_free(ri->issuer_and_serial->serial);
	if (!(ri->issuer_and_serial->serial = ASN1_INTEGER_dup(X509_get_serialNumber(enc_cert))))
	{
		//TODO. 错误处理
		goto end;
	}
	//设置接收者证书
	ri->cert = enc_cert;  //注。ri->cert已指向了enc_cert, enc_cert内存将由p7对象释放
	//指定算法和相应的参数  //digestAlgorithms  用接收者公钥加密数据加密密钥的算法
	ri->key_enc_algor->algorithm = OBJ_txt2obj(OID_SM2_3, 1);
	ri->key_enc_algor->parameter = ASN1_TYPE_new();
	ri->key_enc_algor->parameter->type = V_ASN1_NULL;
	//3. 把加了密的内容加密密钥和接收者的其他信息放入RecipientInfo值中。
	/*ASN1_STRING_set0内部是直接进行指针指向,故而ek内存将由ASN1对象去释放。将ek指向NULL,防止重复释放*/
	ASN1_STRING_set0(ri->enc_key, ek, ekLen);
	ek = NULL;

	//------------将接收者加入到PKCS7_ENVELOPE的接收者信息集合
	if (!SM2_EnvelopedData_add_recipient_info(p7, ri))
	{
		//TODO. 错误处理
		goto end;
	}

	//------------构造enc_data
	if (0 == SM2_EnvelopedData_dataInit(p7, uiSymmAlgorithm, iv, 16))
	{
		//TODO. 错误处理
		goto end;
	}
	if (0 == SM2_EnvelopedData_dataFinal(p7, cont, contLen))
	{
		//TODO. 错误处理
		goto end;
	}

	//------------PKCS7对象Der编码输出
    //pucDerEnvelopedData为缓冲区,用来存放DER编码后的数据;
	pTmp = NULL;
	pTmp = pucDerEnvelopedData;
	if ((derP7Len = i2d_SM2EnvelopedData(p7, &pTmp)) <= 0)
	{
		//TODO. 错误处理
		goto end;
	}	

SM2_EnvelopedData_set_type This method is designed according to the structure of SM2EnvelopedData, and is used to set its type according to OID. The PKCS7_ENVELOPE digital envelope structure object is created internally , and the version number of the PKCS7_ENVELOPE object is set . ( You can set it according to your own custom structure )

    ASN1_OBJECT *obj;

	obj = OBJ_txt2obj(oid, 1);

	if (0 == strcmp(oid, OID_SM2_Enveloped))
	{
		p7->type = obj;
		if ((p7->enveloped = PKCS7_ENVELOPE_new()) == NULL)
			goto err;
		if (!ASN1_INTEGER_set(p7->enveloped->version, 0))
			goto err;
		p7->enveloped->enc_data->content_type = OBJ_txt2obj(OID_SM2_Data, 1);
	}

The SM2_EnvelopedData_dataInit method is a method designed according to the SM2EnvelopedData structure, used to initialize the algorithm and parameters of the encrypted content stored in the structure

int SM2_EnvelopedData_dataInit(SM2EnvelopedData *p7, int symmAlg, unsigned char *iv, unsigned int ivlen)
{
	char objtmp[80] = { 0x00 };
	X509_ALGOR *xalg = NULL;

	OBJ_obj2txt(objtmp, sizeof(objtmp), p7->type, 1);
	if (0 == strcmp(objtmp, OID_SM2_Enveloped))
	{
		xalg = p7->enveloped->enc_data->algorithm;
	}
	else
	{
		LError("SM2_EnvelopedData_dataInit, PKCS7_R_WRONG_CONTENT_TYPE");
		return (0);
	}

	//指定内容加密算法
	int nid_alg = NID_undef;
	switch (symmAlg)
	{
	case SGD_SM4_ECB:
		nid_alg = NID_sms4_ecb;
		break;
	case SGD_SM4_CBC:
		nid_alg = NID_sms4_cbc;
		break;
	case SGD_SM4_CFB:
		nid_alg = NID_sms4_cfb128;
		break;
	case SGD_SM4_OFB:
		nid_alg = NID_sms4_ofb128;
		break;
	default:
		LError("Symm Algorithm undef.");
		nid_alg = NID_undef;
		return 0;
	}
	xalg->algorithm = OBJ_nid2obj(nid_alg);

	if (xalg->parameter == NULL)
		xalg->parameter = ASN1_TYPE_new();
	if (xalg->parameter == NULL)
		return 0;

	if (nid_alg == NID_sms4_ecb)
	{
		ASN1_TYPE_free(xalg->parameter);
		xalg->parameter = NULL;
	}
	else
	{
		//SM4算法非ECB模式,需要将IV向量值存放到enc_data中
		//存放到V_ASN1_OCTET_STRING类型中
		ASN1_TYPE_set_octetstring(xalg->parameter, iv, ivlen);
	}
	return 1;
}

The SM2_EnvelopedData_dataFinal method is a method designed according to the SM2EnvelopedData structure, and fills in the encrypted content.

int SM2_EnvelopedData_dataFinal(SM2EnvelopedData *p7, unsigned char *cont, unsigned int contlen)
{
	char objtmp[80] = { 0x00 };
	ASN1_OCTET_STRING *os = NULL;

	OBJ_obj2txt(objtmp, sizeof(objtmp), p7->type, 1);
	if (0 == strcmp(objtmp, OID_SM2_Enveloped))
	{
		os = p7->enveloped->enc_data->enc_data;
		if (os == NULL) {
			os = ASN1_OCTET_STRING_new();
			if (os == NULL) {
				LError("SM2_EnvelopedData_dataFinal, ERR_R_MALLOC_FAILURE");
				return 0;
			}
			p7->enveloped->enc_data->enc_data = os;
		}
	}
	else
	{
		LError("SM2_EnvelopedData_dataFinal, PKCS7_R_WRONG_CONTENT_TYPE");
		return (0);
	}

	if (os == NULL)
		return 0;
	ASN1_OCTET_STRING_set(os, cont, contlen);

	return 1;
}

Only some of the main codes are posted above for your reference and at the same time to record for your own memory.

Finally, the envelopedData data output by DER encoding is opened and viewed with Asn1View, as follows:

 

 

Guess you like

Origin blog.csdn.net/lt4959/article/details/112569709