ASN.1 / DER 整数编码
ASN.1 / DER Encoding of Integers
我目前开始使用 DER(可分辨编码规则)编码,但在理解整数编码时遇到问题。
在参考文档https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf中这种编码定义如下:
8.3.1 The encoding of an integer value shall be primitive. The contents octets shall consist of one or more octets.
8.3.2 If the contents octets of an integer value encoding consist of more than one octet, then the bits of the first octet and bit 8 of the second octet:
shall not all be ones; and
shall not all be zero.
NOTE – These rules ensure that an integer value is always encoded in the smallest possible number of octets.
8.3.3 The contents octets shall be a two's complement binary number equal to the integer value, and consisting of bits 8 to 1 of the first octet, followed by bits 8 to 1 of the second octet, followed by bits 8 to 1 of each octet in turn up to and including the last octet of the contents octets.
在另一个网站上,https://docs.microsoft.com/en-us/windows/desktop/seccertenroll/about-integer, it is explained that for positive numbers whose binary representation starts with a 1, a zero byte is added at the front. This is also mentioned in the answers to a former question on Whosebug: ASN Basic Encoding Rule of an integer。
不幸的是,从这些答案中我看不出如何从参考文档的规则中推导出后一条指令。
例如,如果我想对数字 128 进行编码,为什么我不能这样做
[标记字节][长度字节]10000000?
我知道正确的编码应该是 [tag byte] [length byte] 00000000 10000000,但是上面的变体破坏了哪个条件?可能跟补码有关系,但是128的补码不就是10000000吗?
我希望你能帮助我理解为什么微软网站上的描述等同于原始定义。谢谢。
Two's complement 规则 (8.3.3) 表示如果设置第一个(最低索引)内容字节的高位,则数字为负数。
02 01 80
有内容 0b1000_0000
。由于设置了高位,所以这个数是负数。
翻转所有位(0b0111_1111
),然后加一:0b1000_0000
;表示代表负数128.
对于一个不太退化的例子,0b1000_0001
=> 0b0111_1110
=> 0b0111_1111
,表明 0x81
是负数 127.
对于数字(正数)127,由于没有设置高位,数字被解释为正数,所以内容只是 0b0111_1111
又名 0x7F
,导致 02 01 7F
ASN.1 中的常见模式是 TLV,类型/长度/值
类型:一个八位字节,整数为 0x02
值:带符号约束的二进制补码已在上面回答。
长度编码有两种模式:
未设置第一个长度八位字节的最高有效位:那么八位字节就是内容长度本身。
设置第一个八位字节的最高有效位:然后第一个八位字节后面是(值-128)个八位字节,形成非负整数的实际长度,字节顺序大端。
长度 0...127 符合第一条规则,128...符合第二条规则。
我目前开始使用 DER(可分辨编码规则)编码,但在理解整数编码时遇到问题。
在参考文档https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf中这种编码定义如下:
8.3.1 The encoding of an integer value shall be primitive. The contents octets shall consist of one or more octets.
8.3.2 If the contents octets of an integer value encoding consist of more than one octet, then the bits of the first octet and bit 8 of the second octet:
shall not all be ones; and
shall not all be zero.
NOTE – These rules ensure that an integer value is always encoded in the smallest possible number of octets.
8.3.3 The contents octets shall be a two's complement binary number equal to the integer value, and consisting of bits 8 to 1 of the first octet, followed by bits 8 to 1 of the second octet, followed by bits 8 to 1 of each octet in turn up to and including the last octet of the contents octets.
在另一个网站上,https://docs.microsoft.com/en-us/windows/desktop/seccertenroll/about-integer, it is explained that for positive numbers whose binary representation starts with a 1, a zero byte is added at the front. This is also mentioned in the answers to a former question on Whosebug: ASN Basic Encoding Rule of an integer。
不幸的是,从这些答案中我看不出如何从参考文档的规则中推导出后一条指令。
例如,如果我想对数字 128 进行编码,为什么我不能这样做
[标记字节][长度字节]10000000?
我知道正确的编码应该是 [tag byte] [length byte] 00000000 10000000,但是上面的变体破坏了哪个条件?可能跟补码有关系,但是128的补码不就是10000000吗?
我希望你能帮助我理解为什么微软网站上的描述等同于原始定义。谢谢。
Two's complement 规则 (8.3.3) 表示如果设置第一个(最低索引)内容字节的高位,则数字为负数。
02 01 80
有内容 0b1000_0000
。由于设置了高位,所以这个数是负数。
翻转所有位(0b0111_1111
),然后加一:0b1000_0000
;表示代表负数128.
对于一个不太退化的例子,0b1000_0001
=> 0b0111_1110
=> 0b0111_1111
,表明 0x81
是负数 127.
对于数字(正数)127,由于没有设置高位,数字被解释为正数,所以内容只是 0b0111_1111
又名 0x7F
,导致 02 01 7F
ASN.1 中的常见模式是 TLV,类型/长度/值
类型:一个八位字节,整数为 0x02
值:带符号约束的二进制补码已在上面回答。
长度编码有两种模式:
未设置第一个长度八位字节的最高有效位:那么八位字节就是内容长度本身。
设置第一个八位字节的最高有效位:然后第一个八位字节后面是(值-128)个八位字节,形成非负整数的实际长度,字节顺序大端。
长度 0...127 符合第一条规则,128...符合第二条规则。