I'm trying to implement a barebones, start-to-finish AES encryption that is correct and secure. For my purposes, I just want to generate the ciphertext of the output of some benchmarking programs, to simulate what kind of ciphertext would be written to say, a cloud storage server. After reading about it some, I came to the conclusion that for my purposes, authenticated encryption produced by AES in GCM mode is representative of ciphertexts I would see in use on real servers.
Starting from the example code on the Crypto++ Wiki page, I came up with the following snippet to read in some strings from a file and dump the ciphertext. The problem is that the ciphertexts I am getting out are very similar, the upper half being identical in many of the outputs. I suspect it is due to the way I am using/initializing the AutoSeededRandomPool, but I don't know enough about it to figure out how to fix it. It looks like the underlying code is making calls to the OS (Ubuntu 16.04) to generate entropy, which leads me to believe that perhaps there is not enough time between calls for this value to change.
Thanks in advance for any help you can give.
#include "osrng.h"
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include "cryptlib.h"
#include "hex.h"
#include "filters.h"
#include "aes.h"
#include "gcm.h"
#include "secblock.h"
using namespace std;
using CryptoPP::AutoSeededRandomPool;
using CryptoPP::AutoSeededX917RNG;
using CryptoPP::HexEncoder;
using CryptoPP::HexDecoder;
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::AuthenticatedEncryptionFilter;
using CryptoPP::AuthenticatedDecryptionFilter;
using CryptoPP::AES;
using CryptoPP::GCM;
using CryptoPP::SecByteBlock;
// Single randomly seeded RNG
AutoSeededRandomPool rnd;
// Generate a string buffer for the input/output data
string plainText, cipherText, encoded;
// Generate a random key
SecByteBlock key(AES::DEFAULT_KEYLENGTH);
rnd.GenerateBlock(key, key.size());
// Generate an initial value vector (public but unique per msg)
SecByteBlock iv(AES::BLOCKSIZE);
rnd.GenerateBlock(iv, iv.size());
for (size_t i = 0; i < numLines; ++i)
{
getline(inputFileStream, plainText);
// Do encryption
GCM<AES>::Encryption e;
e.SetKeyWithIV(key, key.size(), iv, iv.size());
StringSource
(
plainText,
true,
new AuthenticatedEncryptionFilter
(
e,
new StringSink(cipherText)
)
);
encoded.clear();
StringSource
(
cipherText,
true,
new HexEncoder
(
new StringSink(encoded)
)
);
cout << "Cipher Text: " << encoded << endl;
}
Here is an example of output ciphertexts:
Cipher Text:
9DE3A67D5FF42A15834460CD4489B20A352ECEB5F801F7349F3A989DAE8C02675CB48ADDD00604139353F2DEC6335DF8156DA66ACEF953F2E573BB3D88E7AF7D59EE311DC8056CDB0B90B30A232DD7ECB219FB2F9F2D9898B98A1B6749FC8B88D00B5E08DC4EF9C3A52521298D6FBFD75A9A71E8A253D8B9F06D17B07442DA543B8E1CCCEC1E7D7084A1A24DAA71CB688AC2ECD840731F5D57AA7BC61DE5837411596561C36659D95451A003A0E27697528B9BB6B67763F6
Cipher Text:
9DE3A67D5FF42A15834460CD4489B20A352ECEB5F801F7349F3A989DAE8C02675CB48ADDD00604139353F2DEC6335DF8156DA66ACEF953F2E573BB3D88E7AF7D59EE311DC8056CDB0B90B30A232DD7ECB219FB2F9F2D9898B98A1B6749FC8B88D00B5E08DC4EF9C3A52521298D6FBFD75A9A71E8A253D8B9F06D17B07442DA543B8E1CCCEC1E7D7084A1A24DAA71CB688AC2ECD840731F5D57AA7BC61DE5837411596561C36659D95451A003A0E27697528B9BB6B67763F6D8B9F0691B616C2E996B5E473860EE348C09A1F0FC
Moving the IV generation outside of the loop, there is similar behavior:
Cipher Text:
25C638C32E67A7A2C65BF37ABA7C30C19C2714D95FBB68E6E57560CCE2C20F266E6C30768108CF7E01C195991B61AF7FE4F4FA691AFEAAFCFB74292EBE30B9236147722F5785D8F21070D3ACF9E476E39235B4C362D14BF7B2FC2A5BFC0297FCBCBEC37795626029CC30B404A6DB67EA652F5A7FA294D039C4A09BC611F74D8C9FFBD26F49C54470E2C41463440AF050D7FF160CD923FFD0CA6FAF1DB66947C5896B1A39A8E9B694A025E2F521229BDC15C48C5F3AD27A87
Cipher Text:
25C638C32E67A7A2C65BF37ABA7C30C19C2714D95FBB68E6E57560CCE2C20F266E6C30768108CF7E01C195991B61AF7FE4F4FA691AFEAAFCFB74292EBE30B9236147722F5785D8F21070D3ACF9E476E39235B4C362D14BF7B2FC2A5BFC0297FCBCBEC37795626029CC30B404A6DB67EA652F5A7FA294D039C4A09BC611F74D8C9FFBD26F49C54470E2C41463440AF050D7FF160CD923FFD0CA6FAF1DB66947C5896B1A39A8E9B694A025E2F521229BDC15C48C5F3AD27A87FA3272CFE669E235CE452FCEEA59CC8CA34554FF25
Addendum to the answer below:
In the code I neglected to clear the string "cipherText" at each iteration of the loop. Apparently the StringSink operations were just appending the new cipher texts to the end of the cipherText, which is why they were identical. Thanks for all the help!