У меня есть следующий код Python, который создает часть данных DER «x25519_pubic_der».
#!/usr/bin/python3
from cryptography.hazmat.primitives.asymmetric import x25519
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
x25519_key = x25519.X25519PrivateKey.generate()
x25519_public_der = x25519_key.public_key().public_bytes(Encoding.DER,
PublicFormat.SubjectPublicKeyInfo)
Я пытаюсь декодировать этот фрагмент данных обратно в исходные двоичные биты, используя код C, но безуспешно. Ниже приведена одна тестовая программа (при условии, что данные переданы правильно, а также длина).
const unsigned char* ptr = x25519_public_der;
ASN1_OCTET_STRING* octet_string = d2i_ASN1_OCTET_STRING(NULL, &ptr, x25519_public_der_len);
if (!octet_string) {
fprintf(stderr, "Error decoding DER data to binary bytes\n");
return 1;
}
Я подозреваю, что PublicFormat.SubjectPublicKeyInfo может добавить дополнительную кодировку, или я не использую правильную функцию d2i_ (?), только предположение...
По сути, x25519_public_der содержит 44 байта, и я хочу восстановить его до 32 байтов с помощью программирования на C. Я думаю, что этот вопрос может быть актуальным: Как мне передать открытый ключ x25519 длиной 44 байта, созданный openssl, в CryptoKit, для которого требуется длина ключа 32 байта, но у меня недостаточно опыта для реализации его на C.
Поскольку необработанный открытый ключ расположен в конце ключа SPKI/DER X25519, можно просто использовать последние 32 байта.
Более общий подход — импортировать ключ SPKI/DER как EVP_PKEY
и извлечь необработанный ключ с помощью EVP_PKEY_get_raw_public_key
, например. начиная с OpenSSL v3.0 (для простоты, без обработки исключений):
const char spki_der[] = { 0x30, 0x2A, 0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x6E, 0x03, 0x21, 0x00, 0xBB, 0x13, 0xF6, 0x6B, 0x4E, 0xC0, 0x9E, 0xE2, 0xD5, 0xC6, 0xE5, 0x49, 0xDF, 0xE9, 0x06, 0x41, 0x4A, 0x79, 0x99, 0x98, 0xE1, 0xE3, 0x93, 0x46, 0x13, 0xD6, 0xBE, 0xD3, 0xC2, 0xEE, 0x9E, 0x66 };
const unsigned char* data = (const unsigned char*)spki_der;
size_t datalen = sizeof(spki_der);
// Import SPKI/DER X25519 key
OSSL_DECODER_CTX* dctx;
EVP_PKEY* pkeyPub = NULL;
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkeyPub, "DER", NULL, "X25519", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL);
OSSL_DECODER_from_data(dctx, &data, &datalen);
// Export raw X25519 key (32 bytes)
unsigned char rawPub[32];
size_t rawPubLen = 32;
EVP_PKEY_get_raw_public_key(pkeyPub, rawPub, &rawPubLen); // rawPub: 0xbb13f66b4ec09ee2d5c6e549dfe906414a799998e1e3934613d6bed3c2ee9e66
Для полноты картины:
OSSL_DECODER_CTX_new_for_pkey() можно использовать для импорта общедоступных (5-й параметр: OSSL_KEYMGMT_SELECT_PUBLIC_KEY
) и частных (5-й параметр: OSSL_KEYMGMT_SELECT_KEYPAIR
) ключей разных типов (4-й параметр, например "X25519"
) и кодировок (2-й параметр, например "PEM"
или "DER"
).
Для закрытых ключей необходимо использовать EVP_PKEY_get_raw_private_key()
для экспорта необработанного ключа.
В зависимости от OSSL_DECODER_from_... можно выбирать разные источники данных.