经典SM2密文转 ASN1/DER编码格式

最近在国四协议转发国家平台的事宜。新协议要求国四报文要以加密形式转发给国家平台。可以是国密4,国密2.如果使用国密2的时候,注意密文要使用ASN1/DER编码格式。于是我参考了以下几个链接的内容:

基于OpenSSL,实现SM2密文数据的ASN1编码转换_sm2密钥转asn-CSDN博客

如何实现“使用OpenSSL库进行ASN.1 DER编码的C/C++教程”的具体操作步骤_mob649e815c3b9e的技术博客_51CTO博客

关于SM2算法 ASN.1 DER编码_sm2 der编码密文-CSDN博客

写了我的版本,当然我已经编译过了openssl1.1.1d ,并准备好了inlcude 和lib.

下面是我的代码:


#include <string>
#include <iostream>
#include <openssl/asn1.h>
#include <openssl/ec.h>
#include <openssl/asn1t.h>
using namespace std;

// 自定义ASN1编码结构
typedef struct SM2_Ciphertext_st MY_ASN;
DECLARE_ASN1_FUNCTIONS(MY_ASN)

typedef struct SM2_Ciphertext_st
{
    // ASN1_INTEGER *xc;  // x分量
    // ASN1_INTEGER *yc;  // y分量
    BIGNUM *xc;  // x分量
    BIGNUM *yc;  // y分量
    ASN1_OCTET_STRING *hash; // 杂凑值
    ASN1_OCTET_STRING *cipherText;
};

ASN1_SEQUENCE(MY_ASN) = {
	ASN1_SIMPLE(MY_ASN, xc, BIGNUM),
	ASN1_SIMPLE(MY_ASN, yc, BIGNUM),
	ASN1_SIMPLE(MY_ASN, hash, ASN1_OCTET_STRING),
	ASN1_SIMPLE(MY_ASN, cipherText, ASN1_OCTET_STRING),
} ASN1_SEQUENCE_END(MY_ASN)
 
// 由OpenSSL提供的宏,实现自定义的ASN1编码
// 调用此宏,便定义了函数: SM2_Ciphertext_new、SM2_Ciphertext_free、d2i_SM2_Ciphertext、i2d_SM2_Ciphertext
IMPLEMENT_ASN1_FUNCTIONS(MY_ASN)


#define ERR_HEX2BYTE_PARAM_ERROR			13
#define ERR_HEX2BYTE_INVALID_DATA			14
#define ERR_HEX2BYTE_BEYOND_RANGE			15

/**
     * @brief change a string of Ascii(0--f) to BYTE str
     * Eg:"1A2B3C4D" (length of 8) will be trasform to byte string 0x1A2B3C4D  (length will be 4)
     * to use it : hexCharStr2unsignedCharStr("1A2B3C4D", strlen("1A2B3C4D"), 0 , buff, &ulBuffLen);
     * @param src [in] source string
     * @param lsrc [in] source string lenth
     * @param flag [in] just input 0
     * @param out [out] output BYTE str
     * @param lout [out] output BYTE str lenth
     * @return int , 0 -- ok; other : failed
     */
int hexCharStr2unsignedCharStr(const char* src, unsigned long lsrc, int flag, unsigned char* out, unsigned long* lout)
{
    if ((0 == flag && 0 != lsrc % 2) || (0 != flag && 0 != lsrc % 3) || NULL == src || NULL == out)
    {
        return ERR_HEX2BYTE_PARAM_ERROR;//param err
    }

    unsigned int j = 0;//index of out buff
    if (0 == flag)
    {
        for (unsigned int i = 0; i < lsrc; i += 2)
        {
            int tmp = 0;
            int HIGH_HALF_BYTE = 0;
            int LOW_HALF_BYTE = 0;
            if (src[i] >= 0x30 && src[i] <= 0x39)
            {
                HIGH_HALF_BYTE = src[i] - 0x30;
            }
            else if (src[i] >= 0x41 && src[i] <= 0x46)
            {
                HIGH_HALF_BYTE = src[i] - 0x37;
            }
            else if (src[i] >= 0x61 && src[i] <= 0x66)
            {
                HIGH_HALF_BYTE = src[i] - 0x57;
            }
            else if (src[i] == 0x20)
            {
                HIGH_HALF_BYTE = 0x00;
            }
            else
            {
                return ERR_HEX2BYTE_INVALID_DATA;
            }

            if (src[i + 1] >= 0x30 && src[i + 1] <= 0x39)
            {
                LOW_HALF_BYTE = src[i + 1] - 0x30;
            }
            else if (src[i + 1] >= 0x41 && src[i + 1] <= 0x46)
            {
                LOW_HALF_BYTE = src[i + 1] - 0x37;
            }
            else if (src[i + 1] >= 0x61 && src[i + 1] <= 0x66)
            {
                LOW_HALF_BYTE = src[i + 1] - 0x57;
            }
            else if (src[i + 1] == 0x20)
            {
                LOW_HALF_BYTE = 0x00;
            }
            else
            {
                return ERR_HEX2BYTE_INVALID_DATA;
            }

            tmp = (HIGH_HALF_BYTE << 4) + LOW_HALF_BYTE;
            out[j] = tmp;
            j++;
        }
    }
    *lout = j;
    return 0;
}


int main()
{
    string strX = "3174E0481D4989440BD75EB76AB375F097E86DD0BF3C743B28791105C144C4C9";
    string strY = "03D42AD3EF928B270DD7DCBD3A464F6EBA15AE2367D050140A35BEA8D7D5A2CD";
    string strC = "00E848179472475224BFE6E4A11A19BCA3E9576DCF1286EAD62457A74C5A73F8";
    string strText = "3906F12ECD6274B2575583886751E6E5BD6C48C041359B6BDABF34D796A6675736B076C3BA66FAF542817333A666DFF9F571AC55FFEE12582E16663FF8B55B39F350C15949A4189F5482164DAB15E5E4AC5F4A0A297E838A715A4A8E910EF6D65A49314F80FE5D2117B2BE1342944CD8845B95D9";

    unsigned char arrX[32] = {0x00}; unsigned long  xlen = 0;
    unsigned char arrY[32] = {0x00}; unsigned long  ylen = 0;
    unsigned char arrC[32] = {0x00}; unsigned long  Clen = 0;
    unsigned char arrText[1024] = {0x00}; unsigned long textlen =0;
    hexCharStr2unsignedCharStr(strX.c_str(), strX.length(), 0, arrX, &xlen);
    hexCharStr2unsignedCharStr(strY.c_str(), strY.length(), 0, arrY, &ylen);
    hexCharStr2unsignedCharStr(strC.c_str(), strC.length(), 0, arrC, &Clen);
    hexCharStr2unsignedCharStr(strText.c_str(), strText.length(), 0, arrText, &textlen);


    MY_ASN *pObj = MY_ASN_new();
    // ASN1_INTEGER *integer1 = ASN1_INTEGER_new();
    // ASN1_INTEGER *integer2 = ASN1_INTEGER_new();
    BIGNUM* x; BIGNUM* y;
    x = y = NULL;
    x = BN_bin2bn(arrX,32,NULL);
    y = BN_bin2bn(arrY,32,NULL);
    ASN1_OCTET_STRING* phash= ASN1_OCTET_STRING_new();
    ASN1_OCTET_STRING* pCipterTest = ASN1_OCTET_STRING_new();
    // 分配内存
    pObj->xc = x;
    pObj->yc = y;
    pObj->hash = phash;
    pObj->cipherText = pCipterTest;
    ASN1_OCTET_STRING_set(pObj->hash, arrC, 32);
    ASN1_OCTET_STRING_set(pObj->cipherText, arrText, textlen);
    // 进行ASN.1 DER编码
    unsigned char derData[1024];
    unsigned char *pder = &derData[0];
    int derDataLength = i2d_MY_ASN(pObj, &(pder));

    // ASN1_INTEGER_free(pObj->xc);
    // ASN1_INTEGER_free(pObj->yc);
    printf("1\n");
    //ASN1_OCTET_STRING_free(pObj->hash);
    //ASN1_OCTET_STRING_free(pObj->cipherText);
    MY_ASN_free(pObj);

    // 打印
    printf("DER component:\n");
	for (int i = 0; i < derDataLength; i++)
	{
		printf("%02X", derData[i]);
	}
	printf("\n\n");
    return 0;
}

下面是我的一个makefile

############################################################
## makefile of ASN1/DER 验证程序
############################################################
.SUFFIXES: .cpp

SOURCES  =  main.cpp 
					
PROGRAM  = testASN1_Der
CLIB     = 

SPECIAL_MACRO_FLAGS = -DRELEASE
SPECIAL_CCFLAGS = 
#注意这里的 kafka库用的是特殊的版本,而且单独指定了openssl的库-国密2用
SPECIAL_INCL_PATH  = -I../include  -I../dblibs/openssl_1.1.1d/include
#链接库
SPECIAL_LIB_PATH =  -L../dblibs/openssl_1.1.1d/lib 
SPECIAL_LIB_PATH += -L/usr/lib64  
SPECIAL_LIB_PATH += -L/usr/local/lib64/

SPECIAL_LIBS = -lrt -lz -lssl -lcrypto 

#include ../makefile.include
DBLIBS_HOME=../dblibs
SYS_INCL_PATH = -I/usr/include
INCL_PATH = \
        ${SYS_INCL_PATH} \
        ${SPECIAL_INCL_PATH} \
        -I.

SYS_LIB_PATH  = -L/usr/local/lib
        
LIB_PATH += ${SPECIAL_LIB_PATH} ${SYS_LIB_PATH}

SYS_LIBS =  -ldl -lpthread

LIBS = ${SPECIAL_LIBS} ${SYS_LIBS} 

MACRO_FLAGS = ${SPECIAL_MACRO_FLAGS} -D_USE_MACRO -D_DEBUG -D_USE_SECOND

CCC=g++
# 编译基础库 - 注意使用了c++11
CCFLAGS  = -std=c++11 -g -Wall -c -fPIC -ggdb3 -Wno-deprecated ${MACRO_FLAGS} ${INCL_PATH} ${SPECIAL_CCFLAGS} 
            
LFLAGS = -shared -Wl,-soname,$(SONAME)

#因为用到了openssl de libcrypto库又不能改生产环境的状态,就这么搞了
LD_RUN_PATH = -Wl,-rpath=../libc++
# Platform-specific overrides
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
ifeq ($(uname_S),Darwin)
  SYS_LIBS+=-liconv
  MACRO_FLAGS +=-D_MAC_OS -D_UNIX
  LFLAGS = -shared -Wl,-install_name,$(DYLIB_MINOR_NAME)
endif

LFLIBS = $(LIB_PATH) $(LIBS)
            
CPPFLAGS = -g ${LIB_PATH} ${SPECIAL_CCFLAGS} 

CPPLIBS  = ${LIBS}

AR       = ar
ARFLAGS  = -ruv
RANLIB	 = ranlib

INSTALL_BIN_PATH= ${MTRANS_PRJ_HOME}/bin
TARGET_PATH= ./

OBJECTS=${SOURCES:%.cpp=%.o}

all: ${CLIB} ${PROGRAM} ${SONAME}

${CLIB}: ${OBJECTS}
	@if [ ! -d ${TARGET_PATH} ]; then mkdir -p ${TARGET_PATH}; fi
	$(AR) ${ARFLAGS} $@ $(OBJECTS)
	$(RANLIB) $@
	
${SONAME} : ${OBJECTS}
	@if [ ! -d ${TARGET_PATH} ]; then mkdir -p ${TARGET_PATH}; fi
	$(CCC) $(LFLAGS) -o $(SONAME) $(OBJECTS) $(LFLIBS)
	
${PROGRAM}: ${OBJECTS}
	@if [ ! -d ${TARGET_PATH} ]; then mkdir -p ${TARGET_PATH}; fi
	$(CCC) $(LD_RUN_PATH) -o $@ ${CPPFLAGS} $(OBJECTS) $(CPPLIBS)

.cpp.o:
	$(CCC) $(CCFLAGS) -o $@ -c $< 

install:
	@if [ "x${SONAME}" != "x" ]; then echo ${SONAME} ; rm -f "${MTRANS_PRJ_HOME}/libs/lib/${SONAME}"; cp -r ${SONAME} ${MTRANS_PRJ_HOME}/libs/lib; fi	
	@if [ "x${LNNAME}" != "x" ]; then cd "${MTRANS_PRJ_HOME}/libs/lib"; rm -rf ${LNNAME}; ln -s ${SONAME} ${LNNAME}; fi
	@if [ "x${PROGRAM}" != "x" ]; then mkdir -p ${INSTALL_BIN_PATH}; cp $(PROGRAM) $(INSTALL_BIN_PATH); fi
	
setup:
	@if [ "x${PROGRAM}" != "x" ]; then cp $(PROGRAM) /usr/local/lbs/bin/; fi
clean:
	rm -rf ${OBJECTS} ${CLIB} ${PROGRAM} ${SONAME}
#	rm -rf ir.out
	rm -rf core.* 
	rm -rf *.o nohup.out
	@if [ "x${SONAME}" != "x" ]; then rm -rf *.so* ; rm -rf ${MTRANS_PRJ_HOME}/libs/lib/${SONAME}; fi 
	@if [ "x${PROGRAM}" != "x" ]; then rm -rf ${MTRANS_PRJ_HOME}/lbs/log/${PROGRAM}.*; fi
	
log:	
	@rm -f core.* nohup.out valg.log.*
	@rm -f ${MTRANS_PRJ_HOME}/lbs/log/${PROGRAM}.*

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是将PEM格式的SM2公钥换为C/C++中可以使用的数据结构的示例代码: ```c++ #include <openssl/bio.h> #include <openssl/evp.h> #include <openssl/ec.h> #include <openssl/pem.h> /* 将PEM格式的SM2公钥换为EC_KEY结构 */ EC_KEY *pem_to_ec_key(const char *pem_key) { EC_KEY *ec_key = NULL; BIO *bio = NULL; EVP_PKEY *evp_key = NULL; bio = BIO_new(BIO_s_mem()); BIO_puts(bio, pem_key); evp_key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL); if (evp_key != NULL) { ec_key = EVP_PKEY_get1_EC_KEY(evp_key); EVP_PKEY_free(evp_key); } BIO_free(bio); return ec_key; } /* 将EC_KEY结构的SM2公钥换为C/C++中的数据结构 */ void ec_key_to_bytes(EC_KEY *ec_key, unsigned char *buf, int buf_len) { const EC_GROUP *group = EC_KEY_get0_group(ec_key); const EC_POINT *point = EC_KEY_get0_public_key(ec_key); const EC_POINT *generator = EC_GROUP_get0_generator(group); const BIGNUM *x = EC_POINT_get0_affine_coordinates_GFp(group, point, NULL, NULL); const BIGNUM *y = EC_POINT_get0_affine_coordinates_GFp(group, point, x, NULL); const BIGNUM *order = EC_GROUP_get0_order(group); const BIGNUM *a = EC_GROUP_get0_a(group); const BIGNUM *b = EC_GROUP_get0_b(group); const BIGNUM *gx = EC_POINT_get0_affine_coordinates_GFp(group, generator, NULL, NULL); const BIGNUM *gy = EC_POINT_get0_affine_coordinates_GFp(group, generator, gx, NULL); int len = BN_num_bytes(order); if (buf_len < len * 6) { return; } memset(buf, 0, buf_len); buf[0] = len * 2 + 1; buf[1] = 0x02; BN_bn2bin(x, buf + 2 + len - BN_num_bytes(x)); buf[len + 2] = 0x03; BN_bn2bin(y, buf + len + 3 + len - BN_num_bytes(y)); buf[len * 2 + 3] = len; BN_bn2bin(order, buf + len * 2 + 4); BN_bn2bin(a, buf + len * 3 + 4); BN_bn2bin(b, buf + len * 4 + 4); buf[len * 5 + 4] = len * 2; BN_bn2bin(gx, buf + len * 5 + 5 + len - BN_num_bytes(gx)); BN_bn2bin(gy, buf + len * 6 + 5 + len - BN_num_bytes(gy)); } /* 示例用法 */ int main() { const char *pem_key = "-----BEGIN PUBLIC KEY-----\n" "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEyKmZGn1LbXtjJ0Gj4Fg6IhXzgHd\n" "qz5M5zgAvoU+OeGQ0FmLjSw5zUyvJfE8vJx42vZIYdJ1s0j3w/h5lQ+MzA==\n" "-----END PUBLIC KEY-----\n"; EC_KEY *ec_key = pem_to_ec_key(pem_key); if (ec_key != NULL) { int len = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key)) / 8; unsigned char buf[len * 6 + 5]; ec_key_to_bytes(ec_key, buf, sizeof(buf)); /* buf中存储了C/C++中的SM2公钥 */ EC_KEY_free(ec_key); } return 0; } ``` 其中,`pem_to_ec_key`函数将PEM格式的SM2公钥换为EC_KEY结构,`ec_key_to_bytes`函数将EC_KEY结构的SM2公钥换为C/C++中的数据结构。在示例代码中,C/C++中的SM2公钥存储在`buf`中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值