Создайте объект RSAParamats из открытого + закрытого ключа

Мне нужно создать объект RSAParameters в .Net, используя закрытый и открытый ключи (файлы .key и .cer). Можно ли это сделать в .Net без использования стороннего софта? Если да, то где мне искать.

В конечном итоге мне нужно извлечь Exponent, Modulus, D, P, Q, DP, DQ, InverseQ из этого объекта, чтобы создать keyblob для криптосервера.

Спасибо!


person ActiveX    schedule 18.03.2011    source источник


Ответы (1)


Расширения файлов «.key» и «.cer» никоим образом не являются однозначной спецификацией того, как кодируются ключи. Однако вполне вероятно, что файл ".cer" является сертификатом X.509, который содержит (среди прочего) открытый ключ; следовательно, вы можете использовать классы X509Certificate и X509Certificate2 (в пространстве имен System.Security.Cryptography.X509Certificates) для декодирования сертификата и извлечения открытого ключа.

Однако вам нужен закрытый ключ, а не открытый ключ. документация MSDN по X509Certificate2 достаточно сбивает с толку, потому что он использует термин «сертификат» для обозначения либо общедоступной части (то, что у вас есть в вашем файле «.cer»), либо объединения общедоступной и частной частей в виде единого файла (в формате, который MSDN описывает как « PKCS7 (аутентикод)").

Закодированный закрытый ключ RSA обычно соответствует формату, описанному в PKCS#1, который не сложен, но по-прежнему зависит от ASN.1, использование которого требует осторожности. Иногда такие ключи RSA заключаются в более крупную структуру, в которой также указывается тип ключа (т. е. ключ предназначен для RSA); подробности см. в PKCS#8. Кроме того, оба типа кодировок ключей обычно представлены в формате PEM: это Base64 с заголовком (-----BEGIN RSA PRIVATE KEY----- ) и нижний колонтитул. Конечно, ваш закрытый ключ может быть в любом формате (расширение «.key» не слишком информативно). При желании и PKCS#8, и PEM могут быть симметрично зашифрованы (с ключом, полученным из пароля). Существует также формат PKCS#12, который можно рассматривать как формат архива для коллекции сертификатов и закрытых ключей, обертывающий предыдущие форматы; PKCS#12 включает в себя множество уровней шифрования и известен в мире Microsoft под названием «PFX» (или «файл сертификата», что продолжает сбивать с толку).

Декодирование всех этих форматов возможно с помощью небольшого количества кода, но на этом этапе рекомендуется использовать библиотеку, которая уже выполняет такую ​​работу, вместо создания собственной. Bouncy Castle обычно подозревается в этой работе.

Инструмент командной строки OpenSSL может помочь вам преобразовать некоторые форматы ключей и сертификатов.

Редактировать: если ваш закрытый ключ имеет формат PKCS#8 DER и не защищен паролем (PKCS#8 может это сделать), то вы можете декодировать его относительно простой код. DER — это набор правил преобразования структурированных данных в последовательность байтов. Элемент данных кодируется тремя последовательными частями:

  • тег, который сообщает, какое это значение
  • длина, которая кодирует количество байтов в третьей части
  • значение, которое должно интерпретироваться как указанное в теге

отсюда и название «TLV» (как «тег, длина, значение»). Некоторые элементы сами являются структурами, содержащими подэлементы, и в этом случае значение состоит из объединения кодировок подэлементов, каждый со своим собственным тегом, длиной и значением.

Тег обычно состоит из одного байта; для ключей PKCS#8 и RSA вас интересуют теги 0x30 (для «SEQUENCE», т. е. элемента с подэлементами), 0x02 («INTEGER»: целочисленное значение) и 0x04 («OCTET STRING»: большой двоичный объект) .

Длина кодируется одним из следующих способов:

  • один байт значения n от 0 до 127 (включительно): это кодирует длину n;
  • байт со значением n, равным или превышающим 129, за которым следует точно n-128 байтов, которые кодируют длину в формате с обратным порядком байтов. Например, длина 324 будет закодирована как три байта: 0x82 0x01 0x44. Это читается как: «0x82 равно 128+2, следовательно, я должен прочитать два дополнительных байта; длина 256*0x01+0x44 = 324».

Для INTEGER значение должно интерпретироваться в соответствии со знаком и обратным порядком байтов (первый байт является наиболее значимым, а старший бит первого байта определяет знак целого числа; для RSA все значения положительны, поэтому первый байт должен иметь значение от 0 до 127). Обратите внимание, что System.Numerics.BigInteger в .NET 4.0 имеет конструктор, который может декодировать группу байтов, но он ожидает их в соглашении с прямым порядком байтов, а не с прямым порядком байтов, поэтому вам придется изменить порядок байтов.

Структура PKCS#8:

PrivateKeyInfo ::= SEQUENCE {
        version              Version,
        privateKeyAlgorithm  AlgorithmIdentifier,
        privateKey           OCTET STRING,
        attributes           [0] Attributes OPTIONAL
}

Version ::= INTEGER { v1(0) }

Это нотация ASN.1. Здесь необходимо понимать, что объект является элементом ПОСЛЕДОВАТЕЛЬНОСТИ: он кодируется как тег ПОСЛЕДОВАТЕЛЬНОСТИ (0x30), затем длина (n), затем значение (n байт, точно). Затем значение состоит из последовательности закодированных элементов, каждый из которых имеет формат TLV. Первый элемент — это INTEGER, который должен иметь числовое значение 0 при нормальных условиях (ноль кодируется как «0x02 0x01 0x00»). Второй элемент — это AlgorithmIdentifier, который я здесь не описываю; на самом деле это ПОСЛЕДОВАТЕЛЬНОСТЬ, и она определяет тип ключа (здесь должно быть сказано «это ключ RSA»); просто прочитайте тег (должен быть 0x30), затем длину и пропустите значение. Третий элемент — это СТРОКА ОКТЕТОВ: тег 0x04, затем длина m и значение m байт. Это то, что нас интересует. Это значение, которое является содержимым ОКТЕТНОЙ СТРОКИ, должно быть извлечено; мы расшифруем его в следующем абзаце. Четвертый элемент PrivateKeyInfoSEQUENCE является необязательным (его может вообще не быть и обычно не будет) и может использоваться для кодирования различных расширений этого формата.

Предположим, что вы извлекли содержимое ОКТЕТНОЙ СТРОКИ. Это последовательность байтов, которая на самом деле является кодировкой DER структуры, которая в ASN.1 выглядит следующим образом:

RSAPrivateKey ::= SEQUENCE {
        version            INTEGER,
        modulus            INTEGER,  -- n
        publicExponent     INTEGER,  -- e
        privateExponent    INTEGER,  -- d
        prime1             INTEGER,  -- p
        prime2             INTEGER,  -- q
        exponent1          INTEGER,  -- d mod (p-1)
        exponent2          INTEGER,  -- d mod (q-1)
        coefficient        INTEGER,  -- (inverse of q) mod p
        otherPrimeInfos    OtherPrimeInfos OPTIONAL
                -- otherPrimeInfos must be absent if version is two-prime,
                -- present if version is multi-prime.
}

Таким образом, содержимое OCTET STRING должно начинаться с 0x30 (тег SEQUENCE), затем длина (r), затем r байт. Эти r байты представляют собой кодировку девяти целых чисел. Первое ЦЕЛОЕ ЧИСЛО должно быть 0; если это не так, то ключ RSA имеет более двух простых множителей, и вы обречены. Восемь последующих целых чисел — это искомые целые числа; просто расшифруйте их, и все готово. Последнее поле (otherPrimeInfos) является необязательным и должно отсутствовать, если ваш ключ RSA является «нормальным» ключом RSA (с двумя простыми делителями, а не с тремя или более).

person Thomas Pornin    schedule 21.03.2011
comment
Может быть, если я предоставлю немного больше информации о моем ключе. Прежде всего, это ключ RSA, а контейнер представляет собой формат PKCS#8 DER. У меня есть и ключ, и сертификат, но мне нужно извлечь параметры (упомянутые выше) для дальнейшей обработки. Инструменты командной строки не так уж хороши, и вся обработка должна выполняться в коде. Я надеюсь выполнить это в рамках .net, практически не используя дополнительные библиотеки. Любые другие рекомендации? - person ActiveX; 25.03.2011
comment
Я добавил к своему ответу описание правил кодирования DER. Это должно содержать достаточно информации для того, что вам нужно. - person Thomas Pornin; 25.03.2011
comment
Я очень ценю ваш ответ и время, которое вы потратили на детализацию своего ответа. Я уверен, что это будет много полезного и ссылка для многих. Для меня это, кажется, не в моей лиге =D Я искал несколько простую реализацию для тех, кто не знаком с криптографией. У тебя пятерка в моей книге. PS - контейнер PKCS#8 защищен паролем =) - person ActiveX; 20.04.2011