You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
6.7 KiB

/**
* (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 <http://www.gnu.org/licenses/>
*
*/
#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