通常,用户将拥有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 ++进行转换,以便用户可以提供格式和“正常工作”。谢谢你的任何建议。
答案 0 :(得分:7)
是的,它是用Base64编码的DER流。但请注意,除了条带化BEGIN和END标记之外,如果是RSA密钥格式,还需要去除可能插入BEGIN标记和编码数据之间的任何标记。只有其余部分可以成功进行Base64解码。您似乎将完整的证书文件提供给解码器,并且需要修复。
答案 1 :(得分:2)
我知道这是一个老问题,但其他人可能觉得这很有用。剥离标记后,您将使用“内部”密钥材料。根据{{3}},您可以使用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);
}
答案 2 :(得分:2)
...我想在程序中自动将PEM文件转换为DER文件。
2014年7月,为Crypto ++库提供了PEM Pack。 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
需要一个算法,因为没有默认算法。