simpleaes

simpleaes Mercurial Source Tree


Root/simpleAes.cpp

/*!
 * 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..
 *
 * 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;
}
Source at commit tip created 12 years 1 month ago.
By Nathan Adams, initial commit

Archive Download this file

Branches

Tags

Page rendered in 1.68394s using 11 queries.