2

我想使用 Diffie hellman 在 ac# Server 和 c++ Client 之间生成密钥。此代码为服务器生成一个公钥:

        serverECDH = new ECDiffieHellmanCng(ECCurve.NamedCurves.nistP256);
        serverECDH.KeyDerivationFunction = ECDiffieHellmanKeyDerivationFunction.Hash;
        serverECDH.HashAlgorithm = CngAlgorithm.Sha256; 
        ECDHPublicKey =Convert.ToBase64String(serverECDH.PublicKey.ToByteArray());
        Console.WriteLine(serverECDH.KeySize); //256
        Console.WriteLine(serverECDH.PublicKey.ToByteArray().Length); //72
        Console.WriteLine(ECDHPublicKey);

我想知道为什么 publicKey 字节数组大小是 72 而我期望一个 64 字节长的数组?除此之外,这是我在客户端生成公钥的实现:

if (NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) HandleErrors(1);
if (1 != EVP_PKEY_paramgen_init(pctx)) HandleErrors(2);
if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) HandleErrors(3);

if (!EVP_PKEY_paramgen(pctx, &params)) HandleErrors(4);
if (NULL == (kctx = EVP_PKEY_CTX_new(params, NULL))) HandleErrors(5);

if (1 != EVP_PKEY_keygen_init(kctx)) HandleErrors(6);
if (1 != EVP_PKEY_keygen(kctx, &pkey)) HandleErrors(7);

bio = BIO_new(BIO_s_mem());
PEM_write_bio_PUBKEY(bio, pkey);
int publicKeyLen = BIO_pending(bio);
cout << publicKeyLen << endl;
unsigned char* publicKeyChar = (unsigned char*)malloc(publicKeyLen);
BIO_read(bio, publicKeyChar, publicKeyLen);

ECDHPublicKey =  string(reinterpret_cast<char const*>(publicKeyChar),publicKeyLen);
cout << ECDHPublicKey << endl;

在这段代码中,公钥长度为 128 字节(字符?),这又是奇数,因为我指定了 NID_X9_62_prime256v1 曲线。我的错误在哪里?除了 C++ 和 C# 中的 NID_X9_62_prime256v1 和 nistP256 匹配吗?

编辑:这是 cout << ECDHPublicKey << endl output 的示例:

-----开始公钥----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEUFD9ZNby6x2bf/VC16/NHSxIXdit Ips60uLoi0/jKmbmMHRg2xbXVVzV8Uc1DElMlZA817bMFCnVvi1VsM5JYg==

-----结束公钥-----

4

1 回答 1

1

在 C++ 代码中,公钥不仅是 DER 编码的,它也是 PEM 编码的。这在base 64编码的 DER 结构周围添加了页眉和页脚。PEM 用于基于文本的界面,其中二进制数据可能会失真。因此,它有时也被称为“ASCII 盔甲”(或“ASCII 盔甲”,取决于您的方言)。

如果您想查看 C++/OpenSSL 代码的结构,只需将 base 64 编码的 DER 结构粘贴到此站点或使用openssl asn1parse.


返回的 Mickeysoft 结构serverECDH.PublicKey.ToByteArray()似乎包括"ECK1" + 20 00 00 00后跟两个静态大小的编码坐标(可能是大端或小端)。ECK1 可能是椭圆曲线键格式 1 - 不管是什么 - 并且20 00 00 00可能是八位字节中的键/坐标大小为 32 * 8 = 256。请注意,C# 正式使用平台字节序,因此它20 00 00 00是 32 位小字节序值。可能您需要一个外部库来对其密钥进行编码,以便任何其他运行时都可以理解它们。


至于您的附加问题:是的,ANS(I) X9.62 prime256r1 曲线与 NIST P-256 和 secp256r1 相同(我认为)最初由 Certicom corp. 定义。曲线首先被定义,然后被各种组织拾取和标准化。

于 2019-11-13T13:06:07.333 回答