Преобразование ключей RSA в форму SubjectPublicKeyInfo из BigIntegers

ПРЕДУПРЕЖДЕНИЕ: первоначальный вопрос касался ключей, закодированных в PKCS # 1, в то время как фактический пример в вопросе требует ключей в кодировке SubjectPublicKeyInfo (X.509).


В настоящее время я работаю над реализацией алгоритма RSA с нуля в java, особенно над генерацией ключей. Прямо сейчас у меня есть рабочий код, который даст мне три BigInteger n, e и d.

Из того, что я вижу в Интернете, ключ RSA (очень похожий на подпись PGP) обычно представляет собой смесь символов, а не просто очень длинные числа; очевидно, это связано с тем, что ключи зашифрованы / переведены (я не совсем уверен) в PKCS # 1.

Как бы мне самому это сделать? Кроме того, это PKCS # 1 SubjectPublicKeyInfo, в котором я хочу отображать ключи, или есть более обновленный формат?

РЕДАКТИРОВАТЬ: Для ясности вот пример того, что я ищу:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0
FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/
3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB
-----END PUBLIC KEY-----

И на данный момент у меня есть:

Public Key (n,e): (25130290470670502980544427869200613840944965290040433220698179071215137002904823499373962164071905921326803837460733139500455896910114421141830335882737678919237073090149470600927019562678483947908156329730770276498955439764614844798829603416304775442087438623389826719642285111749464396302305124179886483673046650125158307930593778247437940929550491287419436361905923356252487704851166279431792122641372330876814779543893241235355988829436458897455503500810769146739895787437926366072829812130032509796362669335922016603663923790043992999351304972183762844549989472560311169566110061553119311399708581940621713200371,65537)

Я не знаю, как мне превратить это огромное число в ключ стандартной формы.


person ahjohnston25    schedule 25.09.2013    source источник
comment
Взгляните на ietf.org/rfc/rfc3447.txt. В Приложении A приведен формат открытого и закрытого ключей в виде структур ASN.1.   -  person Henry    schedule 25.09.2013
comment
Я просмотрел RFC, а также RFC2315, но все, что я смог найти, это то, что мне следует использовать PKCS # 1 v1.5, но в нем не указано, как я буду это реализовывать.   -  person ahjohnston25    schedule 25.09.2013
comment
Обычно используется кодировка ASN.1 DER (DER = особые правила кодирования). См., Например, luca.ntop.org/Teaching/Appunti/asn1.html.   -  person Henry    schedule 25.09.2013
comment
Ваш пример выглядит в формате OpenPGP, см. tools.ietf.org/html/rfc4880   -  person Henry    schedule 25.09.2013
comment
@ Генри, почему ты так думаешь? Он явно содержит открытый ключ PKCS # 1: {iso (1) member-body (2) us (840) rsadsi (113549) pkcs (1) pkcs-1 (1) rsaEncryption (1)} - это встроенный OID .. .   -  person Maarten Bodewes    schedule 26.09.2013
comment
@owlstead ой, ты прав. Я сделал ошибку, когда выгрузил данные и не распознал кодировку DER.   -  person Henry    schedule 26.09.2013


Ответы (2)


Лучший способ сделать это - использовать Java API. Просто создайте RSAPublicKey и вызовите getEncoded(). В противном случае вы можете использовать библиотеки Bouncy Castle и построить открытый ключ, используя внутренние структуры кодирования Bouncy ASN.1 (возможно, «украдя» реализацию из реализации JCE Bouncy Castle, они также должны реализовать getEncoded()).

Наконец, вы можете просто найти стандарт PKCS # 1 RSA и реализовать структуру ASN.1. Если вы это сделаете, вам придется изучить хотя бы часть правил кодирования ASN.1 и DER. Обратите внимание: если вы хотите реализовать полный анализатор ASN.1 + кодировщик / декодер BER / DER с нуля, вам потребуется пара месяцев времени на реализацию и несколько лет опыта.

Обратите внимание, что getEncoded() просто содержит двоичную структуру ASN.1, закодированную в DER. Вам нужно преобразовать в базу 64 и добавить начальную и начальную строки, чтобы создать структуру PEM, которую вы нам показали. Это также иногда называют «броней ASCII», поскольку она защищает двоичный код от повреждения, когда вы отправляете структуру, например. по почте (PEM означает «Почта с улучшенной конфиденциальностью»).

person Maarten Bodewes    schedule 26.09.2013
comment
Думаю, в данном случае реализация не так уж и сложна. AlgorithmIdentifier является константой, и общая структура во всех случаях одинакова. В основном необходимо вставить только значения для n и e, а поля длины необходимо настроить. - person Henry; 26.09.2013
comment
Действительно, структуры открытого ключа - одна из самых простых структур. Но все же нужно знать правильное форматирование. Чтобы поиграть со структурой, может быть хорошей идеей использовать редактор ASN.1 от Liping Dai. В системе GNU вы также можете использовать openssl asn1parse для просмотра структуры. Также нетрудно найти страницы, которые выполняют декодирование base64 и парсинг ASN.1 в сети с использованием JavaScript в браузере. - person Maarten Bodewes; 26.09.2013
comment
Обратите внимание, что PublicKey.getEncoded() на самом деле является X.509 SubjectPublicKeyInfo содержащим PKCS1. Обычно используется SPKI (и X.509 сертификат, содержащий SPKI, даже больше), но если вам действительно нужен «сырой» PKCS1, вы можете извлечь его из SPKI, как показано в ответе Генри. - person dave_thompson_085; 01.11.2016
comment
@ dave_thompson_085 Этот код выше действительно возвращает SubjectPublicKeyInfo и является неправильным (но я не могу удалить его, потому что это принятый ответ. Думаю, это просто показывает вам, что я был не так хорош в 2013 году. С другой стороны, похоже, что вопрос на самом деле запросил SubjectPublicKeyInfo, а не только PKCS # 1 .... - person Maarten Bodewes; 01.11.2016

Чтобы расшифровать пример

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0
FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/
3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQAB
-----END PUBLIC KEY-----

сначала удалите кодировку base64, которая дает:

00000000  30 81 9f 30 0d 06 09 2a  86 48 86 f7 0d 01 01 01  |0..0...*.H......|
00000010  05 00 03 81 8d 00 30 81  89 02 81 81 00 aa 18 ab  |......0.........|
00000020  a4 3b 50 de ef 38 59 8f  af 87 d2 ab 63 4e 45 71  |.;P..8Y.....cNEq|
00000030  c1 30 a9 bc a7 b8 78 26  74 14 fa ab 8b 47 1b d8  |.0....x&t....G..|
00000040  96 5f 5c 9f c3 81 84 85  ea f5 29 c2 62 46 f3 05  |._\.......).bF..|
00000050  50 64 a8 de 19 c8 c3 38  be 54 96 cb ae b0 59 dc  |Pd.....8.T....Y.|
00000060  0b 35 81 43 b4 4a 35 44  9e b2 64 11 31 21 a4 55  |.5.C.J5D..d.1!.U|
00000070  bd 7f de 3f ac 91 9e 94  b5 6f b9 bb 4f 65 1c db  |...?.....o..Oe..|
00000080  23 ea d4 39 d6 cd 52 3e  b0 81 91 e7 5b 35 fd 13  |#..9..R>....[5..|
00000090  a7 41 9b 30 90 f2 47 87  bd 4f 4e 19 67 02 03 01  |.A.0..G..ON.g...|
000000a0  00 01                                             |..|
000000a2

Теперь у нас есть:

30 81 9f <- a SEQUENCE with 9f bytes
   30 0d <- a SEQUENCE with 0d bytes
      06 09 2a 86 48 86 f7 0d 01 01 01  <- OID 1.2.840.113549.1.1.1
      05 00  <- NULL
   03 81 8d 00  <- BIT STRING with 8d bytes (0 unused bits in last byte)

Содержимое BIT STRING - это открытый ключ, снова закодированный в DER.

30 81 89  <- SEQUENCE with 89 bytes
   02 81 81  <- INTEGER with 81 bytes, this is n
      00 aa 18 ... 4e 19 67
   02 03   <- INTEGER with 3 bytes, this is e
      01 00 01   <- 2^16+1

Таким образом, вся структура представляет собой

SubjectPublicKeyInfo ::= SEQUENCE {
  algorithm AlgorithmIdentifier,
  publicKey BIT STRING }

где AlgorithmIdentifier

AlgorithmIdentifier ::= SEQUENCE {
    algorithm OBJECT IDENTIFIER,
    parameters ANY DEFINED BY algorithm OPTIONAL }

и открытый ключ

RSAPublicKey ::= SEQUENCE {
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e
}
person Henry    schedule 26.09.2013