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_paramsok@ --- *
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 -------------------------------------------------*/