为了项目需要,网上找了下ASN1的工具比较少,尤其是C++的工具类,没办法没有这样的类,自己弄了一个,不完善,但是基本能够解析能用了,满足了自己的项目需要,所以公布出来给大家参考下,大家随意使用,有什么问题可以提出来大家一起改进,本来想弄成一个json模式,但是发现还得引用json库,那么自己随便定了几个结构弄了下,这样使用也方便
ASN1Util.h
#ifndef __ASN1_UTIL_H__
#define __ASN1_UTIL_H__
#include <string>
#include <vector>
//ANS.1工具类
//随便封装了下,可以改造,不完善,自己的功能已经满足就暂时不继续了
//add hmy 2023年7月15日11:01:52
namespace ht_asn1 {
//基础结构
class ASN1Base {
public:
int getType() {
return this->type;
}
int getStype() {
return this->stype;
}
int getLen() {
return this->len;
}
const char* getTypeStr();
friend class ASN1Util;
protected:
int type;//类型 默认-1 0容器(序列) 1 字节存储类型 2字符串 3 集合 5 枚举
int stype;//原始类型
int len;
};
//容器结构
class ASN1Ctn : public ASN1Base {
public :
ASN1Ctn();
std::vector<ASN1Base*> getVal() {
return this->val;
}
void add(ASN1Base* base);
//释放
void free();
friend class ASN1Util;
protected:
std::vector<ASN1Base*> val;
};
//字符串
class ASN1String : public ASN1Base {
public:
std::string getVal() {
return this->val;
}
friend class ASN1Util;
protected:
std::string val;
};
//字节数组
class ASN1Byte : public ASN1Base {
public:
~ASN1Byte();
public:
unsigned char* getVal() {
return this->val;
}
friend class ASN1Util;
protected:
unsigned char* val;
};
//asn.1操作类
class ASN1Util
{
public:
ASN1Util();
~ASN1Util();
private:
//解析值
int paramVal(unsigned char* content, int* start, int contenlen, int len, int isZero, int sub, ASN1Ctn* asn1ctn);
public:
//解析整体结构
int paramAsn1(unsigned char* buf, int len);
ASN1Ctn* getAsn1();
private:
ASN1Ctn asn1Ctn;
};
}
#endif
ASN1Util.cpp
#include "ASN1Util.h"
#include <stdio.h>
#include <iostream>
using namespace std;
/*
*
* TLC T类型定义 L长度 V值
*
* *****************************
*类型定义解析:
*
bit8~bit7:
第一个字节 bit8~bit7 表明tag所属类型
00 通用级 universal class
01 应用级 application class
10 规范级 context-specific class
11 私有级 private class
bit6:
Primitive (P) 0 数据内容仅由一个数据元素组成
Constructed (C) 1 数据内容由多个数据元素组成
第一个字节 bit6 表明本tag的value部分是否包含子tag,1则表示是Constructed(复合)的,为0表示是Primitive(原始);
第一个字节 bit5~bit1 表明是否有第二个字节一起表示本tag,11111 全为1表示有第二个字节,即非11111的都没有第二个字节;
第二个字节 bit8 为1,同时bit7~bit1 大于0 表示有下一个tag
第三~N个字节同第二个字节
bit5~bit1:
bit
类型
数据类型 编码类型 Tag number(十进制) Tag number(十六进制)
Decimal Hexadecimal
End-of-Content (EOC) Primitive 0 0
BOOLEAN Primitive 1 1
INTEGER Primitive 2 2
BIT STRING Both 3 3
OCTET STRING Both 4 4
NULL Primitive 5 5
OBJECT IDENTIFIER Primitive 6 6
Object Descriptor Both 7 7
EXTERNAL Constructed 8 8
REAL (float) Primitive 9 9
ENUMERATED Primitive 10 A
EMBEDDED PDV Constructed 11 B
UTF8String Both 12 C
RELATIVE-OID Primitive 13 D
TIME Primitive 14 E
Reserved 15 F
SEQUENCE and SEQUENCE OF Constructed 16 10
SET and SET OF Constructed 17 11
NumericString Both 18 12
PrintableString Both 19 13
T61String Both 20 14
VideotexString Both 21 15
IA5String Both 22 16
UTCTime Both 23 17
GeneralizedTime Both 24 18
GraphicString Both 25 19
VisibleString Both 26 1A
GeneralString Both 27 1B
UniversalString Both 28 1C
CHARACTER STRING Constructed 29 1D
BMPString Both 30 1E
DATE Primitive 31 1F
TIME-OF-DAY Primitive 32 20
DATE-TIME Primitive 33 21
DURATION Primitive 34 22
OID-IRI Primitive 35 23
RELATIVE-OID-IRI Primitive 36 24
******************************
L长度解析:
bit8:
1: 后面字节为长度
0:当前bit7~bit1表示长度
*/
namespace ht_asn1 {
ASN1Util::ASN1Util() {
}
ASN1Util::~ASN1Util() {
asn1Ctn.free();
}
int ASN1Util::paramVal(unsigned char* content, int* start, int contenlen, int len, int isZero, int sub, ASN1Ctn* asn1ctn) {
int pos = 0;
int tagclass = 0;
int pc = 0;
int type = 0;
int val_len = 0;
unsigned char* buf = (unsigned char*)(content + *start);
len = len - *start;
//printf("%s tag:%02X len:(%d,%d) ", sub == 0 ? "sub" : "main", buf[0], contenlen, len);
//求出tag
tagclass = (buf[pos] & 0xC0) >> 6;
pc = (buf[pos] & 0x20) >> 5;
type = (buf[pos] & 0x1F);
if ((type & 0x0F) == 0x0F) {
type = 0;
for (; pos < contenlen; pos++) {
if ((buf[pos] & 0x80) == 0) {
type = (type << 8) | buf[pos];
}
else {
type = (type << 8) | (buf[pos] & 0x7F);
break;
}
}
}
//cout << "tagclass:" << tagclass << ",pc:" << pc << ",type:" << type;
pos++;
//求出长度
//L长度解析:
// bit8:
// 1: 后面字节为长度
// 0:当前bit7~bit1表示长度
val_len = 0;
if ((buf[pos] & 0x80) != 0) {
int byte_len = (buf[pos] & 0x7F);
if (byte_len == 0x7F || byte_len == 0x00) {
val_len = contenlen;
isZero = (byte_len == 0x7F ? 1 : 0);
pos++;
}
else {
pos++;
for (int i = 0; i < byte_len && pos < contenlen; i++, pos++) {
val_len = (val_len << 8) | (buf[pos]);
}
}
}
else {
val_len = (val_len << 8) | (buf[pos++]);
}
//cout << ",len:" << val_len << ",pos:" << pos<<",contenlen:"<< contenlen << endl;
//结构包含结构
if (pc == 1) {
sub = 1;
do {
ASN1Ctn* asnctn = new ASN1Ctn();
if (asnctn == NULL) {
return -1;
}
asn1ctn->add(asnctn);
paramVal(buf, &pos, sub == 0 ? contenlen : val_len, len, isZero, sub, asnctn);
sub = 0;
} while (pos < len);
}
else {
if (type == 22 || type == 12) {//字符串
ASN1String* asn1 = new ASN1String();
if (asn1 == NULL) {
return -1;
}
asn1->type = 2;
asn1->stype = type;
asn1->len = val_len;
asn1->val.append((char*)(buf + pos), val_len);
asn1ctn->add(asn1);
}
else {
//if (type == 2 || type == 4 || type == 3) {//整形1
ASN1Byte* asn1 = new ASN1Byte();
if (asn1 == NULL) {
return -1;
}
asn1->type = 1;
asn1->stype = type;
asn1->val = new unsigned char[val_len];
if (asn1->val == NULL) {
delete asn1;
return -1;
}
asn1->len = val_len;
memcpy(asn1->val, buf + pos, val_len);
asn1ctn->add(asn1);
}
//int outPos = pos;
//printf("val=");
//for (int i = 0; i < val_len && outPos < contenlen; i++, outPos++) {
// printf("0x%02X ", buf[outPos]);
//}
//cout << endl;
pos += val_len;
//cout << "pos:" << pos << ",contenlen:" << contenlen << endl;
//if (pos > contenlen) pos = contenlen;
}
*start = pos + *start;
return 0;
}
int ASN1Util::paramAsn1(unsigned char* buf, int len) {
int pos = 0;
//1111 1111
do {
/*
* bit8~bit7:
第一个字节 bit8~bit7 表明tag所属类型
bit6:
Primitive (P) 0 数据内容仅由一个数据元素组成
Constructed (C) 1 数据内容由多个数据元素组成
第一个字节 bit6 表明本tag的value部分是否包含子tag,1则表示是Constructed(复合)的,为0表示是Primitive(原始);
第一个字节 bit5~bit1 表明是否有第二个字节一起表示本tag,11111 全为1表示有第二个字节,即非11111的都没有第二个字节;
第二个字节 bit8 为1,同时bit7~bit1 大于0 表示有下一个tag
第三~N个字节同第二个字节
*/
if (paramVal(buf, &pos, len, len, -1, 0, &asn1Ctn) < 0){
return -1;
}
} while (pos < len);
return 0;
}
// 默认-1 0容器(序列) 1 字节存储类型 2字符串 3 集合 4 枚举
const char* ASN1Base::getTypeStr() {
if (type == 0) {
return "SEQUENCE";
}
else if (type == 1) {
return "bytes";
}
else if (type == 2) {
return "string";
}
else if (type == 3) {
return "set";
}
else if (type == 4) {
return "enum";
}
return "unkown";
}
ASN1Ctn* ASN1Util::getAsn1() {
return &(this->asn1Ctn);
}
ASN1Byte::~ASN1Byte() {
if (val != NULL) {
delete val;
}
}
ASN1Ctn::ASN1Ctn() {
this->type = 0;
this->len = 0;
}
void ASN1Ctn::add(ASN1Base* base) {
val.push_back(base);
this->len++;
}
void ASN1Ctn::free() {
for (auto it = val.begin(); it != val.end(); ++it) {
// *it 获取当前迭代器指向的值
if (((ASN1Base*)*it)->getType() == 0) {
((ASN1Ctn*)*it)->free();
}
else if (((ASN1Base*)*it)->getType() == 1) {
delete ((ASN1Byte*)*it)->getVal();
}
delete* it;
*it = NULL;
}
}
}
使用方式:
比较容易
把asn1结构传输解析就好
用例:
void showAsn1(ht_asn1::ASN1Base *base) {
if (base->getType() == 0) {
ht_asn1::ASN1Ctn* ctn = ((ht_asn1::ASN1Ctn*)base);
for (int i = 0; i < ctn->getVal().size(); i++) {
if (ctn->getVal()[i]->getType() == 0) {
cout << "<" << ctn->getVal()[i]->getTypeStr() << ">" << endl;
showAsn1(ctn->getVal()[i]);
cout << "</" << ctn->getVal()[i]->getTypeStr() << ">" << endl;
}
else {
cout << "<" << ctn->getVal()[i]->getTypeStr() << ">" << endl;
if (ctn->getVal()[i]->getType() == 1) {
ht_asn1::ASN1Byte * asn1 = (ht_asn1::ASN1Byte *)ctn->getVal()[i];
printf("len: %d ,type:%d data:", asn1->getLen(), asn1->getStype());
for (int j = 0; j < asn1->getLen(); j++) {
printf("%02X", asn1->getVal()[j]);
}
printf("\n");
}
else if (ctn->getVal()[i]->getStype() == 12) {
ht_asn1::ASN1String * asn1 = (ht_asn1::ASN1String*)ctn->getVal()[i];
printf("len: %d ,type:%d data: %s", asn1->getLen(), asn1->getStype(), asn1->getVal().c_str());
}
else if (ctn->getVal()[i]->getType() == 2) {
cout << ((ht_asn1::ASN1String*)ctn->getVal()[i])->getVal() << endl;
}
cout << "</" << ctn->getVal()[i]->getTypeStr() << ">"<<endl;
}
}
}
}
void testAsn1() {
//test asn1结构
const unsigned char pdata[] = {0x30,0x79,0x02,0x20,0x1A,0xF4,0xEE,0xBB,0x48,0xBA,0x93,0xE1,0xDB,0x9B,0xDC,0xCE,0x70,0x94,0x49,0x7E,0x8C,0x04,0x78,0x35,0x63,0xEF,0x88,0xC6,0x77,0x36,0x31,0x41,0x6A,0x6E,0x38,0x5D,0x02,0x21,0x00,0xF0,0x7C,0x45,0x31,0x4C,0x2D,0x09,0x36,0x65,0x05,0x6B,0x7E,0xD2,0x79,0x75,0xF6,0xEE,0xF3,0x60,0x0D,0xBD,0xB4,0x7B,0xF6,0x71,0x0A,0xF3,0x38,0x1C,0x45,0x74,0x0A,0x04,0x20,0x93,0xF3,0x30,0x18,0x0F,0x7B,0x48,0xE1,0x6A,0x8A,0xDD,0x56,0x36,0x53,0xFE,0xF5,0x6F,0x4C,0xCA,0xE0,0x89,0x91,0xFF,0x0B,0xB8,0x4F,0x05,0x75,0x01,0xBC,0xE7,0xBA,0x04,0x10,0x57,0x3D,0x43,0xCC,0xA8,0x6E,0x34,0xC8,0x07,0xAE,0x47,0xA5,0x41,0x44,0x35,0x03};
int len = sizeof(pdata);
ht_asn1::ASN1Util asn1util;
asn1util.paramAsn1((unsigned char *)pdata, len);
ht_asn1::ASN1Ctn* ctn =asn1util.getAsn1();
for (int i = 0; i < ctn->getVal().size(); i++) {
showAsn1(ctn->getVal()[i]);
}
}
int main(){
testAsn1();
return 0;
}
输出信息
整体就是如此