| /*!␊ |
| * Simple AES␊ |
| * Brendan Long␊ |
| * March 29, 2010␊ |
| * ␊ |
| * Simplified encryption and decryption using OpenSSL's AES library.␊ |
| * Remember to compile with -lcrypto and link against the library␊ |
| * g++ (your stuff) -lcrypto simpleAes.cpp (or simpleAes.o)␊ |
| *␊ |
| * Implementation note: Using the default ivec (0) is not secure. For␊ |
| * the full security that AES offers, use a different␊ |
| * ivec each time (it does not need to be secret,␊ |
| * just different.␊ |
| *␊ |
| * This code is released into the public domain. Yada yada..␊ |
| * Read this for details: http://creativecommons.org/licenses/publicdomain/␊ |
| *␊ |
| * If for some reason public domain isn't good enough, you may use, alter,␊ |
| * distribute or do anything else you want with this code with no restrictions.␊ |
| */␊ |
| ␊ |
| #include <openssl/aes.h>␊ |
| #include <openssl/evp.h>␊ |
| #include <iostream>␊ |
| #include <string.h>␊ |
| ␊ |
| // On Linux, we'll seed openssl with /dev/urandom, on others we use the time␊ |
| #ifdef __unix__␊ |
| #include <fstream>␊ |
| #elif _win32␊ |
| #include <Wincrypt.h>␊ |
| #endif␊ |
| ␊ |
| /*!␊ |
| * Generates 16 random numbers for the initialization vector.␊ |
| * On Linux, this uses /dev/urandom, on other platforms, it uses c's rand() function␊ |
| * \param ivec An unsigned char[16] to fill with random numbers␊ |
| * \return True on success, false otherwise␊ |
| */␊ |
| bool getRandomIvec(unsigned char* ivec){␊ |
| ␉␊ |
| #ifdef __unix__␊ |
| ␊ |
| ␉// Read 16 bytes from /dev/urandom␊ |
| ␉std::ifstream fin("/dev/urandom", std::ios_base::in | std::ios_base::binary);␊ |
| ␉if(!fin.fail()){␊ |
| ␉␉fin.read((char*)ivec, 16);␊ |
| ␉}␊ |
| ␉else{␊ |
| ␉␉fin.open("/dev/urandom", std::ios_base::in | std::ios_base::binary);␊ |
| ␉␉if(!fin.fail()){␊ |
| ␉␉␉fin.read((char*)ivec, 16);␊ |
| ␉␉}␊ |
| ␉␉else return false;␊ |
| ␉}␊ |
| ␉fin.close();␊ |
| ␉return true;␊ |
| ␊ |
| #elif _win32␊ |
| ␉␊ |
| ␉// I don't have a clue if this works..␊ |
| ␉HCRYPTPROV hCryptProv;␊ |
| ␉CryptAcquireContext( &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)␊ |
| ␉if(CryptGenRandom(hCryptProv, 16, (BYTE*) ivec)){␊ |
| ␉␉printf("Random sequence generated. \n");␊ |
| ␉}␊ |
| ␉else{␊ |
| ␉␉std::cout << "ERROR: CryptGenRandom failed." << std::endl;␊ |
| ␉␉return NULL;␊ |
| ␉}␊ |
| ␊ |
| #else␊ |
| ␊ |
| ␉// uhh...␊ |
| ␊ |
| #endif␊ |
| }␊ |
| ␊ |
| /*!␊ |
| * Encrypts a string using AES 256␊ |
| * Note: If the key is less than 32 bytes, it will be null padded.␊ |
| * If the key is greater than 32 bytes, it will be truncated␊ |
| * \param in The string to encrypt␊ |
| * \param key The key to encrypt with␊ |
| * \return The encrypted data␊ |
| */␊ |
| std::string aes_encrypt(std::string in, std::string key){␊ |
| ␊ |
| ␉unsigned char ivec[16];␊ |
| ␉getRandomIvec(ivec);␊ |
| ␉std::string ivecString((char*) ivec, 16); // Save this for later␊ |
| ␊ |
| ␉// Always pad the key to 32 bits.. because we can␊ |
| ␉if(key.length() < 32){␊ |
| ␉␉key.append(32 - key.length(), '\0');␊ |
| ␉}␊ |
| ␉␊ |
| ␉// Get some space ready for the output␊ |
| ␉unsigned char *output = new unsigned char[in.length() + AES_BLOCK_SIZE];␊ |
| ␉␊ |
| ␉// Encrypt the data␊ |
| ␉int length, finalLength = 0;␊ |
| ␉EVP_CIPHER_CTX *encryptHandle = new EVP_CIPHER_CTX;␊ |
| ␉EVP_CIPHER_CTX_init(encryptHandle);␊ |
| ␉EVP_EncryptInit_ex(encryptHandle, EVP_aes_256_cbc(), NULL, (unsigned char*) key.c_str(), ivec);␊ |
| ␉EVP_EncryptUpdate(encryptHandle, output, &length, (unsigned char*)in.c_str(), in.length());␊ |
| ␉finalLength += length;␊ |
| ␉EVP_EncryptFinal_ex(encryptHandle, output + length, &length);␊ |
| ␉finalLength += length;␊ |
| ␊ |
| ␉// Make the data into a string␊ |
| ␉std::string ret((char*) output, finalLength);␊ |
| ␉␊ |
| ␉// clean up␊ |
| ␉delete output;␊ |
| ␉EVP_CIPHER_CTX_cleanup(encryptHandle);␊ |
| ␉delete encryptHandle;␊ |
| ␉␊ |
| ␉return ivecString + ret;␊ |
| }␊ |
| ␊ |
| /*!␊ |
| * Decrypts a string using AES 256␊ |
| * Note: If the key is less than 32 bytes, it will be null padded.␊ |
| * If the key is greater than 32 bytes, it will be truncated␊ |
| * \param in The string to decrypt␊ |
| * \param key The key to decrypt with␊ |
| * \return The decrypted data␊ |
| */␊ |
| std::string aes_decrypt(std::string in, std::string key){␊ |
| ␊ |
| ␉// Get the ivec from the front␊ |
| ␉unsigned char ivec[16];␊ |
| ␉strncpy((char*)ivec, in.c_str(), 16);␊ |
| ␉in = in.substr(16);␊ |
| ␊ |
| ␉// Always pad the key to 32 bits.. because we can␊ |
| ␉if(key.length() < 32){␊ |
| ␉␉key.append(32 - key.length(), '\0');␊ |
| ␉}␊ |
| ␊ |
| ␉// Create some space for output␊ |
| ␉unsigned char *output = new unsigned char[in.length()];␉␊ |
| ␉int length, finalLength = 0;␊ |
| ␉␊ |
| ␉// Decrypt the string␊ |
| ␉EVP_CIPHER_CTX *encryptHandle = new EVP_CIPHER_CTX;␊ |
| ␉EVP_CIPHER_CTX_init(encryptHandle);␊ |
| ␉EVP_DecryptInit_ex(encryptHandle, EVP_aes_256_cbc(), NULL, (unsigned char*) key.c_str(), ivec);␊ |
| ␉EVP_DecryptUpdate(encryptHandle, output, &length, (unsigned char*)in.c_str(), in.length());␊ |
| ␉finalLength += length;␊ |
| ␉EVP_DecryptFinal_ex(encryptHandle, output + length, &length);␊ |
| ␉finalLength += length;␊ |
| ␉␊ |
| ␉//std::cout << finalLength << std::endl;␊ |
| ␉␊ |
| ␉// Make the output into a string␊ |
| ␉std::string ret((char*) output, finalLength);␊ |
| ␉␊ |
| ␉// Clean up␊ |
| ␉delete output;␊ |
| ␉EVP_CIPHER_CTX_cleanup(encryptHandle);␊ |
| ␉delete encryptHandle;␊ |
| ␉␊ |
| ␉return ret;␊ |
| }␊ |