symm/ccm.h, symm/ccm-def.h: Implement the CCM authenticated encryption mode.
[catacomb] / symm / ccm.h
diff --git a/symm/ccm.h b/symm/ccm.h
new file mode 100644 (file)
index 0000000..ebbcc42
--- /dev/null
@@ -0,0 +1,327 @@
+/* -*-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