Как передать открытый ключ 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.