Search code examples
c++crypto++

Loading a key from memory in Crypto++


I'm trying to save a public DLIES key to memory and then read it again, but I keep getting exception BER decode error. I use ArraySink, ArraySource and a char[64] buffer to transfer the key between two CryptoPP::DLIES<>::PublicKey. I even verify that the public key is good. What am I missing?

Below is the full sample that doesn't work properly. How to modify it so that it'll properly load the key?

#include <iostream>
#include <gfpcrypt.h>
#include <filters.h>
#include <osrng.h>

int main() {
    try {
        CryptoPP::DefaultAutoSeededRNG rng;

        CryptoPP::DLIES<>::PrivateKey privateKey;
        privateKey.GenerateRandomWithKeySize(rng, 10);

        CryptoPP::DLIES<>::PublicKey publicKey;
        privateKey.MakePublicKey(publicKey);

        if (!publicKey.Validate(rng, 3)) {
            std::cout << "Something wrong with public key." << std::endl;
            return 1;
        }

        byte buf[64];
        CryptoPP::ArraySink sink(buf, 64);
        publicKey.Save(sink);

        CryptoPP::ArraySource source((const char *)buf, sink.TotalPutLength());
        CryptoPP::DLIES<>::PublicKey pk;
        pk.Load(source);
    } catch (CryptoPP::Exception &ex) {
        std::cout << ex.what() << std::endl;
        return 1;
    }

    return 0;
}

Solution

  • The problem lied in not setting pumpAll=true 3rd parameter of the ArraySource constructor. After adding it, it worked. Another working solution was to use ByteQueue instead. For the sake of completeness, I paste both working examples below.

    ArraySource version:

    #include <iostream>
    #include <gfpcrypt.h>
    #include <filters.h>
    #include <osrng.h>
    
    int main() {
        try {
            CryptoPP::DefaultAutoSeededRNG rng;
    
            CryptoPP::DLIES<>::PrivateKey privateKey;
            privateKey.GenerateRandomWithKeySize(rng, 10);
    
            CryptoPP::DLIES<>::PublicKey publicKey;
            privateKey.MakePublicKey(publicKey);
    
            if (!publicKey.Validate(rng, 3)) {
                std::cout << "Something wrong with sent public key." << std::endl;
                return 1;
            }
    
            byte buf[64];
            CryptoPP::ArraySink sink(buf, 64);
            publicKey.Save(sink);
    
            CryptoPP::ArraySource source(buf, sink.TotalPutLength(), true);
            CryptoPP::DLIES<>::PublicKey pk;
            pk.Load(source);
    
            if (!pk.Validate(rng, 3)) {
                std::cout << "Something wrong with received public key." << std::endl;
                return 1;
            }
        } catch (CryptoPP::Exception &ex) {
            std::cout << ex.what() << std::endl;
            return 1;
        }
    
        return 0;
    }
    

    ByteQueue version (which I found more convenient in the end):

    #include <iostream>
    #include <gfpcrypt.h>
    #include <filters.h>
    #include <osrng.h>
    
    int main() {
        try {
            CryptoPP::DefaultAutoSeededRNG rng;
    
            CryptoPP::DLIES<>::PrivateKey privateKey;
            privateKey.GenerateRandomWithKeySize(rng, 10);
    
            CryptoPP::DLIES<>::PublicKey publicKey;
            privateKey.MakePublicKey(publicKey);
    
            if (!publicKey.Validate(rng, 3)) {
                std::cout << "Something wrong with sent public key." << std::endl;
                return 1;
            }
    
            CryptoPP::ByteQueue queue;
            publicKey.Save(queue);
            CryptoPP::lword size = queue.TotalBytesRetrievable();
    
            byte buf[64];
            queue.Get(buf, size);
    
            CryptoPP::ByteQueue queue2;
            queue2.Put(buf, size);
            CryptoPP::DLIES<>::PublicKey pk;
            pk.Load(queue2);
    
            if (!pk.Validate(rng, 3)) {
                std::cout << "Something wrong with received public key." << std::endl;
                return 1;
            }
        } catch (CryptoPP::Exception &ex) {
            std::cout << ex.what() << std::endl;
            return 1;
        }
    
        return 0;
    }