最近在国四协议转发国家平台的事宜。新协议要求国四报文要以加密形式转发给国家平台。可以是国密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 buffif (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: .cppSOURCES = 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/libLIB_PATH += ${SPECIAL_LIB_PATH} ${SYS_LIB_PATH}SYS_LIBS = -ldl -lpthreadLIBS = ${SPECIAL_LIBS} ${SYS_LIBS} MACRO_FLAGS = ${SPECIAL_MACRO_FLAGS} -D_USE_MACRO -D_DEBUG -D_USE_SECONDCCC=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+=-liconvMACRO_FLAGS +=-D_MAC_OS -D_UNIXLFLAGS = -shared -Wl,-install_name,$(DYLIB_MINOR_NAME)
endifLFLIBS = $(LIB_PATH) $(LIBS)CPPFLAGS = -g ${LIB_PATH} ${SPECIAL_CCFLAGS} CPPLIBS = ${LIBS}AR = ar
ARFLAGS = -ruv
RANLIB = ranlibINSTALL_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); fisetup:@if [ "x${PROGRAM}" != "x" ]; then cp $(PROGRAM) /usr/local/lbs/bin/; fi
clean:rm -rf ${OBJECTS} ${CLIB} ${PROGRAM} ${SONAME}
# rm -rf ir.outrm -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}.*; filog: @rm -f core.* nohup.out valg.log.*@rm -f ${MTRANS_PRJ_HOME}/lbs/log/${PROGRAM}.*