12

通常,用户将拥有 PEM 编码的 RSA 私钥。Crypto++ 要求这些密钥为 DER 格式才能加载。我一直在要求人们事先使用 openssl 手动将他们的 PEM 文件转换为 DER,如下所示:

openssl pkcs8 -in in_file.pem -out out_file.der -topk8 -nocrypt -outform der

这很好用,但有些人不明白如何做到这一点,也不想这样做。所以我想在程序中自动将 PEM 文件转换为 DER 文件。

是像从 PEM 中剥离“-----BEGIN CERTIFICATE-----”和“-----END CERTIFICATE-----”一样简单,还是还需要其他一些转换?有人告诉我,在这些标记之间,它只是 b64 编码的 DER。这是一些演示该问题的代码:

// load the private key
CryptoPP::RSA::PrivateKey PK;
CryptoPP::ByteQueue bytes;

try
{
    CryptoPP::FileSource File( rsa.c_str(), true, new CryptoPP::Base64Decoder() );
    File.TransferTo( bytes );
    bytes.MessageEnd();

    // This line Causes BERDecodeError when a PEM encoded file is used
    PK.Load( bytes );
}

catch ( CryptoPP::BERDecodeErr )
{
    // Convert PEM to DER and try to load the key again
}

我想避免对 openssl 进行系统调用并完全在 Crypto++ 中进行转换,以便用户可以提供任何一种格式和“正常工作”的东西。感谢您的任何建议。

4

3 回答 3

9

是的,它是使用 Base64 编码的 DER 流。但请注意,除了剥离 BEGIN 和 END 标记外,在 RSA 密钥格式的情况下,您还需要剥离可能插入 BEGIN 标记和编码数据之间的任何标志。只有剩下的部分才能成功Base64解码。您似乎将完整的证书文件提供给解码器并且需要修复。

于 2012-03-22T11:12:00.907 回答
3

...我想在程序中自动将 PEM 文件转换为 DER 文件。

2014 年 7 月,为 Crypto++ 库提供了PEM 包。PEM Pack 是消息加密的部分实现,它允许您读取和写入 PEM 编码的密钥和参数,包括加密的私钥。附加文件包括对 RSA、DSA、EC、ECDSA 密钥和 Diffie-Hellman 参数的支持。

它是库的附加组件,而不是库的一部分。您下载一个 ZIP 并将五个源文件添加到库中。然后构建库(Crypto++ 会自动获取它们)。ZIP 包含五个额外的源文件,一个使用 OpenSSL 创建测试密钥的脚本,一个用于测试读取和写入密钥的 C++ 程序,以及一个用于验证 Crypto++ 使用 OpenSSL 编写的密钥的脚本。

以下是您将如何使用它:

CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);

CryptoPP::PEM_Load(file, pk);

CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
    throw ...

如果密钥是加密的,那么你将如何加载它。PEM Pack重新实现了 OpenSSL ,EVP_BytesToKey因此密钥派生将起作用并且您可以互操作:

CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);

std::string pass = "<super secret password>";
CryptoPP::PEM_Load(file, pk, pass.data(), pass.size());

CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
    throw ...

还有一个PEM_Save, 所以你可以直接从 Crypto++ 编写密钥。例如:

// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...; 
CryptoPP::FileSink file("<rsa-key-file.pem>", true);

CryptoPP::PEM_Save(file, pk);

PEM_Save对于加密密钥(或您打算加密的密钥):

// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...; 
CryptoPP::FileSink file("<rsa-key-file.pem>", true);

std::string pass = "<super secret password>";
CryptoPP::PEM_Save(file, pk, "AES-128-CBC", pass.data(), pass.size());

PEM_Load不需要算法,因为它编码在封装的标头中。PEM_Save需要一个算法,因为没有默认算法。

于 2014-08-24T22:17:57.300 回答
3

我知道这是一个老问题,但其他人可能会觉得这很有用。剥离标记后,您将留下“内部”关键材料。根据http://www.cryptopp.com/wiki/Keys_and_Formats#BER_and_DER_Encoding,您可以使用它BERDecodePrivateKey来加载它。因此,要加载已剥离标记的 openssl 密钥,您可以执行以下操作

bool LoadKey(RandomNumberGenerator& rng, const std::string& file, 
    RSA::PrivateKey& key)
{
    ByteQueue q;
    FileSource KeyFile(file.c_str(), true, new Base64Decoder);
    KeyFile.TransferTo(q);
    key.BERDecodePrivateKey(q,false,0); // last 2 params unused
    return key.Validate(rng, 2);
}
于 2013-01-24T02:29:18.333 回答