Как сохранить/получить открытый/закрытый ключ RSA

Я хочу использовать шифрование с открытым ключом RSA. Каков наилучший способ хранения или получения частных и открытых ключей? Является ли XML хорошей идеей здесь?

Как получить ключи?

RSAParameters privateKey = RSA.ExportParameters(true);
RSAParameters publicKey = RSA.ExportParameters(false);

Поскольку RSAParameters имеют следующие элементы: D, DP, DQ, Exponent, InverseQ, Modulus, P, Q

Какой ключ является ключом?

Ответ 1

Что я сделал успешно, так это хранить ключи как XML. В RSACryptoServiceProvider есть два метода: ToXmlString и FromXmlString. ToXmlString вернет строку XML, содержащую либо данные открытого ключа, либо данные открытого и закрытого ключей в зависимости от того, как вы устанавливаете свой параметр. Метод FromXmlString заполняет RSACryptoServiceProvider соответствующими ключевыми данными, если предоставляется строка XML, содержащая либо данные открытого ключа, либо данные открытого и закрытого ключей.

Ответ 2

Я хотел указать что-то в ответ на комментарий ala, спрашивающий:

Открытый ключ = модуль + экспонента

Это точно. Существует несколько способов хранения этого exponent + modulus. Первая попытка стандарта была в RFC 3447 (Стандарты криптографии с открытым ключом (PKCS) № 1: Спецификации шифрования RSA версии 2.1), которая определяет структуру открытого ключа под названием RSAPublicKey:

RSAPublicKey ::= SEQUENCE {
      modulus           INTEGER,  -- n
      publicExponent    INTEGER   -- e
  }

В этом же RFC объявляется, что вы должны использовать DER аромат ASN.1 encoding для хранения открытый ключ. У меня есть образец открытого ключа:

  • publicExponent: 65537 (условно, что все открытые ключи RSA используют 65537 в качестве экспонента)
  • модуль: 0xDC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 8209 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 995D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55

Кодирование DER ASN.1 этого открытого ключа:

30 81 89          ;SEQUENCE (0x89 bytes = 137 bytes)
|  02 81 81       ;INTEGER (0x81 bytes = 129 bytes)
|  |  00          ;leading zero of INTEGER
|  |  DC 67 FA
|  |  F4 9E F2 72 1D 45 2C B4  80 79 06 A0 94 27 50 82
|  |  09 DD 67 CE 57 B8 6C 4A  4F 40 9F D2 D1 69 FB 99
|  |  5D 85 0C 07 A1 F9 47 1B  56 16 6E F6 7F B9 CF 2A
|  |  58 36 37 99 29 AA 4F A8  12 E8 4F C7 82 2B 9D 72
|  |  2A 9C DE 6F C2 EE 12 6D  CF F0 F2 B8 C4 DD 7C 5C
|  |  1A C8 17 51 A9 AC DF 08  22 04 9D 2B D7 F9 4B 09
|  |  DE 9A EB 5C 51 1A D8 F8  F9 56 9E F8 FB 37 9B 3F
|  |  D3 74 65 24 0D FF 34 75  57 A4 F5 BF 55
|  02 03          ;INTEGER (0x03 = 3 bytes)
|  |  01 00 01    ;hex for 65537. see it?

Если вы берете все выше DER ASN.1, закодированное modulus + exponent:

30 81 89 02 81 81 00 DC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 82 09 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 99 5D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55 02 03 01 00 01

и вы PEM закодируете его (то есть base64):

MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY
UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE
3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV
ek9b9VAgMBAAE=

Это соглашение об обертывании данных, закодированных в base64, в:

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY
UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE
3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV
ek9b9VAgMBAAE=
-----END RSA PUBLIC KEY-----

И как вы получите PEM DER ASN.1 PKCS # 1 RSA Открытый ключ.


Следующий стандарт был RFC 4716 (формат файла открытого ключа Secure Shell (SSH)). Они включали идентификатор алгоритма (ssh-rsa) перед экспонентой и модулем:

string    "ssh-rsa"
mpint     e
mpint     n

Они не хотели использовать кодировку DER ASN.1 (поскольку она ужасно сложна) и вместо этого предпочли префикс длины в 4 байта:

00000007                 ;7 byte algorithm identifier
73 73 68 2d 72 73 61     ;"ssh-rsa"
00000003                 ;3 byte exponent
01 00 01                 ;hex for 65,537 
00000080                 ;128 byte modulus
DC 67 FA F4 9E F2 72 1D  45 2C B4 80 79 06 A0 94 
27 50 82 09 DD 67 CE 57  B8 6C 4A 4F 40 9F D2 D1 
69 FB 99 5D 85 0C 07 A1  F9 47 1B 56 16 6E F6 7F 
B9 CF 2A 58 36 37 99 29  AA 4F A8 12 E8 4F C7 82 
2B 9D 72 2A 9C DE 6F C2  EE 12 6D CF F0 F2 B8 C4 
DD 7C 5C 1A C8 17 51 A9  AC DF 08 22 04 9D 2B D7 
F9 4B 09 DE 9A EB 5C 51  1A D8 F8 F9 56 9E F8 FB 
37 9B 3F D3 74 65 24 0D  FF 34 75 57 A4 F5 BF 55

Возьмите всю приведенную выше последовательность байтов, а base-64 закодируйте ее:

AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs
Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4S
bc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80
dVek9b9V

И оберните его в заголовок и трейлер OpenSSH:

---- BEGIN SSH2 PUBLIC KEY ----
AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs
Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4S
bc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80
dVek9b9V
---- END SSH2 PUBLIC KEY ----

Примечание. Что OpenSSH использует четыре тире с пробелом (----), а не пять тире и пробел (-----).


Следующим стандартом был RFC 2459 (Internet X.509 Сертификат инфраструктуры открытого ключа и профиль CRL). Они взяли формат открытого ключа PKCS # 1:

RSAPublicKey ::= SEQUENCE {
      modulus           INTEGER,  -- n
      publicExponent    INTEGER   -- e
  }

и расширил его, включив префикс идентификатора алгоритма (если вы хотите использовать алгоритм шифрования с открытым ключом другой, чем RSA):

SubjectPublicKeyInfo  ::=  SEQUENCE  {
    algorithm            AlgorithmIdentifier,
    subjectPublicKey     RSAPublicKey }

"Идентификатор алгоритма" для RSA 1.2.840.113549.1.1.1, который исходит из:

  • 1 - ISO присвоены идентификаторы OID
    • 1.2 - Корпус члена ISO
      • 1.2.840 - США
        • 1.2.840.113549 - RSADSI
          • 1.2.840.113549.1 - PKCS
            • 1.2.840.113549.1.1 - PKCS-1

X.509 - ужасный стандарт, который определяет ужасно сложный способ кодирования OID в hex, но в конце кодирование DER ASN.1 открытого ключа X.509 SubjectPublicKeyInfo RSA:

30 81 9F            ;SEQUENCE (0x9f bytes = 159 bytes)
|  30 0D            ;SEQUENCE (0x0d bytes = 13 bytes)
|  |  06 09         ;OBJECT_IDENTIFIER (0x09 = 9 bytes)
|  |  2A 86 48 86   ;Hex encoding of 1.2.840.113549.1.1
|  |  F7 0D 01 01 01
|  |  05 00         ;NULL (0 bytes)
|  03 81 8D 00      ;BIT STRING (0x8d bytes = 141 bytes)
|  |  30 81 89          ;SEQUENCE (0x89 bytes = 137 bytes)
|  |  |  02 81 81       ;INTEGER (0x81 bytes = 129 bytes)
|  |  |  00          ;leading zero of INTEGER
|  |  |  DC 67 FA
|  |  |  F4 9E F2 72 1D 45 2C B4  80 79 06 A0 94 27 50 82
|  |  |  09 DD 67 CE 57 B8 6C 4A  4F 40 9F D2 D1 69 FB 99
|  |  |  5D 85 0C 07 A1 F9 47 1B  56 16 6E F6 7F B9 CF 2A
|  |  |  58 36 37 99 29 AA 4F A8  12 E8 4F C7 82 2B 9D 72
|  |  |  2A 9C DE 6F C2 EE 12 6D  CF F0 F2 B8 C4 DD 7C 5C
|  |  |  1A C8 17 51 A9 AC DF 08  22 04 9D 2B D7 F9 4B 09
|  |  |  DE 9A EB 5C 51 1A D8 F8  F9 56 9E F8 FB 37 9B 3F
|  |  |  D3 74 65 24 0D FF 34 75  57 A4 F5 BF 55
|  |  02 03          ;INTEGER (0x03 = 3 bytes)
|  |  |  01 00 01    ;hex for 65537. see it?

В декодированном ASN.1 вы можете видеть, как они только префикс старого RSAPublicKey с помощью OBJECT_IDENTIFIER.

Принимая приведенные выше байты и PEM (то есть base-64), кодируя их:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC
Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y
Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/
03RlJA3/NHVXpPW/VQIDAQAB

Стандарт - это обернуть его заголовком, похожим на RSA PKCS # 1, но без "RSA" (поскольку это может быть нечто иное, чем RSA):

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC
Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y
Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/
03RlJA3/NHVXpPW/VQIDAQAB
-----END PUBLIC KEY-----

И как вы изобретаете формат X.509 SubjectPublicKeyInfo/OpenSSL PEM открытого ключа.


Это не останавливает список стандартных форматов для открытого ключа RSA. Далее следует проприетарный формат открытого ключа, используемый OpenSSH:

SSH-RSA AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn + vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk + oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4 + Vae + Ps3mz/TdGUkDf80dVek9b9V

На самом деле это формат SSH открытого ключа, но с префиксом ssh-rsa, а не завернутый в ---- BEGIN SSH2 PUBLIC KEY ----/---- END SSH2 PUBLIC KEY ----.


Здесь легкодоступный XML RSAKeyValue открытый ключ:

  • Экспонента: 0x 010001 закодировано base64 AQAB
  • Modulus: 0x 00 dc 67 fa f4 9e f2 72 1d 45 2c b4 80 79 06 a0 94 27 50 82 09 dd 67 ce 57 b8 6c 4a 4f 40 9f d2 d1 69 fb 99 5d 85 0c 07 a1 f9 47 1b 56 16 6e f6 7f b9 cf 2a 58 36 37 99 29 aa 4f a8 12 e8 4f c7 82 2b 9d 72 2a 9c de 6f c2 ee 12 6d cf f0 f2 b8 c4 dd 7c 5c 1a c8 17 51 a9 ac df 08 22 04 9d 2b d7 f9 4b 09 de 9a eb 5c 51 1a d8 f8 f9 56 9e f8 fb 37 9b 3f d3 74 65 24 0d ff 34 75 57 a4 f5 bf 55 base64 закодирован ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V.

Это означает, что XML:

<RSAKeyValue>
   <Modulus>ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V</Modulus>
   <Exponent>AQAB</Exponent>
</RSAKeyValue>

Гораздо проще. Недостатком является то, что он не обертывает, не копирует, не вставляет, так же хорошо (например, Xml не так удобен для пользователя):

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY
UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE
3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV
ek9b9VAgMBAAE=
-----END RSA PUBLIC KEY-----

Но он делает большой нейтральный формат хранения.

См. также

  • Переводчик, двоичный: отлично подходит для декодирования и кодирования данных base64.
  • ASN.1 JavaScript-декодер: отлично подходит для декодирования кодированных по ASN.1 шестнадцатеричных данных (которые вы получаете из Translator, Binary
  • Документация Microsoft ASN.1: описывает отличительные правила кодирования (DER), используемые для структур ASN.1 ( вы не найдете лучшего набора документации в другом месте, я бы сказал, что Microsoft - это не только настоящая документация).

Ответ 3

Использовать существующий стандартный формат, например, PEM. Ваша крипто-библиотека должна предоставлять функции для загрузки и сохранения ключей из файлов в формате PEM.

Экспонентом и модулем являются открытый ключ. D и модуль являются частным ключом. Другие значения позволяют ускорить вычисление для владельца секретного ключа.

Ответ 4

Открытый ключ идентифицируется по модулю и экспоненте. Закрытый ключ идентифицируется другими членами.

Ответ 5

Является ли XML хорошей идеей здесь?

Обычно секретные ключи хранятся на смарт-карте HSM. Это обеспечивает хорошую безопасность.