#include #include "aes_gcm.h" namespace util { namespace crypto { int AesGcm::aes_gcm_key( const unsigned char* key, const unsigned char* iv, EVP_CIPHER_CTX* e_ctx, EVP_CIPHER_CTX* d_ctx) { int ret = 0; if (e_ctx != NULL) { ret = EVP_EncryptInit_ex(e_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); if (ret != 1) { return -1; } ret = EVP_CIPHER_CTX_ctrl(e_ctx, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_IV_LENGTH, NULL); if (ret != 1) { return -2; } ret = EVP_EncryptInit_ex(e_ctx, NULL, NULL, key, iv); if (ret != 1) { return -3; } } // initial decrypt ctx if (d_ctx != NULL) { ret = EVP_DecryptInit_ex(d_ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); if (!ret) { return -1; } ret = EVP_CIPHER_CTX_ctrl(d_ctx, EVP_CTRL_GCM_SET_IVLEN, AES_GCM_IV_LENGTH, NULL); if (!ret) { return -2; } ret = EVP_DecryptInit_ex(d_ctx, NULL, NULL, key, iv); if (!ret) { return -3; } } return 0; } int AesGcm::aes_gcm_key( const std::string& key_hex, const std::string& iv_hex, EVP_CIPHER_CTX* e_ctx, EVP_CIPHER_CTX* d_ctx) { // check key_hex and iv_hex length if (key_hex.length() != AES_GCM_KEY_LENGTH * 2 || iv_hex.length() != AES_GCM_IV_LENGTH * 2) { return -4; } unsigned char key[AES_GCM_KEY_LENGTH]; unsigned char iv[AES_GCM_IV_LENGTH]; int ret = Basic::hex_to_byte(key_hex, key); if (ret < 0) { return -5; } ret = Basic::hex_to_byte(iv_hex, iv); if (ret < 0) { return -5; } return aes_gcm_key(key, iv, e_ctx, d_ctx); } int AesGcm::encrypt_aes_gcm( const unsigned char* plaintext, const int& len, const unsigned char* key, const unsigned char* iv, unsigned char* ciphertext, int& out_len) { EVP_CIPHER_CTX* ctx = NULL; int ret = 0; int update_len = 0; int ciphertext_len = 0; unsigned char tag_char[AES_GCM_TAG_LENGTH]; if (!(ctx = EVP_CIPHER_CTX_new())) { return -1; } // initial context ret = aes_gcm_key(key, iv, ctx, NULL); if (ret) { EVP_CIPHER_CTX_free(ctx); return -1; } // encryption ret = EVP_EncryptUpdate(ctx, ciphertext, &update_len, plaintext, len); if (ret != 1) { EVP_CIPHER_CTX_free(ctx); return -2; } ciphertext_len = update_len; ret = EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &update_len); if (1 != ret) { EVP_CIPHER_CTX_free(ctx); return -3; } ciphertext_len += update_len; // Get the tags for authentication ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_GCM_TAG_LENGTH, tag_char); if (1 != ret) { EVP_CIPHER_CTX_free(ctx); return -4; } EVP_CIPHER_CTX_free(ctx); //append the tags to the end of encryption text for (int i = 0; i < AES_GCM_TAG_LENGTH; ++i) { ciphertext[ciphertext_len + i] = tag_char[i]; } out_len = ciphertext_len + AES_GCM_TAG_LENGTH; return 0; } int AesGcm::decrypt_aes_gcm( const unsigned char* ciphertext, const int& len, const unsigned char* key, const unsigned char* iv, unsigned char* plaintext, int& out_len) { EVP_CIPHER_CTX* ctx = NULL; int ret = 0; int update_len = 0; int cipher_len = 0; int plaintext_len = 0; unsigned char tag_char[AES_GCM_TAG_LENGTH]; // get the tag at the end of ciphertext for (int i = 0; i < AES_GCM_TAG_LENGTH; ++i) { tag_char[i] = ciphertext[len - AES_GCM_TAG_LENGTH + i]; } cipher_len = len - AES_GCM_TAG_LENGTH; // initial aes context if (!(ctx = EVP_CIPHER_CTX_new())) { return -1; } ret = aes_gcm_key(key, iv, NULL, ctx); if (ret) { EVP_CIPHER_CTX_free(ctx); return -1; } // decryption ret = EVP_DecryptUpdate(ctx, plaintext, &update_len, ciphertext, cipher_len); if (ret != 1) { EVP_CIPHER_CTX_free(ctx); return -2; } plaintext_len = update_len; // check if the tag is equal to the decrption tag ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AES_GCM_TAG_LENGTH, tag_char); if (!ret) { EVP_CIPHER_CTX_free(ctx); // decrption failed return -3; } ret = EVP_DecryptFinal_ex(ctx, plaintext + update_len, &update_len); if (ret <= 0) { EVP_CIPHER_CTX_free(ctx); return -4; } plaintext_len += update_len; EVP_CIPHER_CTX_free(ctx); out_len = plaintext_len; return 0; } } // namespace crypt } // namespace common