| 1 | /* -*-c-*- |
| 2 | * |
| 3 | * The CCM authenticated-encryption mode |
| 4 | * |
| 5 | * (c) 2017 Straylight/Edgeware |
| 6 | */ |
| 7 | |
| 8 | /*----- Licensing notice --------------------------------------------------* |
| 9 | * |
| 10 | * This file is part of Catacomb. |
| 11 | * |
| 12 | * Catacomb is free software; you can redistribute it and/or modify |
| 13 | * it under the terms of the GNU Library General Public License as |
| 14 | * published by the Free Software Foundation; either version 2 of the |
| 15 | * License, or (at your option) any later version. |
| 16 | * |
| 17 | * Catacomb is distributed in the hope that it will be useful, |
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 20 | * GNU Library General Public License for more details. |
| 21 | * |
| 22 | * You should have received a copy of the GNU Library General Public |
| 23 | * License along with Catacomb; if not, write to the Free |
| 24 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
| 25 | * MA 02111-1307, USA. |
| 26 | */ |
| 27 | |
| 28 | /*----- Notes on CCM ------------------------------------------------------* |
| 29 | * |
| 30 | * The name is short for `Counter with CBC-MAC'. CCM was designed in 2002 by |
| 31 | * Russ Housley, Doug Whiting, and Niels Ferguson to be a patent-free |
| 32 | * alternative to Rogaway's OCB, and is specified by NIST in SP800-38C. It's |
| 33 | * a classic two-pass authenticated encryption scheme, so it needs two |
| 34 | * blockcipher applications per message block. |
| 35 | * |
| 36 | * Unfortunately, CCM is rather annoying in actual use. The internals |
| 37 | * involve quite a lot of fiddly framing, which I've had to generalize for |
| 38 | * block sizes other than 128 bits, but that's not exposed beyond the API. |
| 39 | * (This does mean that it's rather unlikely that Catacomb's CCM will |
| 40 | * interoperate with anyone else's when using a blockcipher with a block size |
| 41 | * other than 128 bits.) |
| 42 | * |
| 43 | * More problematically: |
| 44 | * |
| 45 | * * The mode requires that callers precommit to the header, message, and |
| 46 | * tag sizes before commencing processing. If you don't know these in |
| 47 | * advance then you can't use CCM. |
| 48 | * |
| 49 | * * The mode requires that callers present all of the header data before |
| 50 | * encrypting the message. |
| 51 | * |
| 52 | * * The header data processing is dependent on the nonce (and the message |
| 53 | * and tag lengths), so it's not possible to preprocess a constant prefix |
| 54 | * of the header. |
| 55 | * |
| 56 | * * There's an uncomfortable tradeoff between nonce length and message |
| 57 | * length because the counter input holds both in separate fields, with a |
| 58 | * variably-positioned split between them. |
| 59 | * |
| 60 | * The implementation is very picky and will abort if you get things wrong. |
| 61 | */ |
| 62 | |
| 63 | #ifndef CATACOMB_CCM_H |
| 64 | #define CATACOMB_CCM_H |
| 65 | |
| 66 | #ifdef __cplusplus |
| 67 | extern "C" { |
| 68 | #endif |
| 69 | |
| 70 | /*----- Header files ------------------------------------------------------*/ |
| 71 | |
| 72 | #include <stddef.h> |
| 73 | |
| 74 | #include <mLib/bits.h> |
| 75 | #include <mLib/buf.h> |
| 76 | |
| 77 | #ifndef CATACOMB_GAEAD_H |
| 78 | # include "gaead.h" |
| 79 | #endif |
| 80 | |
| 81 | /*----- Common machinery -------------------------------------------------*/ |
| 82 | |
| 83 | typedef struct ccm_params { |
| 84 | unsigned long hsz, msz; /* AAD and message lengths */ |
| 85 | unsigned bsz, nsz, tsz; /* Block, nonce and tag length */ |
| 86 | } ccm_params; |
| 87 | |
| 88 | enum { CCMST_AAD, CCMST_MSG }; |
| 89 | |
| 90 | /* Minimum and maximum nonce lengths. |
| 91 | * |
| 92 | * Let the block size be %$N$% bytes, and let %$q$% be the length-of-the- |
| 93 | * length of the messaage. The nonce length is not encoded directly; rather, |
| 94 | * it's what's left after the flags bytes and message length fields have been |
| 95 | * allocated. |
| 96 | * |
| 97 | * The maximum is always %$N - 3$%. If %$N \le 16$%, then there is one byte |
| 98 | * used for flags, and at least two bytes for the message length/counter: |
| 99 | * (since %$q$% is encoded in a 3-bit field as %$q - 1$%, %$q = 0$% cannot be |
| 100 | * encoded and the encoding zero, for %$q = 1$%, is reserved. If %$N > 16$ |
| 101 | * then there are two flags bytes, but %$q$% is encoded directly, so only |
| 102 | * %$q = 0$% is reserved. |
| 103 | * |
| 104 | * The minimum is more complicated. If %$N \le 16$% then we must have %$q |
| 105 | * \le 8$%; with one flags byte, this leaves at least %$\max\{ 0, N - 9 \}$% |
| 106 | * bytes for the nonce. When %$N = 8$% this is zero, but when %$N = 16$% |
| 107 | * this is 7. When %$N > 16$%, there are two flags bits, but %$q \le 127$% |
| 108 | * (since %$q$%) is encoded directly: thus the nonce may be empty if |
| 109 | * %$16 < N \le 129$%, and otherwise must be at least %$N - 129$% bytes. |
| 110 | */ |
| 111 | #define CCM_NSZMIN(PRE) (PRE##_BLKSZ == 16 ? 7 : \ |
| 112 | PRE##_BLKSZ <= 129 ? 0 : \ |
| 113 | PRE##_BLKSZ - 129) |
| 114 | #define CCM_NSZMAX(PRE) (PRE##_BLKSZ - 3) |
| 115 | |
| 116 | /* Minimum and maximum tag lengths. |
| 117 | * |
| 118 | * This is even more exasperating. Again, let the block size be %$N$% bytes; |
| 119 | * let %$t$% be the tag length. |
| 120 | * |
| 121 | * When %$N = 16$%, the tag length is encoded as %$t/2 - 1$% in a three-bit |
| 122 | * field, and the encoding zero is reserved. (The security of the scheme |
| 123 | * depends on this reservation to disambiguate MAC header blocks from |
| 124 | * counters; I'd have used the remaining flag bit.) Anyway, this leaves |
| 125 | * %$1 \le t/2 - 1 \le 7$%, so we must have %$4 \le t \le 16$% with %$t$% |
| 126 | * even. |
| 127 | * |
| 128 | * When %$N = 8$%, the tag length is encoded in three bits as %$t - 1$%; |
| 129 | * again, the zero encoding is reserved. This leaves %$2 \le t \le 8$%. |
| 130 | * |
| 131 | * Finally, when %$N \ge 16$%, the tag length is encoded directly in a |
| 132 | * seven-bit field. The zero encoding is still reserved, so we have |
| 133 | * %$1 \le t \le \min \{ N, 127 \}$%. |
| 134 | */ |
| 135 | #define CCM_TSZMIN(PRE) (PRE##_BLKSZ == 8 ? 2 : \ |
| 136 | PRE##_BLKSZ == 16 ? 4 : \ |
| 137 | 1) |
| 138 | #define CCM_TSZMAX(PRE) (PRE##_BLKSZ <= 127 ? PRE##_BLKSZ : 127) |
| 139 | |
| 140 | /*----- Macros ------------------------------------------------------------*/ |
| 141 | |
| 142 | /* --- @CCM_DECL@ --- * |
| 143 | * |
| 144 | * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher |
| 145 | * |
| 146 | * Use: Creates declarations for CCM authenticated-encryption mode. |
| 147 | */ |
| 148 | |
| 149 | #define CCM_DECL(PRE, pre) \ |
| 150 | \ |
| 151 | typedef struct pre##_ccmctx { \ |
| 152 | /* The buffer is split into two portions during encryption/ \ |
| 153 | * decryption. The first N octets hold a chunk of plaintext, which \ |
| 154 | * will be fed into the CBC-MAC calculation; the remaining BLKSZ - N \ |
| 155 | * octets hold E_K(C), which is the XOR mask to apply to the \ |
| 156 | * plaintext or ciphertext. \ |
| 157 | */ \ |
| 158 | pre##_ctx k; /* Underlying key */ \ |
| 159 | ccm_params p; /* CCM parameters */ \ |
| 160 | unsigned long i; /* Current position in bytes */ \ |
| 161 | unsigned st; /* Current state */ \ |
| 162 | uint32 c[PRE##_BLKSZ/4]; /* Current counter value */ \ |
| 163 | uint32 a[PRE##_BLKSZ/4]; /* CBC-MAC accumulator */ \ |
| 164 | uint32 s0[PRE##_BLKSZ/4]; /* Mask for MAC tag */ \ |
| 165 | octet b[PRE##_BLKSZ]; /* AAD or msg/mask buffer */ \ |
| 166 | unsigned off; /* Crossover point in buffer */ \ |
| 167 | } pre##_ccmctx; \ |
| 168 | \ |
| 169 | extern const octet pre##_ccmnoncesz[], pre##_ccmtagsz[]; \ |
| 170 | \ |
| 171 | /* --- @pre_ccminit@ --- * \ |
| 172 | * \ |
| 173 | * Arguments: @pre_ccmctx *aad@ = pointer to CCM context \ |
| 174 | * @const pre_ctx *k@ = pointer to key material \ |
| 175 | * @const void *n@ = pointer to nonce \ |
| 176 | * @size_t nsz@ = size of the nonce \ |
| 177 | * @size_t hsz@ = size of the AAD \ |
| 178 | * @size_t msz@ = size of the message/ciphertext \ |
| 179 | * @size_t tsz@ = size of the tag to produce \ |
| 180 | * \ |
| 181 | * Returns: Zero on success; nonzero if the parameters are invalid. \ |
| 182 | * \ |
| 183 | * Use: Initialize an CCM operation context with a given key. \ |
| 184 | * \ |
| 185 | * The original key needn't be kept around any more. \ |
| 186 | */ \ |
| 187 | \ |
| 188 | extern int pre##_ccminit(pre##_ccmctx */*ctx*/, \ |
| 189 | const pre##_ctx */*k*/, \ |
| 190 | const void */*n*/, size_t /*nsz*/, \ |
| 191 | size_t /*hsz*/, size_t /*msz*/, \ |
| 192 | size_t /*tsz*/); \ |
| 193 | \ |
| 194 | /* --- @pre_ccmreinit@ --- * \ |
| 195 | * \ |
| 196 | * Arguments: @pre_ccmctx *ctx@ = pointer to CCM context \ |
| 197 | * @const void *n@ = pointer to nonce \ |
| 198 | * @size_t nsz@ = size of nonce \ |
| 199 | * @size_t hsz@ = size of the AAD \ |
| 200 | * @size_t msz@ = size of the message/ciphertext \ |
| 201 | * @size_t tsz@ = size of the tag to produce \ |
| 202 | * \ |
| 203 | * Returns: Zero on success; nonzero if the parameters are invalid. \ |
| 204 | * \ |
| 205 | * Use: Reinitialize an CCM operation context, changing the \ |
| 206 | * nonce and/or other parameters. \ |
| 207 | */ \ |
| 208 | \ |
| 209 | extern int pre##_ccmreinit(pre##_ccmctx */*ctx*/, \ |
| 210 | const void */*n*/, size_t /*nsz*/, \ |
| 211 | size_t /*hsz*/, size_t /*msz*/, \ |
| 212 | size_t /*tsz*/); \ |
| 213 | \ |
| 214 | /* --- @pre_ccmaadhash@ --- * \ |
| 215 | * \ |
| 216 | * Arguments: @pre_ccmctx *ctx@ = pointer to AAD context \ |
| 217 | * @const void *p@ = pointer to AAD material \ |
| 218 | * @size_t sz@ = length of AAD material \ |
| 219 | * \ |
| 220 | * Returns: --- \ |
| 221 | * \ |
| 222 | * Use: Feeds AAD into the context. This must be done before \ |
| 223 | * any of the message/ciphertext is processed because CCM \ |
| 224 | * is really annoying like that. \ |
| 225 | */ \ |
| 226 | \ |
| 227 | extern void pre##_ccmaadhash(pre##_ccmctx */*ctx*/, \ |
| 228 | const void */*p*/, size_t /*sz*/); \ |
| 229 | \ |
| 230 | /* --- @pre_ccmencrypt@ --- * \ |
| 231 | * \ |
| 232 | * Arguments: @pre_ccmctx *ctx@ = pointer to CCM operation context \ |
| 233 | * @const void *src@ = pointer to plaintext message chunk \ |
| 234 | * @size_t sz@ = size of the plaintext \ |
| 235 | * @buf *dst@ = a buffer to write the ciphertext to \ |
| 236 | * \ |
| 237 | * Returns: Zero on success; @-1@ on failure. \ |
| 238 | * \ |
| 239 | * Use: Encrypts a chunk of a plaintext message, writing a \ |
| 240 | * chunk of ciphertext to the output buffer and updating \ |
| 241 | * the operation state. \ |
| 242 | * \ |
| 243 | * For CCM, we always write a ciphertext chunk the same \ |
| 244 | * size as the plaintext. The messing about with @buf@ \ |
| 245 | * objects makes the interface consistent with other AEAD \ |
| 246 | * schemes which can't do this. \ |
| 247 | */ \ |
| 248 | \ |
| 249 | extern int pre##_ccmencrypt(pre##_ccmctx */*ctx*/, \ |
| 250 | const void */*src*/, size_t /*sz*/, \ |
| 251 | buf */*dst*/); \ |
| 252 | \ |
| 253 | /* --- @pre_ccmdecrypt@ --- * \ |
| 254 | * \ |
| 255 | * Arguments: @pre_ccmctx *ctx@ = pointer to CCM operation context \ |
| 256 | * @const void *src@ = pointer to ciphertext message chunk \ |
| 257 | * @size_t sz@ = size of the ciphertext \ |
| 258 | * @buf *dst@ = a buffer to write the plaintext to \ |
| 259 | * \ |
| 260 | * Returns: Zero on success; @-1@ on failure. \ |
| 261 | * \ |
| 262 | * Use: Decrypts a chunk of a ciphertext message, writing a \ |
| 263 | * chunk of plaintext to the output buffer and updating \ |
| 264 | * the operation state. \ |
| 265 | * \ |
| 266 | * For CCM, we always write a plaintext chunk the same \ |
| 267 | * size as the ciphertext. The messing about with @buf@ \ |
| 268 | * objects makes the interface consistent with other AEAD \ |
| 269 | * schemes which can't do this. \ |
| 270 | */ \ |
| 271 | \ |
| 272 | extern int pre##_ccmdecrypt(pre##_ccmctx */*ctx*/, \ |
| 273 | const void */*src*/, size_t /*sz*/, \ |
| 274 | buf */*dst*/); \ |
| 275 | \ |
| 276 | /* --- @pre_ccmencryptdone@ --- * \ |
| 277 | * \ |
| 278 | * Arguments: @pre_ccmctx *ctx@ = pointer to an CCM context \ |
| 279 | * @buf *dst@ = buffer for remaining ciphertext \ |
| 280 | * @void *tag@ = where to write the tag \ |
| 281 | * @size_t tsz@ = length of tag to store \ |
| 282 | * \ |
| 283 | * Returns: Zero on success; @-1@ on failure. \ |
| 284 | * \ |
| 285 | * Use: Completes an CCM encryption operation. The @aad@ \ |
| 286 | * pointer may be null if there is no additional \ |
| 287 | * authenticated data. CCM doesn't buffer ciphertext, but \ |
| 288 | * the output buffer is provided anyway for consistency \ |
| 289 | * with other AEAD schemes which don't have this property; \ |
| 290 | * the function will fail if the output buffer is broken. \ |
| 291 | */ \ |
| 292 | \ |
| 293 | extern int pre##_ccmencryptdone(pre##_ccmctx */*ctx*/, buf */*dst*/, \ |
| 294 | void */*tag*/, size_t /*tsz*/); \ |
| 295 | \ |
| 296 | /* --- @pre_ccmdecryptdone@ --- * \ |
| 297 | * \ |
| 298 | * Arguments: @pre_ccmctx *ctx@ = pointer to an CCM context \ |
| 299 | * @buf *dst@ = buffer for remaining plaintext \ |
| 300 | * @const void *tag@ = tag to verify \ |
| 301 | * @size_t tsz@ = length of tag \ |
| 302 | * \ |
| 303 | * Returns: @+1@ for complete success; @0@ if tag verification \ |
| 304 | * failed; @-1@ for other kinds of errors. \ |
| 305 | * \ |
| 306 | * Use: Completes an CCM decryption operation. The @aad@ \ |
| 307 | * pointer may be null if there is no additional \ |
| 308 | * authenticated data. CCM doesn't buffer plaintext, but \ |
| 309 | * the output buffer is provided anyway for consistency \ |
| 310 | * with other AEAD schemes which don't have this property; \ |
| 311 | * the function will fail if the output buffer is broken. \ |
| 312 | */ \ |
| 313 | \ |
| 314 | extern int pre##_ccmdecryptdone(pre##_ccmctx */*ctx*/, buf */*dst*/, \ |
| 315 | const void */*tag*/, size_t /*tsz*/); \ |
| 316 | \ |
| 317 | /* --- Generic AEAD interface --- */ \ |
| 318 | \ |
| 319 | extern const gcaead pre##_ccm; |
| 320 | |
| 321 | /*----- That's all, folks -------------------------------------------------*/ |
| 322 | |
| 323 | #ifdef __cplusplus |
| 324 | } |
| 325 | #endif |
| 326 | |
| 327 | #endif |