--- transform_aes.c.org 2019-05-29 22:16:51.940321577 +0200 +++ transform_aes.c 2019-05-30 18:50:12.734455617 +0200 @@ -25,7 +25,7 @@ #include "openssl/sha.h" #define N2N_AES_TRANSFORM_VERSION 1 /* version of the transform encoding */ -#define N2N_AES_IVEC_SIZE 32 /* Enough space for biggest AES ivec */ +#define N2N_AES_IVEC_SIZE (AES_BLOCK_SIZE) #define AES256_KEY_BYTES (256/8) #define AES192_KEY_BYTES (192/8) @@ -34,27 +34,25 @@ /* AES plaintext preamble */ #define TRANSOP_AES_VER_SIZE 1 /* Support minor variants in encoding in one module. */ #define TRANSOP_AES_SA_SIZE 4 -#define TRANSOP_AES_IV_SEED_SIZE 8 +#define TRANSOP_AES_IV_SEED_SIZE 8 /* size of transmitted random part of IV in bytes, between 0 .. 16 */ +#define TRANSOP_AES_IV_PADDING_SIZE (N2N_AES_IVEC_SIZE - TRANSOP_AES_IV_SEED_SIZE) +#define TRANSOP_AES_IV_KEY_BYTES (AES128_KEY_BYTES) /* use AES128 for IV encryption */ #define TRANSOP_AES_PREAMBLE_SIZE (TRANSOP_AES_VER_SIZE + TRANSOP_AES_SA_SIZE + TRANSOP_AES_IV_SEED_SIZE) /* AES ciphertext preamble */ #define TRANSOP_AES_NONCE_SIZE 4 +const uint8_t RAND_BYTES = log2(RAND_MAX) / 8; /* number of random bytes returned from rand() function */ + typedef unsigned char n2n_aes_ivec_t[N2N_AES_IVEC_SIZE]; typedef struct transop_aes { AES_KEY enc_key; /* tx key */ AES_KEY dec_key; /* tx key */ AES_KEY iv_enc_key; /* key used to encrypt the IV */ - uint8_t iv_ext_val[AES128_KEY_BYTES]; /* key used to extend the random IV seed to full block size */ + uint8_t iv_pad_val[TRANSOP_AES_IV_PADDING_SIZE]; /* key used to pad the random IV seed to full block size */ } transop_aes_t; -struct sha512_keybuf { - uint8_t enc_dec_key[AES256_KEY_BYTES]; /* The key to use for AES CBC encryption/decryption */ - uint8_t iv_enc_key[AES128_KEY_BYTES]; /* The key to use to encrypt the IV with AES ECB */ - uint8_t iv_ext_val[AES128_KEY_BYTES]; /* A value to extend the IV seed */ -}; /* size: SHA512_DIGEST_LENGTH */ - static int transop_deinit_aes(n2n_trans_op_t *arg) { transop_aes_t *priv = (transop_aes_t *)arg->priv; @@ -64,33 +62,12 @@ return 0; } -/* Return the best acceptable AES key size (in bytes) given an input keysize. - * - * The value returned will be one of AES128_KEY_BYTES, AES192_KEY_BYTES or - * AES256_KEY_BYTES. - */ -static size_t aes_best_keysize(size_t numBytes) -{ - if (numBytes >= AES256_KEY_BYTES ) - { - return AES256_KEY_BYTES; - } - else if (numBytes >= AES192_KEY_BYTES) - { - return AES192_KEY_BYTES; - } - else - { - return AES128_KEY_BYTES; - } -} - -static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint64_t iv_seed) { - uint8_t iv_full[AES_BLOCK_SIZE]; +static void set_aes_cbc_iv(transop_aes_t *priv, n2n_aes_ivec_t ivec, uint8_t *iv_seed) { + uint8_t iv_full[N2N_AES_IVEC_SIZE]; - /* Extend the seed to full block size via the fixed ext value */ - memcpy(iv_full, priv->iv_ext_val, sizeof(iv_seed)); // note: only 64bits used of 128 available - memcpy(iv_full + sizeof(iv_seed), &iv_seed, sizeof(iv_seed)); + /* Extend the seed to full block size with padding value */ + memcpy(iv_full, priv->iv_pad_val, TRANSOP_AES_IV_PADDING_SIZE); + memcpy(iv_full + TRANSOP_AES_IV_PADDING_SIZE, iv_seed, TRANSOP_AES_IV_SEED_SIZE); /* Encrypt the IV with secret key to make it unpredictable. * As discussed in https://github.com/ntop/n2n/issues/72, it's important to @@ -128,7 +105,7 @@ int len=-1; size_t idx=0; size_t tx_sa_num = 0; // Not used - uint64_t iv_seed = 0; + uint8_t iv_seed[TRANSOP_AES_IV_SEED_SIZE]; uint8_t padding = 0; n2n_aes_ivec_t enc_ivec = {0}; @@ -141,11 +118,16 @@ encode_uint32( outbuf, &idx, tx_sa_num ); // Not used /* Generate and encode the IV seed. - * Using two calls to rand() because RAND_MAX is usually < 64bit - * (e.g. linux) and sometimes < 32bit (e.g. Windows). + * Assume rand() to deliver 'RAND_BYTES' random bytes and re-calling rand() + * because RAND_MAX is usually < 64bit (e.g. linux) + * and sometimes < 32bit (e.g. Windows). */ - iv_seed = ((((uint64_t)rand() & 0xFFFFFFFF)) << 32) | rand(); - encode_buf(outbuf, &idx, &iv_seed, sizeof(iv_seed)); + uint32_t random_int; + for (int i=0; i < TRANSOP_AES_IV_SEED_SIZE; i++) { + if ((i % RAND_BYTES) == 0) random_int = rand(); + iv_seed[i] = (random_int >> ((i % RAND_BYTES) * 8)) & 0xFF; + } + encode_buf(outbuf, &idx, iv_seed, TRANSOP_AES_IV_SEED_SIZE); /* Encrypt the assembly contents and write the ciphertext after the SA. */ len = in_len + TRANSOP_AES_NONCE_SIZE; @@ -161,8 +143,10 @@ len2 = ( (len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* Round up to next whole AES adding at least one byte. */ padding = (len2-len); assembly[len2 - 1] = padding; - traceEvent( TRACE_DEBUG, "padding = %u, seed = %016lx", padding, iv_seed ); + char * iv_seed_output[TRANSOP_AES_IV_SEED_SIZE*2]; + for (int i=0; i < TRANSOP_AES_IV_SEED_SIZE; i++) sprintf(iv_seed_output, "%s%02x", iv_seed_output,iv_seed[i]); + traceEvent( TRACE_DEBUG, "padding = %u, seed = %s", padding, iv_seed_output ); set_aes_cbc_iv(priv, enc_ivec, iv_seed); AES_cbc_encrypt( assembly, /* source */ @@ -198,7 +182,7 @@ size_t rem=in_len; size_t idx=0; uint8_t aes_enc_ver=0; - uint64_t iv_seed=0; + uint8_t iv_seed[TRANSOP_AES_IV_SEED_SIZE]; /* Get the encoding version to make sure it is supported */ decode_uint8( &aes_enc_ver, inbuf, &rem, &idx ); @@ -208,12 +192,14 @@ decode_uint32( &sa_rx, inbuf, &rem, &idx ); /* Get the IV seed */ - decode_buf((uint8_t *)&iv_seed, sizeof(iv_seed), inbuf, &rem, &idx); + decode_buf(iv_seed, TRANSOP_AES_IV_SEED_SIZE, inbuf, &rem, &idx); - traceEvent( TRACE_DEBUG, "decode_aes %lu with seed %016lx", in_len, iv_seed ); + char * iv_seed_output[TRANSOP_AES_IV_SEED_SIZE*2]; + for (int i=0; i < TRANSOP_AES_IV_SEED_SIZE; i++) sprintf(iv_seed_output, "%s%02x", iv_seed_output,iv_seed[i]); + traceEvent( TRACE_DEBUG, "decode_aes %lu with seed %s", in_len, iv_seed_output); len = (in_len - TRANSOP_AES_PREAMBLE_SIZE); - + if ( 0 == (len % AES_BLOCK_SIZE ) ) { uint8_t padding; n2n_aes_ivec_t dec_ivec = {0}; @@ -259,37 +245,80 @@ } static int setup_aes_key(transop_aes_t *priv, const uint8_t *key, ssize_t key_size) { - size_t aes_keysize_bytes; - size_t aes_keysize_bits; - struct sha512_keybuf keybuf; + size_t aes_key_size_bytes; + size_t aes_key_size_bits; + uint8_t * key_mat_buf; + size_t key_mat_buf_length; /* Clear out any old possibly longer key matter. */ memset( &(priv->enc_key), 0, sizeof(priv->enc_key) ); memset( &(priv->dec_key), 0, sizeof(priv->dec_key) ); memset( &(priv->iv_enc_key), 0, sizeof(priv->iv_enc_key) ); - memset( &(priv->iv_ext_val), 0, sizeof(priv->iv_ext_val) ); + memset( &(priv->iv_pad_val), 0, sizeof(priv->iv_pad_val) ); - /* We still use aes_best_keysize (even not necessary since we hash the key - * into the 256bits enc_dec_key) to let the users choose the degree of encryption. - * Long keys will pick AES192 or AES256 with more robust but expensive encryption. + /* Let the user choose the degree of encryption: + * Long input keys will pick AES192 or AES256 with more robust but expensive encryption. + * + * The input key always gets hashed to make a more unpredictable use of the key space and + * also to derive some additional material (key for IV encrpytion, IV padding). + * + * The following scheme for key setup was discussed on github: + * https://github.com/ntop/n2n/issues/101 */ - aes_keysize_bytes = aes_best_keysize(key_size); - aes_keysize_bits = 8 * aes_keysize_bytes; - /* Hash the main key to generate subkeys */ - SHA512(key, key_size, (u_char*)&keybuf); + /* create a working buffer of maximal occuring hashes size and generate + * the hashes for the aes key material, key_mat_buf_lengh indicates the + * actual "filling level" of the buffer + */ + key_mat_buf = calloc(1, SHA512_DIGEST_LENGTH + SHA256_DIGEST_LENGTH); + if(!key_mat_buf) + return(1); - /* setup of enc_key/dec_key, used for the CBC encryption */ - AES_set_encrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(priv->enc_key)); - AES_set_decrypt_key(keybuf.enc_dec_key, aes_keysize_bits, &(priv->dec_key)); + if (key_size >= 65) + { + aes_key_size_bytes = AES256_KEY_BYTES; + SHA512(key, key_size, key_mat_buf); + key_mat_buf_length = SHA512_DIGEST_LENGTH; + } + else if (key_size >= 44) + { + aes_key_size_bytes = AES192_KEY_BYTES; + SHA384(key, key_size, key_mat_buf); + /* append a hash of the first hash to create enough material for IV padding */ + SHA256(key_mat_buf, SHA384_DIGEST_LENGTH, key_mat_buf + SHA384_DIGEST_LENGTH); + key_mat_buf_length = SHA384_DIGEST_LENGTH + SHA256_DIGEST_LENGTH; + } + else + { + aes_key_size_bytes = AES128_KEY_BYTES; + SHA256(key, key_size, key_mat_buf); + /* append a hash of the first hash to create enough material for IV padding */ + SHA256(key_mat_buf, SHA256_DIGEST_LENGTH, key_mat_buf + SHA256_DIGEST_LENGTH); + key_mat_buf_length = 2 * SHA256_DIGEST_LENGTH; + } - /* setup of iv_enc_key and iv_ext_val, used for generating the CBC IV */ - AES_set_encrypt_key(keybuf.iv_enc_key, sizeof(keybuf.iv_enc_key) * 8, &(priv->iv_enc_key)); - memcpy(priv->iv_ext_val, keybuf.iv_ext_val, sizeof(keybuf.iv_ext_val)); + /* is there enough material available? */ + if (key_mat_buf_length < (aes_key_size_bytes + TRANSOP_AES_IV_KEY_BYTES + TRANSOP_AES_IV_PADDING_SIZE)) + { + /* this should never happen */ + traceEvent( TRACE_ERROR, "AES missing %u bits hashed key material\n", + (aes_key_size_bytes + TRANSOP_AES_IV_KEY_BYTES + TRANSOP_AES_IV_PADDING_SIZE - key_mat_buf_length) * 8); + return(1); + } + + /* setup of enc_key/dec_key, used for the CBC encryption */ + aes_key_size_bits = 8 * aes_key_size_bytes; + AES_set_encrypt_key(key_mat_buf, aes_key_size_bits, &(priv->enc_key)); + AES_set_decrypt_key(key_mat_buf, aes_key_size_bits, &(priv->dec_key)); + + /* setup of iv_enc_key (AES128 key) and iv_pad_val, used for generating the CBC IV */ + AES_set_encrypt_key(key_mat_buf + aes_key_size_bytes, TRANSOP_AES_IV_KEY_BYTES * 8, &(priv->iv_enc_key)); + memcpy(priv->iv_pad_val, key_mat_buf + aes_key_size_bytes + TRANSOP_AES_IV_KEY_BYTES, TRANSOP_AES_IV_PADDING_SIZE); traceEvent( TRACE_DEBUG, "AES %u bits setup completed\n", - aes_keysize_bits, key); + aes_key_size_bits); + free(key_mat_buf); return(0); }