Создать объект RSAParamaters из открытого + закрытого ключа - PullRequest
2 голосов
/ 18 марта 2011

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

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

Спасибо!

1 Ответ

3 голосов
/ 21 марта 2011
Расширения файлов

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

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

Закодированный закрытый ключ 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» (или «файл сертификата», который продолжает сбивать с толку).

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

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

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

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

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

Метка обычно представляет собой один байт; для ключей 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. Здесь следует понимать, что объект является элементом SEQUENCE: он кодируется как тег SEQUENCE (0x30), затем длина ( n ), затем значение ( n байт). , именно так). Затем значение состоит из последовательности закодированных элементов, каждый в формате TLV. Первым элементом является INTEGER, который должен иметь числовое значение 0 при нормальных условиях (ноль кодируется как «0x02 0x01 0x00»). Второй элемент - это AlgorithmIdentifier, который я здесь не буду описывать; на самом деле это SEQUENCE, и он идентифицирует тип ключа (здесь следует сказать «это ключ RSA»); просто прочитайте тег (должен быть 0x30), затем длину и пропустите значение. Третий элемент - это OCTET STRING: тег 0x04, длина m и значение m байтов. Это то, что нас интересует. Это значение, которое является содержанием OCTET STRING, должно быть извлечено; мы расшифруем его в следующем абзаце. Четвертый элемент PrivateKeyInfo SEQUENCE является необязательным (его может вообще не быть и обычно не будет), и его можно использовать для кодирования различных расширений этого формата.

Предположим, что вы извлекли содержимое OCTET STRING. Это последовательность байтов, которая фактически является 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 байтов являются кодировками девяти целых чисел. Первый INTEGER должен быть 0; если это не так, то ключ RSA имеет более двух основных факторов, и вы обречены. Восемь последующих INTEGER - это целые числа, которые вы ищете; просто расшифруйте их, и все готово. Последнее поле (otherPrimeInfos) является необязательным и должно отсутствовать, если ваш ключ RSA является «нормальным» ключом RSA (с двумя простыми множителями, а не с тремя и более).

...