I've incorporated a few of your suggestions and updated my patch for the CCM cipher modes. This improves the API coverage in the CCM test suite, adds the all-at-once API for message processing, and fixes the copyright of the CCM mode source code.
Thanks, Owen
ChangeLog from V1 of the patch:
2014-03-14 Owen Kirby osk@exegin.com * ccm-aes.c: Removed legacy AES API. * ccm.c (ccm_encrypt_message): Added all-at-once API for CCM mode ciphers. * ccm.c (ccm_digest): Added assert to ensure CCM digest length <= block size. * ccm.h: Updated copyright for CCM modes to Owen Kirby and Exegin Technologies. * ccm.c: Minor changes to CCM IV and nonce building functions. * ccm-aesXXX.c: Added all-at-once API, and removed the CCM helper macros. * testsuite/ccm-test.c: Added tests for the cipher-specific CCM functions. * testsuite/.test-rules.make: Fixed the building of the CCM self-test.
From 0e40ade7f0f3e41783973e53c50b10ba497e52e7 Mon Sep 17 00:00:00 2001
From: Owen Kirby osk@exegin.com Date: Wed, 5 Mar 2014 19:40:56 -0800 Subject: [PATCH] Support for CCM mode ciphers.
--- Makefile.in | 1 + ccm-aes128.c | 101 +++++++ ccm-aes192.c | 102 +++++++ ccm-aes256.c | 103 +++++++ ccm.c | 253 ++++++++++++++++ ccm.h | 267 +++++++++++++++++ testsuite/.gitignore | 1 + testsuite/.test-rules.make | 3 + testsuite/Makefile.in | 2 +- testsuite/ccm-test.c | 709 ++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 1541 insertions(+), 1 deletion(-) create mode 100644 ccm-aes128.c create mode 100644 ccm-aes192.c create mode 100644 ccm-aes256.c create mode 100644 ccm.c create mode 100644 ccm.h create mode 100644 testsuite/ccm-test.c
diff --git a/Makefile.in b/Makefile.in index 24349c3..c05d891 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,6 +87,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \ camellia256-set-decrypt-key.c \ camellia256-meta.c \ cast128.c cast128-meta.c cbc.c \ + ccm.c ccm-aes.c ccm-aes128.c ccm-aes192.c ccm-aes256.c \ chacha-crypt.c chacha-core-internal.c \ chacha-poly1305.c chacha-poly1305-meta.c \ chacha-set-key.c chacha-set-nonce.c \ diff --git a/ccm-aes128.c b/ccm-aes128.c new file mode 100644 index 0000000..cb87897 --- /dev/null +++ b/ccm-aes128.c @@ -0,0 +1,101 @@ +/* ccm-aes128.c + * + * Counter with CBC-MAC mode using AES128 as the underlying cipher. + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2014 Exegin Technologies Limited + * Copyright (C) 2014 Owen Kirby + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "aes.h" +#include "ccm.h" + +void +ccm_aes128_set_key(struct ccm_aes128_ctx *ctx, const uint8_t *key) +{ + aes128_set_encrypt_key(&ctx->cipher, key); +} + +void +ccm_aes128_set_nonce(struct ccm_aes128_ctx *ctx, size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen) +{ + ccm_set_nonce(&ctx->ccm, length, nonce, authlen, msglen, taglen); +} + +void +ccm_aes128_update(struct ccm_aes128_ctx *ctx, + size_t length, const uint8_t *data) +{ + ccm_update(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes128_encrypt, length, data); +} + +void +ccm_aes128_encrypt(struct ccm_aes128_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_encrypt(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes128_encrypt, length, dst, src); +} + +void +ccm_aes128_decrypt(struct ccm_aes128_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_decrypt(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes128_encrypt, length, dst, src); +} + +void +ccm_aes128_digest(struct ccm_aes128_ctx *ctx, + size_t length, uint8_t *digest) +{ + ccm_digest(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes128_encrypt, length, digest); +} + +void +ccm_aes128_encrypt_message(struct ccm_aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + ccm_encrypt_message(&ctx->cipher, (nettle_crypt_func *)aes128_encrypt, + nlength, nonce, alength, adata, tlength, tag, mlength, dst, src); +} + +void +ccm_aes128_decrypt_message(struct ccm_aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + ccm_decrypt_message(&ctx->cipher, (nettle_crypt_func *)aes128_encrypt, + nlength, nonce, alength, adata, tlength, tag, mlength, dst, src); +} \ No newline at end of file diff --git a/ccm-aes192.c b/ccm-aes192.c new file mode 100644 index 0000000..6073f4a --- /dev/null +++ b/ccm-aes192.c @@ -0,0 +1,102 @@ +/* ccm-aes192.c + * + * Counter with CBC-MAC mode using AES192 as the underlying cipher. + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2014 Exegin Technologies Limited + * Copyright (C) 2014 Owen Kirby + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "aes.h" +#include "ccm.h" + + +void +ccm_aes192_set_key(struct ccm_aes192_ctx *ctx, const uint8_t *key) +{ + aes192_set_encrypt_key(&ctx->cipher, key); +} + +void +ccm_aes192_set_nonce(struct ccm_aes192_ctx *ctx, size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen) +{ + ccm_set_nonce(&ctx->ccm, length, nonce, authlen, msglen, taglen); +} + +void +ccm_aes192_update(struct ccm_aes192_ctx *ctx, + size_t length, const uint8_t *data) +{ + ccm_update(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes192_encrypt, length, data); +} + +void +ccm_aes192_encrypt(struct ccm_aes192_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_encrypt(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes192_encrypt, length, dst, src); +} + +void +ccm_aes192_decrypt(struct ccm_aes192_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_decrypt(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes192_encrypt, length, dst, src); +} + +void +ccm_aes192_digest(struct ccm_aes192_ctx *ctx, + size_t length, uint8_t *digest) +{ + ccm_digest(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes192_encrypt, length, digest); +} + +void +ccm_aes192_encrypt_message(struct ccm_aes192_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + ccm_encrypt_message(&ctx->cipher, (nettle_crypt_func *)aes192_encrypt, + nlength, nonce, alength, adata, tlength, tag, mlength, dst, src); +} + +void +ccm_aes192_decrypt_message(struct ccm_aes192_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + ccm_decrypt_message(&ctx->cipher, (nettle_crypt_func *)aes192_encrypt, + nlength, nonce, alength, adata, tlength, tag, mlength, dst, src); +} diff --git a/ccm-aes256.c b/ccm-aes256.c new file mode 100644 index 0000000..78906f4 --- /dev/null +++ b/ccm-aes256.c @@ -0,0 +1,103 @@ +/* ccm-aes256.c + * + * Counter with CBC-MAC mode using AES256 as the underlying cipher. + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2014 Exegin Technologies Limited + * Copyright (C) 2014 Owen Kirby + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> + +#include "aes.h" +#include "ccm.h" + + +void +ccm_aes256_set_key(struct ccm_aes256_ctx *ctx, const uint8_t *key) +{ + aes256_set_encrypt_key(&ctx->cipher, key); +} + +void +ccm_aes256_set_nonce(struct ccm_aes256_ctx *ctx, size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen) +{ + ccm_set_nonce(&ctx->ccm, length, nonce, authlen, msglen, taglen); +} + +void +ccm_aes256_update(struct ccm_aes256_ctx *ctx, + size_t length, const uint8_t *data) +{ + ccm_update(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes256_encrypt, length, data); +} + +void +ccm_aes256_encrypt(struct ccm_aes256_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_encrypt(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes256_encrypt, length, dst, src); +} + +void +ccm_aes256_decrypt(struct ccm_aes256_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_decrypt(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes256_encrypt, length, dst, src); +} + +void +ccm_aes256_digest(struct ccm_aes256_ctx *ctx, + size_t length, uint8_t *digest) +{ + ccm_digest(&ctx->ccm, &ctx->cipher, + (nettle_crypt_func *)aes256_encrypt, length, digest); +} + +void +ccm_aes256_encrypt_message(struct ccm_aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + ccm_encrypt_message(&ctx->cipher, (nettle_crypt_func *)aes256_encrypt, + nlength, nonce, alength, adata, tlength, tag, mlength, dst, src); +} + +void +ccm_aes256_decrypt_message(struct ccm_aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + ccm_decrypt_message(&ctx->cipher, (nettle_crypt_func *)aes256_encrypt, + nlength, nonce, alength, adata, tlength, tag, mlength, dst, src); +} + diff --git a/ccm.c b/ccm.c new file mode 100644 index 0000000..44771f0 --- /dev/null +++ b/ccm.c @@ -0,0 +1,253 @@ +/* ccm.c + * + * Counter with CBC-MAC mode, specified by NIST, + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_... + * + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2014 Exegin Technologies Limited + * Copyright (C) 2014 Owen Kirby + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include "ccm.h" +#include "ctr.h" + +#include "memxor.h" +#include "nettle-internal.h" +#include "macros.h" + +/* + * The format of the CCM IV (for both CTR and CBC-MAC) is: flags | nonce | count + * flags = 1 octet + * nonce = N octets + * count >= 1 octet + * + * such that: + * sizeof(flags) + sizeof(nonce) + sizeof(count) == 1 block + */ +#define CCM_FLAG_L 0x07 +#define CCM_FLAG_M 0x38 +#define CCM_FLAG_ADATA 0x40 +#define CCM_FLAG_RESERVED 0x80 +#define CCM_FLAG_GET_L(_x_) (((_x_) & CCM_FLAG_L) + 1) +#define CCM_FLAG_SET_L(_x_) (((_x_) - 1) & CCM_FLAG_L) +#define CCM_FLAG_SET_M(_x_) ((((_x_) - 2) << 2) & CCM_FLAG_M) + +#define CCM_OFFSET_FLAGS 0 +#define CCM_OFFSET_NONCE 1 +#define CCM_L_SIZE(_nlen_) (CCM_BLOCK_SIZE - CCM_OFFSET_NONCE - (_nlen_)) +#define CCM_L_MAX_SIZE (CCM_FLAG_L+1) +#define CCM_IV_MAX_SIZE (CCM_BLOCK_SIZE - CCM_OFFSET_NONCE - 1) +#define CCM_IV_MIN_SIZE (CCM_BLOCK_SIZE - CCM_OFFSET_NONCE - CCM_L_MAX_SIZE) + +/* Pad an unaligned CBC-MAC digest with zero, or initialize B0 if no adata. */ +static void +ccm_pad(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f) +{ + if (ctx->blen) f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b); + ctx->blen = 0; +} + +/* + * Future work: We might be able to support the nettle_aead API by making the + * caller generate the entire IV rather than providing only the nonce. For now, + * this function is only used internally by the CCM mode. + */ +static void +ccm_build_iv(size_t noncelen, const uint8_t *nonce, size_t msglen, + size_t taglen, uint8_t *iv) +{ + unsigned int i; + + /* Sanity check the nonce length. */ + assert(noncelen >= CCM_IV_MIN_SIZE); + assert(noncelen <= CCM_IV_MAX_SIZE); + + /* Generate the IV */ + iv[CCM_OFFSET_FLAGS] = CCM_FLAG_SET_M(taglen) | CCM_FLAG_SET_L(CCM_L_SIZE(noncelen)); + memcpy(&iv[CCM_OFFSET_NONCE], nonce, noncelen); + for (i=(CCM_BLOCK_SIZE - 1); i >= (CCM_OFFSET_NONCE + noncelen); i--) { + iv[i] = msglen & 0xff; + msglen >>= 8; + } + + /* Ensure the message length was not truncated. */ + assert(!msglen); +} + +/* Sets the IVs used by CCM, for now this is only used internally. */ +static void +ccm_set_iv(struct ccm_ctx *ctx, const uint8_t *iv) +{ + int i = CCM_BLOCK_SIZE - CCM_FLAG_GET_L(iv[CCM_OFFSET_FLAGS]); + memcpy(ctx->tag.b, iv, CCM_BLOCK_SIZE); + memcpy(ctx->ctr.b, iv, CCM_BLOCK_SIZE); + ctx->ctr.b[CCM_OFFSET_FLAGS] &= ~(CCM_FLAG_ADATA | CCM_FLAG_M); + ctx->ctr.b[CCM_BLOCK_SIZE-1] = 1; + while (i < (CCM_BLOCK_SIZE-1)) ctx->ctr.b[i++] = 0; + ctx->alen = 0; /* Adata length unknown, streaming not possible. */ + ctx->blen = -1; /* IV is set, but unencrypted. */ +} + +void +ccm_set_nonce(struct ccm_ctx *ctx, size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen) +{ + uint8_t iv[CCM_BLOCK_SIZE]; + ccm_build_iv(length, nonce, msglen, taglen, iv); + ccm_set_iv(ctx, iv); + ctx->alen = authlen; +} + +void +ccm_update(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, const uint8_t *data) +{ + const uint8_t *end = data + length; + + /* nop */ + if (!length) return; + + /* On the first call, encrypt B0 and encode L(a) */ + if (ctx->blen < 0) { + if (!ctx->alen) ctx->alen = length; /* If alen unknown, set it now. */ + ctx->tag.b[CCM_OFFSET_FLAGS] |= CCM_FLAG_ADATA; + f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b); + ctx->blen = 0; + if (ctx->alen >= (0x01ULL << 32)) { + /* Encode L(a) as 0xff || 0xff || <64-bit integer> */ + ctx->tag.b[ctx->blen++] ^= 0xff; + ctx->tag.b[ctx->blen++] ^= 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 56) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 48) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 40) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 32) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 24) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 16) & 0xff; + } + else if (ctx->alen >= ((0x1ULL << 16) - (0x1ULL << 8))) { + /* Encode L(a) as 0xff || 0xfe || <32-bit integer> */ + ctx->tag.b[ctx->blen++] ^= 0xff; + ctx->tag.b[ctx->blen++] ^= 0xfe; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 24) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 16) & 0xff; + } + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 8) & 0xff; + ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 0) & 0xff; + } + + /* Process unaligned blocks. */ + if (ctx->blen) { + if ((ctx->blen + length) < CCM_BLOCK_SIZE) { + memxor(&ctx->tag.b[ctx->blen], data, length); + ctx->blen += length; + return; + } + memxor(&ctx->tag.b[ctx->blen], data, CCM_BLOCK_SIZE - ctx->blen); + data += (CCM_BLOCK_SIZE - ctx->blen); + f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b); + } + + /* Process aligned blocks. */ + while ((data + CCM_BLOCK_SIZE) < end) { + memxor(ctx->tag.b, data, CCM_BLOCK_SIZE); + f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b); + data += CCM_BLOCK_SIZE; + } /* while */ + + /* Save leftovers for later. */ + ctx->blen = (end - data); + if (ctx->blen) memxor(&ctx->tag.b, data, ctx->blen); +} + +/* + * Because of the underlying CTR mode encryption, when called multiple times + * the data in intermediate calls must be provided in multiples of the block + * size. + */ +void +ccm_encrypt(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ccm_pad(ctx, cipher, f); + ccm_update(ctx, cipher, f, length, src); + ctr_crypt(cipher, f, CCM_BLOCK_SIZE, ctx->ctr.b, length, dst, src); +} + +/* + * Because of the underlying CTR mode decryption, when called multiple times + * the data in intermediate calls must be provided in multiples of the block + * size. + */ +void +ccm_decrypt(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, uint8_t *dst, const uint8_t *src) +{ + ctr_crypt(cipher, f, CCM_BLOCK_SIZE, ctx->ctr.b, length, dst, src); + ccm_pad(ctx, cipher, f); + ccm_update(ctx, cipher, f, length, dst); +} + +void +ccm_digest(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, uint8_t *digest) +{ + int i = CCM_BLOCK_SIZE - CCM_FLAG_GET_L(ctx->ctr.b[CCM_OFFSET_FLAGS]); + assert(length <= CCM_BLOCK_SIZE); + while (i < CCM_BLOCK_SIZE) ctx->ctr.b[i++] = 0; + ccm_pad(ctx, cipher, f); + ctr_crypt(cipher, f, CCM_BLOCK_SIZE, ctx->ctr.b, length, digest, ctx->tag.b); +} + +void +ccm_encrypt_message(void *cipher, nettle_crypt_func *f, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + struct ccm_ctx ctx; + ccm_set_nonce(&ctx, nlength, nonce, alength, mlength, tlength); + ccm_update(&ctx, cipher, f, alength, adata); + ccm_encrypt(&ctx, cipher, f, mlength, dst, src); + ccm_digest(&ctx, cipher, f, tlength, tag); +} + +void +ccm_decrypt_message(void *cipher, nettle_crypt_func *f, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + struct ccm_ctx ctx; + ccm_set_nonce(&ctx, nlength, nonce, alength, mlength, tlength); + ccm_update(&ctx, cipher, f, alength, adata); + ccm_decrypt(&ctx, cipher, f, mlength, dst, src); + ccm_digest(&ctx, cipher, f, tlength, tag); +} diff --git a/ccm.h b/ccm.h new file mode 100644 index 0000000..76b4cc4 --- /dev/null +++ b/ccm.h @@ -0,0 +1,267 @@ +/* ccm.h + * + * Counter with CBC-MAC mode, specified by NIST, + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_... + * + * NIST SP800-38C doesn't specify the particular formatting and counter generation + * algorithm for CCM, but it does include an example algorithm. This example + * has become the de-factor standard, and has been adopted by both the IETF and + * IEEE across a wide variety of protocols. + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2014 Exegin Technologies Limited + * Copyright (C) 2014 Owen Kirby + * + * Contributed by Owen Kirby + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ + +#ifndef NETTLE_CCM_H_INCLUDED +#define NETTLE_CCM_H_INCLUDED + +#include "aes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define ccm_set_nonce nettle_ccm_set_nonce +#define ccm_update nettle_ccm_update +#define ccm_encrypt nettle_ccm_encrypt +#define ccm_decrypt nettle_ccm_decrypt +#define ccm_digest nettle_ccm_digest +#define ccm_encrypt_message nettle_ccm_encrypt_message +#define ccm_decrypt_message nettle_ccm_decrypt_message + +#define ccm_aes128_set_key nettle_ccm_aes128_set_key +#define ccm_aes128_set_nonce nettle_ccm_aes128_set_nonce +#define ccm_aes128_update nettle_ccm_aes128_update +#define ccm_aes128_encrypt nettle_ccm_aes128_encrypt +#define ccm_aes128_decrypt nettle_ccm_aes128_decrypt +#define ccm_aes128_digest nettle_ccm_aes128_digest +#define ccm_aes128_encrypt_message nettle_ccm_aes128_encrypt_message +#define ccm_aes128_decrypt_message nettle_ccm_aes128_decrypt_message + +#define ccm_aes192_set_key nettle_ccm_aes192_set_key +#define ccm_aes192_set_nonce nettle_ccm_aes192_set_nonce +#define ccm_aes192_update nettle_ccm_aes192_update +#define ccm_aes192_encrypt nettle_ccm_aes192_encrypt +#define ccm_aes192_decrypt nettle_ccm_aes192_decrypt +#define ccm_aes192_digest nettle_ccm_aes192_digest +#define ccm_aes192_encrypt_message nettle_ccm_aes192_encrypt_message +#define ccm_aes192_decrypt_message nettle_ccm_aes192_decrypt_message + +#define ccm_aes256_set_key nettle_ccm_aes256_set_key +#define ccm_aes256_set_nonce nettle_ccm_aes256_set_nonce +#define ccm_aes256_update nettle_ccm_aes256_update +#define ccm_aes256_encrypt nettle_ccm_aes256_encrypt +#define ccm_aes256_decrypt nettle_ccm_aes256_decrypt +#define ccm_aes256_digest nettle_ccm_aes256_digest +#define ccm_aes256_encrypt_message nettle_ccm_aes256_encrypt_message +#define ccm_aes256_decrypt_message nettle_ccm_aes256_decrypt_message + +/* For CCM, the block size of the block cipher shall be 128 bits. */ +#define CCM_BLOCK_SIZE 16 + +/* Per-message state */ +struct ccm_ctx { + union nettle_block16 ctr; /* Counter for CTR encryption. */ + union nettle_block16 tag; /* CBC-MAC message tag. */ + uint64_t alen; /* Length of adata set during the nonce generation. */ + int blen; /* <0 on init or # of bytes since the last aligned block */ +}; + +/* + * Obnoxiously, CCM mode requires the adata and message lengths when building + * the IV, which prevents any streaming API to the cipher. As such, this makes + * the set_nonce() function incompatible with the nettle AEAD API. + */ +void +ccm_set_nonce(struct ccm_ctx *ctx, size_t noncelen, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen); + +void +ccm_update(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, const uint8_t *data); + +void +ccm_encrypt(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_decrypt(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_digest(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f, + size_t length, uint8_t *digest); + +/* All-in-one encryption and decryption API. */ +void +ccm_encrypt_message(void *cipher, nettle_crypt_func *f, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +void +ccm_decrypt_message(void *cipher, nettle_crypt_func *f, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +/* CCM Mode with AES-128 */ +struct ccm_aes128_ctx { + struct ccm_ctx ccm; + struct aes128_ctx cipher; +}; + +void +ccm_aes128_set_key(struct ccm_aes128_ctx *ctx, const uint8_t *key); + +void +ccm_aes128_set_nonce(struct ccm_aes128_ctx *ctx, + size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen); + +void +ccm_aes128_update (struct ccm_aes128_ctx *ctx, + size_t length, const uint8_t *data); + +void +ccm_aes128_encrypt(struct ccm_aes128_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_aes128_decrypt(struct ccm_aes128_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_aes128_digest(struct ccm_aes128_ctx *ctx, + size_t length, uint8_t *digest); + +void +ccm_aes128_encrypt_message(struct ccm_aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +void +ccm_aes128_decrypt_message(struct ccm_aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +struct ccm_aes192_ctx { + struct ccm_ctx ccm; + struct aes192_ctx cipher; +}; + +/* CCM Mode with AES-192 */ +void +ccm_aes192_set_key(struct ccm_aes192_ctx *ctx, const uint8_t *key); + +void +ccm_aes192_set_nonce(struct ccm_aes192_ctx *ctx, + size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen); + +void +ccm_aes192_update(struct ccm_aes192_ctx *ctx, + size_t length, const uint8_t *data); + +void +ccm_aes192_encrypt(struct ccm_aes192_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_aes192_decrypt(struct ccm_aes192_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_aes192_digest(struct ccm_aes192_ctx *ctx, + size_t length, uint8_t *digest); + +void +ccm_aes192_encrypt_message(struct ccm_aes192_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +void +ccm_aes192_decrypt_message(struct ccm_aes192_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +/* CCM Mode with AES-256 */ +struct ccm_aes256_ctx { + struct ccm_ctx ccm; + struct aes256_ctx cipher; +}; + +void +ccm_aes256_set_key(struct ccm_aes256_ctx *ctx, const uint8_t *key); + +void +ccm_aes256_set_nonce(struct ccm_aes256_ctx *ctx, + size_t length, const uint8_t *nonce, + size_t authlen, size_t msglen, size_t taglen); + +void +ccm_aes256_update(struct ccm_aes256_ctx *ctx, + size_t length, const uint8_t *data); + +void +ccm_aes256_encrypt(struct ccm_aes256_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_aes256_decrypt(struct ccm_aes256_ctx *ctx, + size_t length, uint8_t *dst, const uint8_t *src); + +void +ccm_aes256_digest(struct ccm_aes256_ctx *ctx, + size_t length, uint8_t *digest); + +void +ccm_aes256_encrypt_message(struct ccm_aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +void +ccm_aes256_decrypt_message(struct ccm_aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t tlength, uint8_t *tag, + size_t mlength, uint8_t *dst, const uint8_t *src); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_CCM_H_INCLUDED */ diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 3b836af..8e5521b 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -11,6 +11,7 @@ /camellia-test /cast128-test /cbc-test +/ccm-test /ctr-test /cxx-test /des-compat-test diff --git a/testsuite/.test-rules.make b/testsuite/.test-rules.make index 43079ec..16d107c 100644 --- a/testsuite/.test-rules.make +++ b/testsuite/.test-rules.make @@ -100,6 +100,9 @@ knuth-lfib-test$(EXEEXT): knuth-lfib-test.$(OBJEXT) cbc-test$(EXEEXT): cbc-test.$(OBJEXT) $(LINK) cbc-test.$(OBJEXT) $(TEST_OBJS) -o cbc-test$(EXEEXT)
+ccm-test$(EXEEXT): ccm-test.$(OBJEXT) + $(LINK) ccm-test.$(OBJEXT) $(TEST_OBJS) -o ccm-test$(EXEEXT) + ctr-test$(EXEEXT): ctr-test.$(OBJEXT) $(LINK) ctr-test.$(OBJEXT) $(TEST_OBJS) -o ctr-test$(EXEEXT)
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index d59a2cb..30611c7 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -25,7 +25,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \ sha3-384-test.c sha3-512-test.c \ serpent-test.c twofish-test.c \ knuth-lfib-test.c \ - cbc-test.c ctr-test.c gcm-test.c eax-test.c \ + cbc-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \ poly1305-test.c chacha-poly1305-test.c \ hmac-test.c umac-test.c \ meta-hash-test.c meta-cipher-test.c meta-armor-test.c \ diff --git a/testsuite/ccm-test.c b/testsuite/ccm-test.c new file mode 100644 index 0000000..cd74db7 --- /dev/null +++ b/testsuite/ccm-test.c @@ -0,0 +1,709 @@ +/* ccm-test.c + * + * Self-test and vectors for CCM mode ciphers using AES-128 and AES-256. The + * test vectors have been collected from the following standards: + * NIST SP800-38C + * RFC 3610 + * IEEE 802.15.4-2011 + * IEEE P1619.1/D22 July 2007 (draft version) + */ + +/* nettle, low-level cryptographics library + * + * Copyright (C) 2014 Exegin Technologies Limited + * Copyright (C) 2014 Owen Kirby + * + * The nettle library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The nettle library 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 Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the nettle library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02111-1301, USA. + */ +#include "testutils.h" +#include "aes.h" +#include "ccm.h" +#include "knuth-lfib.h" + +static void +test_compare_results(const char *name, + const struct tstring *adata, + /* Expected results. */ + const struct tstring *e_clear, + const struct tstring *e_cipher, + const struct tstring *e_tag, + /* Actual results. */ + const void *clear, + const void *cipher, + const void *de_tag, + const void *en_tag) +{ + if (!MEMEQ(e_cipher->length, e_cipher->data, cipher)) + { + fprintf(stderr, "%s: encrypt failed\nInput:", name); + tstring_print_hex(e_clear); + fprintf(stderr, "\nOutput: "); + print_hex(e_cipher->length, cipher); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(e_cipher); + fprintf(stderr, "\n"); + FAIL(); + } + if (!MEMEQ(e_clear->length, e_clear->data, clear)) + { + fprintf(stderr, "%s decrypt failed:\nInput:", name); + tstring_print_hex(e_cipher); + fprintf(stderr, "\nOutput: "); + print_hex(e_clear->length, clear); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(e_clear); + fprintf(stderr, "\n"); + FAIL(); + } + if (!MEMEQ(e_tag->length, e_tag->data, en_tag)) + { + fprintf(stderr, "%s digest failed during encryption:\nAdata:", name); + tstring_print_hex(adata); + fprintf(stderr, "\nInput: "); + tstring_print_hex(e_clear); + fprintf(stderr, "\nOutput: "); + print_hex(e_tag->length, en_tag); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(e_tag); + fprintf(stderr, "\n"); + FAIL(); + } + if (!MEMEQ(e_tag->length, e_tag->data, de_tag)) + { + fprintf(stderr, "%s digest failed during decryption:\nAdata:", name); + tstring_print_hex(adata); + fprintf(stderr, "\nInput: "); + tstring_print_hex(e_clear); + fprintf(stderr, "\nOutput: "); + print_hex(e_tag->length, de_tag); + fprintf(stderr, "\nExpected:"); + tstring_print_hex(e_tag); + fprintf(stderr, "\n"); + FAIL(); + } +} /* test_compare_results */ + +static void +test_cipher_ccm(const struct nettle_cipher *cipher, + const struct tstring *key, + const struct tstring *nonce, + const struct tstring *authdata, + int repeat, + const struct tstring *cleartext, + const struct tstring *ciphertext, + const struct tstring *tag) +{ + void *ctx = xalloc(cipher->context_size); + uint8_t *en_data; + uint8_t *de_data; + uint8_t en_digest[CCM_BLOCK_SIZE]; + uint8_t de_digest[CCM_BLOCK_SIZE]; + size_t len; + size_t tlen; + struct ccm_ctx ccm; + int i; + + ASSERT (key->length == cipher->key_size); + ASSERT (cleartext->length == ciphertext->length); + len = cleartext->length; + tlen = tag->length; + if (!authdata) repeat = 0; + + en_data = xalloc(len); + de_data = xalloc(len); + cipher->set_encrypt_key(ctx, key->data); + + /* Encrypt using the incremental API. */ + ccm_set_nonce(&ccm, nonce->length, nonce->data, authdata->length * repeat, len, tlen); + for (i = 0; i < repeat; i++) { + ccm_update(&ccm, ctx, cipher->encrypt, authdata->length, authdata->data); + } + ccm_encrypt(&ccm, ctx, cipher->encrypt, len, en_data, cleartext->data); + ccm_digest(&ccm, ctx, cipher->encrypt, tag->length, en_digest); + + /* Decrypt using the incremental API. */ + ccm_set_nonce(&ccm, nonce->length, nonce->data, authdata->length * repeat, len, tlen); + for (i = 0; i < repeat; i++) { + ccm_update(&ccm, ctx, cipher->encrypt, authdata->length, authdata->data); + } + ccm_decrypt(&ccm, ctx, cipher->encrypt, len, de_data, ciphertext->data); + ccm_digest(&ccm, ctx, cipher->encrypt, tag->length, de_digest); + + /* Compare results using the generic API. */ + test_compare_results("CCM", authdata, + cleartext, ciphertext, tag, + de_data, en_data, de_digest, en_digest); + + /* Ensure we get the same answers using the all-in-one API. */ + if (repeat <= 1) { + memset(en_data, 0, len); memset(de_data, 0, len); + memset(en_digest, 0, tlen); memset(de_digest, 0, tlen); + + ccm_encrypt_message(ctx, cipher->encrypt, nonce->length, nonce->data, + authdata->length, authdata->data, tlen, en_digest, len, en_data, cleartext->data); + + ccm_decrypt_message(ctx, cipher->encrypt, nonce->length, nonce->data, + authdata->length, authdata->data, tlen, de_digest, len, de_data, ciphertext->data); + + test_compare_results("CCM_MSG", authdata, + cleartext, ciphertext, tag, + de_data, en_data, de_digest, en_digest); + } + + /* Ensure we get the same answers using the per-cipher API. */ + if (cipher == &nettle_aes128) { + struct ccm_aes128_ctx aes; + memset(en_data, 0, len); memset(de_data, 0, len); + memset(en_digest, 0, tlen); memset(de_digest, 0, tlen); + + /* AES-128 encrypt. */ + ccm_aes128_set_key(&aes, key->data); + ccm_aes128_set_nonce(&aes, nonce->length, nonce->data, authdata->length * repeat, len, tlen); + for (i = 0; i < repeat; i++) { + ccm_aes128_update(&aes, authdata->length, authdata->data); + } + ccm_aes128_encrypt(&aes,len, en_data, cleartext->data); + ccm_aes128_digest(&aes, tag->length, en_digest); + + /* AES-128 decrypt. */ + ccm_aes128_set_nonce(&aes, nonce->length, nonce->data, authdata->length * repeat, len, tlen); + for (i = 0; i < repeat; i++) { + ccm_aes128_update(&aes, authdata->length, authdata->data); + } + ccm_aes128_decrypt(&aes, len, de_data, ciphertext->data); + ccm_aes128_digest(&aes, tag->length, de_digest); + + test_compare_results("CCM_AES_128", authdata, + cleartext, ciphertext, tag, + de_data, en_data, de_digest, en_digest); + } + /* TODO: I couldn't find any test cases for CCM-AES-192 */ + if (cipher == &nettle_aes256) { + struct ccm_aes256_ctx aes; + memset(en_data, 0, len); memset(de_data, 0, len); + memset(en_digest, 0, tlen); memset(de_digest, 0, tlen); + + /* AES-256 encrypt. */ + ccm_aes256_set_key(&aes, key->data); + ccm_aes256_set_nonce(&aes, nonce->length, nonce->data, authdata->length * repeat, len, tlen); + for (i = 0; i < repeat; i++) { + ccm_aes256_update(&aes, authdata->length, authdata->data); + } + ccm_aes256_encrypt(&aes,len, en_data, cleartext->data); + ccm_aes256_digest(&aes, tag->length, en_digest); + + /* AES-256 decrypt. */ + ccm_aes256_set_nonce(&aes, nonce->length, nonce->data, authdata->length * repeat, len, tlen); + for (i = 0; i < repeat; i++) { + ccm_aes256_update(&aes, authdata->length, authdata->data); + } + ccm_aes256_decrypt(&aes,len, de_data, ciphertext->data); + ccm_aes256_digest(&aes, tag->length, de_digest); + + test_compare_results("CCM_AES_256", authdata, + cleartext, ciphertext, tag, + de_data, en_data, de_digest, en_digest); + } + + free(ctx); + free(en_data); + free(de_data); +} + +void +test_main(void) +{ + /* Create a pattern of 00010203 04050607 08090a00b 0c0d0e0f ... */ + struct tstring *adata; + unsigned int i; + adata = tstring_alloc(256); + for (i=0; i<adata->length; i++) adata->data[i] = (i & 0xff); + + /* From NIST spec 800-38C on AES modes. + * + * Appendix C: Example Vectors + */ + /* + * C.1 Example 1 + * Klen = 128, Tlen = 32, Nlen = 56, Alen = 64, Plen = 32 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("404142434445464748494a4b4c4d4e4f"), + SHEX("10111213141516"), + SHEX("0001020304050607"), 1, + SHEX("20212223"), + SHEX("7162015b"), + SHEX("4dac255d")); + + /* + * C.2 Example 2 + * Klen = 128, Tlen = 48, Nlen = 64, Alen = 128, Plen = 128 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("404142434445464748494a4b4c4d4e4f"), + SHEX("1011121314151617"), + SHEX("000102030405060708090a0b0c0d0e0f"), 1, + SHEX("202122232425262728292a2b2c2d2e2f"), + SHEX("d2a1f0e051ea5f62081a7792073d593d"), + SHEX("1fc64fbfaccd")); + + /* + * C.3 Example 3 + * Klen = 128, Tlen = 64, Nlen = 96, Alen = 160, Plen = 192 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("404142434445464748494a4b4c4d4e4f"), + SHEX("101112131415161718191a1b"), + SHEX("000102030405060708090a0b0c0d0e0f" + "10111213"), 1, + SHEX("202122232425262728292a2b2c2d2e2f" + "3031323334353637"), + SHEX("e3b201a9f5b71a7a9b1ceaeccd97e70b" + "6176aad9a4428aa5"), + SHEX("484392fbc1b09951")); + + /* + * C.4 Example 4 + * Klen = 128, Tlen = 112, Nlen = 104, Alen = 524288, Plen = 256 + * A = 00010203 04050607 08090a0b 0c0d0e0f + * 10111213 ... + */ + test_cipher_ccm(&nettle_aes128, + SHEX("404142434445464748494a4b4c4d4e4f"), + SHEX("101112131415161718191a1b1c"), + adata, 256, + SHEX("202122232425262728292a2b2c2d2e2f" + "303132333435363738393a3b3c3d3e3f"), + SHEX("69915dad1e84c6376a68c2967e4dab61" + "5ae0fd1faec44cc484828529463ccf72"), + SHEX("b4ac6bec93e8598e7f0dadbcea5b")); + + /* From RFC 3610 + * + * Section 8: Test Vectors + * Packet Vector #1 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 03 02 01 00 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07"), 1, + SHEX("08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E"), + SHEX("58 8C 97 9A 61 C6 63 D2 F0 66 D0 C2 C0 F9 89 80 6D 5F 6B 61 DA C3 84"), + SHEX("17 E8 D1 2C FD F9 26 E0")); + + /* + * Packet Vector #2 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 04 03 02 01 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07"), 1, + SHEX("08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"), + SHEX("72 C9 1A 36 E1 35 F8 CF 29 1C A8 94 08 5C 87 E3 CC 15 C4 39 C9 E4 3A 3B"), + SHEX("A0 91 D5 6E 10 40 09 16")); + + /* + * Packet Vector #3 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 05 04 03 02 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07"), 1, + SHEX("08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20"), + SHEX("51 B1 E5 F4 4A 19 7D 1D A4 6B 0F 8E 2D 28 2A E8 71 E8 38 BB 64 DA 85 96 57"), + SHEX("4A DA A7 6F BD 9F B0 C5")); + + /* + * Packet Vector #4 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 06 05 04 03 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07 08 09 0A 0B"), 1, + SHEX("0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E"), + SHEX("A2 8C 68 65 93 9A 9A 79 FA AA 5C 4C 2A 9D 4A 91 CD AC 8C"), + SHEX("96 C8 61 B9 C9 E6 1E F1")); + + /* + * Packet Vector #5 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 07 06 05 04 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07 08 09 0A 0B"), 1, + SHEX("0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"), + SHEX("DC F1 FB 7B 5D 9E 23 FB 9D 4E 13 12 53 65 8A D8 6E BD CA 3E"), + SHEX("51 E8 3F 07 7D 9C 2D 93")); + + /* + * Packet Vector #6 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 08 07 06 05 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07 08 09 0A 0B"), 1, + SHEX("0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20"), + SHEX("6F C1 B0 11 F0 06 56 8B 51 71 A4 2D 95 3D 46 9B 25 70 A4 BD 87"), + SHEX("40 5A 04 43 AC 91 CB 94")); + + /* + * Packet Vector #7 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 09 08 07 06 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07"), 1, + SHEX("08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E"), + SHEX("01 35 D1 B2 C9 5F 41 D5 D1 D4 FE C1 85 D1 66 B8 09 4E 99 9D FE D9 6C"), + SHEX("04 8C 56 60 2C 97 AC BB 74 90")); + + /* + * Packet Vector #8 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 0A 09 08 07 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07"), 1, + SHEX("08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"), + SHEX("7B 75 39 9A C0 83 1D D2 F0 BB D7 58 79 A2 FD 8F 6C AE 6B 6C D9 B7 DB 24"), + SHEX("C1 7B 44 33 F4 34 96 3F 34 B4")); + + /* + * Packet Vector #9 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 0B 0A 09 08 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07"), 1, + SHEX("08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20"), + SHEX("82 53 1A 60 CC 24 94 5A 4B 82 79 18 1A B5 C8 4D F2 1C E7 F9 B7 3F 42 E1 97"), + SHEX("EA 9C 07 E5 6B 5E B1 7E 5F 4E")); + + /* + * Packet Vector #10 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 0C 0B 0A 09 A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07 08 09 0A 0B"), 1, + SHEX("0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E"), + SHEX("07 34 25 94 15 77 85 15 2B 07 40 98 33 0A BB 14 1B 94 7B"), + SHEX("56 6A A9 40 6B 4D 99 99 88 DD")); + + /* + * Packet Vector #11 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 0D 0C 0B 0A A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07 08 09 0A 0B"), 1, + SHEX("0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F"), + SHEX("67 6B B2 03 80 B0 E3 01 E8 AB 79 59 0A 39 6D A7 8B 83 49 34"), + SHEX("F5 3A A2 E9 10 7A 8B 6C 02 2C")); + + /* + * Packet Vector #12 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("00 00 00 0E 0D 0C 0B A0 A1 A2 A3 A4 A5"), + SHEX("00 01 02 03 04 05 06 07 08 09 0A 0B"), 1, + SHEX("0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20"), + SHEX("C0 FF A0 D6 F0 5B DB 67 F2 4D 43 A4 33 8D 2A A4 BE D7 B2 0E 43"), + SHEX("CD 1A A3 16 62 E7 AD 65 D6 DB")); + + /* + * Packet Vector #13 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 41 2B 4E A9 CD BE 3C 96 96 76 6C FA"), + SHEX("0B E1 A8 8B AC E0 18 B1"), 1, + SHEX("08 E8 CF 97 D8 20 EA 25 84 60 E9 6A D9 CF 52 89 05 4D 89 5C EA C4 7C"), + SHEX("4C B9 7F 86 A2 A4 68 9A 87 79 47 AB 80 91 EF 53 86 A6 FF BD D0 80 F8"), + SHEX("E7 8C F7 CB 0C DD D7 B3")); + + /* + * Packet Vector #14 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 33 56 8E F7 B2 63 3C 96 96 76 6C FA"), + SHEX("63 01 8F 76 DC 8A 1B CB"), 1, + SHEX("90 20 EA 6F 91 BD D8 5A FA 00 39 BA 4B AF F9 BF B7 9C 70 28 94 9C D0 EC"), + SHEX("4C CB 1E 7C A9 81 BE FA A0 72 6C 55 D3 78 06 12 98 C8 5C 92 81 4A BC 33"), + SHEX("C5 2E E8 1D 7D 77 C0 8A")); + + /* + * Packet Vector #15 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 10 3F E4 13 36 71 3C 96 96 76 6C FA"), + SHEX("AA 6C FA 36 CA E8 6B 40"), 1, + SHEX("B9 16 E0 EA CC 1C 00 D7 DC EC 68 EC 0B 3B BB 1A 02 DE 8A 2D 1A A3 46 13 2E"), + SHEX("B1 D2 3A 22 20 DD C0 AC 90 0D 9A A0 3C 61 FC F4 A5 59 A4 41 77 67 08 97 08"), + SHEX("A7 76 79 6E DB 72 35 06")); + + /* + * Packet Vector #16 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 76 4C 63 B8 05 8E 3C 96 96 76 6C FA"), + SHEX("D0 D0 73 5C 53 1E 1B EC F0 49 C2 44"), 1, + SHEX("12 DA AC 56 30 EF A5 39 6F 77 0C E1 A6 6B 21 F7 B2 10 1C"), + SHEX("14 D2 53 C3 96 7B 70 60 9B 7C BB 7C 49 91 60 28 32 45 26"), + SHEX("9A 6F 49 97 5B CA DE AF")); + + /* + * Packet Vector #17 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 F8 B6 78 09 4E 3B 3C 96 96 76 6C FA"), + SHEX("77 B6 0F 01 1C 03 E1 52 58 99 BC AE"), 1, + SHEX("E8 8B 6A 46 C7 8D 63 E5 2E B8 C5 46 EF B5 DE 6F 75 E9 CC 0D"), + SHEX("55 45 FF 1A 08 5E E2 EF BF 52 B2 E0 4B EE 1E 23 36 C7 3E 3F"), + SHEX("76 2C 0C 77 44 FE 7E 3C")); + + /* + * Packet Vector #18 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 D5 60 91 2D 3F 70 3C 96 96 76 6C FA"), + SHEX("CD 90 44 D2 B7 1F DB 81 20 EA 60 C0"), 1, + SHEX("64 35 AC BA FB 11 A8 2E 2F 07 1D 7C A4 A5 EB D9 3A 80 3B A8 7F"), + SHEX("00 97 69 EC AB DF 48 62 55 94 C5 92 51 E6 03 57 22 67 5E 04 C8"), + SHEX("47 09 9E 5A E0 70 45 51")); + + /* + * Packet Vector #19 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 42 FF F8 F1 95 1C 3C 96 96 76 6C FA"), + SHEX("D8 5B C7 E6 9F 94 4F B8"), 1, + SHEX("8A 19 B9 50 BC F7 1A 01 8E 5E 67 01 C9 17 87 65 98 09 D6 7D BE DD 18"), + SHEX("BC 21 8D AA 94 74 27 B6 DB 38 6A 99 AC 1A EF 23 AD E0 B5 29 39 CB 6A"), + SHEX("63 7C F9 BE C2 40 88 97 C6 BA")); + + /* + * Packet Vector #20 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 92 0F 40 E5 6C DC 3C 96 96 76 6C FA"), + SHEX("74 A0 EB C9 06 9F 5B 37"), 1, + SHEX("17 61 43 3C 37 C5 A3 5F C1 F3 9F 40 63 02 EB 90 7C 61 63 BE 38 C9 84 37"), + SHEX("58 10 E6 FD 25 87 40 22 E8 03 61 A4 78 E3 E9 CF 48 4A B0 4F 44 7E FF F6"), + SHEX("F0 A4 77 CC 2F C9 BF 54 89 44")); + + /* + * Packet Vector #21 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 27 CA 0C 71 20 BC 3C 96 96 76 6C FA"), + SHEX("44 A3 AA 3A AE 64 75 CA"), 1, + SHEX("A4 34 A8 E5 85 00 C6 E4 15 30 53 88 62 D6 86 EA 9E 81 30 1B 5A E4 22 6B FA"), + SHEX("F2 BE ED 7B C5 09 8E 83 FE B5 B3 16 08 F8 E2 9C 38 81 9A 89 C8 E7 76 F1 54"), + SHEX("4D 41 51 A4 ED 3A 8B 87 B9 CE")); + + /* + * Packet Vector #22 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 5B 8C CB CD 9A F8 3C 96 96 76 6C FA"), + SHEX("EC 46 BB 63 B0 25 20 C3 3C 49 FD 70"), 1, + SHEX("B9 6B 49 E2 1D 62 17 41 63 28 75 DB 7F 6C 92 43 D2 D7 C2"), + SHEX("31 D7 50 A0 9D A3 ED 7F DD D4 9A 20 32 AA BF 17 EC 8E BF"), + SHEX("7D 22 C8 08 8C 66 6B E5 C1 97")); + + /* + * Packet Vector #23 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 3E BE 94 04 4B 9A 3C 96 96 76 6C FA"), + SHEX("47 A6 5A C7 8B 3D 59 42 27 E8 5E 71"), 1, + SHEX("E2 FC FB B8 80 44 2C 73 1B F9 51 67 C8 FF D7 89 5E 33 70 76"), + SHEX("E8 82 F1 DB D3 8C E3 ED A7 C2 3F 04 DD 65 07 1E B4 13 42 AC"), + SHEX("DF 7E 00 DC CE C7 AE 52 98 7D")); + + /* + * Packet Vector #24 + */ + test_cipher_ccm(&nettle_aes128, + SHEX("D7 82 8D 13 B2 B0 BD C3 25 A7 62 36 DF 93 CC 6B"), + SHEX("00 8D 49 3B 30 AE 8B 3C 96 96 76 6C FA"), + SHEX("6E 37 A6 EF 54 6D 95 5D 34 AB 60 59"), 1, + SHEX("AB F2 1C 0B 02 FE B8 8F 85 6D F4 A3 73 81 BC E3 CC 12 85 17 D4"), + SHEX("F3 29 05 B8 8A 64 1B 04 B9 C9 FF B5 8C C3 90 90 0F 3D A1 2A B1"), + SHEX("6D CE 9E 82 EF A1 6D A6 20 59")); + + /* From IEEE 802.15.4-2011 + * + * Annex C: Test vectors for cryptographic building blocks + * C.2.1 MAC beacon frame + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("AC DE 48 00 00 00 00 01 00 00 00 05 02"), + SHEX("08 D0 84 21 43 01 00 00 00 00 48 DE AC 02 05 00 00 00 55 CF 00 00 51 52 53 54"), 1, + SHEX(""), + SHEX(""), + SHEX("22 3B C1 EC 84 1A B5 53")); + + /* + * C.2.2 MAC data frame + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("AC DE 48 00 00 00 00 01 00 00 00 05 04"), + SHEX("69 DC 84 21 43 02 00 00 00 00 48 DE AC 01 00 00 00 00 48 DE AC 04 05 00 00 00"), 1, + SHEX("61 62 63 64"), + SHEX("D4 3E 02 2B"), + SHEX("")); + + /* + * C.2.3 MAC command frame + */ + test_cipher_ccm(&nettle_aes128, + SHEX("C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF"), + SHEX("AC DE 48 00 00 00 00 01 00 00 00 05 06"), + SHEX("2B DC 84 21 43 02 00 0000 00 48 DE AC FF FF 01 00 00 00 00 48 DE AC 06 05 00 00 00 01"), 1, + SHEX("CE"), + SHEX("D8"), + SHEX("4F DE 52 90 61 F9 C6 F1")); + + /* From IEEE P1619.1/D22 July 2007 (draft version) + * + * Annex D: Test Vectors + * D.2.1 CCM-128-AES-256 test vector 1 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("0000000000000000000000000000000000000000000000000000000000000000"), + SHEX("000000000000000000000000"), + SHEX(""), 0, + SHEX("00000000000000000000000000000000"), + SHEX("c1944044c8e7aa95d2de9513c7f3dd8c"), + SHEX("4b0a3e5e51f151eb0ffae7c43d010fdb")); + + /* + * D.2.2 CCM-128-AES-256 test vector 2 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("0000000000000000000000000000000000000000000000000000000000000000"), + SHEX("000000000000000000000000"), + SHEX("00000000000000000000000000000000"), 1, + SHEX(""), + SHEX(""), + SHEX("904704e89fb216443cb9d584911fc3c2")); + + /* + * D.2.3 CCM-128-AES-256 test vector 3 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("0000000000000000000000000000000000000000000000000000000000000000"), + SHEX("000000000000000000000000"), + SHEX("00000000000000000000000000000000"), 1, + SHEX("00000000000000000000000000000000"), + SHEX("c1944044c8e7aa95d2de9513c7f3dd8c"), + SHEX("87314e9c1fa01abe6a6415943dc38521")); + + /* + * D.2.4 CCM-128-AES-256 test vector 4 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("fb7615b23d80891dd470980bc79584c8b2fb64ce60978f4d17fce45a49e830b7"), + SHEX("dbd1a3636024b7b402da7d6f"), + SHEX(""), 0, + SHEX("a845348ec8c5b5f126f50e76fefd1b1e"), + SHEX("cc881261c6a7fa72b96a1739176b277f"), + SHEX("3472e1145f2c0cbe146349062cf0e423")); + + /* + * D.2.5 CCM-128-AES-256 test vector 5 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"), + SHEX("101112131415161718191a1b"), + SHEX("000102030405060708090a0b0c0d0e0f10111213"), 1, + SHEX("202122232425262728292a2b2c2d2e2f3031323334353637"), + SHEX("04f883aeb3bd0730eaf50bb6de4fa2212034e4e41b0e75e5"), + SHEX("9bba3f3a107f3239bd63902923f80371")); + + /* + * D.2.6 CCM-128-AES-256 test vector 6 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"), + SHEX("101112131415161718191a1b"), + adata, 256, + SHEX("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), + SHEX("04f883aeb3bd0730eaf50bb6de4fa2212034e4e41b0e75e577f6bf2422c0f6d2"), + SHEX("3376d2cf256ef613c56454cbb5265834")); + + /* + * D.2.7 CCM-128-AES-256 test vector 7 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"), + SHEX("101112131415161718191a1b"), + SHEX("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), 1, + SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" + "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f" + "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" + "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + "e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"), + SHEX("24d8a38e939d2710cad52b96fe6f82010014c4c43b2e55c557d69f0402e0d6f2" + "06c53d6cbd3f1c3c6de5dcdcad9fb74f25741dea741149fe4278a0cc24741e86" + "58cc0523b8d7838c60fb1de4b7c3941f5b26dea9322aa29656ec37ac18a9b108" + "a6f38b7917f5a9c398838b22afbd17252e96694a9e6237964a0eae21c0a6e152" + "15a0e82022926be97268249599e456e05029c3ebc07d78fc5b4a0862e04e68c2" + "9514c7bdafc4b52e04833bf30622e4eb42504a44a9dcbc774752de7bb82891ad" + "1eba9dc3281422a8aba8654268d3d9c81705f4c5a531ef856df5609a159af738" + "eb753423ed2001b8f20c23725f2bef18c409f7e52132341f27cb8f0e79894dd9"), + SHEX("ebb1fa9d28ccfe21bdfea7e6d91e0bab")); + + /* + * D.2.8 CCM-128-AES-256 test vector 8 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("fb7615b23d80891dd470980bc79584c8b2fb64ce6097878d17fce45a49e830b7"), + SHEX("dbd1a3636024b7b402da7d6f"), + SHEX("36"), 1, + SHEX("a9"), + SHEX("9d"), + SHEX("3261b1cf931431e99a32806738ecbd2a")); + + /* + * D.2.9 CCM-128-AES-256 test vector 9 + */ + test_cipher_ccm(&nettle_aes256, + SHEX("f8d476cfd646ea6c2384cb1c27d6195dfef1a9f37b9c8d21a79c21f8cb90d289"), + SHEX("dbd1a3636024b7b402da7d6f"), + SHEX("7bd859a247961a21823b380e9fe8b65082ba61d3"), 1, + SHEX("90ae61cf7baebd4cade494c54a29ae70269aec71"), + SHEX("6c05313e45dc8ec10bea6c670bd94f31569386a6"), + SHEX("8f3829e8e76ee23c04f566189e63c686")); +}
Owen Kirby osk@exegin.com writes:
I've incorporated a few of your suggestions and updated my patch for the CCM cipher modes. This improves the API coverage in the CCM test suite, adds the all-at-once API for message processing, and fixes the copyright of the CCM mode source code.
Thanks!
--- /dev/null +++ b/ccm.c +/* Pad an unaligned CBC-MAC digest with zero, or initialize B0 if no adata. */ +static void +ccm_pad(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f) +{
- if (ctx->blen) f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b);
- ctx->blen = 0;
+}
Can you explain what this is intended for? It's called unconditionally by ccm_encrypt and ccm_decrypt, and I imagine it's a nop for all calls but the first (otherwise, ccm_encrypt (..., 16, msg...); ccm_encrypt (..., 16, msg+16...); would seem to give different output than ccm_encrypt(...32, msg))?
It is intended that _update and encrypt_/_decrypt can be called multiple times, as long as the total length equals the corresponding value passed to _set_nonce, right?
+void +ccm_update(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, const uint8_t *data)
+{
- const uint8_t *end = data + length;
- /* nop */
- if (!length) return;
- /* On the first call, encrypt B0 and encode L(a) */
- if (ctx->blen < 0) {
- if (!ctx->alen) ctx->alen = length; /* If alen unknown, set it now. */
- ctx->tag.b[CCM_OFFSET_FLAGS] |= CCM_FLAG_ADATA;
Why the special handling of zero ctx->alen here? As far as I can see, this can happen only if ccm_set_nonce is called with alength = 0, and then nevertheless calls ccm_update with length > 0, which seems like an invalid use of the api.
- f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b);
- ctx->blen = 0;
- if (ctx->alen >= (0x01ULL << 32)) {
/* Encode L(a) as 0xff || 0xff || <64-bit integer> */
ctx->tag.b[ctx->blen++] ^= 0xff;
ctx->tag.b[ctx->blen++] ^= 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 56) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 48) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 40) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 32) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 24) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 16) & 0xff;
- }
- else if (ctx->alen >= ((0x1ULL << 16) - (0x1ULL << 8))) {
/* Encode L(a) as 0xff || 0xfe || <32-bit integer> */
ctx->tag.b[ctx->blen++] ^= 0xff;
ctx->tag.b[ctx->blen++] ^= 0xfe;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 24) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 16) & 0xff;
- }
- ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 8) & 0xff;
- ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 0) & 0xff;
- }
Is it possible to move this initial processing to ccm_set_nonce? The alength *is* known there, and that would let you eliminate the ctx->blen < 0 cases, and maybe you could eliminate the alen state variable too (or keep it for sanity checking only).
+void +ccm_digest(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, uint8_t *digest)
+{
- int i = CCM_BLOCK_SIZE - CCM_FLAG_GET_L(ctx->ctr.b[CCM_OFFSET_FLAGS]);
Maybe it would be nicer to stick to a one-way encoding of the ctr block (done by ccm_build_iv, if I understand correctly), and never decode that format? One would need to store the needed information in some simpler "uncoded" way in the ctx. That's a judgment call, adding redundant info to the context is also a bit ugly.
+void +ccm_encrypt_message(void *cipher, nettle_crypt_func *f,
size_t nlength, const uint8_t *nonce,
size_t alength, const uint8_t *adata,
size_t tlength, uint8_t *tag,
size_t mlength, uint8_t *dst, const uint8_t *src)
+{
- struct ccm_ctx ctx;
- ccm_set_nonce(&ctx, nlength, nonce, alength, mlength, tlength);
- ccm_update(&ctx, cipher, f, alength, adata);
- ccm_encrypt(&ctx, cipher, f, mlength, dst, src);
- ccm_digest(&ctx, cipher, f, tlength, tag);
+}
I think this function should append the tag to the ciphertext (assuming ccm is specified as an aead with a single output string?).
+void +ccm_decrypt_message(void *cipher, nettle_crypt_func *f,
size_t nlength, const uint8_t *nonce,
size_t alength, const uint8_t *adata,
size_t tlength, uint8_t *tag,
size_t mlength, uint8_t *dst, const uint8_t *src)
+{
- struct ccm_ctx ctx;
- ccm_set_nonce(&ctx, nlength, nonce, alength, mlength, tlength);
- ccm_update(&ctx, cipher, f, alength, adata);
- ccm_decrypt(&ctx, cipher, f, mlength, dst, src);
- ccm_digest(&ctx, cipher, f, tlength, tag);
+}
I think this function should have a tag *input* (possibly reading it at te end of the cryptotext), compare it to the tag it computes, and return 1 on success, 0 for failure.
If the tag is appended to the cryptotext, I'm not sure if the mlength should be the message length with or without the tag (i.e., the length of the clear text message, or of the encrypted and authenticated message).
Maybe it's best to let it be the length of the clear text message, same as passed to ccm_encrypt_message. In any case, the caller must be aware of both lengths.
One *could* pass both message length, and derive the tag length as the difference. But I'm afraid that style won't generalize nicely to other aead algorithms.
diff --git a/ccm.h b/ccm.h new file mode 100644 index 0000000..76b4cc4 +/* Per-message state */ +struct ccm_ctx {
- union nettle_block16 ctr; /* Counter for CTR encryption. */
- union nettle_block16 tag; /* CBC-MAC message tag. */
- uint64_t alen; /* Length of adata set during the nonce generation. */
- int blen; /* <0 on init or # of bytes since the last aligned block */
+};
In nettle, length is usually not abbreviated to "len". If negative blen values can be eliminated, it should be changed to unsigned.
--- /dev/null +++ b/testsuite/ccm-test.c
- /* Ensure we get the same answers using the all-in-one API. */
- if (repeat <= 1) {
- memset(en_data, 0, len); memset(de_data, 0, len);
- memset(en_digest, 0, tlen); memset(de_digest, 0, tlen);
- ccm_encrypt_message(ctx, cipher->encrypt, nonce->length, nonce->data,
authdata->length, authdata->data, tlen, en_digest, len, en_data, cleartext->data);
- ccm_decrypt_message(ctx, cipher->encrypt, nonce->length, nonce->data,
authdata->length, authdata->data, tlen, de_digest, len, de_data, ciphertext->data);
If the all-in-one interface is changed as suggested above, adding a return value for ccm_decrypt_message, one should also check that ccm_decrypt_message returns 1 for the correct data, and 0 if any of message, adata or or tag is corrupted.
Regards, /Niels
On Sat, Mar 15, 2014 at 12:07 AM, Niels Möller nisse@lysator.liu.se wrote:
--- /dev/null +++ b/ccm.c +/* Pad an unaligned CBC-MAC digest with zero, or initialize B0 if no adata. */ +static void +ccm_pad(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f) +{
- if (ctx->blen) f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b);
- ctx->blen = 0;
+}
Can you explain what this is intended for? It's called unconditionally by ccm_encrypt and ccm_decrypt, and I imagine it's a nop for all calls but the first (otherwise, ccm_encrypt (..., 16, msg...); ccm_encrypt (..., 16, msg+16...); would seem to give different output than ccm_encrypt(...32, msg))?
It is intended that _update and encrypt_/_decrypt can be called multiple times, as long as the total length equals the corresponding value passed to _set_nonce, right?
The Input to the CBC-MAC used in CCM mode takes the form: L(adata) | adata | padding | plaintext | padding
Where L(adata) is a variable length transformation that encodes the length of adata, and padding is the minimum number of 0-bits necessary to align the input to a multiple of the block size (note that input to the CBC-MAC is just an XOR with the previous block, so padding becomes a NOP)
Because ccm_update() might be called multiple times, with data that doesn't necessarily leave the input aligned to the block size, blen is used to count the number of bytes that were already added to block, but haven't been processed by another iteration of the CBC-MAC. If the last call to left the input data aligned to the block size, then blen will be zero. In other words, blen is the length of data input to the CBC-MAC modulus the block size.
Once we find the end of the adata (this is currently done on the first call to ccm_encrypt() or ccm_decrypt()), we need to insert the padding before the plaintext, which is what ccm_pad() does. Then, because the CTR functions must always in a multiple of the block size, blen should always be zero except for the last block of the message.
+void +ccm_update(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, const uint8_t *data)
+{
- const uint8_t *end = data + length;
- /* nop */
- if (!length) return;
- /* On the first call, encrypt B0 and encode L(a) */
- if (ctx->blen < 0) {
- if (!ctx->alen) ctx->alen = length; /* If alen unknown, set it now. */
- ctx->tag.b[CCM_OFFSET_FLAGS] |= CCM_FLAG_ADATA;
Why the special handling of zero ctx->alen here? As far as I can see, this can happen only if ccm_set_nonce is called with alength = 0, and then nevertheless calls ccm_update with length > 0, which seems like an invalid use of the api.
Since the IV only contains a single bit that indicates whether adata exists at all, in theory the alength parameter could be omitted from set_nonce() entirely and then handled in ccm_update(), which is what this check is doing.
This is more or less an artifact of an attempt to support the AEAD API. Note that if you call ccm_set_nonce() with alength==0, and then pass the entire adata to ccm_update(), you would still get the correct authentication tag and ciphertext because of this special check on alen.
- f(cipher, CCM_BLOCK_SIZE, ctx->tag.b, ctx->tag.b);
- ctx->blen = 0;
- if (ctx->alen >= (0x01ULL << 32)) {
/* Encode L(a) as 0xff || 0xff || <64-bit integer> */
ctx->tag.b[ctx->blen++] ^= 0xff;
ctx->tag.b[ctx->blen++] ^= 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 56) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 48) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 40) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 32) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 24) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 16) & 0xff;
- }
- else if (ctx->alen >= ((0x1ULL << 16) - (0x1ULL << 8))) {
/* Encode L(a) as 0xff || 0xfe || <32-bit integer> */
ctx->tag.b[ctx->blen++] ^= 0xff;
ctx->tag.b[ctx->blen++] ^= 0xfe;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 24) & 0xff;
ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 16) & 0xff;
- }
- ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 8) & 0xff;
- ctx->tag.b[ctx->blen++] ^= (ctx->alen >> 0) & 0xff;
- }
Is it possible to move this initial processing to ccm_set_nonce? The alength *is* known there, and that would let you eliminate the ctx->blen < 0 cases, and maybe you could eliminate the alen state variable too (or keep it for sanity checking only).
Yes, that could be done, but this operation requires the use of the cipher encrypt function, which would need to be added to the set_nonce() API.
+void +ccm_digest(struct ccm_ctx *ctx, void *cipher, nettle_crypt_func *f,
size_t length, uint8_t *digest)
+{
- int i = CCM_BLOCK_SIZE - CCM_FLAG_GET_L(ctx->ctr.b[CCM_OFFSET_FLAGS]);
Maybe it would be nicer to stick to a one-way encoding of the ctr block (done by ccm_build_iv, if I understand correctly), and never decode that format? One would need to store the needed information in some simpler "uncoded" way in the ctx. That's a judgment call, adding redundant info to the context is also a bit ugly.
Yes, this was a bit of a judgement call, whether it was uglier to store the nonce length in the ctx, or to parse it out of the flags byte of the counter. There are other possible ways to do this, but they all require extra storage in the ctx, which I was hoping to avoid.
+void +ccm_encrypt_message(void *cipher, nettle_crypt_func *f,
size_t nlength, const uint8_t *nonce,
size_t alength, const uint8_t *adata,
size_t tlength, uint8_t *tag,
size_t mlength, uint8_t *dst, const uint8_t *src)
+{
- struct ccm_ctx ctx;
- ccm_set_nonce(&ctx, nlength, nonce, alength, mlength, tlength);
- ccm_update(&ctx, cipher, f, alength, adata);
- ccm_encrypt(&ctx, cipher, f, mlength, dst, src);
- ccm_digest(&ctx, cipher, f, tlength, tag);
+}
I think this function should append the tag to the ciphertext (assuming ccm is specified as an aead with a single output string?).
CCM is indeed specified as an AEAD function with a single output string, for example, RFC 5166 specifies that the ciphertext is always exactly 16 bytes longer than the plaintext, so this might be a good way to simplify the function call API.
+void +ccm_decrypt_message(void *cipher, nettle_crypt_func *f,
size_t nlength, const uint8_t *nonce,
size_t alength, const uint8_t *adata,
size_t tlength, uint8_t *tag,
size_t mlength, uint8_t *dst, const uint8_t *src)
+{
- struct ccm_ctx ctx;
- ccm_set_nonce(&ctx, nlength, nonce, alength, mlength, tlength);
- ccm_update(&ctx, cipher, f, alength, adata);
- ccm_decrypt(&ctx, cipher, f, mlength, dst, src);
- ccm_digest(&ctx, cipher, f, tlength, tag);
+}
I think this function should have a tag *input* (possibly reading it at te end of the cryptotext), compare it to the tag it computes, and return 1 on success, 0 for failure.
If the tag is appended to the cryptotext, I'm not sure if the mlength should be the message length with or without the tag (i.e., the length of the clear text message, or of the encrypted and authenticated message).
In the language of the CCM publications, mlen is always the length of the plaintext message. clen would be the length of the ciphertext, and can always be determined by: clen = mlen + tlen
Maybe it's best to let it be the length of the clear text message, same as passed to ccm_encrypt_message. In any case, the caller must be aware of both lengths.
Generally, I would prefer that the length provided should be the length of data that actually gets written (ie: ciphertext in this case). If a naive programmer using this API just passes buffer size as a sizeof() they might miss that the encrypt function would write passed the end of the buffer and cause an overflow.
One *could* pass both message length, and derive the tag length as the difference. But I'm afraid that style won't generalize nicely to other aead algorithms.
I didn't see any similar functions for the EAX or CGM modes, so I'm not sure that we really need to be concerned with breaking a precedent here.
diff --git a/ccm.h b/ccm.h new file mode 100644 index 0000000..76b4cc4 +/* Per-message state */ +struct ccm_ctx {
- union nettle_block16 ctr; /* Counter for CTR encryption. */
- union nettle_block16 tag; /* CBC-MAC message tag. */
- uint64_t alen; /* Length of adata set during the nonce generation. */
- int blen; /* <0 on init or # of bytes since the last aligned block */
+};
In nettle, length is usually not abbreviated to "len". If negative blen values can be eliminated, it should be changed to unsigned.
I'll change the names accordingly with the next patch.
The negative value of blen is currently only used as a special value to flag the first time that ccm_update() gets called so that we can encrypt the IV to the CBC-MAC (B0) and generate the L(a). These operations could be moved into ccm_set_nonce(), provided that ccm_set_nonce() is also provided with the cipher encrypt function.
--- /dev/null +++ b/testsuite/ccm-test.c
- /* Ensure we get the same answers using the all-in-one API. */
- if (repeat <= 1) {
- memset(en_data, 0, len); memset(de_data, 0, len);
- memset(en_digest, 0, tlen); memset(de_digest, 0, tlen);
- ccm_encrypt_message(ctx, cipher->encrypt, nonce->length, nonce->data,
authdata->length, authdata->data, tlen, en_digest, len, en_data, cleartext->data);
- ccm_decrypt_message(ctx, cipher->encrypt, nonce->length, nonce->data,
authdata->length, authdata->data, tlen, de_digest, len, de_data, ciphertext->data);
If the all-in-one interface is changed as suggested above, adding a return value for ccm_decrypt_message, one should also check that ccm_decrypt_message returns 1 for the correct data, and 0 if any of message, adata or or tag is corrupted.
Of course, I'll make sure that any changes to the API will be tested in the ccm-test program.
Cheers, Owen
Owen Kirby osk@exegin.com writes:
The Input to the CBC-MAC used in CCM mode takes the form: L(adata) | adata | padding | plaintext | padding
[...]
In other words, blen is the length of data input to the CBC-MAC modulus the block size.
[...]
Once we find the end of the adata (this is currently done on the first call to ccm_encrypt() or ccm_decrypt()), we need to insert the padding before the plaintext, which is what ccm_pad() does.
Thanks for the explanations. Might make sense to add a comment saying that when ccm_pad is called from _encrypt/_decrypt, all but the first calls are always nops.
If the context kept track of the amount of message data processed, it would be clearer to do something like if (ctx->processed_msg_data == 0) ccm_pad(), but it's not worth adding an additional counter to the context only for this purpose.
And implicit signalling end of adata by the first call to _encrypt/_decrypt (or directly to _digest, in case of an empty message) is the convention used for other aead algorithms in nettle.
Since the IV only contains a single bit that indicates whether adata exists at all, in theory the alength parameter could be omitted from set_nonce() entirely and then handled in ccm_update(), which is what this check is doing.
This is more or less an artifact of an attempt to support the AEAD API. Note that if you call ccm_set_nonce() with alength==0, and then pass the entire adata to ccm_update(), you would still get the correct authentication tag and ciphertext because of this special check on alen.
I think one should choose to either require alength to be passed to set_nonce, and drop support for the usage above. Or restrict the api to allow only a single call to ccm_update, and then drop the alength argument from set_nonce. And I think allowing multiple calls to ccm_update seems desirable, so I'd prefer the first option. Do you agree?
On Sat, Mar 15, 2014 at 12:07 AM, Niels Möller nisse@lysator.liu.se wrote:
Is it possible to move this initial processing to ccm_set_nonce? The alength *is* known there, and that would let you eliminate the ctx->blen < 0 cases, and maybe you could eliminate the alen state variable too (or keep it for sanity checking only).
Yes, that could be done, but this operation requires the use of the cipher encrypt function, which would need to be added to the set_nonce() API.
I think it's fine to have set_nonce call the encrypt function. chacha_poly1305_set_nonce does something a bit similar (but with fixed algorithms so no function pointers passed around).
And in general, nettle applications are expected to call the appropriate _set_key function *before* calling _set_nonce, so there is little point in allowing _set_nonce first for ccm.
Yes, this was a bit of a judgement call, whether it was uglier to store the nonce length in the ctx, or to parse it out of the flags byte of the counter. There are other possible ways to do this, but they all require extra storage in the ctx, which I was hoping to avoid.
I see. Your choice makes sense to me.
CCM is indeed specified as an AEAD function with a single output string, for example, RFC 5166 specifies that the ciphertext is always exactly 16 bytes longer than the plaintext, so this might be a good way to simplify the function call API.
Then the all-in-one encrypt function should have a single output, formatted accordingly. And the decrypt function should accept the same format as input.
About the tag length, do other protocols or applications use shorter tag length with ccm? The all-in-one-functions should aim to be easy to use, and they don't need to be fully general (since applications with special needs can always call the more general and lower-level functions). *If* almost all potential users of the all-in-one-functions use tag length 16, we might consider restricting the all-in-one functions to always use this size, and then drop the taglength argument.
Generally, I would prefer that the length provided should be the length of data that actually gets written (ie: ciphertext in this case).
I think that's a reasonable guideline. Then, the length arguments should be clen for ccm_encrypt_message, and mlen for ccm_decrypt_message.
I didn't see any similar functions for the EAX or CGM modes, so I'm not sure that we really need to be concerned with breaking a precedent here.
Similar all-in-one functions for other aead algorithms are on the roadmap, but not yet implemented. So when designing the interface for ccm, we should try to avoid that coming interface design for other aead algorithms have to choose between, on one hand, beauty, and on the other hand, consistency with ccm.
The negative value of blen is currently only used as a special value to flag the first time that ccm_update() gets called so that we can encrypt the IV to the CBC-MAC (B0) and generate the L(a). These operations could be moved into ccm_set_nonce(), provided that ccm_set_nonce() is also provided with the cipher encrypt function.
I think moving these operations will be an improvement.
Regards, /Niels
nettle-bugs@lists.lysator.liu.se