OpenSSL:读取EC密钥,然后再次写入,这是不同的

The*_*ist 5 c++ openssl elliptic-curve private-key

我为 OpenSSL 编写了一个支持 ECC 的包装器。我正在尝试读取我生成的私钥

openssl ecparam -name secp384r1 -genkey -noout -out privkey.pem
Run Code Online (Sandbox Code Playgroud)

将其与 OpenSSL 将密钥读入 a 并再次打印到字符串中后生成的结果进行EVP_PKEY比较EC_KEY。读完后的结果并不一样。

简而言之:

  1. 读取密钥
  2. 保存到EVP_PKEY
  3. 再写一次

而且结果不匹配。我的程序相当大,因此我制作了一个 MCVE 来演示该问题

我怀疑问题的发生是因为我正在读取 an EC_KEY,然后从 写入EVP_PKEY,这是通用的。我在这里猜测是因为输入说它是 EC,但输出却没有这么说。我不知道如何解决这个问题,因为我没有找到直接从文件EC_KEY(生物对象)写入的方法。我的评估正确吗?

请指教。


编辑:我被要求将整个代码放在注释中,所以你可以:

#include <iostream>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/ec.h>
#include <openssl/pem.h>

EC_KEY* ecKey = nullptr;
EVP_PKEY* pkey = nullptr;

void setPrivateKeyFromPEM(const std::string& pemkey)
{
    pkey = EVP_PKEY_new();

    BIO* bio = BIO_new(BIO_s_mem());

    int bio_write_ret = BIO_write(
        bio, static_cast<const char*>(pemkey.c_str()), pemkey.size());
    if (bio_write_ret <= 0) {
        throw std::runtime_error("error1");
    }

    if (!PEM_read_bio_PrivateKey(bio, &pkey, NULL, NULL)) {
        throw std::runtime_error("error1.5");
    }

    EC_KEY* eckey_local = EVP_PKEY_get1_EC_KEY(pkey);

    if (!eckey_local) {
        throw std::runtime_error("error2");
    } else {
        ecKey = eckey_local;
        EC_KEY_set_asn1_flag(ecKey, OPENSSL_EC_NAMED_CURVE);
    }
}

std::string getPrivateKeyAsPEM()
{
    if (!pkey) {
        throw std::runtime_error("error3");
    }

    BIO* outbio = BIO_new(BIO_s_mem());

    if (!PEM_write_bio_PrivateKey(outbio, pkey, NULL, NULL, 0, 0,
                                  NULL)) {
        throw std::runtime_error("error4");
    }

    std::string keyStr;
    int         priKeyLen = BIO_pending(outbio);
    keyStr.resize(priKeyLen);
    BIO_read(outbio, (void*)&(keyStr.front()), priKeyLen);
    return keyStr;
}

int main()
{
    std::string expectedPrivKey =
        "-----BEGIN EC PRIVATE KEY-----\n"
        "MIGkAgEBBDBNK0jwKqqf8zkM+Z2l++9r8bzdTS/XCoB4N1J07dPxpByyJyGbhvIy\n"
        "1kLvY2gIvlmgBwYFK4EEACKhZANiAAQvPxAK2RhvH/k5inDa9oMxUZPvvb9fq8G3\n"
        "9dKW1tS+ywhejnKeu/48HXAXgx2g6qMJjEPpcTy/DaYm12r3GTaRzOBQmxSItStk\n"
        "lpQg5vf23Fc9fFrQ9AnQKrb1dgTkoxQ=\n"
        "-----END EC PRIVATE KEY-----\n";

    setPrivateKeyFromPEM(expectedPrivKey);
    // compare priv key
    {
        std::string privKeyRead = getPrivateKeyAsPEM();
        std::cout << privKeyRead << std::endl;
        std::cout<<expectedPrivKey<<std::endl;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

rus*_*tyx 5

PEM_write_bio_ECPrivateKeyOpenSSL 1.0.2 中也可用,只是缺少文档。

存储的密钥是​​相同的,只是编码不同。

该标签-----BEGIN PRIVATE KEY-----表示 PEM 编码的 ASN.1 格式。

该标签-----BEGIN EC PRIVATE KEY-----表示 PEM 编码的 ANSI X9.62 密钥。

比较:key 1key 2。请注意 key2 不包含密钥类型 OID,密钥本身是相同的。

要编写 EC 密钥格式,只需使用以下命令:

    if (!PEM_write_bio_ECPrivateKey(outbio, ecKey, NULL, NULL, 0, 0, NULL)) {
Run Code Online (Sandbox Code Playgroud)

coliru-演示