Search code examples
c++encryptioncrypto++

Encrypt/Decrypt byte array Crypto++


I am trying to encrypt a byte array using AES. I have been able to encrypt strings and files no problem, however byte arrays seem to not be working for me. I pass in a byte array to be encrypted, for ease of testing I just pass in a generated AES key by crypto++ (bArrayToEncrypt). The encryption appears to be working but then the decryption does work at all. I also found it strange that the encryption has a large amount of duplicate characters. What I am doing wrong here??

I saw a similar question Here, but it was pertaining to RSA as well as the example provided encrypts strings which I already have up a running.

How functions are called:

   size_t ksize = CryptoPP::AES::MAX_KEYLENGTH;
   size_t vsize = CryptoPP::AES::BLOCKSIZE;

   byte key[ksize];
   byte testArray[ksize];
   byte encryptedksize];
   byte decrypted[ksize];
   byte iv[vsize];

   //generate key & iv, then generate a random byte array to encrypt/decrypt
   CryptoPP::AutoSeededRandomPool prng;
   prng.GenerateBlock(key, ksize);
   prng.GenerateBlock(iv, vsize);
   prng.GenerateBlock(testArray, ksize);


   encrypt_barray(key, ksize, iv, vsize, testArray, ksize, encrypted);

   //printed results here

   decrypt_barray(key, ksize, iv, vsize, encrypted, ksize, decrypted);

   //printed results here

Encrypt_barray

void encrypt_barray(byte* key, 
                    size_t kSize,
                    byte* iv, 
                    size_t ivSize, 
                    byte* bArrayToEncrypt,
                    size_t bArraySize,
                    byte* encrypted) {

   CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption e;
   e.SetKeyWithIV(key, kSize, iv, ivSize);

   CryptoPP::ArraySource(key, true,
      new CryptoPP::StreamTransformationFilter(e, new CryptoPP::ArraySink(encrypted, bArraySize)));
}

Decrypt_barray

void decrypt_barray(byte* key,
                    size_t kSize,
                    byte* iv,
                    size_t ivSize,
                    byte* bArrayToDecrypt,
                    size_t bArraySize,
                    byte* decrypted) {

   CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption d;
   d.SetKeyWithIV(keyFromHash, kfhSize, iv1, iv1Size);

   CryptoPP::ArraySource(keyToDecrypt, true,
      new CryptoPP::StreamTransformationFilter(d, new CryptoPP::ArraySink(decrypted, bArraySize)));
}

Output:

 Encrypted: ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠E1A2AFC5D820ADF7
7DB656DEF3245570╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╨Ñ♫

Decrypted: ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠E
1A2AFC5D820ADF77DB656DEF3245570╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╨Ñ♫
Press any key to continue . . .

Solution

  • Here's the way to do things using ArraySource and ArraySink. The Redirector ensures the ArraySink survives so you can call TotalPutLength.

    #include <iostream>
    #include <string>
    using namespace std;
    
    #include "cryptlib.h"
    #include "filters.h"
    #include "files.h"
    #include "modes.h"
    #include "hex.h"
    #include "aes.h"
    using namespace CryptoPP;
    
    int main(int argc, char* argv[])
    {
      byte key[AES::MAX_KEYLENGTH];
      byte iv[AES::BLOCKSIZE];
      vector<byte> plain, cipher, recover;
      HexEncoder encoder(new FileSink(cout));
    
      memset(key, 0x00, sizeof(key));
      memset(iv, 0x00, sizeof(iv));
    
      string str("Attack at dawn!");
      std::copy(str.begin(), str.end(), std::back_inserter(plain));
    
      cout << "Plain text: ";
      encoder.Put(plain.data(), plain.size());
      encoder.MessageEnd();
      cout << endl;
    
      /////////////////////////////////////////////////////////////
    
      CBC_Mode<AES>::Encryption enc;
      enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    
      // Make room for padding
      cipher.resize(plain.size()+AES::BLOCKSIZE);
      ArraySink cs(&cipher[0], cipher.size());
    
      ArraySource(plain.data(), plain.size(), true,
        new StreamTransformationFilter(enc, new Redirector(cs)));
    
      // Set cipher text length now that its known
      cipher.resize(cs.TotalPutLength());
    
      cout << "Cipher text: ";
      encoder.Put(cipher.data(), cipher.size());
      encoder.MessageEnd();
      cout << endl;
    
      /////////////////////////////////////////////////////////////
    
      CBC_Mode<AES>::Decryption dec;
      dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    
      // Recovered text will be less than cipher text
      recover.resize(cipher.size());
      ArraySink rs(&recover[0], recover.size());
    
      ArraySource(cipher.data(), cipher.size(), true,
        new StreamTransformationFilter(dec, new Redirector(rs)));
    
      // Set recovered text length now that its known
      recover.resize(rs.TotalPutLength());
    
      cout << "Recovered text: ";
      encoder.Put(recover.data(), recover.size());
      encoder.MessageEnd();
      cout << endl;
    
      return 0;
    }
    

    Running the program results in:

    $ ./test.exe
    Plain text: 41747461636B206174206461776E21
    Cipher text: 85928E5511BFE9E6EE235BCACC4894D4
    Recovered text: 41747461636B206174206461776E21
    

    Here's the example using ByteQueue. The Redirector helps chain the pipeline together because a ByteQueue is a BufferedTransformation.

    #include <iostream>
    #include <string>
    #include <iomanip>
    using namespace std;
    
    #include "cryptlib.h"
    #include "filters.h"
    #include "files.h"
    #include "modes.h"
    #include "queue.h"
    #include "hex.h"
    #include "aes.h"
    using namespace CryptoPP;
    
    int main(int argc, char* argv[])
    {
      byte key[AES::MAX_KEYLENGTH];
      byte iv[AES::BLOCKSIZE];
      HexEncoder encoder(new FileSink(cout));
    
      memset(key, 0x00, sizeof(key));
      memset(iv, 0x00, sizeof(iv));
    
      ByteQueue plain, cipher, recover;
      string str("Attack at dawn!");
      plain.Put(reinterpret_cast<const byte*>(str.data()), str.size());
    
      cout << "Plain text: ";
      plain.CopyTo(encoder);
      encoder.MessageEnd();
      cout << endl;
    
      /////////////////////////////////////////////////////////////
    
      CBC_Mode<AES>::Encryption enc;
      enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    
      StreamTransformationFilter f1(enc, new Redirector(cipher));
      plain.CopyTo(f1);
      f1.MessageEnd();
    
      cout << "Cipher text: ";
      cipher.CopyTo(encoder);
      encoder.MessageEnd();
      cout << endl;
    
      /////////////////////////////////////////////////////////////
    
      CBC_Mode<AES>::Decryption dec;
      dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    
      StreamTransformationFilter f2(dec, new Redirector(recover));
      cipher.CopyTo(f2);
      f2.MessageEnd();
    
      cout << "Recovered text: ";
      recover.CopyTo(encoder);
      encoder.MessageEnd();
      cout << endl;
    
      return 0;
    }
    

    It also results in:

    skylake:cryptopp$ ./test.exe
    Plain text: 41747461636B206174206461776E21
    Cipher text: 85928E5511BFE9E6EE235BCACC4894D4
    Recovered text: 41747461636B206174206461776E21