Search code examples
c++arraysvectorfile-iocrypto++

How to read and write an AES key to and from a file?


I am trying to write an AES key to a file then read it later. I'm using the Crypto++ library, and the AES key is initialized as follows. Below, byte is a typedef of unsigned char.

byte key[CryptoPP::AES::MAX_KEYLENGTH]

The key is 32 bytes long. I try to write it into a file with this:

FILE* file = fopen("C:\\key", "wb");
fwrite(key, 1, sizeof(key), file);
fclose(file);

And recover it using:

FILE* read_file = fopen("C:\\key", "rb");
fseek(read_file, 0, SEEK_END);
long int size = ftell(read_file);
fclose(read_file);

read_file = fopen("C:\\key", "rb");
unsigned char * in = (unsigned char *)malloc(size);
byte readed_key = fread(in, sizeof(unsigned char), size, read_file);
fclose(read_file);
if (key == readed_key)
{
    cout << "this is the right key !";
}
free(in);

However, I get an error message:

incompatible operand types : byte* and byte.

I don't understand why, since readed_key and key are initialized with byte and not byte*.


I looked at AES on the Crypto++ wiki, and the key is generated as follow. I figured out that I was just creating the key (not generating it):

SecByteBlock key(0x00, AES::MAX_KEYLENGTH);
rnd.GenerateBlock( key, key.size() );

With that I can't use

std::vector<byte> key(32);
rnd.GenerateBlock(key, key.size());

Because rnd.Generateblock can't convert std::vector< byte > into byte*

This is driving me crazy....


Solution

  • How to read and write an AES key to and from a file?

    I'm going to avoid your code since its mostly C code. Andrew pointed out some of the problems with it, so there's no sense in rehashing it. Instead I'll show you the Crypto++ and C++ way of doing things. I'll also discuss SecByteBlock a little.


    Here's the Crypto++ way to read the data into a byte array using sources and sinks. You can read more about them at Pipelines in the Crypto++ wiki.

    byte key[CryptoPP::AES::MAX_KEYLENGTH];
    FileSource fs("C:\\key.bin", true, new ArraySink(key, sizeof(key)));
    

    Here's the Crypto++ way to write data to a file using sources and sinks.

    byte key[CryptoPP::AES::MAX_KEYLENGTH];
    ArraySource as(key, sizeof(key), true, new FileSink("C:\\key.bin"));
    

    Here's the C++ way to read the data into a byte array using streams. Its taken from Reading and writing binary file

    byte key[CryptoPP::AES::MAX_KEYLENGTH];
    std::ifstream fs("C:\\key.bin", std::ios::binary);
    fs.read(key, sizeof(key));
    

    Here's the C++ way to write data to a file using streams.

    byte key[CryptoPP::AES::MAX_KEYLENGTH];
    std::ofstream fs("C:\\key.bin", std::ios::binary);
    fs.write(key, sizeof(key));
    

    std::vector<byte> key(32);
    rnd.GenerateBlock(key, key.size());
    

    Because rnd.Generateblock can't convert std::vector< byte > into byte*. This is driving me crazy....

    Here, you need a non-const pointer to the first element. Take the address of the first element in your vector. The same would apply to a std::string.

    std::vector<byte> key(32);
    rnd.GenerateBlock(&key[0], key.size());
    

    Since the key is sensitive, you should use a SecByteBlock. It zeroizes the key from memory once you are done using it.

    Generally speaking, if the information is sensitive, then you want to use a SecBlock<T>. In the case of SecByteBlock, T is a byte and there's a typedef for SecByteBlock. But you can make a SecBlock<T> out of anything.

    Here's the Crypto++ way to read the data into a SecByteBlock using sources and sinks.

    SecByteBlock key(AES::MAX_KEYLENGTH);
    FileSource fs("C:\\key.bin", true, new ArraySink(key.begin(), key.size()));
    

    SecByteBlock can initialize elements to a known value upon construction. You are using the feature below. All elements are initialized to 0x00.

    SecByteBlock key(0x00, AES::MAX_KEYLENGTH);
    rnd.GenerateBlock(key, key.size());
    

    Since you are overwriting the elements immediately with random data, you should forgo initialization. Just ask for an uninitialized block of memory:

    SecByteBlock key(AES::MAX_KEYLENGTH);
    rnd.GenerateBlock(key, key.size());