本文将详细介绍ASN.1中的BER编码规则,包括其编码机制、数据类型表示、以及如何将复杂的数据结构转换为二进制数据。通过本文的阅读,读者将对ASN.1中的BER编码有一个全面的理解。
目录
一.引言
二.BER编码基本结构
▐ 1. 类型域(Type)
示例一
示例二
▐ 2. 长度域(Length)
示例一
示例二
▐ 3. 内容域(Value)
布尔型(BOOLEAN)
整型(INTEGER)
位串(BIT STRING)
字符串(OCTET STRING)
NULL
对象标识符(OBJECT IDENTIFIER)
序列(SEQUENCE)
一.引言
在现代通信和信息技术领域,数据的精确表示和高效传输是至关重要的。ASN.1(Abstract Syntax Notation One)作为一种国际标准化组织(ISO)和国际电信联盟(ITU)制定的国际标准,提供了一种抽象的方法来描述、编码、解码和传输数据。ASN.1的核心组成部分之一是BER(Basic Encoding Rules),它定义了一种将ASN.1数据结构转换为二进制形式的编码规则。
BER编码不仅确保了数据的一致性和互操作性,而且通过其灵活的编码机制,支持了广泛的数据类型和结构。从简单的整数和字符串到复杂的数据结构,如序列和集合,BER编码都能够提供一种标准化的表示方法。这使得不同系统和应用程序能够无缝地交换数据,无论它们运行在何种平台或使用何种编程语言。
二.BER编码基本结构
BER(Basic Encoding Rules)是一种用于描述ASN.1(Abstract Syntax Notation One)数据的编码规则。BER编码广泛用于网络协议和数据交换标准,例如SNMP和LDAP。BER编码使用一种TLV(Type-Length-Value)的结构方法编码。
即,BER编码的基本结构由以下三个部分组成:
- 类型域(Type)
- 长度域(Length)
- 内容域(Value)
其中类型(Type)部分又有三部分组成:
- 标签类型(Class)
- 构造类型(P/C)
- 标签号(Tag)
就拿C语言的数据结构来说,除了有单一的Int类型,Doubel类型等,还有复杂的自定义类型结构体,对于一种数据结构中包含了其他数据结构的情况,BER编码也对其进行了规定,称之为结构类型。结构类型与一般简单类型的不同如下图:
如图所示,在复杂的结构类型中,他的内容域往往包含了许多简单类型。毕竟结构类型也只是简单类型的复合,因此下午的讲解全部都通过简单类型进行讲解。
我们分别对三部分进行分析:
▐ 1. 类型域(Type)
在 BER(Basic Encoding Rules)编码中,类型域(Type)用于标识数据的类型和类别。类型域编码包含三个部分:类(Class)、构造类型(PC, Primitive/Constructed)、和标签号(Tag Number)。下面详细说明这三个部分的编码:
类型域结构
类型域是一个字节(8 位)或多个字节(对于较大的标签号)。第一个字节的结构如下:
-
第1-2位:类(Class)
-
00:通用类(Universal)
-
01:应用类(Application)
-
10:上下文特定类(Context-specific)
-
11:私有类(Private)
-
-
第3位:构造类型(Constructed/Primitive)
-
0:原始类型(Primitive)
-
1:构造类型(Constructed)
-
-
第4-8位:标签号(Tag Number)
-
若标签号小于 31(即 0-30),则直接使用这些位表示标签号。
-
若标签号大于等于 31,则这些位全为 1,并且标签号在后续字节中以一种特殊的方式编码。
-
笔者这里给出图示如下:
对于标签号,这里在解释一下:
简单标签号(0-30)
对于标签号在 0 到 30 之间的情况,直接在类型域的第4-8位表示。例如:
通用类(Universal)布尔类型(Boolean):
0000 0001
,即0x01
应用类(Application)整数类型(Integer):
0100 0010
,即0x42
复杂标签号(>= 31)
对于标签号大于等于 31 的情况,第4-8位全为 1(即 0b11111),并且标签号以基于 7 位的块形式在后续字节中表示,每个字节的最高位为 1,表示后续有更多字节,最后一个字节的最高位为 0。例如:
标签号 31:
0b1111 1111 0011 1111
,即0x1F 0x1F
标签号 128:
0b1111 1111 1000 0001 0000 0000
,即0x1F 0x81 0x00
示例一
Tag number < 31
yesterdayINTEGER ::=127
Class = Universal
P/C = Primitive(简单类型)
Tag = 2(INTEGER)
Length =1 byte
Content =127
按照给出的信息,我们就可以得到如下结论:
类型域值为:00000010(0x02)
长度域值为:01
内容域值为:7F
BER编码为:00000010 0000000101111111
(02 01 7F)
示例二
Tag number >= 31
OwnInt ::=[APPLICATION 33]IMPLICIT INTEGER
HillTall Ownint ::= 110
Class = Application
P/C = Primitive(简单类型)
Tag = 33
Length = 1
Content = 110
按照给出的信息,我们就可以得到如下结论:
类型值为:01011111 00100001(5F21)
长度值为:1
内容值为:6E(110)
BER编码为:5F 21 01 6E
总结
-
类型域的前两位表示类(Class),第三位表示构造类型(Primitive/Constructed),第四至第八位表示标签号(Tag Number)。
-
对于标签号小于 31 的情况,直接使用第4-8位。
-
对于标签号大于等于 31 的情况,使用多个字节表示,第一字节的第4-8位全为 1,后续字节以 7 位块形式表示标签号。
通过这种编码方式,BER 能够灵活地表示各种数据类型,并确保编码的准确性和可扩展性。
▐ 2. 长度域(Length)
在 BER(Basic Encoding Rules)编码中,长度域用于指示随后的值域(Value)的长度。长度域的编码有主要两种形式:短形式和长形式。下面是对这两种形式的详细说明:
短形式
短形式用于表示长度小于 128 字节(即 0 到 127)的情况。在这种形式中,长度域仅占一个字节。该字节的最高位(第八位)为 0,低七位表示长度的值。例如:
-
若长度为 5,则长度域为
0000 0101
(即 0x05)。 -
若长度为 127,则长度域为
0111 1111
(即 0x7F)。
长形式
长形式用于表示长度大于等于 128 字节的情况。在这种形式中,长度域的第一个字节的最高位(第八位)为 1,低七位表示后续长度字节的个数。例如:
-
若长度为 128,则长度域为
1000 0001
(表示后续有 1 个字节)加上1000 0000
(表示长度为 128),即0x81 0x80
。 -
若长度为 300,则长度域为
1000 0010
(表示后续有 2 个字节)加上0000 0001 0010 1100
(即 300),即0x82 0x01 0x2C
。
长度不确定
上述俩种情况适合用于长度确定的情况,当长度不确定的时候,长度字节最高位置1,该字节的低7位置0。紧随的字节为内容字节,最后以两个字节 0x00 和 0x00 作为结束标志
图示如下:
示例一
Length < 128
DayOfYear ::= [application 17]IMPLICIT INTEGER
Today DayOfYear ::=128
Class = Application
P/C = Primitive
Tag = 17
Length = 2
Content =128
按照给出的信息,我们就可以得到如下结论:
提示:这里的内容域首位为 1 所有前面要加一个字节的0,后文会讲这部分
类型值:01 0 10001
长度值:0000 0010
内容值:0x00 80
BER编码为:01010001 00000010 00000000 10000000
示例二
Length >= 128
MemoString ::= Octest String( size(256))
memo MemoString ::=“abc...
Class = Universal
P/C = Primitive
Tag = 4
Length = 256
按照给出的信息,我们就可以得到如下结论:
类型值:00 0 00100(04)
长度值:1000 0010(0x82) 0000 0001 0000 0000(0x0100)
内容值:61 62 63...(”abc...”)
BER编码为:04 82 01 00 61 62 63
总结
-
对于长度小于 128 的值,使用短形式,只需要一个字节,最高位为 0。
-
对于长度大于等于 128 的值,使用长形式,首字节的最高位为 1,低七位表示后续字节的数量,这些后续字节组成一个大端整数,表示长度值。
-
如果长度不确定,长度字节最高位置1,该字节的低7位置0,最后以俩个字节 0x00 和 0x00 作为结束标志
这样,BER 编码能够灵活地表示不同长度的数据,确保编码的效率和可扩展性。
▐ 3. 内容域(Value)
在 BER(Basic Encoding Rules)编码中,内容域(Value)包含实际的数据信息,其编码方式取决于数据的类型。不同数据类型有不同的编码规则。以下是一些常见数据类型的编码方式:
布尔型(BOOLEAN)
布尔型值使用一个字节表示:
-
TRUE
编码为0xFF
-
FALSE
编码为0x00
整型(INTEGER)
整型值以大端顺序(高字节在前)编码,使用最少的字节数来表示值。如果最高有效位为 1,则需要在前面加一个 0x00
以避免符号扩展。例如:
-
0
编码为0x00
-
127
编码为0x7F
-
128
编码为0x00 0x80
-
-1
编码为0xFF
位串(BIT STRING)
位串由一个初始字节和实际数据组成。初始字节表示未使用的位数。实际数据按字节顺序排列。例如:
-
0x01101011
(假设全用)编码为0x00 0x6B
-
0x01101010
(未使用1位)编码为0x01 0x6A
字符串(OCTET STRING)
字符串(八位字节串)按字节顺序直接编码。例如:
-
"Hello" 编码为
0x48 0x65 0x6C 0x6C 0x6F
NULL
NULL 值没有内容,其长度为 0。因此,NULL 值的编码只是标记和长度,值为空。例如:
-
NULL 编码为
0x05 0x00
对象标识符(OBJECT IDENTIFIER)
对象标识符使用变量长度编码。前两个节点由 (X * 40) + Y
公式表示,后续节点使用基于 7 位的块形式编码,最高位为 1 表示有后续字节。例如:
-
1.2.840.113549
编码为0x2A 0x86 0x48 0x86 F7 0x0D
(1*40 + 2 = 42, 840 = 0x86 0x48, 113549 = 0x86 0xF7 0x0D)
序列(SEQUENCE)
序列包含一个或多个元素,每个元素按其类型编码,然后依次排列。例如,一个包含一个整数和一个字符串的序列:
-
整数:42 编码为
0x02 0x01 0x2A
-
字符串:"Hi" 编码为
0x04 0x02 0x48 0x69
整个序列编码为:0x30
(标记) 0x07
(长度) 0x02 0x01 0x2A
(整数) 0x04 0x02 0x48 0x69
(字符串)
总结
值域的编码方式根据数据类型的不同而不同,具体编码规则如下:
-
布尔型:使用一个字节表示 TRUE 或 FALSE。
-
整型:大端顺序,使用最少的字节数。
-
位串:一个初始字节表示未使用的位数,后跟实际数据。
-
八位字节串:直接按字节顺序编码。
-
NULL:无内容,长度为 0。
-
对象标识符:使用变量长度编码,前两个节点压缩表示,后续节点基于 7 位块编码。
-
序列:包含一个或多个元素,按其类型编码后依次排列。
通过这些编码规则,BER 能够灵活且高效地表示各种类型的数据。
以上便是BER编码的基础结构和编码方法,掌握了上述种种就可以构建基本的BER编码,而更加复杂的编码也只是多个简单的编码复合而成。研究BER编码对于以下应用场景也有着重要的作用:
-
网络协议:BER编码在网络协议中用于确保数据在不同系统和平台之间传输时的准确性和完整性。
-
安全协议:在安全领域,BER编码用于加密和解密过程中,确保数据的安全传输,如在SSL/TLS协议中。
-
数字证书:BER编码用于数字证书的编码,这是公钥基础设施(PKI)的关键组成部分,广泛应用于身份验证和数据加密。
-
数据库:在数据库系统中,BER编码用于存储和检索结构化数据,提高数据的组织和访问效率。
-
数据存储:BER编码在数据存储解决方案中用于优化数据的存储格式,减少存储空间的使用。
-
图像和视频传输:在多媒体领域,BER编码可以用于图像和视频数据的高效传输和存储。
本次的分享就到此为止了,希望我的分享能给您带来帮助,创作不易也欢迎大家三连支持,你们的点赞就是博主更新最大的动力!如有不同意见,欢迎评论区积极讨论交流,让我们一起学习进步!有相关问题也可以私信博主,评论区和私信都会认真查看的,我们下次再见