diff options
Diffstat (limited to 'siv_nettle_int.c')
-rw-r--r-- | siv_nettle_int.c | 452 |
1 files changed, 452 insertions, 0 deletions
diff --git a/siv_nettle_int.c b/siv_nettle_int.c new file mode 100644 index 0000000..714eff6 --- /dev/null +++ b/siv_nettle_int.c @@ -0,0 +1,452 @@ +/* This is a single-file implementation of AES-SIV-CMAC-256 based on + a patch for GNU Nettle by Nikos Mavrogiannopoulos */ + +/* + AES-CMAC-128 (rfc 4493) + Copyright (C) Stefan Metzmacher 2012 + Copyright (C) Jeremy Allison 2012 + Copyright (C) Michael Adam 2012 + Copyright (C) 2017, Red Hat Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ +/* siv-aes128.c, siv-cmac.c, siv.h + + AES-SIV, RFC5297 + SIV-CMAC, RFC5297 + + Copyright (C) 2017 Nikos Mavrogiannopoulos + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ +/* cmac.h, siv-cmac.h, cmac-aes128.c + + CMAC mode, as specified in RFC4493 + SIV-CMAC mode, as specified in RFC5297 + CMAC using AES128 as the underlying cipher. + + Copyright (C) 2017 Red Hat, Inc. + + Contributed by Nikos Mavrogiannopoulos + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +# include "config.h" + +#include <assert.h> +#include <string.h> + +#include "nettle/aes.h" +#include "nettle/ctr.h" +#include "nettle/macros.h" +#include "nettle/memxor.h" +#include "nettle/memops.h" + +#include "nettle/nettle-types.h" + +/* For SIV, the block size of the block cipher shall be 128 bits. */ +#define SIV_BLOCK_SIZE 16 +#define SIV_DIGEST_SIZE 16 +#define SIV_MIN_NONCE_SIZE 1 + +/* + * SIV mode requires the aad and plaintext when building the IV, which + * prevents streaming processing and it incompatible with the AEAD API. + */ + +/* AES_SIV_CMAC_256 */ +struct siv_cmac_aes128_ctx { + struct aes128_ctx cipher; + uint8_t s2vk[AES128_KEY_SIZE]; +}; + +struct cmac128_ctx +{ + /* Key */ + union nettle_block16 K1; + union nettle_block16 K2; + + /* MAC state */ + union nettle_block16 X; + + /* Block buffer */ + union nettle_block16 block; + size_t index; +}; + +/* shift one and XOR with 0x87. */ +static void +_cmac128_block_mulx(union nettle_block16 *dst, + const union nettle_block16 *src) +{ + uint64_t b1 = READ_UINT64(src->b); + uint64_t b2 = READ_UINT64(src->b+8); + + b1 = (b1 << 1) | (b2 >> 63); + b2 <<= 1; + + if (src->b[0] & 0x80) + b2 ^= 0x87; + + WRITE_UINT64(dst->b, b1); + WRITE_UINT64(dst->b+8, b2); +} + +static void +cmac128_set_key(struct cmac128_ctx *ctx, const void *cipher, + nettle_cipher_func *encrypt) +{ + static const uint8_t const_zero[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + union nettle_block16 *L = &ctx->block; + memset(ctx, 0, sizeof(*ctx)); + + /* step 1 - generate subkeys k1 and k2 */ + encrypt(cipher, 16, L->b, const_zero); + + _cmac128_block_mulx(&ctx->K1, L); + _cmac128_block_mulx(&ctx->K2, &ctx->K1); +} + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +static void +cmac128_update(struct cmac128_ctx *ctx, const void *cipher, + nettle_cipher_func *encrypt, + size_t msg_len, const uint8_t *msg) +{ + union nettle_block16 Y; + /* + * check if we expand the block + */ + if (ctx->index < 16) + { + size_t len = MIN(16 - ctx->index, msg_len); + memcpy(&ctx->block.b[ctx->index], msg, len); + msg += len; + msg_len -= len; + ctx->index += len; + } + + if (msg_len == 0) { + /* if it is still the last block, we are done */ + return; + } + + /* + * now checksum everything but the last block + */ + memxor3(Y.b, ctx->X.b, ctx->block.b, 16); + encrypt(cipher, 16, ctx->X.b, Y.b); + + while (msg_len > 16) + { + memxor3(Y.b, ctx->X.b, msg, 16); + encrypt(cipher, 16, ctx->X.b, Y.b); + msg += 16; + msg_len -= 16; + } + + /* + * copy the last block, it will be processed in + * cmac128_digest(). + */ + memcpy(ctx->block.b, msg, msg_len); + ctx->index = msg_len; +} + +static void +cmac128_digest(struct cmac128_ctx *ctx, const void *cipher, + nettle_cipher_func *encrypt, + unsigned length, + uint8_t *dst) +{ + union nettle_block16 Y; + + memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index); + + /* re-use ctx->block for memxor output */ + if (ctx->index < 16) + { + ctx->block.b[ctx->index] = 0x80; + memxor(ctx->block.b, ctx->K2.b, 16); + } + else + { + memxor(ctx->block.b, ctx->K1.b, 16); + } + + memxor3(Y.b, ctx->block.b, ctx->X.b, 16); + + assert(length <= 16); + if (length == 16) + { + encrypt(cipher, 16, dst, Y.b); + } + else + { + encrypt(cipher, 16, ctx->block.b, Y.b); + memcpy(dst, ctx->block.b, length); + } + + /* reset state for re-use */ + memset(&ctx->X, 0, sizeof(ctx->X)); + ctx->index = 0; +} + + +#define CMAC128_CTX(type) \ + { struct cmac128_ctx ctx; type cipher; } + +/* NOTE: Avoid using NULL, as we don't include anything defining it. */ +#define CMAC128_SET_KEY(self, set_key, encrypt, cmac_key) \ + do { \ + (set_key)(&(self)->cipher, (cmac_key)); \ + if (0) (encrypt)(&(self)->cipher, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0); \ + cmac128_set_key(&(self)->ctx, &(self)->cipher, \ + (nettle_cipher_func *) (encrypt)); \ + } while (0) + +#define CMAC128_UPDATE(self, encrypt, length, src) \ + cmac128_update(&(self)->ctx, &(self)->cipher, \ + (nettle_cipher_func *)encrypt, (length), (src)) + +#define CMAC128_DIGEST(self, encrypt, length, digest) \ + (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0) \ + : cmac128_digest(&(self)->ctx, &(self)->cipher, \ + (nettle_cipher_func *) (encrypt), \ + (length), (digest))) + +struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx); + +static void +cmac_aes128_set_key(struct cmac_aes128_ctx *ctx, const uint8_t *key) +{ + CMAC128_SET_KEY(ctx, aes128_set_encrypt_key, aes128_encrypt, key); +} + +static void +cmac_aes128_update (struct cmac_aes128_ctx *ctx, + size_t length, const uint8_t *data) +{ + CMAC128_UPDATE (ctx, aes128_encrypt, length, data); +} + +static void +cmac_aes128_digest(struct cmac_aes128_ctx *ctx, + size_t length, uint8_t *digest) +{ + CMAC128_DIGEST(ctx, aes128_encrypt, length, digest); +} + +static const uint8_t const_one[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 +}; + +static const uint8_t const_zero[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static +void _siv_s2v(nettle_set_key_func *cmac_set_key, + nettle_hash_update_func *cmac_update, + nettle_hash_digest_func *cmac_digest, + size_t cmac_ctx_size, + const uint8_t *s2vk, size_t alength, const uint8_t *adata, + size_t nlength, const uint8_t *nonce, + size_t plength, const uint8_t *pdata, + uint8_t *v) +{ + uint8_t ctx[sizeof(struct cmac128_ctx)+sizeof(struct aes_ctx)]; + union nettle_block16 D, S, T; + + assert(cmac_ctx_size <= sizeof (ctx)); + + cmac_set_key(ctx, s2vk); + + if (nlength == 0 && alength == 0) { + cmac_update(ctx, 16, const_one); + cmac_digest(ctx, 16, v); + return; + } + + cmac_update(ctx, 16, const_zero); + cmac_digest(ctx, 16, D.b); + + if (1) { + _cmac128_block_mulx(&D, &D); + cmac_update(ctx, alength, adata); + cmac_digest(ctx, 16, S.b); + + memxor(D.b, S.b, 16); + } + + if (nlength > 0) { + _cmac128_block_mulx(&D, &D); + cmac_update(ctx, nlength, nonce); + cmac_digest(ctx, 16, S.b); + + memxor(D.b, S.b, 16); + } + + /* Sn */ + if (plength >= 16) { + cmac_update(ctx, plength-16, pdata); + + pdata += plength-16; + + memxor3(T.b, pdata, D.b, 16); + } else { + union nettle_block16 pad; + + _cmac128_block_mulx(&T, &D); + memcpy(pad.b, pdata, plength); + pad.b[plength] = 0x80; + if (plength+1 < 16) + memset(&pad.b[plength+1], 0, 16-plength-1); + + memxor(T.b, pad.b, 16); + } + + cmac_update(ctx, 16, T.b); + cmac_digest(ctx, 16, v); +} + +static void +siv_cmac_aes128_set_key(struct siv_cmac_aes128_ctx *ctx, const uint8_t *key) +{ + memcpy(ctx->s2vk, key, 16); + aes128_set_encrypt_key(&ctx->cipher, key+16); +} + +static void +siv_cmac_aes128_encrypt_message(struct siv_cmac_aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src) +{ + union nettle_block16 siv; + size_t slength; + + assert (clength >= SIV_DIGEST_SIZE); + slength = clength - SIV_DIGEST_SIZE; + + /* create CTR nonce */ + _siv_s2v((nettle_set_key_func*)cmac_aes128_set_key, + (nettle_hash_update_func*)cmac_aes128_update, + (nettle_hash_digest_func*)cmac_aes128_digest, + sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata, + nlength, nonce, slength, src, siv.b); + memcpy(dst, siv.b, SIV_DIGEST_SIZE); + siv.b[8] &= ~0x80; + siv.b[12] &= ~0x80; + + ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE, + siv.b, slength, dst+SIV_DIGEST_SIZE, src); +} + +static int +siv_cmac_aes128_decrypt_message(struct siv_cmac_aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + union nettle_block16 siv; + union nettle_block16 ctr; + + memcpy(ctr.b, src, SIV_DIGEST_SIZE); + ctr.b[8] &= ~0x80; + ctr.b[12] &= ~0x80; + + ctr_crypt(&ctx->cipher, (nettle_cipher_func *)aes128_encrypt, AES_BLOCK_SIZE, + ctr.b, mlength, dst, src+SIV_DIGEST_SIZE); + + /* create CTR nonce */ + _siv_s2v((nettle_set_key_func*)cmac_aes128_set_key, + (nettle_hash_update_func*)cmac_aes128_update, + (nettle_hash_digest_func*)cmac_aes128_digest, + sizeof(struct cmac_aes128_ctx), ctx->s2vk, alength, adata, + nlength, nonce, mlength, dst, siv.b); + + return memeql_sec(siv.b, src, SIV_DIGEST_SIZE); +} + |