ASN.1编码学习笔记二

本文详细介绍了ASN.1中的各种数据类型,包括布尔型、整数、位串等,并探讨了这些类型如何用于密码学应用。同时,还介绍了ASN.1编码的基本原则及其在序列和集合中的应用。

3.ASN.1数据类型

        ASN.1针对广泛的应用定义了多种数据类型,我们这里只讨论跟密码学应用相关的数据类型.我们将讨论如下数据类型:

  •  
    •  
      •   布尔型 (Boolean);
      •         八位位组串 (OCTET String);
      •         位串 (BIT String);
      •         IA5String;
      •         可打印字符串 (PrintableString);
      •         整数 (INTEGER);
      •         对象标识符 (OBJECT Identifier, OID);
      •         世界协调时 (UTCTIME);
      •         空 (NULL);
      •         序列,单一序列;
      •         集合;
      •         单一集合;

 

  任何ASN.1编码都是以两个字节开始(或者八位位组,含有8个二进制位),不管什么类型,它们都是通用的.第一个字节是类型标识符,也包含一 些修正位;第二各字节是长度.

 

3.1 ASN.1头字节

      头字节(hearder byte)位于ASN.1编码的开始,由3部分组成。如下图:

    

        <1>. 类别位。

                 类别位(classification bits)由两位表示,用来描述数据将要解释的上下文。

                  

位8位7类别
00通用(Universal)
01应用(Application)
10上下文特定(Context Specific)
11专用(Private)

 

                  所有的类型中,通用类别最常用。

       <2>. 结构化位。

                结构化位(constructed bit)表示一个给定的编码是否是相同类型的多种编码的结构化。结构化元素是容器类型必需的,因为在逻辑上,它们只是其他元素的集合。

               结构化元素有自己的头字节和长度字节,之后是元素各个要素组件的单独编码。也就是说,这些要素组件是独立地可解码 ASN.1数据类型。

               严格的说,容器类是唯一允许使用结构化位的数据类型。这是因为对于其他数据类型,给定内容,只允许一种编码。所以其他所有数据类型的结构化位都为0。

      <3>. 原始类型。

              ASN.1头字节的低5位定义了32种ASN.1的原始类型(primitive type)

 

代码 ASN.1类型 作用
1布尔型储存布尔值
2整数储存大整数
3位串存储位数组
4八位位串存储字节数组
5预留位(例如在选择修改器中)
6对象标识符标识算法及协议
16序列和单一序列未分类元素的容器
17集合和单一集合已分类元素的容器
19可打印字符串ASCII编码(忽略一些不可打印字符)
22IA5StringASCII编码
23世界协调时以统一格式表示的时间

 

3.2 ASN.1长度编码

根据编码的实际长度,ASN.1定义了两种长度编码(length encoding)方法,长编码和短编码。

编码字节的最高位代表的是短编码还是长编码;而低7位则形成一个长度立即数。

<1>. 短编码。

        在短编码中,负载的长度必须小于128字节。长度立即数用来表示负载的长度。例如,对于一个长度为65 (0x41)的负载进行编码,其长度编码字节只需简单的设置为0x41即可。因为其最高位是0,则编码器可以判断出这是短编码,而且长度是65。

<2>. 长编码。

        在长编码中,定义了附加的抽象数据来对长度进行编码,它仅适用于所有长度为128字节或以上的负载。在这种模式下,长度立即数存储的是为了表示负载长度所 需的字节数。这个长度必须以big-endian格式进行编码。(其实big endian是指低地址存放最高有效字节(MSB),而little endian则是低地址存放最低有效字节(LSB)。)。

         例如,为一个长度为47310 (0xB8CE)的负载进行编码,因为它的长度大于127, 所以要采用长编码方式。实际的长度需要两个字节来表示。则,长度编码字节为0x82; 然后用big-endian格式存储的长度值为0xB8 0xCE。则全部长度编码为 0x82 B8 CE。

 

3.3 ASN.1布尔类型

      布尔编码的负载或者是全0或者是全1的八位位组。头字节以0x01开始,长度编码字节为0x01,负载内容取决于布尔值的取值。

 

布尔值编码
False0x01 01 00
True0x01 01 FF

 

3.4 ASN.1整数类型

      整数类型表示一个有符号的任意精度的标量,它的编码是可移植,平台无关的。

      正整数的编码比较简单。每个字节表示的最大整数是255 (0xFF), 存储的实际数值分成字节大小的数字,并且以big-endian格式存储。例如:

八位位组{Xk, Xk-1,...., X0}将以递减的顺序从Xk到X0进行存储.编码规定正整数的第一个字节的最高位必须是0,即Xk的最高为必须是0,为1的话则为负数.例如: x = 49468= 193 * 256 + 60 = 0xC1 * 0x FF + 0x3C; 即X1=0xC1, X0 = 0x3C. 按正常规定,编码应该是 0x02 02 C1 3C, 但是X1的最高位是1, 应该被看成负数.最简单的方法是用前端零字节进行填充.编码变为 0x02 02 00 C1 3C.

  负整数的编码有些复杂.要先找到一个最小的256的幂,使它比要编码的负数的绝对值还要大.例如:x = - 1555; 被1555大的256的最小的幂是256^2 = 65536; 然后将这个数跟负数相加以得到2的补码. 65536 + (-1555) = 63981 =  0xF9 * 0xFF + 0x ED. 则编码为 0x02 02 F9 ED.

      以下是一些常用整数编码的例子.

 

编码
00x02 01 00
10x02 01 01
20x02 01 02
1270x02 01 7F
1280x02 02 00 80
-10x02 01 FF
-1280x02 01 80
-327680x02 02 80 00
12345678900x02 04 49 96 02 D2

 

3.5 ANS.1位串类型

      位串(BIT STRING)类型以可移植形式表示位数组.除了ASN.1头部两个字节之外,还有一个附加的头部用来表示填充数据(通常是一个字节,因为填充是为了形成 一个完整的字节).编码规则:位串的第一位放到第一个负载字节的第8位;位串的第二位放到第一个负载字节的第7位; 依此类推.填充满第一个负载字节,就继续填充第二个负载字节.如果最后一个负载字节未被填充满,空的位用0来填充, 0的个数存放到头部用来表示填充数据的那个字节里.

下面举例说明:

有一个位串{1,0,0,0,1,1,1,0,1,0,0,1},开始填充负载字节.第一个字节填充后为10001110 = 0x 8E; 第二个字节填充后为10010000 = 0x90, 低位4个0为填充的空位.则,负载为2个字节加上表示填充0个数的一个字节0x04总共3个字节.则完整的编码为:0x03 03 04 8E 90.

 

解码器通过计算8 * 负载长度 - 填充数 来得到存储输出所需要的位数.

 

3.6 ASN.1八位位组串类型

  八位位组串(OCTET STRING)是保存字节数组,它和位串类型(BIT STRING)很相似.这种编码非常简单,像其他类型一样对头部进行编码,然后直接将八位位组复制过去即可.例如:对{FE, ED, 6A, B4}编码;首先存储类型0x04, 接着是长度0x04,然后是字节本身0xFE ED 6A B4; 完整的编码为 0x04 04 FE ED 6A B4.

 

3.7 空类型

     空(NULL)类型实际上是"占位符", 它是含有空白选项的选择修改器所特有.例如:

          MyAccount ::= SEQUENCE {

                    Name                            IA5String,

                    Group                           IA5String,

                   Credentials                    CHOICE{

                                                              rsaKey           RSAPublicKey,

                                                              passwdHash  OCTET STRING,

                                                              none               NULL

                                                         }

           }

     在上面这个结构中,帐号的证书应该包含一个RSA密钥或一个密码散列值或什么都没有.

 空类型的编码是 0x05 00.

 

3.8 ASN.1 对象标识符类型

      对象标识符(OBJECT IDENTIFIER, OID)类型用层次的形式来表示标准规范.标识符树通过一个点分的十进制符号来定义,这个符号以组织,子部分然后是标准的类型和各自的子标识符开始.

      例如:MD5的OID 是 1.2.840.113549.2.5  表示为"iso(1) member-body (2) US (840) rsadsi(113549) digestAlgorithm (2) md5 (5)", 所以当解码程序看到这个OID时,就知道是MD5散列.

      OID在公钥算法标准中很流行,它指出证书绑定了哪种散列算法. 同样,也有公钥算法,分组算法,和操作模式的OID. 它们是一种高效且可移植的表示数据包中所选算法的形式.

      对OID的编码规则:

  •  
    • 前两部分如果定义为x.y, 那么它们将合成一个字40*x + y, 其余部分单独作为一个字节进行编码.
    • 每个字首先被分割为最少数量的没有头零数字的7位数字.这些数字以big-endian格式进行组织,并且一个接一个地组合成字节. 除了编码的最后一个字节外,其他所有字节的最高位(位8)都为1.

     举例: 30331 = 1 * 128^2 + 108 * 128 + 123  分割成7位数字(0x80)后为{1,108,123}设置最高位后变成{129,236,123}.如果该字只有一个7位数字,那么最高为0.

 

     MD5 OID的编码:

        1. 将1.2.840.113549.2.5转换成字数组 {42, 840, 113549, 2, 5}.

        2. 然后将每个字分割为带有最高位的7位数字,{{0x2A},{0x86,0x48},{0x86,0xF7,0x0D},{0x02},{0x05}}.

        3. 最后完整的编码为 0x06 08 2A 86 48 86 F7 0D 02 05. 

 

3.9 ASN.1序列和集合类型

  序列(SEQUENCE)和单一序列(SEQUENCE OF)以及相应的集合(SET)和单一集合(SET OF)类型叫做"结构"类型或简单容器.它们是一种用来把相关数据元素收集为一个独立的可解码元素的简单方法.

      序列编码有以下性质:

      1. 编码是结构化的.即头字节的位6必须设置. 

  2. 编码的内容是由ASN.1序列类型定义列表中的所有数据类型值的完全编码所组成,并且按照它们出现的顺序进行编码,除非这些类型被可选 (OPTIONAL)或默认(DEFAULT)关键字所引用.

  例:考虑如下序列

  User ::== SEQUENCE{

          ID        INTEGER,

          Active BOOLEAN

      }

     当取值为{32,TRUE}时,编码为 0x 30 06 02 01 20 01 01 FF} 在ASN.1文档里,使用空格来表示编码的属性.

 0x30 06

               02 01 20

               01 01 FF

 

3.10 ASN.1可打印字符串和IA5String类型

        可打印字符串(PrintableString)和IA5String类型定义了一种独立于本地代码页和字符集定义,在任何平台上都可以将ASCII字符 串编码为可读字符串的可移植方法.

       可打印字符串对象是ASCII集合的一个有限子集,这个子集包括32,39,40~41,43~58,61,63以及65~122.

       IA5String类型的编码对象是ASCII集合中的大多数.包括NULL,BEL,TAB,NL,LF,CR以及32~126.

       可打印字符串和IA5String的编码和八位位组串相似.可打印字符串的头字节是0x13, IA5String的是0x16. 例如:"Hello World"的编码为0x13 0B 48 65 6D 6D 6F 20 57 6F 72 6D 64.

 

3.11 ASN.1世界协调时类型

        世界协调时(UTCTIME)定义了一种相对GMT时间的标准时间(以日期)编码.它使用"YYMMDDHHMMSSZ"的格式分别表示年,月,日,时, 分,秒. 其中"Z"是遗留自初始的UTCTIME. 如果没有"Z",就允许两种附加组"[+/-]hh 'mm'",其中"hh"和"mm"分别为与GMT的时差和分差. 如果有"Z",则时间是以Zulu或GMT时间表示.

        字符串的编码按照IA5String编码规则进行转换(ASCII字符集),其头字节为0x17而不是0x16. 例如:

        July 4,2003 at 11:33 and 28 seconds编码为"030704113328Z", 再编码0x17 0D 30 33 30 37 30 34 31 31 33 33 32 38 5A.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值