Saving then loading RSA key occasionally fails with a BER decode error

33 views
Skip to first unread message

Davis Wen

unread,
May 16, 2020, 3:57:39 PM5/16/20
to cryptop...@googlegroups.com
#include <cryptopp/base64.h>
#include <cryptopp/filters.h>
#include <cryptopp/osrng.h>
#include <cryptopp/rsa.h>
#include <string>

CryptoPP::AutoSeededRandomPool rng;

int main() {
CryptoPP::RSA::PrivateKey private_key;
    private_key.GenerateRandomWithKeySize(rng, 2048);

std::string base64_private_key;
CryptoPP::Base64Encoder private_key_sink(new CryptoPP::StringSink(base64_private_key));
    private_key.Save(private_key_sink);

CryptoPP::ArraySource as((const byte *)base64_private_key.data(), base64_private_key.size(), true, new CryptoPP::Base64Decoder());
    private_key.Load(as);

return 0;
}

Compiling and running with the following command occasionally fails with a decoding error
g++ save_then_load.cc -lcrypto++ && ./a.out

Error:
terminate called after throwing an instance of 'CryptoPP::BERDecodeErr'
  what():  BER decode error
Aborted (core dumped)

The version of the library I am using:
ii  libcrypto++-dev                               5.6.4-9build1                              amd64        General purpose cryptographic library - C++ development
ii  libcrypto++6                                  5.6.4-9build1                              amd64        General purpose cryptographic library - shared library

OS environment:
Distributor ID: Ubuntu
Description: Ubuntu 20.04 LTS
Release: 20.04
Codename: focal



Is there any caveat in those Load and Save functions that I am missing?

Davis Wen

unread,
May 21, 2020, 10:57:08 PM5/21/20
to Crypto++ Users
This code works:
#include <cryptopp/osrng.h>
#include <cryptopp/rsa.h>
#include <cstdint>

CryptoPP::AutoSeededRandomPool rng;

int main() {
CryptoPP::RSA::PrivateKey private_key;
    private_key.GenerateRandomWithKeySize(rng, 2048);

    std::vector<uint8_t> signed_bytes(2048);
    CryptoPP::ArraySink sink(signed_bytes.data(), 2048);
    private_key.Save(sink);
    signed_bytes.resize(sink.TotalPutLength());

CryptoPP::ArraySource source(signed_bytes.data(), signed_bytes.size(), /*pumpAll=*/true);
private_key.Load(source);

return 0;
}

Apparently there is something wrong with how I used the base64 encoder/decoder. But I don't want to spend anymore time on this issue. I'll go ahead and store raw bytes intead.

在 2020年5月16日星期六 UTC-7下午12:57:39,Davis Wen写道:

Jeffrey Walton

unread,
Jun 29, 2020, 10:20:53 PM6/29/20
to Crypto++ Users


On Thursday, May 21, 2020 at 10:57:08 PM UTC-4, Davis Wen wrote:
This code works:
#include <cryptopp/osrng.h>
#include <cryptopp/rsa.h>
#include <cstdint>

CryptoPP::AutoSeededRandomPool rng;

int main() {
CryptoPP::RSA::PrivateKey private_key;
    private_key.GenerateRandomWithKeySize(rng, 2048);

    std::vector<uint8_t> signed_bytes(2048);
    CryptoPP::ArraySink sink(signed_bytes.data(), 2048);
    private_key.Save(sink);
    signed_bytes.resize(sink.TotalPutLength());

CryptoPP::ArraySource source(signed_bytes.data(), signed_bytes.size(), /*pumpAll=*/true);
private_key.Load(source);

return 0;
}

Apparently there is something wrong with how I used the base64 encoder/decoder. But I don't want to spend anymore time on this issue. I'll go ahead and store raw bytes intead.

The fixed size ArraySource and ArraySink is probably wrong. Use a FileSource and FileSink instead.

When you write a 2048-bit RSA public key (or private key) with a FileSink you will likely find it is a different size then 2048 bytes.

Jeff

Jeffrey Walton

unread,
Jun 29, 2020, 10:22:09 PM6/29/20
to Crypto++ Users

Jeffrey Walton

unread,
Jun 29, 2020, 10:31:10 PM6/29/20
to Crypto++ Users
This is probably a better reference for your issue. It takes your through the keys and formats (which you already know), and it also shows you how to save and load them.


You might also be interested in the following. It adds PEM encodings, but it is a library add-on. Crypto++ does not offer PEM support in the library itself.

Jeff
Reply all
Reply to author
Forward
0 new messages