Как передать открытый ключ x25519 размером 44 байта, созданный openssl, в CryptoKit, для которого требуется длина ключа 32 байта

Предположим, я создаю пару ключей x25519 с помощью openssl, она выведет 64-байтовый закрытый ключ и соответствующий 44-байтовый открытый ключ в кодировке Base64, который будет выглядеть как

-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----


-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=
-----END PUBLIC KEY-----

Swift CryptoKit принимает только 32 байта для каждой инициализации закрытого и открытого ключа.

Если я правильно понял, закрытый ключ на 64 байта - это начальное число, где первые 32 байта - это фактический закрытый ключ.

Тем не менее, использование того же принципа для открытого ключа не работает (что не удивительно)

Теперь возникает вопрос: как мне преобразовать открытый ключ в 32 байта, необходимые для Swift CryptoKit?

Вот неработающий пример использования первых 32 байтов открытого ключа, декодированного с помощью base64.

let base64PublicKey = Data(base64Encoded: "MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=")!.dropLast(12)

let publicKey = try! Curve25519.KeyAgreement.PublicKey(rawRepresentation: rawPublicKey) 

1 ответ

Решение
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIMBF8S7zUco4bRrMiIuyTcSYU/rAVlNtE8SMYWphUatw
-----END PRIVATE KEY-----

per rfc7468 - это незашифрованный PKCS8 PrivateKeyInfo, который закодирован в ASN.1 DER и содержит данные об алгоритме (и в целом, но не здесь параметрах), а также фактический ключ. Запуск этого вopenssl asn1parse -i (который автоматически de-base64) дает

    0:d=0  hl=2 l=  46 cons: SEQUENCE
    2:d=1  hl=2 l=   1 prim:  INTEGER           :00
    5:d=1  hl=2 l=   5 cons:  SEQUENCE
    7:d=2  hl=2 l=   3 prim:   OBJECT            :X25519
   12:d=1  hl=2 l=  34 prim:  OCTET STRING      [HEX DUMP]:0420C045F12EF351CA386D1ACC888BB24DC49853FAC056536D13C48C616A6151AB70

Частный ключ для конкретного алгоритма - это OCTETSTRING со значением со смещением 12+2 и длиной 34, но на самом деле он содержит вложенную кодировку OCTETSTRING, первые два октета которой равны 04= тег и 20= длина, поэтому истинный закрытый ключ находится со смещением 16 с длиной. 32 - или, проще говоря, последние 32 байта.

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VuAyEAE0eiiP0PKjy9AVM/0z2ZIZn453WSJNemrQ58HAXDaX0=
-----END PUBLIC KEY-----

Аналогичным является SubjectPublicKeyInfo структура, определенная X.509 и PKIX, который аналогично является МЭД и содержит данные в дополнение к ключу. Разбирая его (с-dump) дает:

    0:d=0  hl=2 l=  42 cons: SEQUENCE
    2:d=1  hl=2 l=   5 cons:  SEQUENCE
    4:d=2  hl=2 l=   3 prim:   OBJECT            :X25519
    9:d=1  hl=2 l=  33 prim:  BIT STRING
      0000 - 00 13 47 a2 88 fd 0f 2a-3c bd 01 53 3f d3 3d 99   ..G....*<..S?.=.
      0010 - 21 99 f8 e7 75 92 24 d7-a6 ad 0e 7c 1c 05 c3 69   !...u.$....|...i
      0020 - 7d

Первый октет значения BITSTRING используется для количества неиспользуемых / заполненных битов, здесь 00, поэтому реальное значение открытого ключа составляет 33-1=32 октета со смещением 9+2+1=12, или снова последние 32 байта..


Ed25519 хеширует закрытый ключ для создания как 32-байтового скаляра, который иногда называется начальным значением, так и 32-байтового значения, которое определяет открытый ключ. Это начальное число может храниться с закрытым ключом, чтобы сделать подписывание более эффективным, но OpenSSL не делает этого для Ed25519 и вообще не применяется к X25519.

Другие вопросы по тегам