openssl 对自定义结构体 按ASN.1的der编码规则进行编码

        数据序列化,为将高级语言代码转变成二进制流的过程称为数据的序列号,数据序列化的目的是物理存储或网络传输。在计算机高级程序编程语言里有许多结构化的结构,比如:数、图和结构体等,如何在网络中传输这些结构化的结构数据呢?我们知道高级语言里面的任何代码最终在网络中都是以二进制流的形式进行传输的,但是对于结构化的数据除了编成二进制码外,他们之间还存有一定的关系,为了在对方仍然知道这些关系以用来还原之前的结构,因此除了对结构化的数据进行编码外还得需要保存好他们的结构关系。

为了解决高级语言中结构化数据在网络传输中的结构关系能送达目的地进行还原,历史上出现了以下几种数据序列化的方法:ASN.1,XML,Json等(可参考:在维基百科中搜索数据序列号格式)。

        上面我们分析了ASN.1的作用(或者说为什么要引入ASN.1),下面看看ASN.1是什么东西?

        ASN.1本身只定义了表示信息的抽象句法,但是没有限定其编码的方法。各种ASN.1编码规则提供了由ASN.1描述其抽象句法的数据的值的传送语法(具体表达)。标准的ASN.1编码规则有基本编码规则(BER,Basic Encoding Rules)、规范编码规则(CER,Canonical Encoding Rules)、唯一编码规则(DER,Distinguished Encoding Rules)、压缩编码规则(PER,Packed Encoding Rules)和XML编码规则(XER,XML Encoding Rules)。为了使ASN.1能够描述一些原先没有使用ASN.1定义,因此不适用上述任一编码规则的数据传输和表示的应用和协议,另外制订了ECN来扩展ASN.1的编码形式。ECN可以提供非常灵活的表明方法,但还没有得到普遍应用。

        ASN.1与特定的ASN.1编码规则一起通过使用独立于计算机架构和编程语言的方法来描述数据结构,为结构化数据的交互提供了手段,特别是在网络环境的应用程序。

        openssl中SM2加密产生的密文为der编码的密文,因此解密接口需要的密文也是der编码的密文。而别的设备或者库产生的密文可能只是裸密文。因此要将裸密文进行der编码。
        以下为将一个自定义结构体进行der编码示例代码

#include <openssl/bn.h>
#include <openssl/ossl_typ.h>
#include <openssl/ec.h>
#include <openssl/opensslconf.h>
#include <iostream>
#include <sm4decryption.h>

int i2dSm2EnStr(char* enStr,int enStrLen,unsigned char* ASNEnStr);

//注册i2d结构体与转化函数
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;
};

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)

IMPLEMENT_ASN1_FUNCTIONS(SM2_Ciphertext)
//sm2密文格式问C1x(32字节)+c1y(32字节)+c3(32字节hash杂凑值)+c2(密文,长度等于明文)
int i2dSm2EnStr(char* enStr,int enStrLen,unsigned char* ASNEnStr)
{
    SM2_Ciphertext* sm2En=NULL;
    sm2En=SM2_Ciphertext_new();
    int c2Len=enStrLen-96;
    unsigned char C1x[32];
    unsigned char C1y[32];
    unsigned char C3[32];
    unsigned char C2[512];
    memcpy(C1x,(unsigned char*)enStr,32);  
    memcpy(C1y,(unsigned char*)enStr+32,32);
    memcpy(C3,(unsigned char*)enStr+64,32);
    memcpy(C2,(unsigned char*)enStr+96,c2Len);
    //print
    std::string resC1x;
    std::string resC1y;
    char buf2[3];
    for (int i = 0; i < 32; i++)
    {
        sprintf(buf2,"%02x",C1x[i]);
        resC1x+=buf2;
    }
    printf("\n");
    std::cout<<"resC1x:"<<resC1x;

    for (int i = 0; i < 32; i++)
    {
        sprintf(buf2,"%02x",C1y[i]);
        resC1y+=buf2;
    }
    printf("\n");
    std::cout<<"resC1y:"<<resC1y;
    BIGNUM* bC1x=BN_new();
    BIGNUM* bC1y=BN_new();
    BN_hex2bn(&bC1x,resC1x.c_str()))
    BN_hex2bn(&bC1y,resC1y.c_str()));
    sm2En->C1x=bC1x;
    sm2En->C1y=bC1y;

    if(!ASN1_OCTET_STRING_set(sm2En->C3,C3,32))
    {
        printf("C3 ASN1_OCTET_STRING_set fail");
    }
    if(!ASN1_OCTET_STRING_set(sm2En->C2,C2,c2Len))
    {
        printf("C2 ASN1_OCTET_STRING_set fail");
    }
    unsigned char * tem=ASNEnStr;
    int nLen=i2d_SM2_Ciphertext(sm2En,&tem);
    printf("asnLen:%d \n",nLen);
    for(int i=0;i<nLen;i++)
    {
    printf("0x%02x ",ASNEnStr[i]);
    }
    return nLen;
}


int main(int argc, char *argv[])
{

     unsigned char enStr2[116]={0xa0,0x3c,0x0b,0x75,0x4e,0x67,0x43,0xdd,0x4a,0x0a,0xd9,0xbb,0xf9,0xb3,0x73,0x87,0x17,0xb0,0xf8,0x49,0xea,0x8c,0x90,0xec,0x20,0x41,0xe6,0x77,0xb5,0xe6,0xab,0xbd,0xb0,0x18,0xc6,0xb6,0x76,0x22,0xb1,0x04,0x50,0xe7,0x65,0xac,0x26,0xcc,0x4d,0x61,0xa4,0x4a,0xf2,0x4a,0xcb,0x5b,0xe5,0xd4,0x40,0xa2,0x7c,0x9c,0x5b,0x57,0x2c,0xcd,0x67,0x74,0x24,0xfa,0x94,0x91,0x15,0x12,0xa2,0x35,0xdc,0x1e,0xfd,0xbe,0xba,0x40,0xf5,0x62,0x76,0x2b,0x88,0xfb,0xed,0xc8,0xbb,0xae,0x01,0x26,0xe3,0xf3,0xfb,0x4e,0xf1,0x20,0xdd,0x79,0x37,0x1a,0x5d,0x50,0xa9,0x24,0x91,0xe4,0x7a,0x26,0x5f,0xe7,0x41,0x8f,0x0a,0x5a};
     printf("deStr:\n");
     for(int i=0;i<116;i++)
    {
        printf("0x%02x ",enStr2[i]);
    }
      printf("\n");
      unsigned char ASNenStr[512];
      int ASNStrLen=i2dSm2EnStr((char*)enStr2,116,ASNenStr);
      printf("ASNStrLen:%d \n",ASNStrLen);
      printf("ASNenStr:\n");

      for(int i=0;i<ASNStrLen;i++)
      {
        printf("0x%02x ",ASNenStr[i]);
      }
      printf("\n");
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值