/** * (C) 2007-20 - ntop.org and contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not see see * */ #include "n2n.h" #ifdef N2N_HAVE_AES /* ****************************************************** */ #ifdef HAVE_OPENSSL_1_1 // get any erorr message out of openssl // taken from https://en.wikibooks.org/wiki/OpenSSL/Error_handling static char *openssl_err_as_string (void) { BIO *bio = BIO_new (BIO_s_mem ()); ERR_print_errors (bio); char *buf = NULL; size_t len = BIO_get_mem_data (bio, &buf); char *ret = (char *) calloc (1, 1 + len); if(ret) memcpy (ret, buf, len); BIO_free (bio); return ret; } #endif /* ****************************************************** */ int aes_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, const unsigned char *iv, aes_context_t *ctx) { #ifdef HAVE_OPENSSL_1_1 int evp_len; int evp_ciphertext_len; if(1 == EVP_EncryptInit_ex(ctx->enc_ctx, ctx->cipher, NULL, ctx->key, iv)) { if(1 == EVP_CIPHER_CTX_set_padding(ctx->enc_ctx, 0)) { if(1 == EVP_EncryptUpdate(ctx->enc_ctx, out, &evp_len, in, in_len)) { evp_ciphertext_len = evp_len; if(1 == EVP_EncryptFinal_ex(ctx->enc_ctx, out + evp_len, &evp_len)) { evp_ciphertext_len += evp_len; if(evp_ciphertext_len != in_len) traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl encryption: encrypted %u bytes where %u were expected", evp_ciphertext_len, in_len); } else traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl final encryption: %s", openssl_err_as_string()); } else traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl encrpytion: %s", openssl_err_as_string()); } else traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl padding setup: %s", openssl_err_as_string()); } else traceEvent(TRACE_ERROR, "aes_cbc_encrypt openssl init: %s", openssl_err_as_string()); EVP_CIPHER_CTX_reset(ctx->enc_ctx); #else uint8_t tmp_iv[AES_IV_SIZE]; memcpy (tmp_iv, iv, AES_IV_SIZE); AES_cbc_encrypt(in, // source out, // destination in_len, // enc size &(ctx->enc_key), tmp_iv, AES_ENCRYPT); #endif } /* ****************************************************** */ int aes_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, const unsigned char *iv, aes_context_t *ctx) { #ifdef HAVE_OPENSSL_1_1 int evp_len; int evp_plaintext_len; if(1 == EVP_DecryptInit_ex(ctx->dec_ctx, ctx->cipher, NULL, ctx->key, iv)) { if(1 == EVP_CIPHER_CTX_set_padding(ctx->dec_ctx, 0)) { if(1 == EVP_DecryptUpdate(ctx->dec_ctx, out, &evp_len, in, in_len)) { evp_plaintext_len = evp_len; if(1 == EVP_DecryptFinal_ex(ctx->dec_ctx, out + evp_len, &evp_len)) { evp_plaintext_len += evp_len; if(evp_plaintext_len != in_len) traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl decryption: decrypted %u bytes where %u were expected", evp_plaintext_len, in_len); } else traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl final decryption: %s", openssl_err_as_string()); } else traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl decrpytion: %s", openssl_err_as_string()); } else traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl padding setup: %s", openssl_err_as_string()); } else traceEvent(TRACE_ERROR, "aes_cbc_decrypt openssl init: %s", openssl_err_as_string()); EVP_CIPHER_CTX_reset(ctx->dec_ctx); #else uint8_t tmp_iv[AES_IV_SIZE]; memcpy (tmp_iv, iv, AES_IV_SIZE); AES_cbc_encrypt(in, // source out, // destination in_len, // enc size &(ctx->dec_key), tmp_iv, AES_DECRYPT); #endif return 0; } /* ****************************************************** */ int aes_ecb_decrypt (unsigned char *out, const unsigned char *in, aes_context_t *ctx) { #ifdef HAVE_OPENSSL_1_1 AES_ecb_encrypt(in, out, &(ctx->ecb_dec_key), AES_DECRYPT); #else AES_ecb_encrypt(in, out, &(ctx->dec_key), AES_DECRYPT); #endif } /* ****************************************************** */ int aes_init (const unsigned char *key, size_t key_size, aes_context_t **ctx) { // allocate context... *ctx = (aes_context_t*) calloc(1, sizeof(aes_context_t)); if (!(*ctx)) return -1; // ...and fill her up // initialize data structures #ifdef HAVE_OPENSSL_1_1 if(!((*ctx)->enc_ctx = EVP_CIPHER_CTX_new())) { traceEvent(TRACE_ERROR, "aes_init openssl's evp_* encryption context creation failed: %s", openssl_err_as_string()); return(-1); } if(!((*ctx)->dec_ctx = EVP_CIPHER_CTX_new())) { traceEvent(TRACE_ERROR, "aes_init openssl's evp_* decryption context creation failed: %s", openssl_err_as_string()); return(-1); } #endif // check key size and make key size (given in bytes) dependant settings switch(key_size) { case AES128_KEY_BYTES: // 128 bit key size #ifdef HAVE_OPENSSL_1_1 (*ctx)->cipher = EVP_aes_128_cbc(); #endif break; case AES192_KEY_BYTES: // 192 bit key size #ifdef HAVE_OPENSSL_1_1 (*ctx)->cipher = EVP_aes_192_cbc(); #endif break; case AES256_KEY_BYTES: // 256 bit key size #ifdef HAVE_OPENSSL_1_1 (*ctx)->cipher = EVP_aes_256_cbc(); #endif break; default: traceEvent(TRACE_ERROR, "aes_init invalid key size %u\n", key_size); return -1; } // key materiel handling #ifdef HAVE_OPENSSL_1_1 memcpy((*ctx)->key, key, key_size); AES_set_decrypt_key(key, key_size * 8, &((*ctx)->ecb_dec_key)); #else AES_set_encrypt_key(key, key_size * 8, &((*ctx)->enc_key)); AES_set_decrypt_key(key, key_size * 8, &((*ctx)->dec_key)); #endif return 0; } #endif // N2N_HAVE_AES