Как преобразовать jwk в открытый ключ через openssl

#encryption #openssl #public-key-encryption #elliptic-curve #jwk

#шифрование #openssl #шифрование с открытым ключом #эллиптическая кривая #jwk

Вопрос:

У меня есть JWE, а в заголовке — эфемерный открытый ключ. Итак, у меня есть координаты X и Y.

Мой вопрос в режиме оболочки, как преобразовать JWK в открытый ключ ECC в формате pem.

Например, здесь jwk

 {"epk":{"kty":"EC","crv":"P-256","x":"GCl--lQHb7NKYU3jXpKVI_BYaTlALT5JFPdl3sbB9mY","y":"ADRX25PBSlZJE79drET0ARtRqZAkUIMNt9aa2bbjBYY"}}
  

После того, как я сделаю это

 > # I convert the x coordonate from base64url to base64
> echo -n -e "GCl  lQHb7NKYU3jXpKVI/BYaTlALT5JFPdl3sbB9mY" | base64 -d | hexdump

0000000 2918 fa7e 0754 b36f 614a e34d 925e 2395
0000010 58f0 3969 2d40 493e f714 de65 c1c6 66f6
0000020

> echo -n -e "ADRX25PBSlZJE79drET0ARtRqZAkUIMNt9aa2bbjBYY" | base64 -d | hexdump

0000000 3400 db57 c193 564a 1349 5dbf 44ac 01f4
0000010 511b 90a9 5024 0d83 d6b7 d99a e3b6 8605
0000020
  

Итак, открытый ключ
04
2918 fa7e 0754 b36f 614a e34d 925e 2395
58f0 3969 2d40 493e f714 de65 c1c6 66f6
3400 db57 c193 564a 1349 5dbf 44ac 01f4
511b 90a9 5024 0d83 d6b7 d99a e3b6 8605

Но у меня есть кривая, открытый ключ, я хочу знать, как сгенерировать pem?

Другими словами,

У меня есть файл mykey.pub, который содержит это:

 -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETGUwowNEfqQ0LtHiMXJPY Os5pXc
lsYCRPOi3F6K0n4k1RjJ7PGp/9RhZy3XS1yn1Qlu4hoCClHcc9rPXPn4fQ==
-----END PUBLIC KEY-----
  

Я выполняю эту команду для отображения открытого ключа:

 > openssl ec -in mykey.pub -pubin -text -noout
read EC key
Public-Key: (256 bit)
pub:
    04:4c:65:30:a3:03:44:7e:a4:34:2e:d1:e2:31:72:
    4f:63:e3:ac:e6:95:dc:96:c6:02:44:f3:a2:dc:5e:
    8a:d2:7e:24:d5:18:c9:ec:f1:a9:ff:d4:61:67:2d:
    d7:4b:5c:a7:d5:09:6e:e2:1a:02:0a:51:dc:73:da:
    cf:5c:f9:f8:7d
ASN1 OID: prime256v1
NIST CURVE: P-256

  

Итак, мой вопрос в том, есть ли у меня эти данные

 > openssl ec -in mykey.pub -pubin -text -noout
read EC key
Public-Key: (256 bit)
pub:
    04:4c:65:30:a3:03:44:7e:a4:34:2e:d1:e2:31:72:
    4f:63:e3:ac:e6:95:dc:96:c6:02:44:f3:a2:dc:5e:
    8a:d2:7e:24:d5:18:c9:ec:f1:a9:ff:d4:61:67:2d:
    d7:4b:5c:a7:d5:09:6e:e2:1a:02:0a:51:dc:73:da:
    cf:5c:f9:f8:7d
ASN1 OID: prime256v1
NIST CURVE: P-256

  

как получить это в режиме оболочки

 -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETGUwowNEfqQ0LtHiMXJPY Os5pXc
lsYCRPOi3F6K0n4k1RjJ7PGp/9RhZy3XS1yn1Qlu4hoCClHcc9rPXPn4fQ==
-----END PUBLIC KEY-----
  

Ответ №1:

Позвольте мне сначала кратко описать ваш целевой формат. То, что вы хотите получить, — это файл SubjectPublicKeyInfo (SPKI) в кодировке PEM. Кодирование PEM — это, по сути, кодирование DER (двоичный формат), а затем кодирование base64 с помощью верхнего и нижнего колонтитулов. Структура SPKI определена в RFC5280 (см. Раздел 4.1):

https://www.rfc-editor.org/rfc/rfc5280#section-4.1

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

Итак, первый фрагмент байтов в двоичной кодировке DER состоит из заголовка, который идентифицирует используемый алгоритм (и часть этого включает кривую). Последние байты — это необработанный открытый ключ (который представляет собой закодированные координаты x и y на кривой).

Поскольку ваш образец ключа соответствует той же кривой, что и ключ, который вы хотите создать, он будет иметь те же байты заголовка AlgorithmIdentifier. Берем ваш mykey.файл pub мы можем преобразовать его в двоичный формат DER:

 $ openssl ec -in mykey.pub -pubin -outform DER -out key.der
  

Давайте посмотрим на содержимое:

 $ hexdump -C key.der
00000000  30 59 30 13 06 07 2a 86  48 ce 3d 02 01 06 08 2a  |0Y0...*.H.=....*|
00000010  86 48 ce 3d 03 01 07 03  42 00 04 4c 65 30 a3 03  |.H.=....B..Le0..|
00000020  44 7e a4 34 2e d1 e2 31  72 4f 63 e3 ac e6 95 dc  |D~.4...1rOc.....|
00000030  96 c6 02 44 f3 a2 dc 5e  8a d2 7e 24 d5 18 c9 ec  |...D...^..~$....|
00000040  f1 a9 ff d4 61 67 2d d7  4b 5c a7 d5 09 6e e2 1a  |....ag-.K...n..|
00000050  02 0a 51 dc 73 da cf 5c  f9 f8 7d                 |..Q.s....}|
0000005b
  

Вы можете увидеть первые байты открытого ключа, которые вы распечатали выше, начиная со смещения 0x1a (т. Е. 26 байт): 04 4c 65 30 ... . Необработанные данные открытого ключа простираются до конца файла и имеют длину 65 байт. Он состоит из начального байта 0x04, за которым следуют 32 байта координаты x и 32 байта координаты y. Начальный 0x04 сообщает нам, как представлена координата. 0x04 означает «несжатый» — что удобно, потому что нам проще всего иметь дело. Мы также будем использовать несжатый формат для нашего целевого ключа. Поэтому нам нужно взять первые 26 байт заголовка плюс байт 0x04 (всего 27 байт) из нашего образца ключа:

 $ head -c 27 key.der >key.head
  

И просто чтобы проверить, мы получили то, что ожидали:

 $ hexdump -C key.head
00000000  30 59 30 13 06 07 2a 86  48 ce 3d 02 01 06 08 2a  |0Y0...*.H.=....*|
00000010  86 48 ce 3d 03 01 07 03  42 00 04                 |.H.=....B..|
0000001b
  

Теперь мы создаем элементы x и y нашей координаты, что вы уже сделали:

 $ echo -n "GCl  lQHb7NKYU3jXpKVI/BYaTlALT5JFPdl3sbB9mY=" | base64 -d >key.x
$ echo -n "ADRX25PBSlZJE79drET0ARtRqZAkUIMNt9aa2bbjBYY=" | base64 -d >key.y
  

А затем соединить все элементы вместе:

 cat key.head key.x key.y >keynew.der
  

Мы можем преобразовать новый ключ в формате DER в формат PEM:

 $ openssl ec -in keynew.der -inform DER -pubin -out keynew.pem
  

Что дает нам:

 -----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGCl  lQHb7NKYU3jXpKVI/BYaTlA
LT5JFPdl3sbB9mYANFfbk8FKVkkTv12sRPQBG1GpkCRQgw231prZtuMFhg==
-----END PUBLIC KEY-----
  

И просто чтобы проверить, что это выглядит разумно:

 $ openssl ec -in keynew.pem -pubin -noout -text
read EC key
Public-Key: (256 bit)
pub:
    04:18:29:7e:fa:54:07:6f:b3:4a:61:4d:e3:5e:92:
    95:23:f0:58:69:39:40:2d:3e:49:14:f7:65:de:c6:
    c1:f6:66:00:34:57:db:93:c1:4a:56:49:13:bf:5d:
    ac:44:f4:01:1b:51:a9:90:24:50:83:0d:b7:d6:9a:
    d9:b6:e3:05:86
ASN1 OID: prime256v1
NIST CURVE: P-256
  

Комментарии:

1. У меня есть еще один вопрос, теперь у меня есть эфемерный открытый ключ и закрытый ключ. С помощью openssl я генерирую производный ключ openssl pkeyutl -derive -inkey ../mykey.key -peerkey keynew.pem -out secret_key.bin . Но байт меняется на группу из двух байтов. Я не знаю почему: ключ должен быть e6030796243ce743acc266e18122bf411e90538dec4c67d7c5b4033e180ad10c , но с openssl я получаю 03e6 9607 3c24 43e7 c2ac e166 2281 41bf 901e 8d53 4cec d767 b4c5 3e03 0a18 0cd1 . Вы знаете, почему?

2. Я предполагаю, что вы используете «hexdump» без строки формата для отображения ключа. Это, по умолчанию, интерпретирует и отображает значения в 2 байтовых фрагментах. Целое значение в 2 байта интерпретируется как одно целое значение и отображается. Это даст странные результаты в системах с малым порядком. Попробуйте «hexdump -C» для более удобочитаемого вывода