--- /dev/null
+/* -*-c-*-
+ *
+ * The CCM authenticated-encryption mode
+ *
+ * (c) 2017 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Notes on CCM ------------------------------------------------------*
+ *
+ * The name is short for `Counter with CBC-MAC'. CCM was designed in 2002 by
+ * Russ Housley, Doug Whiting, and Niels Ferguson to be a patent-free
+ * alternative to Rogaway's OCB, and is specified by NIST in SP800-38C. It's
+ * a classic two-pass authenticated encryption scheme, so it needs two
+ * blockcipher applications per message block.
+ *
+ * Unfortunately, CCM is rather annoying in actual use. The internals
+ * involve quite a lot of fiddly framing, which I've had to generalize for
+ * block sizes other than 128 bits, but that's not exposed beyond the API.
+ * (This does mean that it's rather unlikely that Catacomb's CCM will
+ * interoperate with anyone else's when using a blockcipher with a block size
+ * other than 128 bits.)
+ *
+ * More problematically:
+ *
+ * * The mode requires that callers precommit to the header, message, and
+ * tag sizes before commencing processing. If you don't know these in
+ * advance then you can't use CCM.
+ *
+ * * The mode requires that callers present all of the header data before
+ * encrypting the message.
+ *
+ * * The header data processing is dependent on the nonce (and the message
+ * and tag lengths), so it's not possible to preprocess a constant prefix
+ * of the header.
+ *
+ * * There's an uncomfortable tradeoff between nonce length and message
+ * length because the counter input holds both in separate fields, with a
+ * variably-positioned split between them.
+ *
+ * The implementation is very picky and will abort if you get things wrong.
+ */
+
+#ifndef CATACOMB_CCM_H
+#define CATACOMB_CCM_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+#include <mLib/buf.h>
+
+#ifndef CATACOMB_GAEAD_H
+# include "gaead.h"
+#endif
+
+/*----- Common machinery -------------------------------------------------*/
+
+typedef struct ccm_params {
+ unsigned long hsz, msz; /* AAD and message lengths */
+ unsigned bsz, nsz, tsz; /* Block, nonce and tag length */
+} ccm_params;
+
+enum { CCMST_AAD, CCMST_MSG };
+
+/* Minimum and maximum nonce lengths.
+ *
+ * Let the block size be %$N$% bytes, and let %$q$% be the length-of-the-
+ * length of the messaage. The nonce length is not encoded directly; rather,
+ * it's what's left after the flags bytes and message length fields have been
+ * allocated.
+ *
+ * The maximum is always %$N - 3$%. If %$N \le 16$%, then there is one byte
+ * used for flags, and at least two bytes for the message length/counter:
+ * (since %$q$% is encoded in a 3-bit field as %$q - 1$%, %$q = 0$% cannot be
+ * encoded and the encoding zero, for %$q = 1$%, is reserved. If %$N > 16$
+ * then there are two flags bytes, but %$q$% is encoded directly, so only
+ * %$q = 0$% is reserved.
+ *
+ * The minimum is more complicated. If %$N \le 16$% then we must have %$q
+ * \le 8$%; with one flags byte, this leaves at least %$\max\{ 0, N - 9 \}$%
+ * bytes for the nonce. When %$N = 8$% this is zero, but when %$N = 16$%
+ * this is 7. When %$N > 16$%, there are two flags bits, but %$q \le 127$%
+ * (since %$q$%) is encoded directly: thus the nonce may be empty if
+ * %$16 < N \le 129$%, and otherwise must be at least %$N - 129$% bytes.
+ */
+#define CCM_NSZMIN(PRE) (PRE##_BLKSZ == 16 ? 7 : \
+ PRE##_BLKSZ <= 129 ? 0 : \
+ PRE##_BLKSZ - 129)
+#define CCM_NSZMAX(PRE) (PRE##_BLKSZ - 3)
+
+/* Minimum and maximum tag lengths.
+ *
+ * This is even more exasperating. Again, let the block size be %$N$% bytes;
+ * let %$t$% be the tag length.
+ *
+ * When %$N = 16$%, the tag length is encoded as %$t/2 - 1$% in a three-bit
+ * field, and the encoding zero is reserved. (The security of the scheme
+ * depends on this reservation to disambiguate MAC header blocks from
+ * counters; I'd have used the remaining flag bit.) Anyway, this leaves
+ * %$1 \le t/2 - 1 \le 7$%, so we must have %$4 \le t \le 16$% with %$t$%
+ * even.
+ *
+ * When %$N = 8$%, the tag length is encoded in three bits as %$t - 1$%;
+ * again, the zero encoding is reserved. This leaves %$2 \le t \le 8$%.
+ *
+ * Finally, when %$N \ge 16$%, the tag length is encoded directly in a
+ * seven-bit field. The zero encoding is still reserved, so we have
+ * %$1 \le t \le \min \{ N, 127 \}$%.
+ */
+#define CCM_TSZMIN(PRE) (PRE##_BLKSZ == 8 ? 2 : \
+ PRE##_BLKSZ == 16 ? 4 : \
+ 1)
+#define CCM_TSZMAX(PRE) (PRE##_BLKSZ <= 127 ? PRE##_BLKSZ : 127)
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @CCM_DECL@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates declarations for CCM authenticated-encryption mode.
+ */
+
+#define CCM_DECL(PRE, pre) \
+ \
+typedef struct pre##_ccmctx { \
+ /* The buffer is split into two portions during encryption/ \
+ * decryption. The first N octets hold a chunk of plaintext, which \
+ * will be fed into the CBC-MAC calculation; the remaining BLKSZ - N \
+ * octets hold E_K(C), which is the XOR mask to apply to the \
+ * plaintext or ciphertext. \
+ */ \
+ pre##_ctx k; /* Underlying key */ \
+ ccm_params p; /* CCM parameters */ \
+ unsigned long i; /* Current position in bytes */ \
+ unsigned st; /* Current state */ \
+ uint32 c[PRE##_BLKSZ/4]; /* Current counter value */ \
+ uint32 a[PRE##_BLKSZ/4]; /* CBC-MAC accumulator */ \
+ uint32 s0[PRE##_BLKSZ/4]; /* Mask for MAC tag */ \
+ octet b[PRE##_BLKSZ]; /* AAD or msg/mask buffer */ \
+ unsigned off; /* Crossover point in buffer */ \
+} pre##_ccmctx; \
+ \
+extern const octet pre##_ccmnoncesz[], pre##_ccmtagsz[]; \
+ \
+/* --- @pre_ccminit@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *aad@ = pointer to CCM context \
+ * @const pre_ctx *k@ = pointer to key material \
+ * @const void *n@ = pointer to nonce \
+ * @size_t nsz@ = size of the nonce \
+ * @size_t hsz@ = size of the AAD \
+ * @size_t msz@ = size of the message/ciphertext \
+ * @size_t tsz@ = size of the tag to produce \
+ * \
+ * Returns: Zero on success; nonzero if the parameters are invalid. \
+ * \
+ * Use: Initialize an CCM operation context with a given key. \
+ * \
+ * The original key needn't be kept around any more. \
+ */ \
+ \
+extern int pre##_ccminit(pre##_ccmctx */*ctx*/, \
+ const pre##_ctx */*k*/, \
+ const void */*n*/, size_t /*nsz*/, \
+ size_t /*hsz*/, size_t /*msz*/, \
+ size_t /*tsz*/); \
+ \
+/* --- @pre_ccmreinit@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *ctx@ = pointer to CCM context \
+ * @const void *n@ = pointer to nonce \
+ * @size_t nsz@ = size of nonce \
+ * @size_t hsz@ = size of the AAD \
+ * @size_t msz@ = size of the message/ciphertext \
+ * @size_t tsz@ = size of the tag to produce \
+ * \
+ * Returns: Zero on success; nonzero if the parameters are invalid. \
+ * \
+ * Use: Reinitialize an CCM operation context, changing the \
+ * nonce and/or other parameters. \
+ */ \
+ \
+extern int pre##_ccmreinit(pre##_ccmctx */*ctx*/, \
+ const void */*n*/, size_t /*nsz*/, \
+ size_t /*hsz*/, size_t /*msz*/, \
+ size_t /*tsz*/); \
+ \
+/* --- @pre_ccmaadhash@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *ctx@ = pointer to AAD context \
+ * @const void *p@ = pointer to AAD material \
+ * @size_t sz@ = length of AAD material \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Feeds AAD into the context. This must be done before \
+ * any of the message/ciphertext is processed because CCM \
+ * is really annoying like that. \
+ */ \
+ \
+extern void pre##_ccmaadhash(pre##_ccmctx */*ctx*/, \
+ const void */*p*/, size_t /*sz*/); \
+ \
+/* --- @pre_ccmencrypt@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *ctx@ = pointer to CCM operation context \
+ * @const void *src@ = pointer to plaintext message chunk \
+ * @size_t sz@ = size of the plaintext \
+ * @buf *dst@ = a buffer to write the ciphertext to \
+ * \
+ * Returns: Zero on success; @-1@ on failure. \
+ * \
+ * Use: Encrypts a chunk of a plaintext message, writing a \
+ * chunk of ciphertext to the output buffer and updating \
+ * the operation state. \
+ * \
+ * For CCM, we always write a ciphertext chunk the same \
+ * size as the plaintext. The messing about with @buf@ \
+ * objects makes the interface consistent with other AEAD \
+ * schemes which can't do this. \
+ */ \
+ \
+extern int pre##_ccmencrypt(pre##_ccmctx */*ctx*/, \
+ const void */*src*/, size_t /*sz*/, \
+ buf */*dst*/); \
+ \
+/* --- @pre_ccmdecrypt@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *ctx@ = pointer to CCM operation context \
+ * @const void *src@ = pointer to ciphertext message chunk \
+ * @size_t sz@ = size of the ciphertext \
+ * @buf *dst@ = a buffer to write the plaintext to \
+ * \
+ * Returns: Zero on success; @-1@ on failure. \
+ * \
+ * Use: Decrypts a chunk of a ciphertext message, writing a \
+ * chunk of plaintext to the output buffer and updating \
+ * the operation state. \
+ * \
+ * For CCM, we always write a plaintext chunk the same \
+ * size as the ciphertext. The messing about with @buf@ \
+ * objects makes the interface consistent with other AEAD \
+ * schemes which can't do this. \
+ */ \
+ \
+extern int pre##_ccmdecrypt(pre##_ccmctx */*ctx*/, \
+ const void */*src*/, size_t /*sz*/, \
+ buf */*dst*/); \
+ \
+/* --- @pre_ccmencryptdone@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *ctx@ = pointer to an CCM context \
+ * @buf *dst@ = buffer for remaining ciphertext \
+ * @void *tag@ = where to write the tag \
+ * @size_t tsz@ = length of tag to store \
+ * \
+ * Returns: Zero on success; @-1@ on failure. \
+ * \
+ * Use: Completes an CCM encryption operation. The @aad@ \
+ * pointer may be null if there is no additional \
+ * authenticated data. CCM doesn't buffer ciphertext, but \
+ * the output buffer is provided anyway for consistency \
+ * with other AEAD schemes which don't have this property; \
+ * the function will fail if the output buffer is broken. \
+ */ \
+ \
+extern int pre##_ccmencryptdone(pre##_ccmctx */*ctx*/, buf */*dst*/, \
+ void */*tag*/, size_t /*tsz*/); \
+ \
+/* --- @pre_ccmdecryptdone@ --- * \
+ * \
+ * Arguments: @pre_ccmctx *ctx@ = pointer to an CCM context \
+ * @buf *dst@ = buffer for remaining plaintext \
+ * @const void *tag@ = tag to verify \
+ * @size_t tsz@ = length of tag \
+ * \
+ * Returns: @+1@ for complete success; @0@ if tag verification \
+ * failed; @-1@ for other kinds of errors. \
+ * \
+ * Use: Completes an CCM decryption operation. The @aad@ \
+ * pointer may be null if there is no additional \
+ * authenticated data. CCM doesn't buffer plaintext, but \
+ * the output buffer is provided anyway for consistency \
+ * with other AEAD schemes which don't have this property; \
+ * the function will fail if the output buffer is broken. \
+ */ \
+ \
+extern int pre##_ccmdecryptdone(pre##_ccmctx */*ctx*/, buf */*dst*/, \
+ const void */*tag*/, size_t /*tsz*/); \
+ \
+/* --- Generic AEAD interface --- */ \
+ \
+extern const gcaead pre##_ccm;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif