Cra*_*lus 23 security binary encoding asn.1
我无法理解ASN.1的基本概念.
如果类型是OID,相应的数字是否实际编码在二进制数据中?
例如,在这个定义中:
id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
Run Code Online (Sandbox Code Playgroud)
相应的1.3.6.1.5.5.7.48.1是否完全像这样编码在二进制文件中?
我问这个是因为我试图理解我在DER文件(证书)中看到的特定值,即04020500,我不知道如何解释它.
Cod*_*odo 36
是的,OID以二进制数据编码.您提到的OID 1.3.6.1.5.5.7.48.1变为2b 06 01 05 05 07 30 01(前两个数字以单字节编码,所有剩余数字也以单个字节编码,因为它们都是小于128).
OID编码的一个很好的描述中找到这里.
但分析ASN.1数据的最佳方法是粘贴到在线解码器中,例如http://lapo.it/asn1js/.
Des*_*tar 17
如果你的所有数字都小于或等于127,那么你很幸运,因为它们每个都可以用一个八位字节表示.棘手的部分是你有更多的常见数字,例如1.2.840.113549.1.1.5 (sha1WithRsaEncryption).这些例子侧重于解码,但编码正好相反.
1.前两个'数字'用一个字节表示
您可以通过将第一个字节读入整数来进行解码
var firstByteNumber = 42;
var firstDigit = firstByteNumber / 40;
var secondDigit = firstByteNumber % 40;
Run Code Online (Sandbox Code Playgroud)
产生价值
1.2
Run Code Online (Sandbox Code Playgroud)
2.使用可变长度数量表示后续字节,也称为基数128.
VLQ有两种形式,
短格式 - 如果八位字节以0开头,则使用剩余的7位简单表示.
长格式 - 如果八位字节以1(最高有效位)开始,则组合该八位字节的后7位加上每个后续八位字节的7位,直到遇到一个以0为最高位的八位位组(这标记为最后一个八位字节).
值840将用以下两个字节表示,
10000110
01001000
Combine to 00001101001000 and read as int.
Run Code Online (Sandbox Code Playgroud)
BER编码的重要资源,http://luca.ntop.org/Teaching/Appunti/asn1.html
第一个八位字节的值为40*value1 + value2.(这是明确的,因为value1限于值0,1和2;当value1为0或1时,value2被限制在0到39的范围内;并且,根据X.208,n总是至少为2.)
以下八位字节(如果有)编码value3,...,valuen.每个值编码为128,最高有效位,尽可能少的数字,以及每个八位字节的最高有效位,除了值的编码设置为"1"的最后一位.示例:RSA Data Security,Inc.的BER编码的第一个八位字节的对象标识符是40*1 + 2 = 42 = 2a16.840 = 6*128 + 4816的编码是86 48,并且113549 = 6*1282 + 7716*128 + d16的编码是86 f7 0d.这导致以下BER编码:
06 06 2a 86 48 86 f7 0d
最后,这是我刚刚在Perl中编写的OID解码器.
sub getOid {
my $bytes = shift;
#first 2 nodes are 'special';
use integer;
my $firstByte = shift @$bytes;
my $number = unpack "C", $firstByte;
my $nodeFirst = $number / 40;
my $nodeSecond = $number % 40;
my @oidDigits = ($nodeFirst, $nodeSecond);
while (@$bytes) {
my $num = convertFromVLQ($bytes);
push @oidDigits, $num;
}
return join '.', @oidDigits;
}
sub convertFromVLQ {
my $bytes = shift;
my $firstByte = shift @$bytes;
my $bitString = unpack "B*", $firstByte;
my $firstBit = substr $bitString, 0, 1;
my $remainingBits = substr $bitString, 1, 7;
my $remainingByte = pack "B*", '0' . $remainingBits;
my $remainingInt = unpack "C", $remainingByte;
if ($firstBit eq '0') {
return $remainingInt;
}
else {
my $bitBuilder = $remainingBits;
my $nextFirstBit = "1";
while ($nextFirstBit eq "1") {
my $nextByte = shift @$bytes;
my $nextBits = unpack "B*", $nextByte;
$nextFirstBit = substr $nextBits, 0, 1;
my $nextSevenBits = substr $nextBits, 1, 7;
$bitBuilder .= $nextSevenBits;
}
my $MAX_BITS = 32;
my $missingBits = $MAX_BITS - (length $bitBuilder);
my $padding = 0 x $missingBits;
$bitBuilder = $padding . $bitBuilder;
my $finalByte = pack "B*", $bitBuilder;
my $finalNumber = unpack "N", $finalByte;
return $finalNumber;
}
}
Run Code Online (Sandbox Code Playgroud)
OID编码为假人:):
这是ITU-T建议X.690第8.19章的重写
这是上述内容的简单 Python 3 实现。将对象标识符的字符串形式转换为 ASN.1 DER 或 BER 形式。
def encode_variable_length_quantity(v:int) -> list:
# Break it up in groups of 7 bits starting from the lowest significant bit
# For all the other groups of 7 bits than lowest one, set the MSB to 1
m = 0x00
output = []
while v >= 0x80:
output.insert(0, (v & 0x7f) | m)
v = v >> 7
m = 0x80
output.insert(0, v | m)
return output
def encode_oid_string(oid_str:str) -> tuple:
a = [int(x) for x in oid_str.split('.')]
oid = [a[0]*40 + a[1]] # First two items are coded by a1*40+a2
# A rest is Variable-length_quantity
for n in a[2:]:
oid.extend(encode_variable_length_quantity(n))
oid.insert(0, len(oid)) # Add a Length
oid.insert(0, 0x06) # Add a Type (0x06 for Object Identifier)
return tuple(oid)
if __name__ == '__main__':
oid = encode_oid_string("1.2.840.10045.3.1.7")
print(oid)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31010 次 |
| 最近记录: |