1 year ago
#77473
user2366975
crypto++ public/private key generation - differences between Base64 & Hex
When I execute my testsuite of which below test is part of, sometimes it is PASSED, sometimes it FAILED. After How can the behavior be so erratic? I don't know the cryptopp library well enough to debug it correctly. What makes it even more strange is that I have the same functions for a hex-encoded key, copy/pasted, only the function names changed accordingly, and it works.
The error in the failure case is
unknown file: Failure
C++ exception with description "BER decode error" thrown in the test body.
Update - Solution found, but not understood
// Switched to these methods, and added missing `MessageEnd`
CryptoPP::Base64Encoder privKeySink(new CryptoPP::StringSink(keyPair.privateKey),insertLineBreaks);
privateKey.DEREncode(privKeySink);
privKeySink.MessageEnd(); // This was missing!
CryptoPP::Base64Encoder pubKeySink(new CryptoPP::StringSink(keyPair.publicKey),insertLineBreaks);
publicKey.DEREncode(pubKeySink);
pubKeySink.MessageEnd(); // This was missing!
// Why does this code not work?
// What should be added to make it work?
// For example the exact same code, only with `HexEncoder`
// instead of `Base64Encoder` is used for a hex key generation,
// and it works without issues. I don't understand the difference.
//publicKey.Save( CryptoPP::Base64Encoder(
// new CryptoPP::StringSink(keyPair.publicKey), insertLineBreaks).Ref());
//privateKey.Save(CryptoPP::Base64Encoder(
// new CryptoPP::StringSink(keyPair.privateKey), insertLineBreaks).Ref());
The next code snippet shows that the pipelining style works for HexEncode, and I wonder why this does not work for Base64Encoder. Do I maybe need to add another pipeline step that does the "MessageEnd" in case of Base64Encoder?
publicKey.Save( CryptoPP::HexEncoder(
new CryptoPP::StringSink(keyPair.publicKey)).Ref());
privateKey.Save(CryptoPP::HexEncoder(
new CryptoPP::StringSink(keyPair.privateKey)).Ref());
Update end
Original question
Testcase:
TEST(signature, rsa_new_pem)
{
bool ok;
KeyPairBase64 keys;
keys = RsaGenerateBase64KeyPair(3072);
std::string message("secret message");
// The code sometimes fails at next call.
auto signature = RsaPemSignStringCreateHexSignature(keys.privateKey, message);
bool verified = RsaPemVerifyStringWithHexSignature(keys.publicKey, message, signature);
EXPECT_TRUE(verified);
}
This is how I generate the key pair. I even tried multiple methods of which I think they are interchangeable.
struct KeyPairBase64 {
std::string publicKey;
std::string privateKey;
};
inline KeyPairBase64 RsaGenerateBase64KeyPair(unsigned int aKeySize)
{
KeyPairBase64 keyPair;
CryptoPP::AutoSeededRandomPool rng;
// generate keys
CryptoPP::RSA::PrivateKey privateKey;
privateKey.Initialize(rng,aKeySize);
//privateKey.GenerateRandomWithKeySize(rng, aKeySize);
CryptoPP::RSA::PublicKey publicKey(privateKey);
bool insertLineBreaks = false;
// CryptoPP::Base64Encoder privKeySink(new CryptoPP::StringSink(keyPair.privateKey),insertLineBreaks);
// privateKey.DEREncode(privKeySink);
// CryptoPP::Base64Encoder pubKeySink(new CryptoPP::StringSink(keyPair.publicKey),insertLineBreaks);
// publicKey.DEREncode(pubKeySink);
publicKey.Save( CryptoPP::Base64Encoder(
new CryptoPP::StringSink(keyPair.publicKey), insertLineBreaks).Ref());
privateKey.Save(CryptoPP::Base64Encoder(
new CryptoPP::StringSink(keyPair.privateKey), insertLineBreaks).Ref());
return keyPair;
}
Here is my custom convenience function that creates a signature
inline std::string RsaPemSignStringCreateHexSignature(
const std::string &aPrivateKeyStrPem,
const std::string &aMessage)
{
// `cleanPemInputFile` is a simple custom function that strips
// of pem file header and footer.
std::string encodedPriv = cleanPemInputFile(aPrivateKeyStrPem);
CryptoPP::RSA::PrivateKey privateKey;
CryptoPP::StringSource ss(encodedPriv, true, new CryptoPP::Base64Decoder);
privateKey.BERDecode(ss);
// sign message
std::string signature;
Signer signer(privateKey);
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::StringSource ss2(aMessage, true,
new CryptoPP::SignerFilter(rng, signer,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(signature))));
return signature;
}
c++
rsa
digital-signature
crypto++
0 Answers
Your Answer