Skip to content

sciurid/asn1util

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ASN.1编解码工具(asn1util)

根据X.680/690/696规定,实现ASN.1的编解码和部分数据类型处理的纯Pyhon库。

  • BER解码
  • DER解码编码
  • 部分通用类(Universal Class)数据类型格式处理

介绍

抽象语法标记(版本1)ASN.1 (Abstract Syntax Notation One)是由国际电信联盟(ITU)下属的 电信和信息通信技术标准化部门(ITU-T)推荐的用户表示信息数据语法的编码格式。

ASN.1格式定义多种基本的数据元素类型和结构类型,以及基本编码规则(Basic Encoding Rule, BER)、 规范编码规则(Canonical Encoding Rule, CER)和区分编码规则(Distinguished Encoding Rule, DER) 三种编码规则。其中BER规则最为宽松,典型应用如在智能卡领域中;DER规则最为严格,可以确保编码的一致性, 典型应用在数字证书等密码学相关领域。

主要模块和相应功能

  • asn1util.tlv
    • Tag和Length的定义,实现了编码语法规则
  • asn1util.exceptions
    • 抛出的异常
  • asn1util.util
    • 处理数据的工具
  • asn1util.codec.basic
    • 基于ASN.1编码规则的TLV对象和字节串/流的基本编解码函数
  • asn1util.codec.decoder
    • 基于ASN.1编码规则的流式输出的解码类
  • asn1util.codec.encoder
    • 基于ASN.1编码规则的流式输出的编码类
  • asn1util.data_types.general_data_types
    • ASN.1元素的基本类型定义:ASN1DataType/ASN1GeneralDataType
    • 基于ASN.1编码规则的ASN.1元素和字节串/流的编解码
  • asn1util.data_types.primitive_data_types
    • ASN.1通用类(Universal Class)的基本类型(Primitive Type)元素定义
  • asn1util.data_types.constructed_data_types
    • ASN.1通用类(Universal Class)的基本类型(Constructed Type)元素定义
  • asn1util.data_types.real
    • ASN.1实数类型(ASN1Real)的处理方法

下载和安装

git clone https://github.com/sciurid/asn1util.git
pip install -e asn1util

或者

git clone https://gitee.com/LanceChen/asn1.git
pip install -e asn1

快速使用

ASN.1基本数据类型编码

a = ASN1Integer(1234567890)  # 整数
print(a, a.octets.hex())

b = ASN1Real(1.2345678)  # 实数(二进制浮点数)
c = ASN1Real(Decimal('1.2345678'))  # 实数(十进制浮点数)
print(b, c)
d = ASN1Real(12345678, base=2)  # 实数(二进制整数)
print(d, d.octets.hex())
e = ASN1Real(12345678)  # 实数(十进制整数)
print(e, e.octets.hex())

# 文本的各种编码格式
f = ASN1PrintableString('A fox jumps over a lazy dog.')  # ISO-8859-1
print(f, f.octets.hex(), f.value)
g = ASN1UTF8String('中华人民共和国万岁 世界人民大团结万岁')  # UTF-8
h = ASN1UniversalString('中华人民共和国万岁 世界人民大团结万岁')  # UTF-32BE (UCS-4)
i = ASN1BMPString('中华人民共和国万岁 世界人民大团结万岁')  # UTF-16BE (UCS-2)
print(g, g.octets.hex(), g.value)
print(h, h.octets.hex(), h.value)
print(i, i.octets.hex(), i.value)

j = ASN1ObjectIdentifier('1.2.840.113549.1.1.11')  # OID
print(j)

k = ASN1OctetString(bytes.fromhex('00 01 02 03 04 05 06 07 08'))  # 字节串
print(k, k.octets.hex())
l = ASN1BitString((bytes.fromhex('00 01 02 03 04 05 06 07 08'), 4))  # 比特串,注意末尾的未用比特数
print(l, l.octets.hex())

now = datetime.now().astimezone(timezone.utc)
m = ASN1GeneralizedTime(now)  # 通用时间
print(m, m.octets)
n = ASN1UTCTime(now)  # UTC时间
print(n, n.octets)

ASN.1组合数据类型编码

层次构造

使用StreamEncoder类来进行各种嵌套层次的构建。

from asn1util import *
encoder = StreamEncoder()
with encoder.construct(TAG_Sequence):
    encoder.append_primitive(TAG_Boolean, b'\xff')
    encoder.append_primitive(TAG_Integer, b'\x01\x02\x03\x04')
    encoder.append_primitive(TAG_UTF8String, '中华人民共和国万岁 世界人民大团结万岁'.encode('utf-8'))
    with encoder.construct(TAG_Sequence):
        encoder.append_primitive(TAG_Boolean, b'\x00')
        encoder.append_primitive(TAG_PrintableString, 'The fox jumps over a lazy dog.'.encode('ascii'))
print(encoder.data.hex(' '))

for t, l, v in iter_descendant_tlvs(encoder.data, in_octets=False):
    print(t, l, v.hex())

asn1_print_data(encoder.data)

支持直接编码Python基本数据类型

encoder = StreamEncoder()
with encoder.within_sequence():
    encoder.append_boolean(True)
    encoder.append_integer(32767)
    encoder.append_integer(-32768)

with encoder.within_set():
    encoder.append_real(1234567890)
    encoder.append_real(Decimal(1234567890))
    encoder.append_real(1.23456789)
    encoder.append_real(1.23456789, base=10)

with encoder.within_sequence():
    encoder.append_utf8_string('中华人民共和国万岁 世界人民大团结万岁')
    encoder.append_printable_string('The fox jumps over a lazy dog. (1234567890)')
    encoder.append_object_identifier('1.2.840.113549.1.1.11')

print(encoder.data.hex(' '))
for t, l, v in iter_descendant_tlvs(encoder.data, return_octets=False):
    print(t, l, v.hex())
asn1_print_data(encoder.data)

支持不定长(Indefinite Length)

注:不定长组合元素不符合DER规范,较为少见。

from asn1util import *
encoder = StreamEncoder()
with encoder.construct(TAG_Sequence, True):
    encoder.append_primitive(TAG_Boolean, b'\xff')
    encoder.append_primitive(TAG_Integer, b'\x01\x02\x03\x04')
    encoder.append_primitive(TAG_UTF8String, '中华人民共和国万岁 世界人民大团结万岁'.encode('utf-8'))
    with encoder.construct(TAG_Sequence, True):
        encoder.append_primitive(TAG_Boolean, b'\x00')
        encoder.append_primitive(TAG_PrintableString, 'The fox jumps over a lazy dog.'.encode('ascii'))
print(encoder.data.hex(' '))

for t, l, v in iter_descendant_tlvs(encoder.data, in_octets=False):
    print(t, l, v.hex())

asn1_print_data(encoder.data)

ASN.1解码

简单解码

  • read_next_tlv 从字符流中读取下一个TLV
  • iter_tlvs 遍历当前层次的TLV,组合元素视为本层的单个TLV
  • iter_descendant_tlvs 以深度遍历方式遍历所有TLV
encoder = StreamEncoder()
encoder.append_primitive(TAG_Integer, b'\x01\x02\x03\x04')
with encoder.construct(TAG_Sequence):
    encoder.append_primitive(TAG_Boolean, b'\x00')
    encoder.append_primitive(TAG_PrintableString, 'The fox jumps over a lazy dog.'.encode('ascii'))

print(encoder.data.hex(' '))
for t, l, v in iter_tlvs(encoder.data, return_octets=False):
    print(t, l, v.hex())

print(encoder.data.hex(' '))
for t, l, v in iter_descendant_tlvs(encoder.data, return_octets=False):
    print(t, l, v.hex())

print(encoder.data.hex(' '))
stream = BytesIO(encoder.data)
t, l, v = read_next_tlv(stream, return_octets=True)
print(t.hex(), l.hex(), v.hex())
t, l, v = read_next_tlv(stream, return_octets=True)
print(t.hex(), l.hex(), v.hex())
t, l, v = read_next_tlv(stream, return_octets=True)
self.assertIsNone(t)
self.assertIsNone(l)
self.assertIsNone(v)

已知类型解码

通用类型的实现在asn1util.data_types包里,都是以ASN1DataType为基类的子类,分别对应不同的数据类型。 已经实现的具体类型有:

  • ASN1EndOfContent
  • ASN1Boolean
  • ASN1Integer
  • ASN1Enumerated
  • ASN1Real
  • ASN1BitString
  • ASN1OctetString
  • ASN1Null
  • ASN1ObjectIdentifier
  • ASN1UTF8String
  • ASN1UniversalString
  • ASN1BMPString
  • ASN1ISO2022String
  • ASN1NumericString
  • ASN1PrintableString
  • ASN1VisibleString
  • ASN1GraphicString
  • ASN1ObjectDescriptor
  • ASN1GeneralString
  • ASN1IA5String
  • ASN1GeneralizedTime
  • ASN1UTCTime
  • ASN1Sequence
  • ASN1Set

此外还有一个通用的未专门化的类型:

  • ASN1GeneralDataType

这些类型大多都可以通过from_bytes函数实现从bytes-like数据中生成相应对象; octets属性是整个对象的bytes(二进制)表示。 tag和length属性分别为Tag和Length类型的标签、长度, value属性为相应类型的数值,value_octets属性为数值的字节串表示。 详情可见ASN1DataType基类。

此部分有三个函数用于处理连续的asn1数据:

  • asn1_encode函数:用于将一个或一组ASN1DataType对象转化为二进制数据。
  • asn1_decode函数:用于从二进制数据中读出一个或一组ASN1DataType并保持其结构。
    • 例如,SEQUENCE类型的数据读出为ASN1Sequence对象,其value为所包含对象的列表。
  • asn1_print函数:用于以结构化的方式打印asn.1格式的二进制数据。

后续开发计划

  • 扩充常见的ASN.1类型
  • 增加默认类型的StreamEncoder类或者方法

主要参考资料

  • X.690: Information technology – ASN.1 encoding rules: Specification of Basic Encoding Rules (BER), Canonical Encoding Rules (CER) and Distinguished Encoding Rules (DER)
  • X.680: Information technology – Abstract Syntax Notation One (ASN.1): Specification of basic notation

About

ASN.1编解码工具的纯Python实现

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages