#include <iostream>
#include <string>

//#include "crypto++/HASHCrypt.hpp"

#include <crypto++/aes.h>
#include <crypto++/stdcpp.h>

#include <crypto++/hex.h>
using CryptoPP::HexEncoder;
using CryptoPP::HexDecoder;

#include <crypto++/cryptlib.h>
using CryptoPP::BufferedTransformation;
using CryptoPP::AuthenticatedSymmetricCipher;

#include <crypto++/secblock.h>
using CryptoPP::SecByteBlock;

#include <crypto++/modes.h>
using CryptoPP::CFB_Mode;

#include <crypto++/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::AuthenticatedEncryptionFilter;
using CryptoPP::AuthenticatedDecryptionFilter;



#include <crypto++/osrng.h>
using CryptoPP::AutoSeededRandomPool;

#include <crypto++/aes.h>
using CryptoPP::AES;

#include <crypto++/md5.h>


#include <crypto++/gcm.h>
using CryptoPP::GCM;
using CryptoPP::GCM_TablesOption;





void getKI(std::string chaine,byte* key, byte* iv, int size){




    CryptoPP::MD5 hash;
byte digest[ CryptoPP::MD5::DIGESTSIZE ];
std::string message = chaine;


hash.CalculateDigest( digest, (byte*) message.c_str(), message.length() );


CryptoPP::HexEncoder encoder;
std::string output;
encoder.Attach( new CryptoPP::StringSink( output ) );
encoder.Put( digest, sizeof(digest) );
encoder.MessageEnd();



    for(int i=0; i<size;i++){
        key[i]=output[i];
        iv[i]=0x1;
    }


// stub for how you really get it, e.g. reading it from a file, off of a network socket encrypted with an asymmetric cipher, or whatever
//read_key(aes_key, sizeof(aes_key));

// stub for how you really get it, e.g. filling it with random bytes or reading it from the other side of the socket since both sides have to use the same IV as well as the same key
//read_initialization_vector(iv);

// the final argument is specific to CFB mode, and specifies the refeeding size in bytes. This invocation corresponds to Java's Cipher.getInstance("AES/CFB8/NoPadding")
CryptoPP::CFB_Mode<CryptoPP::Rijndael>::Encryption* enc = new CFB_Mode<AES>::Encryption(key, size, iv, 1);


// the final argument is specific to CFB mode, and specifies the refeeding size in bytes. This invocation corresponds to Java's Cipher.getInstance("AES/CFB8/NoPadding")
CryptoPP::CFB_Mode<CryptoPP::Rijndael>::Decryption* dec = new CFB_Mode<AES>::Decryption(key, size, iv, 1);





}


void aff(std::string chaine);
//#include "crypto++/sha3.h"
int main(){

/*    /home/loic/Documents/c/forgetIt/crypto++/HASHCrypt.cpp|21aff("------------------\n");

    HASHCrypt monhash=HASHCrypt("loic");
    aff(monhash.getMD5_128());
    aff("\n");

    aff("--------------\n");*/


    std::string MessageS="Bonjours les amis, je vais être crypter !!!!";
    char* Message=(char*)MessageS.c_str();

    std::cout << Message << std::endl;

    AutoSeededRandomPool rnd;

    // Generate a random key
    //SecByteBlock key(0x00, AES::DEFAULT_KEYLENGTH);
    //rnd.GenerateBlock( key, key.size() );

    // Generate a random IV
    //byte iv[AES::BLOCKSIZE];
    //rnd.GenerateBlock(iv, AES::BLOCKSIZE);











    std::string cle;


    aff("Entrez une clé de cryptage : ");
    std::cin >> cle;



    byte key[32];
    byte iv[32];

    getKI(cle,key,iv, sizeof(key));






    int messageLen = (int)strlen(Message) + 1;

    //////////////////////////////////////////////////////////////////////////
    // Encrypt

    CFB_Mode<AES>::Encryption cfbEncryption(key, sizeof(key), iv);
    cfbEncryption.ProcessData((byte*)Message, (byte*)Message, messageLen);



    while(not(cle=="exit")){
            byte key2[32];
            byte iv2[32];


    MessageS="Bonjours les amis, je vais être crypter !!!!";

    CFB_Mode<AES>::Encryption cfbEncryption(key, sizeof(key), iv);
    cfbEncryption.ProcessData((byte*)Message, (byte*)Message, messageLen);


    aff("Entrez une clé de décryptage : ");
    std::cin >> cle;


    getKI(cle,key2,iv2, sizeof(key));


    //////////////////////////////////////////////////////////////////////////
    // Decrypt

    std::cout << std::endl << "Decryptage : " << std::endl;

    CFB_Mode<AES>::Decryption cfbDecryption(key2,sizeof(key2), iv2);
    cfbDecryption.ProcessData((byte*)Message, (byte*)Message, messageLen);

    std::cout <<std::endl << Message << std::endl << std::endl;

    }














    return 0;


}


void aff(std::string chaine){


        std::cout << chaine;


}
