Вам не нужно экспортировать существующие параметры, а затем повторно импортировать их поверх них. Это заставляет вашу машину генерировать ключ RSA, а затем выбрасывать его. Таким образом, указание размера ключа для конструктора не имеет значения (если вы не используете ключ, он не будет его генерировать... обычно).
Файл открытого ключа представляет собой большой двоичный объект в кодировке DER.
-----BEGIN PUBLIC KEY-----
MIGgMA0GCSqGSIb3DQEBAQUAA4GOADCBigKBggC8rLGlNJ17NaWArDs5mOsV6/kA
7LMpvx91cXoAshmcihjXkbWSt+xSvVry2w07Y18FlXU9/3unyYctv34yJt70SgfK
Vo0QF5ksK0G/5ew1cIJM8fSxWRn+1RP9pWIEryA0otCP8EwsyknRaPoD+i+jL8zT
SEwV8KLlRnx2/HYLVQkCAwEAAQ==
-----END PUBLIC KEY-----
Если вы возьмете содержимое внутри брони PEM, это массив байтов в кодировке Base64.
30 81 A0 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01
05 00 03 81 8E 00 30 81 8A 02 81 82 00 BC AC B1
A5 34 9D 7B 35 A5 80 AC 3B 39 98 EB 15 EB F9 00
EC B3 29 BF 1F 75 71 7A 00 B2 19 9C 8A 18 D7 91
B5 92 B7 EC 52 BD 5A F2 DB 0D 3B 63 5F 05 95 75
3D FF 7B A7 C9 87 2D BF 7E 32 26 DE F4 4A 07 CA
56 8D 10 17 99 2C 2B 41 BF E5 EC 35 70 82 4C F1
F4 B1 59 19 FE D5 13 FD A5 62 04 AF 20 34 A2 D0
8F F0 4C 2C CA 49 D1 68 FA 03 FA 2F A3 2F CC D3
48 4C 15 F0 A2 E5 46 7C 76 FC 76 0B 55 09 02 03
01 00 01
ITU-T X.690 определяет, как читать элементы, закодированные в соответствии с базовыми Правила кодирования (BER), правила канонического кодирования (CER, которые я никогда не видел в явном виде) и особые правила кодирования (DER). По большей части CER ограничивает BER, а DER ограничивает CER, что делает DER наиболее простым для чтения. (ITU-T X.680 описывает абстрактную синтаксическую нотацию один (ASN .1), которая представляет собой грамматику, для которой DER является двоичным кодированием)
Теперь мы можем сделать небольшой разбор:
30
Это идентифицирует ПОСЛЕДОВАТЕЛЬНОСТЬ (0x10) с установленным битом CONSTRUCTED (0x20), что означает, что она содержит другие значения DER/помеченные. (ПОСЛЕДОВАТЕЛЬНОСТЬ всегда КОНСТРУКТИРУЕТСЯ в DER)
81 A0
Эта следующая часть является длиной. Поскольку у него установлен старший бит (> 0x7F), первый байт является значением «длина длины». Это указывает на то, что истинная длина закодирована в следующем 1 байте (байтах) (lengthLength & 0x7F
). Таким образом, содержимое этой ПОСЛЕДОВАТЕЛЬНОСТИ составляет всего 160 байтов. (В данном случае «остальные данные», но ПОСЛЕДОВАТЕЛЬНОСТЬ могла содержаться в чем-то другом). Итак, читаем содержимое:
30 0D
Мы снова видим нашу CONSTRUCTED SEQUENCE (0x30
) со значением длины 0x0D
, поэтому у нас есть полезная нагрузка размером 13 байт.
06 09 2A 86 48 86 F7 0D 01 01 01 05 00
06
– это ОБЪЕКТНЫЙ ИДЕНТИФИКАТОР с полезной нагрузкой _11 байт. OID имеет несколько неинтуитивную кодировку, но она эквивалентна текстовому представлению 1.2.840.113549.1.1.1
, которое равно id-rsaEncryption
(http://www.oid-info.com/get/1.2.840.113549.1.1.1).
Это по-прежнему оставляет нам два байта (05 00
), которые, как мы видим, являются NULL (с полезной нагрузкой 0 байтов, потому что это NULL).
Так что пока у нас есть
SEQUENCE
SEQUENCE
OID 1.2.840.113549.1.1.1
NULL
143 more bytes.
Продолжение:
03 81 8E 00
03
означает БИТОВАЯ СТРОКА. BIT STRING кодируется как [тег] [длина] [количество неиспользуемых битов]. Неиспользуемые биты по существу всегда равны нулю. Итак, это последовательность битов длиной 0x8E
байт, и все они используются.
Технически мы должны остановиться на этом, потому что CONSTRUCTED не был установлен. Но поскольку нам известен формат этой структуры, мы обрабатываем значение так, как если бы бит CONSTRUCTED был установлен в любом случае:
30 81 8A
Вот наш друг CONSTRUCTED SEQUENCE снова, 0x8A
байт полезной нагрузки, что удобно соответствует «всему, что осталось».
02 81 82
02
идентифицирует INTEGER, и у этого есть 0x82
байт полезной нагрузки:
00 BC AC B1 A5 34 9D 7B 35 A5 80 AC 3B 39 98 EB
15 EB F9 00 EC B3 29 BF 1F 75 71 7A 00 B2 19 9C
8A 18 D7 91 B5 92 B7 EC 52 BD 5A F2 DB 0D 3B 63
5F 05 95 75 3D FF 7B A7 C9 87 2D BF 7E 32 26 DE
F4 4A 07 CA 56 8D 10 17 99 2C 2B 41 BF E5 EC 35
70 82 4C F1 F4 B1 59 19 FE D5 13 FD A5 62 04 AF
20 34 A2 D0 8F F0 4C 2C CA 49 D1 68 FA 03 FA 2F
A3 2F CC D3 48 4C 15 F0 A2 E5 46 7C 76 FC 76 0B
55 09
Начальный 0x00 будет нарушением DER, за исключением того, что в следующем байте установлен старший бит. Это означает, что 0x00 был там, чтобы предотвратить установку бита знака, что делает это число положительным.
02 03 01 00 01
Другой INTEGER, 3 байта, значение 01 00 01
. И мы закончили.
SEQUENCE
SEQUENCE
OID 1.2.840.113549.1.1.1
NULL
BIT STRING
SEQUENCE
INTEGER 00 BC AC ... 0B 55 09
INTEGER 01 00 01
Собрав https://tools.ietf.org/html/rfc5280, мы видим, что это очень похоже на структуру SubjectPublicKeyInfo
:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
-- contains a value of the type
-- registered for use with the
-- algorithm object identifier value
Конечно, он не знает, что такое формат открытого ключа RSA. Но сайт oid-info посоветовал нам проверить RFC 2313, где мы видим
An RSA public key shall have ASN.1 type RSAPublicKey:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e }
Таким образом, это говорит о том, что первое INTEGER, которое мы читаем, является значением модуля, а второе — (общедоступным) показателем степени.
Кодировка DER имеет обратный порядок байтов, что также является кодировкой RSAParameters, но для RSAParameters вам необходимо удалить начальные значения 0x00
из модуля.
Хотя это не так просто, как дать вам код для этого, должно быть довольно просто написать синтаксический анализатор для ключей RSA с учетом этой информации. Я бы порекомендовал вам написать его как internal static RSAParameters ReadRsaPublicKey(...)
, а затем вам просто нужно сделать
RSAParameters rsaParameters = ReadRsaPublicKey(...);
using (RSA rsa = RSA.Create())
{
rsa.ImportParameters(rsaParameters);
// things you want to do with the key go here
}
person
bartonjs
schedule
24.01.2017