Commit | Line | Data |
---|---|---|
55b6b722 MW |
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 |