最近在国四协议转发国家平台的事宜。新协议要求国四报文要以加密形式转发给国家平台。可以是国密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}.*