我有以下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 代码将这段数据解码回其原始二进制位,但不起作用。下面是一个测试程序(假设der数据传输正确,长度也正确)。
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字节,我想使用C编程将其恢复到32字节。我认为这个问题可能是相关的,我如何将openssl创建的44字节x25519公钥传递给CryptoKit,它需要32字节的密钥长度,但我没有足够的背景来在C中实现它。
由于原始公钥位于 SPKI/DER Ed25519 密钥的末尾,因此可以简单地使用最后 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, 0x70, 0x03, 0x21, 0x00, 0xf3, 0x7d, 0x76, 0xed, 0xe5, 0xd9, 0x01, 0xd1, 0xb5, 0x0c, 0x76, 0x8b, 0x68, 0x34, 0x12, 0x67, 0xa9, 0x88, 0xb6, 0xd9, 0x87, 0xde, 0x88, 0x3e, 0x47, 0xb7, 0xba, 0x17, 0x7d, 0x21, 0x3d, 0xe5 };
const unsigned char* data = (const unsigned char*)spki_der;
size_t datalen = sizeof(spki_der);
// Import SPKI/DER Ed25519 key
OSSL_DECODER_CTX* dctx;
EVP_PKEY* pkeyPub = NULL;
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkeyPub, "DER", NULL, "ED25519", OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL);
OSSL_DECODER_from_data(dctx, &data, &datalen);
// Export raw 32 bytes key
unsigned char rawPub[32];
size_t rawPubLen = 32;
EVP_PKEY_get_raw_public_key(pkeyPub, rawPub, &rawPubLen); // pkey: 0xf37d76ede5d901d1b50c768b68341267a988b6d987de883e47b7ba177d213de5
为了完整起见:
OSSL_DECODER_CTX_new_for_pkey()
可用于导入不同类型的公共(第5个参数:OSSL_KEYMGMT_SELECT_PUBLIC_KEY
)和私有(第5个参数:OSSL_KEYMGMT_SELECT_KEYPAIR
)密钥(第4个参数,例如"ED25519"
)和编码(第2个参数,例如"PEM"
)或 "DER"
)。EVP_PKEY_get_raw_private_key()
导出原始密钥。