#include "aes.h" #include #include #include #include //----------------------------------------------------------------------------- AES::AES(std::string password, unsigned long long salt) { int nrounds = 5; unsigned char key[32], iv[32]; /* * Gen key & IV for AES 256 CBC mode. A SHA1 digest is used to hash the supplied key material. * nrounds is the number of times the we hash the material. More rounds are more secure but * slower. */ EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), reinterpret_cast(&salt), reinterpret_cast(password.c_str()), static_cast(password.length()), nrounds, key, iv); #if OPENSSL_VERSION_NUMBER >= 0x1010000fL encCipherContext = EVP_CIPHER_CTX_new(); decCipherContext = EVP_CIPHER_CTX_new(); EVP_CIPHER_CTX_init(encCipherContext); EVP_EncryptInit_ex(encCipherContext, EVP_aes_256_cbc(), nullptr, key, iv); EVP_CIPHER_CTX_init(decCipherContext); EVP_DecryptInit_ex(decCipherContext, EVP_aes_256_cbc(), nullptr, key, iv); #else EVP_CIPHER_CTX_init(&encCipherContext); EVP_EncryptInit_ex(&encCipherContext, EVP_aes_256_cbc(), nullptr, key, iv); EVP_CIPHER_CTX_init(&decCipherContext); EVP_DecryptInit_ex(&decCipherContext, EVP_aes_256_cbc(), nullptr, key, iv); #endif } //----------------------------------------------------------------------------- AES::~AES() { #if OPENSSL_VERSION_NUMBER >= 0x1010000fL EVP_CIPHER_CTX_free(encCipherContext); EVP_CIPHER_CTX_free(decCipherContext); #else EVP_CIPHER_CTX_cleanup(&encCipherContext); EVP_CIPHER_CTX_cleanup(&decCipherContext); #endif } //----------------------------------------------------------------------------- std::string AES::encrypt(std::string plainText) { unsigned long sourceLen = static_cast(plainText.length() + 1); unsigned long destLen = sourceLen * 2; unsigned char* compressed = new unsigned char[destLen]; int err = compress2(compressed, &destLen, reinterpret_cast(plainText.c_str()), sourceLen, 9); if (err != Z_OK) { return {}; } int pLen = static_cast(destLen); int cLen = pLen + AES_BLOCK_SIZE; int fLen = 0; unsigned char* cipherText = new unsigned char[cLen]; #if OPENSSL_VERSION_NUMBER >= 0x1010000fL EVP_EncryptInit_ex(encCipherContext, nullptr, nullptr, nullptr, nullptr); EVP_EncryptUpdate(encCipherContext, cipherText, &cLen, compressed, pLen); EVP_EncryptFinal_ex(encCipherContext, cipherText + cLen, &fLen); #else EVP_EncryptInit_ex(&encCipherContext, nullptr, nullptr, nullptr, nullptr); EVP_EncryptUpdate(&encCipherContext, cipherText, &cLen, compressed, pLen); EVP_EncryptFinal_ex(&encCipherContext, cipherText + cLen, &fLen); #endif std::vector data(cipherText, cipherText + cLen + fLen); std::string res = base64Encode(data); delete[] cipherText; delete[] compressed; return res; } //----------------------------------------------------------------------------- std::string AES::decrypt(std::string cipherText) { int fLen = 0; std::vector text = base64Decode(cipherText); int pLen = static_cast(text.size()); unsigned char* plainText = new unsigned char[pLen]; #if OPENSSL_VERSION_NUMBER >= 0x1010000fL EVP_DecryptInit_ex(decCipherContext, nullptr, nullptr, nullptr, nullptr); EVP_DecryptUpdate(decCipherContext, plainText, &pLen, text.data(), pLen); EVP_DecryptFinal_ex(decCipherContext, plainText + pLen, &fLen); #else EVP_DecryptInit_ex(&decCipherContext, nullptr, nullptr, nullptr, nullptr); EVP_DecryptUpdate(&decCipherContext, plainText, &pLen, text.data(), pLen); EVP_DecryptFinal_ex(&decCipherContext, plainText + pLen, &fLen); #endif unsigned long destLen = static_cast((pLen + fLen) * 2); unsigned char* uncompressed = new unsigned char[destLen]; int err = uncompress(uncompressed, &destLen, plainText, static_cast(pLen + fLen)); if (err != Z_OK) { return {}; } std::string res(reinterpret_cast(uncompressed)); delete[] uncompressed; return res; } //----------------------------------------------------------------------------- struct BIOFreeAll { void operator()(BIO* p) { BIO_free_all(p); } }; std::string AES::base64Encode(const std::vector& binary) { std::unique_ptr b64(BIO_new(BIO_f_base64())); BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL); BIO* sink = BIO_new(BIO_s_mem()); BIO_push(b64.get(), sink); BIO_write(b64.get(), binary.data(), static_cast(binary.size())); BIO_ctrl(b64.get(), BIO_CTRL_FLUSH, 0, nullptr); const char* encoded; const unsigned long len = static_cast(BIO_ctrl(sink, BIO_CTRL_INFO, 0, &encoded)); return std::string(encoded, len); } //----------------------------------------------------------------------------- std::vector AES::base64Decode(std::string encoded) { std::unique_ptr b64(BIO_new(BIO_f_base64())); BIO_set_flags(b64.get(), BIO_FLAGS_BASE64_NO_NL); BIO* source = BIO_new_mem_buf(encoded.c_str(), -1); // read-only source BIO_push(b64.get(), source); const unsigned long maxlen = encoded.length() / 4 * 3 + 1; std::vector decoded(maxlen); const unsigned long len = static_cast(BIO_read(b64.get(), decoded.data(), static_cast(maxlen))); decoded.resize(len); return decoded; } //-----------------------------------------------------------------------------