On Wed, 2018-01-17 at 10:59 +0100, Nikos Mavrogiannopoulos wrote: > Thank you for the catch. Hopefully the x86 run on our CI would have > caught it but I never run it there. I've now sent a build with the > 0001 > patch at: > https://gitlab.com/nmav/nettle/pipelines/16256301
Following up on my patchset, this (hopefully final) version introduces CMAC with AES-256 as well. It also removes the CMAC128_KEY_SIZE definition as the key size only depends on the block algorithm used. regards, Nikos
From cc60df9f2e083633fe1d258f3d0ddc17da251508 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos <n...@redhat.com> Date: Wed, 10 Jan 2018 09:29:17 +0100 Subject: [PATCH 1/3] Added support for CMAC That adds support for CMAC as a generic framework for 128-bit block and key ciphers, as well as API for AES-128-CMAC. Signed-off-by: Nikos Mavrogiannopoulos <n...@redhat.com> --- Makefile.in | 2 + cmac-aes128.c | 60 ++++++++++++++++ cmac.c | 162 ++++++++++++++++++++++++++++++++++++++++++++ cmac.h | 118 ++++++++++++++++++++++++++++++++ examples/nettle-benchmark.c | 24 ++++++- nettle.texinfo | 47 ++++++++++++- testsuite/.test-rules.make | 3 + testsuite/Makefile.in | 1 + testsuite/cmac-test.c | 111 ++++++++++++++++++++++++++++++ 9 files changed, 526 insertions(+), 2 deletions(-) create mode 100644 cmac-aes128.c create mode 100644 cmac.c create mode 100644 cmac.h create mode 100644 testsuite/cmac-test.c diff --git a/Makefile.in b/Makefile.in index 6a0c13ec..a25c0f99 100644 --- a/Makefile.in +++ b/Makefile.in @@ -103,6 +103,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 \ 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 \ @@ -195,6 +196,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \ gcm.h gosthash94.h hmac.h \ knuth-lfib.h hkdf.h \ macros.h \ + cmac.h \ md2.h md4.h \ md5.h md5-compat.h \ memops.h memxor.h \ diff --git a/cmac-aes128.c b/cmac-aes128.c new file mode 100644 index 00000000..e53e114e --- /dev/null +++ b/cmac-aes128.c @@ -0,0 +1,60 @@ +/* cmac-aes128.c + + CMAC using AES128 as the underlying cipher. + + 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/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "cmac.h" + +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); +} + +void +cmac_aes128_update (struct cmac_aes128_ctx *ctx, + size_t length, const uint8_t *data) +{ + CMAC128_UPDATE (ctx, aes128_encrypt, length, data); +} + +void +cmac_aes128_digest(struct cmac_aes128_ctx *ctx, + size_t length, uint8_t *digest) +{ + CMAC128_DIGEST(ctx, aes128_encrypt, length, digest); +} diff --git a/cmac.c b/cmac.c new file mode 100644 index 00000000..a4d2468a --- /dev/null +++ b/cmac.c @@ -0,0 +1,162 @@ +/* + 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/. +*/ + +#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" + +static const uint8_t const_zero[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* shift one and XOR with 0x87. */ +static inline void block_mulx(union nettle_block16 *out, + const union nettle_block16 *in) +{ + uint64_t b1 = READ_UINT64(in->b); + uint64_t b2 = READ_UINT64(in->b+8); + unsigned overflow = (b2 & UINT64_C(0x8000000000000000))?1:0; + + b1 <<= 1; + b2 <<= 1; + + if (overflow) + b1 |= 0x01; + + if (in->b[0] & 0x80) + b2 ^= 0x87; + + WRITE_UINT64(out->b, b1); + WRITE_UINT64(out->b+8, b2); +} + +void cmac128_set_key(struct cmac128 *ctx, void *key, + nettle_cipher_func *encrypt) +{ + union nettle_block16 *L = &ctx->block; + memset(ctx, 0, sizeof(*ctx)); + + /* step 1 - generate subkeys k1 and k2 */ + encrypt(key, 16, L->b, const_zero); + + block_mulx(&ctx->K1, L); + block_mulx(&ctx->K2, &ctx->K1); +} + +#define MIN(x,y) ((x)<(y)?(x):(y)) + +void cmac128_update(struct cmac128 *ctx, void *key, + 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(key, 16, ctx->X.b, Y.b); + + while (msg_len > 16) { + memxor3(Y.b, ctx->X.b, msg, 16); + encrypt(key, 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; +} + +void cmac128_digest(struct cmac128 *ctx, void *key, + nettle_cipher_func *encrypt, + unsigned length, + uint8_t *out) +{ + 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(key, 16, out, Y.b); + } else { + encrypt(key, 16, ctx->block.b, Y.b); + memcpy(out, ctx->block.b, length); + } + + /* reset state for re-use */ + memset(&ctx->X, 0, sizeof(ctx->X)); + ctx->index = 0; +} diff --git a/cmac.h b/cmac.h new file mode 100644 index 00000000..168ca95a --- /dev/null +++ b/cmac.h @@ -0,0 +1,118 @@ +/* cmac.h + + CMAC mode, as specified in RFC4493 + + 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/. +*/ + +#ifndef NETTLE_CMAC_H_INCLUDED +#define NETTLE_CMAC_H_INCLUDED + +#include "aes.h" +#include "nettle-types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CMAC128_KEY_SIZE 16 +#define CMAC128_DIGEST_SIZE 16 + +#define cmac128_set_key nettle_cmac128_set_key +#define cmac128_update nettle_cmac128_update +#define cmac128_digest nettle_cmac128_digest +#define cmac_aes128_set_key nettle_cmac_aes128_set_key +#define cmac_aes128_update nettle_cmac_aes128_update +#define cmac_aes128_digest nettle_cmac_aes128_digest + +struct cmac128 { + union nettle_block16 K1; + union nettle_block16 K2; + + union nettle_block16 X; + + union nettle_block16 block; + size_t index; +}; + +void cmac128_set_key(struct cmac128 *ctx, void *key, + nettle_cipher_func *encrypt); +void cmac128_update(struct cmac128 *ctx, void *key, + nettle_cipher_func *encrypt, + size_t msg_len, const uint8_t *msg); +void cmac128_digest(struct cmac128 *ctx, void *key, + nettle_cipher_func *encrypt, + unsigned length, + uint8_t *out); + + +#define CMAC128_CTX(type) \ + { struct cmac128 data; type cipher; } + +/* NOTE: Avoid using NULL, as we don't include anything defining it. */ +#define CMAC128_SET_KEY(ctx, set_key, encrypt, cmac_key) \ + do { \ + (set_key)(&(ctx)->cipher, (cmac_key)); \ + if (0) (encrypt)(&(ctx)->cipher, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0); \ + cmac128_set_key(&(ctx)->data, &(ctx)->cipher, \ + (nettle_cipher_func *) (encrypt)); \ + } while (0) + +#define CMAC128_UPDATE(ctx, encrypt, length, data) \ + cmac128_update(&(ctx)->data, &(ctx)->cipher, \ + (nettle_cipher_func *)encrypt, (length), (data)) + +#define CMAC128_DIGEST(ctx, encrypt, length, digest) \ + (0 ? (encrypt)(&(ctx)->cipher, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0) \ + : cmac128_digest(&(ctx)->data, &(ctx)->cipher, \ + (nettle_cipher_func *) (encrypt), \ + (length), (digest))) + +struct cmac_aes128_ctx CMAC128_CTX(struct aes128_ctx); + +void +cmac_aes128_set_key(struct cmac_aes128_ctx *ctx, const uint8_t *key); + +void +cmac_aes128_update(struct cmac_aes128_ctx *ctx, + size_t length, const uint8_t *data); + +void +cmac_aes128_digest(struct cmac_aes128_ctx *ctx, + size_t length, uint8_t *digest); + +#ifdef __cplusplus +} +#endif + +#endif /* CMAC_H_INCLUDED */ diff --git a/examples/nettle-benchmark.c b/examples/nettle-benchmark.c index 4efcca5c..b8062c5b 100644 --- a/examples/nettle-benchmark.c +++ b/examples/nettle-benchmark.c @@ -64,6 +64,7 @@ #include "sha3.h" #include "twofish.h" #include "umac.h" +#include "cmac.h" #include "poly1305.h" #include "nettle-meta.h" @@ -403,7 +404,7 @@ time_umac(void) struct umac64_ctx ctx64; struct umac96_ctx ctx96; struct umac128_ctx ctx128; - + uint8_t key[16]; umac32_set_key (&ctx32, key); @@ -439,6 +440,24 @@ time_umac(void) time_function(bench_hash, &info)); } +static void +time_cmac(void) +{ + static uint8_t data[BENCH_BLOCK]; + struct bench_hash_info info; + struct cmac_aes128_ctx ctx; + + uint8_t key[16]; + + cmac_aes128_set_key (&ctx, key); + info.ctx = &ctx; + info.update = (nettle_hash_update_func *) cmac_aes128_update; + info.data = data; + + display("cmac-aes128", "update", AES_BLOCK_SIZE, + time_function(bench_hash, &info)); +} + static void time_poly1305_aes(void) { @@ -846,6 +865,9 @@ main(int argc, char **argv) if (!alg || strstr ("umac", alg)) time_umac(); + if (!alg || strstr ("cmac", alg)) + time_cmac(); + if (!alg || strstr ("poly1305-aes", alg)) time_poly1305_aes(); diff --git a/nettle.texinfo b/nettle.texinfo index f501cfbe..4c7b5312 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -101,6 +101,7 @@ Keyed Hash Functions * HMAC:: * UMAC:: +* CMAC:: Public-key algorithms @@ -271,6 +272,9 @@ The implementation of the TWOFISH cipher is written by Ruud de Rooij. @item UMAC Written by @value{AUTHOR}. +@item CMAC +Written by Nikos Mavrogiannopoulos, @value{AUTHOR}, Jeremy Allison, Michael Adam and Stefan Metzmacher. + @item RSA Written by @value{AUTHOR}. Uses the GMP library for bignum operations. @@ -3134,6 +3138,7 @@ as well. @menu * HMAC:: * UMAC:: +* CMAC:: * Poly1305:: @end menu @@ -3476,7 +3481,47 @@ as described above, the new value is used unless you call the @code{_set_nonce} function explicitly for each message. @end deftypefun -@node Poly1305,, UMAC, Keyed hash functions +@node CMAC,, UMAC, Keyed hash functions +@subsection @acronym{CMAC} +@cindex CMAC + +@acronym{CMAC} is a message authentication code based on CBC encryption +mode. It is suitable for systems where block ciphers are preferrable +and perform better than hash functions. @acronym{CMAC} is specified in +@cite{RFC4493}. The secret key is always 128 bits (16 octets). + +Nettle provides helper functions for @acronym{CMAC } with +the @acronym{AES} block cipher. + +Nettle defines @acronym{CMAC} in @file{<nettle/cmac.h>}. + +@deftp {Context struct} {struct cmac128_ctx} +@end deftp + +@defvr Constant CMAC128_KEY_SIZE +The CMAC key size, 16. +@end defvr +@defvr Constant CMAC128_DIGEST_SIZE +The size of an CMAC digest, 16. +@end defvr + +@deftypefun void cmac_aes128_set_key (struct cmac_aes128_ctx *@var{ctx}, const uint8_t *@var{key}) +This function initializes the @acronym{CMAC} context struct. +@end deftypefun + +@deftypefun void cmac_aes128_update (struct cmac_aes128_ctx *@var{ctx}, size_t @var{length}, const uint8_t *@var{data}) +This function is called zero or more times to process the message. +@end deftypefun + +@deftypefun void cmac_aes128_digest (struct cmac_aes128_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{digest}) +Extracts the @acronym{MAC} of the message, writing it to @var{digest}. +@var{length} is usually equal to the specified output size, but if you +provide a smaller value, only the first @var{length} octets of the +@acronym{MAC} are written. This function resets the context for +processing of a new message with the same key. +@end deftypefun + +@node Poly1305,, CMAC, Keyed hash functions @comment node-name, next, previous, up @subsection Poly1305 diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make index 1f780310..c7e04cb4 100644 --- a/testsuite/.test-rules.make +++ b/testsuite/.test-rules.make @@ -130,6 +130,9 @@ eax-test$(EXEEXT): eax-test.$(OBJEXT) ccm-test$(EXEEXT): ccm-test.$(OBJEXT) $(LINK) ccm-test.$(OBJEXT) $(TEST_OBJS) -o ccm-test$(EXEEXT) +cmac-test$(EXEEXT): cmac-test.$(OBJEXT) + $(LINK) cmac-test.$(OBJEXT) $(TEST_OBJS) -o cmac-test$(EXEEXT) + poly1305-test$(EXEEXT): poly1305-test.$(OBJEXT) $(LINK) poly1305-test.$(OBJEXT) $(TEST_OBJS) -o poly1305-test$(EXEEXT) diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 3117d66d..dd1ecf41 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -26,6 +26,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \ serpent-test.c twofish-test.c version-test.c \ knuth-lfib-test.c \ cbc-test.c cfb-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \ + cmac-test.c \ poly1305-test.c chacha-poly1305-test.c \ hmac-test.c umac-test.c \ meta-hash-test.c meta-cipher-test.c\ diff --git a/testsuite/cmac-test.c b/testsuite/cmac-test.c new file mode 100644 index 00000000..983c5127 --- /dev/null +++ b/testsuite/cmac-test.c @@ -0,0 +1,111 @@ +#include "testutils.h" +#include "nettle-internal.h" +#include "cmac.h" + +static void +test_cmac_hash (const struct tstring *key, const struct tstring *msg, const struct tstring *ref) +{ + struct cmac_aes128_ctx ctx; + uint8_t digest[16]; + unsigned i; + + ASSERT (ref->length == sizeof(digest)); + ASSERT (key->length == 16); + cmac_aes128_set_key (&ctx, key->data); + cmac_aes128_update (&ctx, msg->length, msg->data); + cmac_aes128_digest (&ctx, sizeof(digest), digest); + if (!MEMEQ (ref->length, ref->data, digest)) + { + fprintf (stderr, "cmac_hash failed, msg: "); + print_hex (msg->length, msg->data); + fprintf(stderr, "Output:"); + print_hex (16, digest); + fprintf(stderr, "Expected:"); + tstring_print_hex(ref); + fprintf(stderr, "\n"); + FAIL(); + } + + /* attempt to re-use the structure */ + cmac_aes128_update (&ctx, msg->length, msg->data); + cmac_aes128_digest (&ctx, sizeof(digest), digest); + if (!MEMEQ (ref->length, ref->data, digest)) + { + fprintf (stderr, "cmac_hash failed on re-use, msg: "); + print_hex (msg->length, msg->data); + fprintf(stderr, "Output:"); + print_hex (16, digest); + fprintf(stderr, "Expected:"); + tstring_print_hex(ref); + fprintf(stderr, "\n"); + FAIL(); + } + + /* attempt byte-by-byte hashing */ + cmac_aes128_set_key (&ctx, key->data); + for (i=0;i<msg->length;i++) + cmac_aes128_update (&ctx, 1, msg->data+i); + cmac_aes128_digest (&ctx, sizeof(digest), digest); + if (!MEMEQ (ref->length, ref->data, digest)) + { + fprintf (stderr, "cmac_hash failed on byte-by-byte, msg: "); + print_hex (msg->length, msg->data); + fprintf(stderr, "Output:"); + print_hex (16, digest); + fprintf(stderr, "Expected:"); + tstring_print_hex(ref); + fprintf(stderr, "\n"); + FAIL(); + } +} + +void +test_main(void) +{ + /* + * CMAC-AES Test Vectors from RFC4493. + */ + + test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + SDATA(""), + SHEX("bb1d6929e95937287fa37d129b756746")); + + test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + SHEX("6bc1bee22e409f96e93d7e117393172a"), + SHEX("070a16b46b4d4144f79bdd9dd04a287c")); + + test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411"), + SHEX("dfa66747de9ae63030ca32611497c827")); + + test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + SHEX("51f0bebf7e3b9d92fc49741779363cfe")); + + /* Additional tests with different keys (same plaintext) + * to check all variants of set_key() */ + test_cmac_hash (SHEX("2b7e151628aed2a8abf7158809cf4f3c"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411"), + SHEX("87dd33c2945a4e228028690ae8954945")); + + test_cmac_hash (SHEX("2b7e1ab628aed2a8abf7158809cf4f3c"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411"), + SHEX("f0dc613a88886c7ed76eeb51f1c5e8d3")); + + test_cmac_hash (SHEX("2b7e1ab628aed2a8abf7158809cf4f3d"), + SHEX("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411"), + SHEX("b9d092dc387a9e42cdfeb9f9930cf567")); + +} + -- 2.14.3
From 627ddf9b745f4fa8da61e0cedb11d024c5b0ddeb Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos <n...@redhat.com> Date: Wed, 17 Jan 2018 10:47:23 +0100 Subject: [PATCH 2/3] cmac: block_mulx: simplify shifts Signed-off-by: Nikos Mavrogiannopoulos <n...@redhat.com> --- cmac.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmac.c b/cmac.c index a4d2468a..27df917e 100644 --- a/cmac.c +++ b/cmac.c @@ -57,14 +57,10 @@ static inline void block_mulx(union nettle_block16 *out, { uint64_t b1 = READ_UINT64(in->b); uint64_t b2 = READ_UINT64(in->b+8); - unsigned overflow = (b2 & UINT64_C(0x8000000000000000))?1:0; - b1 <<= 1; + b1 = (b1 << 1) | (b2 >> 63); b2 <<= 1; - if (overflow) - b1 |= 0x01; - if (in->b[0] & 0x80) b2 ^= 0x87; -- 2.14.3
From 6551e67f07eb5cf0ed08ab5324492c5d56edfde7 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos <n...@redhat.com> Date: Tue, 23 Jan 2018 11:33:56 +0100 Subject: [PATCH 3/3] Added support for cmac with aes-256 Signed-off-by: Nikos Mavrogiannopoulos <n...@redhat.com> --- Makefile.in | 2 +- cmac-aes256.c | 60 ++++++++++++++++++++++++++++++++++ cmac.h | 17 +++++++++- nettle.texinfo | 21 +++++++++--- testsuite/cmac-test.c | 89 +++++++++++++++++++++++++++++++++++---------------- 5 files changed, 156 insertions(+), 33 deletions(-) create mode 100644 cmac-aes256.c diff --git a/Makefile.in b/Makefile.in index a25c0f99..f6d92755 100644 --- a/Makefile.in +++ b/Makefile.in @@ -103,7 +103,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.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-aes256.c b/cmac-aes256.c new file mode 100644 index 00000000..ec3b50db --- /dev/null +++ b/cmac-aes256.c @@ -0,0 +1,60 @@ +/* cmac-aes256.c + + CMAC using AES256 as the underlying cipher. + + 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/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "cmac.h" + +void +cmac_aes256_set_key(struct cmac_aes256_ctx *ctx, const uint8_t *key) +{ + CMAC128_SET_KEY(ctx, aes256_set_encrypt_key, aes256_encrypt, key); +} + +void +cmac_aes256_update (struct cmac_aes256_ctx *ctx, + size_t length, const uint8_t *data) +{ + CMAC128_UPDATE (ctx, aes256_encrypt, length, data); +} + +void +cmac_aes256_digest(struct cmac_aes256_ctx *ctx, + size_t length, uint8_t *digest) +{ + CMAC128_DIGEST(ctx, aes256_encrypt, length, digest); +} diff --git a/cmac.h b/cmac.h index 168ca95a..1632f54e 100644 --- a/cmac.h +++ b/cmac.h @@ -43,7 +43,6 @@ extern "C" { #endif -#define CMAC128_KEY_SIZE 16 #define CMAC128_DIGEST_SIZE 16 #define cmac128_set_key nettle_cmac128_set_key @@ -52,6 +51,9 @@ extern "C" { #define cmac_aes128_set_key nettle_cmac_aes128_set_key #define cmac_aes128_update nettle_cmac_aes128_update #define cmac_aes128_digest nettle_cmac_aes128_digest +#define cmac_aes256_set_key nettle_cmac_aes256_set_key +#define cmac_aes256_update nettle_cmac_aes256_update +#define cmac_aes256_digest nettle_cmac_aes256_digest struct cmac128 { union nettle_block16 K1; @@ -111,6 +113,19 @@ void cmac_aes128_digest(struct cmac_aes128_ctx *ctx, size_t length, uint8_t *digest); +struct cmac_aes256_ctx CMAC128_CTX(struct aes256_ctx); + +void +cmac_aes256_set_key(struct cmac_aes256_ctx *ctx, const uint8_t *key); + +void +cmac_aes256_update(struct cmac_aes256_ctx *ctx, + size_t length, const uint8_t *data); + +void +cmac_aes256_digest(struct cmac_aes256_ctx *ctx, + size_t length, uint8_t *digest); + #ifdef __cplusplus } #endif diff --git a/nettle.texinfo b/nettle.texinfo index 4c7b5312..657c4d4c 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -3498,15 +3498,12 @@ Nettle defines @acronym{CMAC} in @file{<nettle/cmac.h>}. @deftp {Context struct} {struct cmac128_ctx} @end deftp -@defvr Constant CMAC128_KEY_SIZE -The CMAC key size, 16. -@end defvr @defvr Constant CMAC128_DIGEST_SIZE The size of an CMAC digest, 16. @end defvr @deftypefun void cmac_aes128_set_key (struct cmac_aes128_ctx *@var{ctx}, const uint8_t *@var{key}) -This function initializes the @acronym{CMAC} context struct. +This function initializes the @acronym{CMAC} context struct for AES-128. @end deftypefun @deftypefun void cmac_aes128_update (struct cmac_aes128_ctx *@var{ctx}, size_t @var{length}, const uint8_t *@var{data}) @@ -3521,6 +3518,22 @@ provide a smaller value, only the first @var{length} octets of the processing of a new message with the same key. @end deftypefun +@deftypefun void cmac_aes256_set_key (struct cmac_aes256_ctx *@var{ctx}, const uint8_t *@var{key}) +This function initializes the @acronym{CMAC} context struct for AES-256. +@end deftypefun + +@deftypefun void cmac_aes256_update (struct cmac_aes256_ctx *@var{ctx}, size_t @var{length}, const uint8_t *@var{data}) +This function is called zero or more times to process the message. +@end deftypefun + +@deftypefun void cmac_aes256_digest (struct cmac_aes256_ctx *@var{ctx}, size_t @var{length}, uint8_t *@var{digest}) +Extracts the @acronym{MAC} of the message, writing it to @var{digest}. +@var{length} is usually equal to the specified output size, but if you +provide a smaller value, only the first @var{length} octets of the +@acronym{MAC} are written. This function resets the context for +processing of a new message with the same key. +@end deftypefun + @node Poly1305,, CMAC, Keyed hash functions @comment node-name, next, previous, up @subsection Poly1305 diff --git a/testsuite/cmac-test.c b/testsuite/cmac-test.c index 983c5127..58544f2a 100644 --- a/testsuite/cmac-test.c +++ b/testsuite/cmac-test.c @@ -2,24 +2,43 @@ #include "nettle-internal.h" #include "cmac.h" +typedef void set_key_func(void *ctx, const uint8_t *key); +typedef void update_func(void *ctx, size_t length, const uint8_t *data); +typedef void digest_func(void *ctx, size_t length, uint8_t *digest); + +#define test_cmac_aes128(key, msg, ref) \ + test_cmac_hash ((set_key_func*)cmac_aes128_set_key, (update_func*)cmac_aes128_update, \ + (digest_func*)cmac_aes128_digest, sizeof(struct cmac_aes128_ctx), \ + key, msg, ref) + +#define test_cmac_aes256(key, msg, ref) \ + test_cmac_hash ((set_key_func*)cmac_aes256_set_key, (update_func*)cmac_aes256_update, \ + (digest_func*)cmac_aes256_digest, sizeof(struct cmac_aes256_ctx), \ + key, msg, ref) + static void -test_cmac_hash (const struct tstring *key, const struct tstring *msg, const struct tstring *ref) +test_cmac_hash (set_key_func *set_key, update_func *update, + digest_func *digest, size_t ctx_size, + const struct tstring *key, const struct tstring *msg, + const struct tstring *ref) { - struct cmac_aes128_ctx ctx; - uint8_t digest[16]; + void *ctx; + uint8_t hash[16]; unsigned i; - ASSERT (ref->length == sizeof(digest)); - ASSERT (key->length == 16); - cmac_aes128_set_key (&ctx, key->data); - cmac_aes128_update (&ctx, msg->length, msg->data); - cmac_aes128_digest (&ctx, sizeof(digest), digest); - if (!MEMEQ (ref->length, ref->data, digest)) + ctx = xalloc(ctx_size); + + ASSERT (ref->length == sizeof(hash)); + ASSERT (key->length == 16 || key->length == 32); + set_key (ctx, key->data); + update (ctx, msg->length, msg->data); + digest (ctx, sizeof(hash), hash); + if (!MEMEQ (ref->length, ref->data, hash)) { fprintf (stderr, "cmac_hash failed, msg: "); print_hex (msg->length, msg->data); fprintf(stderr, "Output:"); - print_hex (16, digest); + print_hex (16, hash); fprintf(stderr, "Expected:"); tstring_print_hex(ref); fprintf(stderr, "\n"); @@ -27,14 +46,14 @@ test_cmac_hash (const struct tstring *key, const struct tstring *msg, const stru } /* attempt to re-use the structure */ - cmac_aes128_update (&ctx, msg->length, msg->data); - cmac_aes128_digest (&ctx, sizeof(digest), digest); - if (!MEMEQ (ref->length, ref->data, digest)) + update (ctx, msg->length, msg->data); + digest (ctx, sizeof(hash), hash); + if (!MEMEQ (ref->length, ref->data, hash)) { fprintf (stderr, "cmac_hash failed on re-use, msg: "); print_hex (msg->length, msg->data); fprintf(stderr, "Output:"); - print_hex (16, digest); + print_hex (16, hash); fprintf(stderr, "Expected:"); tstring_print_hex(ref); fprintf(stderr, "\n"); @@ -42,16 +61,16 @@ test_cmac_hash (const struct tstring *key, const struct tstring *msg, const stru } /* attempt byte-by-byte hashing */ - cmac_aes128_set_key (&ctx, key->data); + set_key (ctx, key->data); for (i=0;i<msg->length;i++) - cmac_aes128_update (&ctx, 1, msg->data+i); - cmac_aes128_digest (&ctx, sizeof(digest), digest); - if (!MEMEQ (ref->length, ref->data, digest)) + update (ctx, 1, msg->data+i); + digest (ctx, sizeof(hash), hash); + if (!MEMEQ (ref->length, ref->data, hash)) { fprintf (stderr, "cmac_hash failed on byte-by-byte, msg: "); print_hex (msg->length, msg->data); fprintf(stderr, "Output:"); - print_hex (16, digest); + print_hex (16, hash); fprintf(stderr, "Expected:"); tstring_print_hex(ref); fprintf(stderr, "\n"); @@ -65,22 +84,21 @@ test_main(void) /* * CMAC-AES Test Vectors from RFC4493. */ - - test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + test_cmac_aes128 (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), SDATA(""), SHEX("bb1d6929e95937287fa37d129b756746")); - test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + test_cmac_aes128 (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), SHEX("6bc1bee22e409f96e93d7e117393172a"), SHEX("070a16b46b4d4144f79bdd9dd04a287c")); - test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + test_cmac_aes128 (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), SHEX("6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" "30c81c46a35ce411"), SHEX("dfa66747de9ae63030ca32611497c827")); - test_cmac_hash (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), + test_cmac_aes128 (SHEX("2b7e151628aed2a6abf7158809cf4f3c"), SHEX("6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" "30c81c46a35ce411e5fbc1191a0a52ef" @@ -89,23 +107,40 @@ test_main(void) /* Additional tests with different keys (same plaintext) * to check all variants of set_key() */ - test_cmac_hash (SHEX("2b7e151628aed2a8abf7158809cf4f3c"), + test_cmac_aes128 (SHEX("2b7e151628aed2a8abf7158809cf4f3c"), SHEX("6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" "30c81c46a35ce411"), SHEX("87dd33c2945a4e228028690ae8954945")); - test_cmac_hash (SHEX("2b7e1ab628aed2a8abf7158809cf4f3c"), + test_cmac_aes128 (SHEX("2b7e1ab628aed2a8abf7158809cf4f3c"), SHEX("6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" "30c81c46a35ce411"), SHEX("f0dc613a88886c7ed76eeb51f1c5e8d3")); - test_cmac_hash (SHEX("2b7e1ab628aed2a8abf7158809cf4f3d"), + test_cmac_aes128 (SHEX("2b7e1ab628aed2a8abf7158809cf4f3d"), SHEX("6bc1bee22e409f96e93d7e117393172a" "ae2d8a571e03ac9c9eb76fac45af8e51" "30c81c46a35ce411"), SHEX("b9d092dc387a9e42cdfeb9f9930cf567")); + /* CMAC-AES256 vectors taken from phplib */ + test_cmac_aes256 (SHEX("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + SDATA(""), + SHEX("028962f61b7bf89efc6b551f4667d983")); + + test_cmac_aes256 (SHEX("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + SHEX("6bc1bee22e409f96e93d7e117393172a"), + SHEX("28a7023f452e8f82bd4bf28d8c37c35c")); + + test_cmac_aes256 (SHEX("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + SHEX("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411"), + SHEX("aaf3d8f1de5640c232f5b169b9c911e6")); + + test_cmac_aes256 (SHEX("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + SHEX("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"), + SHEX("e1992190549f6ed5696a2c056c315410")); + } -- 2.14.3
_______________________________________________ nettle-bugs mailing list nettle-bugs@lists.lysator.liu.se http://lists.lysator.liu.se/mailman/listinfo/nettle-bugs