当前位置:   article > 正文

SM2算法的加密签名消息语法规范(四)如何构造envelopedData_数字信封 openssl 编码 sm2

数字信封 openssl 编码 sm2

前面的文章中已经介绍了国密规范中的数字信封数据envelopedData类型。接下来讲一下怎么构造出这种类型的数据~~\( ̄︶ ̄)/ 

1、构造流程

根据RFC规范,在结合GM/T 0010规范的要求,构造数字信封数据的过程如下:    
    a. 产生一个对应于特定加密算法的内容加密密钥(即会话密钥或对称密钥);
    b. 将内容加密密钥用每个接收者的公钥加密。(算法为:sm2-3 公钥加密算法   OID:1.2.156.10197.1.301.3)
    c. 对于每一个接收者,把加了密的内容加密密钥和接收者的其他信息放入RecipientInfo值中。
    d. 用内容加密密钥加密内容。
    e. 将所有接收者的RecipientInfo值和加了密的内容放入EnvelopedData值中。      

2、编码实现

国密规范中定义的数字信封结构相较于RFC规范中,新增了2个字段用于存放协商好的共享信息。但是是可选的,小编这里并不需要这俩字段。因此可直接使用gmssl中定义的PKCS7_ENVELOPE结构。

然后通过ASN.1库自定义oid类型为envelopedData(1.2.156.10197.6.1.4.2.3)的类型来实现DER编码。自定义ASN结构方案请查看小编之前的文章。这里就不在赘述了。

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

(=゚ω゚)ノ ---===≡≡≡一顿操作猛如虎......

OK 小编已自定义好了针对数字信封数据的结构(SM2EnvelopedData);

然后根据构造流程中,调用相关算法计算得到了会话密钥密文(经接收者公钥加密)、被会话密钥加密后的内容密文;并将密文结构数据均进行了DER编码。

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

构造部分主要代码如下:

  1. 封装pkcs7数字信封///
  2. if ((p7 = SM2EnvelopedData_new()) == NULL)
  3. {
  4. //TODO. 错误处理
  5. goto end;
  6. }
  7. //------------设置类型为NID_pkcs7_enveloped
  8. if (!SM2_EnvelopedData_set_type(p7, OID_SM2_Enveloped)) {
  9. //TODO. 错误处理
  10. goto end;
  11. }
  12. //------------构造recipientinfo
  13. PKCS7_RECIP_INFO *ri = NULL;
  14. if ((ri = PKCS7_RECIP_INFO_new()) == NULL)
  15. {
  16. //TODO. 错误处理
  17. goto end;
  18. }
  19. //设置版本信息
  20. if (!ASN1_INTEGER_set(ri->version, 0))
  21. {
  22. //TODO. 错误处理
  23. goto end;
  24. }
  25. //填充issuer_and_serial 颁发者信息
  26. if (!X509_NAME_set(&ri->issuer_and_serial->issuer, X509_get_issuer_name(enc_cert)))
  27. {
  28. //TODO. 错误处理
  29. goto end;
  30. }
  31. ASN1_INTEGER_free(ri->issuer_and_serial->serial);
  32. if (!(ri->issuer_and_serial->serial = ASN1_INTEGER_dup(X509_get_serialNumber(enc_cert))))
  33. {
  34. //TODO. 错误处理
  35. goto end;
  36. }
  37. //设置接收者证书
  38. ri->cert = enc_cert; //注。ri->cert已指向了enc_cert, enc_cert内存将由p7对象释放
  39. //指定算法和相应的参数 //digestAlgorithms 用接收者公钥加密数据加密密钥的算法
  40. ri->key_enc_algor->algorithm = OBJ_txt2obj(OID_SM2_3, 1);
  41. ri->key_enc_algor->parameter = ASN1_TYPE_new();
  42. ri->key_enc_algor->parameter->type = V_ASN1_NULL;
  43. //3. 把加了密的内容加密密钥和接收者的其他信息放入RecipientInfo值中。
  44. /*ASN1_STRING_set0内部是直接进行指针指向,故而ek内存将由ASN1对象去释放。将ek指向NULL,防止重复释放*/
  45. ASN1_STRING_set0(ri->enc_key, ek, ekLen);
  46. ek = NULL;
  47. //------------将接收者加入到PKCS7_ENVELOPE的接收者信息集合
  48. if (!SM2_EnvelopedData_add_recipient_info(p7, ri))
  49. {
  50. //TODO. 错误处理
  51. goto end;
  52. }
  53. //------------构造enc_data
  54. if (0 == SM2_EnvelopedData_dataInit(p7, uiSymmAlgorithm, iv, 16))
  55. {
  56. //TODO. 错误处理
  57. goto end;
  58. }
  59. if (0 == SM2_EnvelopedData_dataFinal(p7, cont, contLen))
  60. {
  61. //TODO. 错误处理
  62. goto end;
  63. }
  64. //------------PKCS7对象Der编码输出
  65. //pucDerEnvelopedData为缓冲区,用来存放DER编码后的数据;
  66. pTmp = NULL;
  67. pTmp = pucDerEnvelopedData;
  68. if ((derP7Len = i2d_SM2EnvelopedData(p7, &pTmp)) <= 0)
  69. {
  70. //TODO. 错误处理
  71. goto end;
  72. }

SM2_EnvelopedData_set_type该方法是根据SM2EnvelopedData结构设计的方法,用于根据OID设置其type。 内部会创建PKCS7_ENVELOPE数字信封结构对象,并设置PKCS7_ENVELOPE对象的版本号。(大家可以根据自己自定义的结构去进行设置

  1. ASN1_OBJECT *obj;
  2. obj = OBJ_txt2obj(oid, 1);
  3. if (0 == strcmp(oid, OID_SM2_Enveloped))
  4. {
  5. p7->type = obj;
  6. if ((p7->enveloped = PKCS7_ENVELOPE_new()) == NULL)
  7. goto err;
  8. if (!ASN1_INTEGER_set(p7->enveloped->version, 0))
  9. goto err;
  10. p7->enveloped->enc_data->content_type = OBJ_txt2obj(OID_SM2_Data, 1);
  11. }

SM2_EnvelopedData_dataInit方法是根据SM2EnvelopedData结构设计的方法,用于初始化结构中存储加密内容的算法及参数等

  1. int SM2_EnvelopedData_dataInit(SM2EnvelopedData *p7, int symmAlg, unsigned char *iv, unsigned int ivlen)
  2. {
  3. char objtmp[80] = { 0x00 };
  4. X509_ALGOR *xalg = NULL;
  5. OBJ_obj2txt(objtmp, sizeof(objtmp), p7->type, 1);
  6. if (0 == strcmp(objtmp, OID_SM2_Enveloped))
  7. {
  8. xalg = p7->enveloped->enc_data->algorithm;
  9. }
  10. else
  11. {
  12. LError("SM2_EnvelopedData_dataInit, PKCS7_R_WRONG_CONTENT_TYPE");
  13. return (0);
  14. }
  15. //指定内容加密算法
  16. int nid_alg = NID_undef;
  17. switch (symmAlg)
  18. {
  19. case SGD_SM4_ECB:
  20. nid_alg = NID_sms4_ecb;
  21. break;
  22. case SGD_SM4_CBC:
  23. nid_alg = NID_sms4_cbc;
  24. break;
  25. case SGD_SM4_CFB:
  26. nid_alg = NID_sms4_cfb128;
  27. break;
  28. case SGD_SM4_OFB:
  29. nid_alg = NID_sms4_ofb128;
  30. break;
  31. default:
  32. LError("Symm Algorithm undef.");
  33. nid_alg = NID_undef;
  34. return 0;
  35. }
  36. xalg->algorithm = OBJ_nid2obj(nid_alg);
  37. if (xalg->parameter == NULL)
  38. xalg->parameter = ASN1_TYPE_new();
  39. if (xalg->parameter == NULL)
  40. return 0;
  41. if (nid_alg == NID_sms4_ecb)
  42. {
  43. ASN1_TYPE_free(xalg->parameter);
  44. xalg->parameter = NULL;
  45. }
  46. else
  47. {
  48. //SM4算法非ECB模式,需要将IV向量值存放到enc_data中
  49. //存放到V_ASN1_OCTET_STRING类型中
  50. ASN1_TYPE_set_octetstring(xalg->parameter, iv, ivlen);
  51. }
  52. return 1;
  53. }

SM2_EnvelopedData_dataFinal方法是根据SM2EnvelopedData结构设计的方法,填入加密后的内容。

  1. int SM2_EnvelopedData_dataFinal(SM2EnvelopedData *p7, unsigned char *cont, unsigned int contlen)
  2. {
  3. char objtmp[80] = { 0x00 };
  4. ASN1_OCTET_STRING *os = NULL;
  5. OBJ_obj2txt(objtmp, sizeof(objtmp), p7->type, 1);
  6. if (0 == strcmp(objtmp, OID_SM2_Enveloped))
  7. {
  8. os = p7->enveloped->enc_data->enc_data;
  9. if (os == NULL) {
  10. os = ASN1_OCTET_STRING_new();
  11. if (os == NULL) {
  12. LError("SM2_EnvelopedData_dataFinal, ERR_R_MALLOC_FAILURE");
  13. return 0;
  14. }
  15. p7->enveloped->enc_data->enc_data = os;
  16. }
  17. }
  18. else
  19. {
  20. LError("SM2_EnvelopedData_dataFinal, PKCS7_R_WRONG_CONTENT_TYPE");
  21. return (0);
  22. }
  23. if (os == NULL)
  24. return 0;
  25. ASN1_OCTET_STRING_set(os, cont, contlen);
  26. return 1;
  27. }

以上仅贴出了一些主要代码,供大家参考的同时也记录下方便自己记忆。

最后DER编码输出的envelopedData数据用Asn1View打开查看,如下:

 

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号