From 393b1838ad08a1e088f4e11a9adb0681d3ec5fb2 Mon Sep 17 00:00:00 2001 From: Cedric Izoard Date: Mon, 1 Feb 2016 17:11:00 +0100 Subject: Add AES-CMAC encryption support -Add AES-CMAC encryption need to check MIC when deriving TDLS keys (802.11) -Tested against NIST test vector for AES128-CMAC Bug: 11312 Change-Id: Id4fd839bdedd3aa135823334e59d98271aea7c2b Reviewed-on: https://code.wireshark.org/review/13663 Petri-Dish: Alexis La Goutte Tested-by: Petri Dish Buildbot Reviewed-by: Anders Broman --- wsutil/aes.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ wsutil/aes.h | 41 +++++++++++++++++++++++++ 2 files changed, 138 insertions(+) (limited to 'wsutil') diff --git a/wsutil/aes.c b/wsutil/aes.c index 11543b7ff2..ee910c2b64 100644 --- a/wsutil/aes.c +++ b/wsutil/aes.c @@ -26,6 +26,7 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include "aes.h" @@ -1251,6 +1252,102 @@ void rijndael_decrypt( rijndaelDecrypt(ctx->dk, ctx->Nr, src, dst); } + +/* + * CMAC + */ +void aes_cmac_encrypt_starts(aes_cmac_ctx *ctx, const guint8 *key, guint key_len) +{ + if (ctx == NULL || key == NULL) { + ctx->key_len = 0; + return; + } + + ctx->key_len = key_len; + memset(ctx->state, 0, key_len); + ctx->input_used = 0; + ctx->aes.Nr = rijndaelKeySetupEnc(ctx->aes.ek, key, key_len * 8); +} + +#define XOR_BLOCK(b, a, len) \ + { \ + guint __i__; \ + for (__i__ = 0; __i__ < (guint)(len); __i__++) \ + (b)[__i__] ^= (a)[__i__]; \ + } + +void aes_cmac_encrypt_update(aes_cmac_ctx *ctx, const guint8 *input, guint length) +{ + guint left ; + + if (ctx == NULL || input == NULL || ctx->key_len == 0) { + return; + } + + left = ctx->key_len - ctx->input_used; + + if (length <= left) { + memcpy(&ctx->input[ctx->input_used], input, length); + ctx->input_used += length; + return; + } + + if (ctx->input_used > 0) { + memcpy(&ctx->input[ctx->input_used], input, left); + input += left; + length -= left; + XOR_BLOCK(ctx->state, ctx->input, ctx->key_len); + rijndael_encrypt(&(ctx->aes), ctx->state, ctx->state); + } + + while (length > ctx->key_len) { + XOR_BLOCK(ctx->state, input, ctx->key_len); + rijndael_encrypt(&(ctx->aes), ctx->state, ctx->state); + input += ctx->key_len; + length -= ctx->key_len; + } + + if (length > 0) { + memcpy(ctx->input, input, length); + ctx->input_used = length; + } +} + +static void sub_key_shift(guint8* sub_key, guint key_len) +{ + guint8 carry = (sub_key[0] & 0x80); + guint i; + + for (i = 0; i < key_len - 1; i++) + sub_key[i] = (sub_key[i] << 1) | (sub_key[i + 1] >> 7); + sub_key[key_len - 1] <<= 1; + + if (carry) + sub_key[key_len - 1] ^= 0x87; +} + +void aes_cmac_encrypt_finish(aes_cmac_ctx *ctx, guint8 *output) +{ + guint8 sub_key[RIJNDAEL_MAXKB]; + memset(sub_key, 0, ctx->key_len); + rijndael_encrypt(&(ctx->aes), sub_key, sub_key); + sub_key_shift(sub_key, ctx->key_len); + + if (ctx->input_used == ctx->key_len) { + XOR_BLOCK(sub_key, ctx->input, ctx->key_len); + } else { + sub_key_shift(sub_key, ctx->key_len); + XOR_BLOCK(sub_key, ctx->input, ctx->input_used); + sub_key[ctx->input_used] ^= 0x80; + } + + XOR_BLOCK(ctx->state, sub_key, ctx->key_len); + rijndael_encrypt(&(ctx->aes), ctx->state, output); +} + +#undef XOR_BLOCK + + /* * Editor modelines - http://www.wireshark.org/tools/modelines.html * diff --git a/wsutil/aes.h b/wsutil/aes.h index e384667900..df319c69af 100644 --- a/wsutil/aes.h +++ b/wsutil/aes.h @@ -62,5 +62,46 @@ void rijndael_decrypt( const guchar *src, guchar *dst); +typedef struct s_aes_cmac_ctx { + rijndael_ctx aes; + guint key_len; + guint input_used; + guint8 state[RIJNDAEL_MAXKB]; + guint8 input[RIJNDAEL_MAXKB]; +} aes_cmac_ctx; + +/** + * Initialize AES-CMAC calculation with the provided key. + * @param [OUT] ctx Context to initialize + * @param [IN] key Key to used + * @param [IN] key_len Key length in bytes + */ +WS_DLL_PUBLIC +void aes_cmac_encrypt_starts( + aes_cmac_ctx *ctx, + const guint8 *key, + guint key_len); + +/** + * Add a new buffer for AES-CMAC calculation + * @param [IN] ctx Context (initialize with @ref AES_CMAC_encrypt_starts) + * @param [IN] input Buffer to add in AES-CMAC calculation + * @param [IN] length Length of input buffer (in bytes) + */ +WS_DLL_PUBLIC +void aes_cmac_encrypt_update( + aes_cmac_ctx *ctx, + const guint8 *input, + guint length); + +/** + * Ends AES-CMAC calculation + * @param [IN] ctx Context (initialize with @ref AES_CMAC_encrypt_starts) + * @param [OUT] output Buffer to store MAC (must be at least key_len long) + */ +WS_DLL_PUBLIC +void aes_cmac_encrypt_finish( + aes_cmac_ctx *ctx, + guint8 *output); #endif -- cgit v1.2.3