Если все ваши цифры меньше или равны 127, то вам очень повезло, потому что они могут быть представлены одним октетом каждый. Сложнее всего, когда у вас есть общие числа, такие как 1.2.840.113549.1.1.5 (sha1WithRsaEncryption)
. Эти примеры фокусируются на декодировании, но кодирование - это наоборот.
1. Первые две «цифры» представлены одним байтом
Вы можете декодировать, считав первый байт в целое число
var firstByteNumber = 42;
var firstDigit = firstByteNumber / 40;
var secondDigit = firstByteNumber % 40;
Производит значения
1.2
2. Последующие байты представлены с использованием Количество переменной длины , также называемое основанием 128.
VLQ имеет две формы,
Сокращенная форма - если октет начинается с 0, то он просто представляется с использованием оставшихся 7 битов.
Длинная форма - если октет начинается с 1 (старшего значащего бита), объедините следующие 7 битов этого октета плюс 7 бит каждого последующего октета, пока не встретите октет с 0 в качестве самого старшего бита ( это отмечает последний октет).
Значение 840 будет представлено следующими двумя байтами,
10000110
01001000
Combine to 00001101001000 and read as int.
Отличный ресурс для кодирования BER, http://luca.ntop.org/Teaching/Appunti/asn1.html
Первый октет имеет значение 40 * значение1 + значение2. (Это однозначно,
поскольку значение1 ограничено значениями 0, 1 и 2; значение2 ограничено
диапазон от 0 до 39, когда значение 1 равно 0 или 1; и, согласно X.208, n является
всегда минимум 2.)
Следующие октеты, если таковые имеются, кодируют значение 3, ...,
valuen. Каждое значение кодируется основанием 128, в первую очередь старшая цифра
с как можно меньшим количеством цифр и наиболее значимым битом каждого
Октет, кроме последнего в кодировке значения, установленного в «1». Пример:
первый октет кодировки BER объекта RSA Data Security, Inc.
идентификатор 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
Наконец, вот OID-декодер, который я только что написал на Perl.
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;
}
}