ASN.1结构解析c++

  为了项目需要,网上找了下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;
}

输出信息

 整体就是如此

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值