Как сохранить / получить открытый / закрытый ключ RSA
Я хочу использовать шифрование с открытым ключом RSA. Каков наилучший способ хранения или получения закрытых и открытых ключей? Является ли XML хорошей идеей здесь?
Как получить ключи?
RSAParameters privateKey = RSA.ExportParameters(true);
RSAParameters publicKey = RSA.ExportParameters(false);
Потому что RSAParameters имеют следующие члены: D, DP, DQ, экспонента, InverseQ, модуль, P, Q
Какой ключ?
6 ответов
То, что я сделал успешно - это сохранить ключи в формате XML. В RSACryptoServiceProvider есть два метода: ToXmlString и FromXmlString. ToXmlString вернет строку XML, содержащую либо только данные открытого ключа, либо данные открытого и закрытого ключа, в зависимости от того, как вы установили его параметр. Метод FromXmlString заполняет RSACryptoServiceProvider соответствующими данными ключа, когда предоставляется строка XML, содержащая либо только данные открытого ключа, либо данные открытого и закрытого ключей.
Я хотел бы указать на что-то в качестве ответа на комментарий аля, спрашивая, если:
Открытый ключ = модуль + показатель степени
Это точно правильно. Есть несколько способов сохранить это exponent
+ modulus
, Первая попытка в стандарте была в RFC 3447 (Стандарты криптографии с открытым ключом (PKCS) #1: Спецификации криптографии RSA версии 2.1), который определяет структуру для открытого ключа вызываемого RSAPublicKey
:
RSAPublicKey ::= SEQUENCE {
modulus INTEGER, -- n
publicExponent INTEGER -- e
}
Тот же RFC заявляет, что вы должны использовать аромат DER ASN.1
кодировка для хранения открытого ключа. у меня есть образец открытого ключа:
- 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-----
И вот как вы получаете открытый ключ RSA PEM DER ASN.1 PKCS#1.
Следующим стандартом был RFC 4716 (формат открытого ключа защищенной оболочки (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 назначенные OID1.2
- член ISO1.2.840
- СОЕДИНЕННЫЕ ШТАТЫ АМЕРИКИ1.2.840.113549
- RSADSI1.2.840.113549.1
- PKCS1.2.840.113549.1.1
- ПККС-1
X.509 - ужасный стандарт, который определяет ужасно сложный способ кодирования OID
в гекс, но в конце концов кодирование 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-----
И вот как вы изобрели формат открытого ключа PEM X.509 SubjectPublicKeyInfo / OpenSSL.
Это не останавливает список стандартных форматов для открытого ключа 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
закодировано в base64AQAB
- Модуль:
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
закодировано в base64ANxn+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-----
Но это делает отличный нейтральный формат хранения.
Смотрите также
- Translator, Binary: отлично подходит для декодирования и кодирования данных base64
- ASN.1 JavaScript декодер: отлично подходит для декодирования шестнадцатеричных данных, закодированных в ASN.1 (которые вы получаете от
Translator, Binary
- Документация Microsoft ASN.1. Описывает правила выдающегося кодирования (DER), используемые для структур ASN.1 (лучшего набора документации вы не найдете нигде; я бы сказал, что Microsoft - это не только настоящая документация)
Используйте существующий стандартный формат, такой как PEM. Ваша криптографическая библиотека должна предоставлять функции для загрузки и сохранения ключей из файлов в формате PEM.
Экспонент и Модуль являются Открытым ключом. D и модуль являются закрытым ключом. Другие значения обеспечивают более быстрое вычисление для владельца закрытого ключа.
Открытый ключ определяется модулем и экспонентом. Закрытый ключ идентифицируется другими участниками.
Я полагаю, что ответ от @Ian Boyd будет не совсем точным, формат должен быть SSH2, а не OpenSSH, поскольку RFC4716, определенный для SSH2, формат OpenSSH является проприетарным:
Примечание. В этом OpenSSH используются четыре дефиса с пробелом (----), а не пять дефисов без пробела (-----).
Является ли XML хорошей идеей здесь?
Обычно закрытые ключи хранятся на смарт-карте HSM. Это обеспечивает хорошую безопасность.