I have written a C++ program that uses the Crypto++ library to encrypt files using AES-256Bit (in GCM mode). I am planning to eventually have the program store the keys for the files in a file e.g. *keys.txt* and encrypt that file again, maybe with a different algorithm which apparently adds security instead of using the same key for each file (correct me if I'm wrong).

OK, well, I have mostly "stolen" and modified the code but I wanted to know if my code is actually secure or not, as well as if I should stick with GCM or if I should use a different mode instead. Lastly, I have read that a random IV generation in the GCM mode is bad because of IV collision, but others say it's not a problem. What is the case in my program?

This is my first time using such an advanced tool (or whatever you like to call it) so please don't be to hard on me when you find mistakes I've made, but do still call them out.

Thanks in advance for checking.

```
#include <cryptopp/files.h>   // to encryt files (for FileSink and stuff like that)
#include <cryptopp/modes.h>   // different AES modes (GCM is used here)
#include <cryptopp/osrng.h>   // random key and iv gneration

#include <fstream>   // library to convert file to binary
#include <iostream>  // self explanitory

using aes_key_t = std::array<CryptoPP::byte, 32>;  // keysize definition (AES-256bit here)
using aes_iv_t = std::array<CryptoPP::byte, CryptoPP::AES::BLOCKSIZE>;  // block size definition (16 bytes)

void encrypt(const aes_key_t &key, const aes_iv_t &iv, const std::string &filename_in, const std::string &filename_out) {
  CryptoPP::GCM_Mode<CryptoPP::AES>::Encryption cipher{};
  cipher.SetKeyWithIV(key.data(), key.size(), iv.data());

  std::ifstream in{filename_in, std::ios::binary};    // open the inputfile in binary mode
  std::ofstream out{filename_out, std::ios::binary};  // open the outputfile in binary mode

  CryptoPP::FileSource{in, /*pumpAll=*/true,
                       new CryptoPP::StreamTransformationFilter{
                           cipher, new CryptoPP::FileSink{out}}};
}

void decrypt(const aes_key_t &key, const aes_iv_t &iv,const std::string &filename_in, const std::string &filename_out) {
  CryptoPP::GCM_MODE<CryptoPP::AES>::Decryption cipher{};
  cipher.SetKeyWithIV(key.data(), key.size(), iv.data());

  std::ifstream in{filename_in, std::ios::binary};
  std::ofstream out{filename_out, std::ios::binary};

  CryptoPP::FileSource{in, /*pumpAll=*/true,
                       new CryptoPP::StreamTransformationFilter{
                           cipher, new CryptoPP::FileSink{out}}};
}

int main(int argc, char **argv) {
  // prints block size
  std::cout <<  CryptoPP::AES::BLOCKSIZE << std::endl;

  CryptoPP::AutoSeededRandomPool rng{};

  // Generate a random key
  aes_key_t key{};
  rng.GenerateBlock(key.data(), key.size());

  // Generate a random IV
  aes_iv_t iv{};
  rng.GenerateBlock(iv.data(), iv.size());

  // encrypt
  encrypt(key, iv, "notes.txt", "notes_encrypted");

  // decrypt
  decrypt(key, iv, "notes_encrypted", "notes_decrypted.txt");

  return 0;
}

```