5 * (c) 2018 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
12 * Catacomb is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU Library General Public License as published
14 * by the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * Catacomb is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 /*----- Header files ------------------------------------------------------*/
33 /*----- MAC header and counter formatting ---------------------------------*
35 * CCM's most endearing feature is its complex formatting of the MAC
36 * initialization vector and counter blocks. This is only specified for
37 * 128-bit blocks, so I've made up formats for 64-, 192-, and 256-bit blocks.
38 * For completeness and ease of comparison, all of the encodings are defined
39 * here. Encoding of the rest of the MAC input data is common.
41 * The notation is taken from the definition of CCM in NIST SP800-38C.
43 * * [x]_w = encoding of x, as w bits
44 * * P = plaintext/ciphertext
45 * * p = length of P in octets
46 * * Q = [p]_{8q} = encoding of p
47 * * q = length of Q in octets
49 * * H = B_0 = MAC header block
50 * * C_i = the i-th counter block
51 * * t = length of tag in octets
53 * 128-bit blocks (SP800-38C, appendix A):
58 * Meaning 0 AAD? [t/2 - 1]_3 [q - 1]_3
60 * Then H = F || N || Q and C_i = 0^5 || [q - 1]_3 || N || [i]_{8q}.
62 * 64-bit blocks (new):
67 * Meaning 0 AAD? [t - 1]_3 [q - 1]_3
69 * Then H = F || N || Q and C_i = 0^5 || [q - 1]_3 || N || [i]_{8q}.
71 * (i.e., almost exactly the same, except that the tag no longer needs to be
72 * an even number of octets).
74 * n-bit blocks, for n > 128
76 * Let F be a 16-bit flags word:
79 * Meaning 0 [t]_7 AAD? [q]_7
81 * Then H = F || N || Q and C_i = 0^9 || [q - 1]_7 || N || [i]_{8q}.
84 /* --- @ccm_check@ --- *
86 * Arguments: @const ccm_params *p@ = pointer to parameters
88 * Returns: True (nonzero) if the parameters are OK; false (zero) if
91 * Use: Verify that the CCM parameters are acceptable.
94 int ccm_check(const ccm_params *p)
96 unsigned fsz = p->bsz <= 16 ? 1 : 2, q = p->bsz - p->nsz - fsz, i;
99 /* Check that the block size hasn't been bungled. */
100 if (p->bsz < 16 && p->bsz != 8) return (0);
102 /* The length-of-the-length must be representable, and its encoding must
103 * not be zero, since this is `reserved'. The small-block encoding stores
104 * %$q - 1$%, so we must have %$q \ge 2$%; the large-block encoding stores
105 * %$q$% directly, so only %$q = 0$% is forbidden.
107 if (p->nsz > p->bsz - fsz - (p->bsz <= 16 ? 2 : 1)) return (0);
108 if (q > (p->bsz <= 16 ? 8 : 127)) return (0);
110 /* Verify that the message length will fit in the space allotted. */
111 for (i = 1, msz = p->msz >> 8; msz; i++, msz >>= 8);
112 if (i > q) return (0);
114 /* The tag can't be larger than the block size. Also, it must be
115 * representable, and its encoding must not be zero, because otherwise it'd
116 * be possible for a MAC header block to look like a counter block. The
117 * tag encoding is fiddly: for 64-bit blocks, we store %$t - 1$%, so we
118 * must have %$t \ge 2$%; for 128-bit blocks, we store %$t/2 - 2$%, so
119 * we must have %$t \ge 4$% with %$t$% even; otherwise, we store %$t$%
120 * directly, so the only requirement is that %$t \ge 1$%.
122 if (p->tsz > p->bsz) return (0);
123 if (p->tsz < (p->bsz == 8 ? 2 : p->bsz == 16 ? 4 : 1)) return (0);
124 if (p->bsz == 16 && p->tsz%2 != 0) return (0);
126 /* All looks good. */
130 /* --- @ccm_fmthdr@ --- *
132 * Arguments: @const ccm_params *p@ = pointer to parameters
133 * @octet *b@ = block-size buffer to write header
134 * @const void *n@ = pointer to nonce
138 * Use: Format a MAC header block.
141 void ccm_fmthdr(const ccm_params *p, octet *b, const void *n)
143 size_t fsz = p->bsz <= 16 ? 1 : 2, q = p->bsz - p->nsz - fsz;
144 unsigned f0 = 0, f1 = 0;
147 /* Encode whether the AAD is empty. */
148 if (!p->hsz) /* do nothing */;
149 else if (p->bsz <= 16) f0 |= 0x40;
152 /* Encode the tag size. */
154 case 8: f0 |= (p->tsz - 1) << 3; break;
155 case 16: f0 |= (p->tsz - 2) << 2; break;
156 default: f0 |= p->tsz; break;
159 /* Encode the length-of-the-length. (This is the most bletcherous part of
162 if (p->bsz <= 16) f0 |= q - 1;
165 /* Insert the flags and nonce. */
166 b[0] = f0; memcpy(b + fsz, n, p->nsz);
167 if (p->bsz > 16) b[1] = f1;
169 /* Write the message length. */
170 for (i = 0, t = p->msz; i < q; i++, t >>= 8) b[p->bsz - i - 1] = U8(t);
173 /* --- @ccm_fmtctr@ --- *
175 * Arguments: @const ccm_params *p@ = pointer to parameters
176 * @octet *b@ = block-size buffer to write header
177 * @const void *n@ = pointer to nonce
181 * Use: Format an initial counter block.
184 void ccm_fmtctr(const ccm_params *p, octet *b, const void *n)
186 size_t fsz = p->bsz <= 16 ? 1 : 2, q = p->bsz - p->nsz - fsz;
187 unsigned f0 = 0, f1 = 0;
189 /* Encode the message length length. (Did I complain about this?) */
190 if (p->bsz <= 16) f0 |= q - 1;
193 /* Insert the flags and nonce. */
194 b[0] = f0; memcpy(b + fsz, n, p->nsz);
195 if (p->bsz > 16) b[1] = f1;
197 /* Zero out the initial counter. */
198 memset(b + fsz + p->nsz, 0, q);
201 /*----- That's all, folks -------------------------------------------------*/