Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- Makefile.in | 2 +- cmac.h | 69 +++++++++++++++++++ cmac64.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++ nettle-types.h | 6 ++ 4 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 cmac64.c
diff --git a/Makefile.in b/Makefile.in index b54e64b053c3..bad2baf3a29e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -102,7 +102,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \ gcm-aes256.c gcm-aes256-meta.c \ gcm-camellia128.c gcm-camellia128-meta.c \ gcm-camellia256.c gcm-camellia256-meta.c \ - cmac.c cmac-aes128.c cmac-aes256.c \ + cmac.c cmac64.c cmac-aes128.c cmac-aes256.c \ gosthash94.c gosthash94-meta.c \ hmac.c hmac-md5.c hmac-ripemd160.c hmac-sha1.c \ hmac-sha224.c hmac-sha256.c hmac-sha384.c hmac-sha512.c \ diff --git a/cmac.h b/cmac.h index 3c5b7bea3e55..0cf9462d2120 100644 --- a/cmac.h +++ b/cmac.h @@ -44,6 +44,7 @@ extern "C" { #endif
#define CMAC128_DIGEST_SIZE 16 +#define CMAC64_DIGEST_SIZE 8
#define cmac128_set_key nettle_cmac128_set_key #define cmac128_init nettle_cmac128_init @@ -56,6 +57,11 @@ extern "C" { #define cmac_aes256_update nettle_cmac_aes256_update #define cmac_aes256_digest nettle_cmac_aes256_digest
+#define cmac64_set_key nettle_cmac64_set_key +#define cmac64_init nettle_cmac64_init +#define cmac64_update nettle_cmac64_update +#define cmac64_digest nettle_cmac64_digest + struct cmac128_key { union nettle_block16 K1; @@ -72,6 +78,22 @@ struct cmac128_ctx size_t index; };
+struct cmac64_key +{ + union nettle_block8 K1; + union nettle_block8 K2; +}; + +struct cmac64_ctx +{ + /* MAC state */ + union nettle_block8 X; + + /* Block buffer */ + union nettle_block8 block; + size_t index; +}; + void cmac128_set_key(struct cmac128_key *key, const void *cipher, nettle_cipher_func *encrypt); @@ -118,6 +140,53 @@ cmac128_digest(struct cmac128_ctx *ctx, const struct cmac128_key *key, (nettle_cipher_func *) (encrypt), \ (length), (digest)))
+void +cmac64_set_key(struct cmac64_key *key, const void *cipher, + nettle_cipher_func *encrypt); + +void +cmac64_init(struct cmac64_ctx *ctx); + +void +cmac64_update(struct cmac64_ctx *ctx, const void *cipher, + nettle_cipher_func *encrypt, + size_t msg_len, const uint8_t *msg); + +void +cmac64_digest(struct cmac64_ctx *ctx, const struct cmac64_key *key, + const void *cipher, nettle_cipher_func *encrypt, + unsigned length, uint8_t *digest); + + +#define CMAC64_CTX(type) \ + { struct cmac64_key key; struct cmac64_ctx ctx; type cipher; } + +/* NOTE: Avoid using NULL, as we don't include anything defining it. */ +#define CMAC64_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); \ + cmac64_set_key(&(self)->key, &(self)->cipher, \ + (nettle_cipher_func *) (encrypt)); \ + cmac64_init(&(self)->ctx); \ + } while (0) + +#define CMAC64_UPDATE(self, encrypt, length, src) \ + (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0) \ + : cmac64_update(&(self)->ctx, &(self)->cipher, \ + (nettle_cipher_func *)encrypt, \ + (length), (src))) + +#define CMAC64_DIGEST(self, encrypt, length, digest) \ + (0 ? (encrypt)(&(self)->cipher, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0) \ + : cmac64_digest(&(self)->ctx, &(self)->key, \ + &(self)->cipher, \ + (nettle_cipher_func *) (encrypt), \ + (length), (digest))) + struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx);
void diff --git a/cmac64.c b/cmac64.c new file mode 100644 index 000000000000..9b711d6698ab --- /dev/null +++ b/cmac64.c @@ -0,0 +1,177 @@ +/* + AES-CMAC-128 (rfc 4493) / CMAC-64 + Copyright (C) Stefan Metzmacher 2012 + Copyright (C) Jeremy Allison 2012 + Copyright (C) Michael Adam 2012 + Copyright (C) 2017, Red Hat Inc. + Copyright (C) 2019, Dmitry Eremin-Solenikov + + 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/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "cmac.h" + +#include "memxor.h" +#include "nettle-internal.h" +#include "macros.h" + +/* shift one and XOR with 0x87. */ +#if WORDS_BIGENDIAN +static void +_cmac64_block_mulx(union nettle_block8 *dst, + const union nettle_block8 *src) +{ + uint64_t carry = src->u64 >> 63; + + dst->u64 = (src->u64 << 1) ^ (0x1b & -carry); +} +#else /* !WORDS_BIGENDIAN */ +#define LE_SHIFT(x) ((((x) & 0x7f7f7f7f7f7f7f7f) << 1) | \ + (((x) & 0x8080808080808080) >> 15)) +static void +_cmac64_block_mulx(union nettle_block8 *dst, + const union nettle_block8 *src) +{ + uint64_t carry = (src->u64 & 0x80) >> 7; + + dst->u64 = LE_SHIFT(src->u64) ^ (0x1b00000000000000 & -carry); +} +#endif /* !WORDS_BIGENDIAN */ + +void +cmac64_set_key(struct cmac64_key *key, const void *cipher, + nettle_cipher_func *encrypt) +{ + static const union nettle_block8 zero_block; + union nettle_block8 L; + + /* step 1 - generate subkeys k1 and k2 */ + encrypt(cipher, 8, L.b, zero_block.b); + + _cmac64_block_mulx(&key->K1, &L); + _cmac64_block_mulx(&key->K2, &key->K1); +} + +void +cmac64_init(struct cmac64_ctx *ctx) +{ + memset(&ctx->X, 0, sizeof(ctx->X)); + ctx->index = 0; +} + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +void +cmac64_update(struct cmac64_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 < 8) + { + size_t len = MIN(8 - 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, 8); + encrypt(cipher, 8, ctx->X.b, Y.b); + + while (msg_len > 8) + { + memxor3(Y.b, ctx->X.b, msg, 8); + encrypt(cipher, 8, ctx->X.b, Y.b); + msg += 8; + msg_len -= 8; + } + + /* + * copy the last block, it will be processed in + * cmac64_digest(). + */ + memcpy(ctx->block.b, msg, msg_len); + ctx->index = msg_len; +} + +void +cmac64_digest(struct cmac64_ctx *ctx, const struct cmac64_key *key, + const void *cipher, nettle_cipher_func *encrypt, + unsigned length, uint8_t *dst) +{ + union nettle_block8 Y; + + memset(ctx->block.b+ctx->index, 0, sizeof(ctx->block.b)-ctx->index); + + /* re-use ctx->block for memxor output */ + if (ctx->index < 8) + { + ctx->block.b[ctx->index] = 0x80; + memxor(ctx->block.b, key->K2.b, 8); + } + else + { + memxor(ctx->block.b, key->K1.b, 8); + } + + memxor3(Y.b, ctx->block.b, ctx->X.b, 8); + + assert(length <= 8); + if (length == 8) + { + encrypt(cipher, 8, dst, Y.b); + } + else + { + encrypt(cipher, 8, 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; +} diff --git a/nettle-types.h b/nettle-types.h index 87292ac69730..5addf3600d69 100644 --- a/nettle-types.h +++ b/nettle-types.h @@ -65,6 +65,12 @@ union nettle_block16 uint64_t u64[2]; };
+union nettle_block8 +{ + uint8_t b[8]; + uint64_t u64; +}; + /* Randomness. Used by key generation and dsa signature creation. */ typedef void nettle_random_func(void *ctx, size_t length, uint8_t *dst);