1 1.6 jmcneill /* $NetBSD: aes_ccm.c,v 1.6 2021/10/17 14:45:45 jmcneill Exp $ */ 2 1.1 riastrad 3 1.1 riastrad /*- 4 1.1 riastrad * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 1.1 riastrad * All rights reserved. 6 1.1 riastrad * 7 1.1 riastrad * Redistribution and use in source and binary forms, with or without 8 1.1 riastrad * modification, are permitted provided that the following conditions 9 1.1 riastrad * are met: 10 1.1 riastrad * 1. Redistributions of source code must retain the above copyright 11 1.1 riastrad * notice, this list of conditions and the following disclaimer. 12 1.1 riastrad * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 riastrad * notice, this list of conditions and the following disclaimer in the 14 1.1 riastrad * documentation and/or other materials provided with the distribution. 15 1.1 riastrad * 16 1.1 riastrad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 riastrad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 riastrad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 riastrad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 riastrad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 riastrad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 riastrad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 riastrad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 riastrad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 riastrad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 riastrad * POSSIBILITY OF SUCH DAMAGE. 27 1.1 riastrad */ 28 1.1 riastrad 29 1.1 riastrad /* 30 1.1 riastrad * AES-CCM, as defined in: 31 1.1 riastrad * 32 1.1 riastrad * D. Whiting, R. Housley, and N. Ferguson, `Counter with CBC-MAC 33 1.1 riastrad * (CCM)', IETF RFC 3610, September 2003. 34 1.1 riastrad * https://tools.ietf.org/html/rfc3610 35 1.1 riastrad */ 36 1.1 riastrad 37 1.1 riastrad #include <sys/cdefs.h> 38 1.6 jmcneill __KERNEL_RCSID(1, "$NetBSD: aes_ccm.c,v 1.6 2021/10/17 14:45:45 jmcneill Exp $"); 39 1.1 riastrad 40 1.1 riastrad #include <sys/types.h> 41 1.1 riastrad #include <sys/param.h> 42 1.1 riastrad #include <sys/systm.h> 43 1.1 riastrad 44 1.1 riastrad #include <lib/libkern/libkern.h> 45 1.1 riastrad 46 1.1 riastrad #include <crypto/aes/aes.h> 47 1.1 riastrad #include <crypto/aes/aes_ccm.h> 48 1.2 riastrad #include <crypto/aes/aes_impl.h> 49 1.1 riastrad 50 1.1 riastrad static inline void 51 1.1 riastrad xor(uint8_t *x, const uint8_t *a, const uint8_t *b, size_t n) 52 1.1 riastrad { 53 1.1 riastrad 54 1.1 riastrad while (n --> 0) 55 1.1 riastrad *x++ = *a++ ^ *b++; 56 1.1 riastrad } 57 1.1 riastrad 58 1.1 riastrad /* RFC 3610, 2.2 Authentication */ 59 1.1 riastrad #define CCM_AFLAGS_ADATA __BIT(6) 60 1.1 riastrad #define CCM_AFLAGS_M __BITS(5,3) 61 1.1 riastrad #define CCM_AFLAGS_L __BITS(2,0) 62 1.1 riastrad 63 1.1 riastrad /* RFC 3610, 2.3 Encryption */ 64 1.1 riastrad #define CCM_EFLAGS_L __BITS(2,0) 65 1.1 riastrad 66 1.1 riastrad static void 67 1.1 riastrad aes_ccm_inc(struct aes_ccm *C) 68 1.1 riastrad { 69 1.4 riastrad uint8_t *ctr = C->authctr + 16; 70 1.1 riastrad 71 1.1 riastrad KASSERT(C->L == 2); 72 1.4 riastrad if (++ctr[15] == 0 && ++ctr[14] == 0) 73 1.1 riastrad panic("AES-CCM overflow"); 74 1.1 riastrad } 75 1.1 riastrad 76 1.1 riastrad static void 77 1.1 riastrad aes_ccm_zero_ctr(struct aes_ccm *C) 78 1.1 riastrad { 79 1.4 riastrad uint8_t *ctr = C->authctr + 16; 80 1.1 riastrad 81 1.1 riastrad KASSERT(C->L == 2); 82 1.4 riastrad ctr[14] = ctr[15] = 0; 83 1.1 riastrad } 84 1.1 riastrad 85 1.1 riastrad void 86 1.1 riastrad aes_ccm_init(struct aes_ccm *C, unsigned nr, const struct aesenc *enc, 87 1.1 riastrad unsigned L, unsigned M, 88 1.1 riastrad const uint8_t *nonce, unsigned noncelen, const void *ad, size_t adlen, 89 1.1 riastrad size_t mlen) 90 1.1 riastrad { 91 1.1 riastrad const uint8_t *adp = ad; 92 1.4 riastrad uint8_t *auth = C->authctr; 93 1.4 riastrad uint8_t *ctr = C->authctr + 16; 94 1.1 riastrad unsigned i; 95 1.1 riastrad 96 1.1 riastrad KASSERT(L == 2); 97 1.1 riastrad KASSERT(M % 2 == 0); 98 1.1 riastrad KASSERT(M >= 4); 99 1.1 riastrad KASSERT(M <= 16); 100 1.1 riastrad KASSERT(noncelen == 15 - L); 101 1.1 riastrad 102 1.1 riastrad C->enc = enc; 103 1.1 riastrad C->nr = nr; 104 1.1 riastrad C->L = L; 105 1.1 riastrad C->M = M; 106 1.1 riastrad C->mlen = C->mleft = mlen; 107 1.1 riastrad 108 1.1 riastrad /* Encode B0, the initial authenticated data block. */ 109 1.4 riastrad auth[0] = __SHIFTIN(adlen == 0 ? 0 : 1, CCM_AFLAGS_ADATA); 110 1.4 riastrad auth[0] |= __SHIFTIN((M - 2)/2, CCM_AFLAGS_M); 111 1.4 riastrad auth[0] |= __SHIFTIN(L - 1, CCM_AFLAGS_L); 112 1.4 riastrad memcpy(auth + 1, nonce, noncelen); 113 1.1 riastrad for (i = 0; i < L; i++, mlen >>= 8) { 114 1.1 riastrad KASSERT(i < 16 - 1 - noncelen); 115 1.4 riastrad auth[16 - i - 1] = mlen & 0xff; 116 1.1 riastrad } 117 1.4 riastrad aes_enc(enc, auth, auth, C->nr); 118 1.1 riastrad 119 1.1 riastrad /* Process additional authenticated data, if any. */ 120 1.1 riastrad if (adlen) { 121 1.1 riastrad /* Encode the length according to the table on p. 4. */ 122 1.1 riastrad if (adlen < 0xff00) { 123 1.4 riastrad auth[0] ^= adlen >> 8; 124 1.4 riastrad auth[1] ^= adlen; 125 1.1 riastrad i = 2; 126 1.1 riastrad } else if (adlen < 0xffffffff) { 127 1.4 riastrad auth[0] ^= 0xff; 128 1.4 riastrad auth[1] ^= 0xfe; 129 1.4 riastrad auth[2] ^= adlen >> 24; 130 1.4 riastrad auth[3] ^= adlen >> 16; 131 1.4 riastrad auth[4] ^= adlen >> 8; 132 1.4 riastrad auth[5] ^= adlen; 133 1.1 riastrad i = 6; 134 1.1 riastrad #if SIZE_MAX > 0xffffffffU 135 1.1 riastrad } else { 136 1.1 riastrad CTASSERT(SIZE_MAX <= 0xffffffffffffffff); 137 1.4 riastrad auth[0] ^= 0xff; 138 1.4 riastrad auth[1] ^= 0xff; 139 1.4 riastrad auth[2] ^= adlen >> 56; 140 1.4 riastrad auth[3] ^= adlen >> 48; 141 1.4 riastrad auth[4] ^= adlen >> 40; 142 1.4 riastrad auth[5] ^= adlen >> 32; 143 1.4 riastrad auth[6] ^= adlen >> 24; 144 1.4 riastrad auth[7] ^= adlen >> 16; 145 1.4 riastrad auth[8] ^= adlen >> 8; 146 1.4 riastrad auth[9] ^= adlen; 147 1.1 riastrad i = 10; 148 1.1 riastrad #endif 149 1.1 riastrad } 150 1.1 riastrad 151 1.1 riastrad /* Fill out the partial block if we can, and encrypt. */ 152 1.4 riastrad xor(auth + i, auth + i, adp, MIN(adlen, 16 - i)); 153 1.1 riastrad adp += MIN(adlen, 16 - i); 154 1.1 riastrad adlen -= MIN(adlen, 16 - i); 155 1.4 riastrad aes_enc(enc, auth, auth, C->nr); 156 1.1 riastrad 157 1.1 riastrad /* If there was anything more, process 16 bytes at a time. */ 158 1.2 riastrad if (adlen - (adlen % 16)) { 159 1.2 riastrad aes_cbcmac_update1(enc, adp, adlen - (adlen % 16), 160 1.4 riastrad auth, C->nr); 161 1.2 riastrad adlen %= 16; 162 1.1 riastrad } 163 1.1 riastrad 164 1.1 riastrad /* 165 1.1 riastrad * If there's anything at the end, enter it in (padded 166 1.1 riastrad * with zeros, which is a no-op) and process it. 167 1.1 riastrad */ 168 1.1 riastrad if (adlen) { 169 1.4 riastrad xor(auth, auth, adp, adlen); 170 1.4 riastrad aes_enc(enc, auth, auth, C->nr); 171 1.1 riastrad } 172 1.1 riastrad } 173 1.1 riastrad 174 1.1 riastrad /* Set up the AES input for AES-CTR encryption. */ 175 1.4 riastrad ctr[0] = __SHIFTIN(L - 1, CCM_EFLAGS_L); 176 1.4 riastrad memcpy(ctr + 1, nonce, noncelen); 177 1.4 riastrad memset(ctr + 1 + noncelen, 0, 16 - 1 - noncelen); 178 1.1 riastrad 179 1.1 riastrad /* Start on a block boundary. */ 180 1.1 riastrad C->i = 0; 181 1.1 riastrad } 182 1.1 riastrad 183 1.1 riastrad void 184 1.1 riastrad aes_ccm_enc(struct aes_ccm *C, const void *in, void *out, size_t nbytes) 185 1.1 riastrad { 186 1.4 riastrad uint8_t *auth = C->authctr; 187 1.4 riastrad uint8_t *ctr = C->authctr + 16; 188 1.1 riastrad const uint8_t *p = in; 189 1.1 riastrad uint8_t *q = out; 190 1.1 riastrad 191 1.1 riastrad KASSERTMSG(C->i != ~0u, 192 1.1 riastrad "%s not allowed after message complete", __func__); 193 1.1 riastrad KASSERTMSG(nbytes <= C->mleft, 194 1.1 riastrad "message too long: promised %zu bytes, processing >=%zu", 195 1.1 riastrad C->mlen, C->mlen - C->mleft + nbytes); 196 1.1 riastrad C->mleft -= nbytes; 197 1.1 riastrad 198 1.1 riastrad /* Finish a partial block if it was already started. */ 199 1.1 riastrad if (C->i) { 200 1.1 riastrad unsigned m = MIN(16 - C->i, nbytes); 201 1.1 riastrad 202 1.4 riastrad xor(auth + C->i, auth + C->i, p, m); 203 1.1 riastrad xor(q, C->out + C->i, p, m); 204 1.1 riastrad C->i += m; 205 1.1 riastrad p += m; 206 1.1 riastrad q += m; 207 1.1 riastrad nbytes -= m; 208 1.1 riastrad 209 1.1 riastrad if (C->i == 16) { 210 1.1 riastrad /* Finished a block; authenticate it. */ 211 1.4 riastrad aes_enc(C->enc, auth, auth, C->nr); 212 1.1 riastrad C->i = 0; 213 1.1 riastrad } else { 214 1.1 riastrad /* Didn't finish block, must be done with input. */ 215 1.1 riastrad KASSERT(nbytes == 0); 216 1.1 riastrad return; 217 1.1 riastrad } 218 1.1 riastrad } 219 1.1 riastrad 220 1.1 riastrad /* Process 16 bytes at a time. */ 221 1.2 riastrad if (nbytes - (nbytes % 16)) { 222 1.4 riastrad aes_ccm_enc1(C->enc, p, q, nbytes - (nbytes % 16), auth, 223 1.2 riastrad C->nr); 224 1.2 riastrad p += nbytes - (nbytes % 16); 225 1.2 riastrad q += nbytes - (nbytes % 16); 226 1.2 riastrad nbytes %= 16; 227 1.1 riastrad } 228 1.1 riastrad 229 1.1 riastrad /* Incorporate any <16-byte unit as a partial block. */ 230 1.1 riastrad if (nbytes) { 231 1.1 riastrad /* authenticate */ 232 1.4 riastrad xor(auth, auth, p, nbytes); 233 1.1 riastrad 234 1.1 riastrad /* encrypt */ 235 1.1 riastrad aes_ccm_inc(C); 236 1.4 riastrad aes_enc(C->enc, ctr, C->out, C->nr); 237 1.1 riastrad xor(q, C->out, p, nbytes); 238 1.1 riastrad 239 1.1 riastrad C->i = nbytes; 240 1.1 riastrad } 241 1.1 riastrad } 242 1.1 riastrad 243 1.1 riastrad void 244 1.1 riastrad aes_ccm_dec(struct aes_ccm *C, const void *in, void *out, size_t nbytes) 245 1.1 riastrad { 246 1.4 riastrad uint8_t *auth = C->authctr; 247 1.4 riastrad uint8_t *ctr = C->authctr + 16; 248 1.1 riastrad const uint8_t *p = in; 249 1.1 riastrad uint8_t *q = out; 250 1.1 riastrad 251 1.1 riastrad KASSERTMSG(C->i != ~0u, 252 1.1 riastrad "%s not allowed after message complete", __func__); 253 1.1 riastrad KASSERTMSG(nbytes <= C->mleft, 254 1.1 riastrad "message too long: promised %zu bytes, processing >=%zu", 255 1.1 riastrad C->mlen, C->mlen - C->mleft + nbytes); 256 1.1 riastrad C->mleft -= nbytes; 257 1.1 riastrad 258 1.1 riastrad /* Finish a partial block if it was already started. */ 259 1.1 riastrad if (C->i) { 260 1.1 riastrad unsigned m = MIN(16 - C->i, nbytes); 261 1.1 riastrad 262 1.1 riastrad xor(q, C->out + C->i, p, m); 263 1.4 riastrad xor(auth + C->i, auth + C->i, q, m); 264 1.1 riastrad C->i += m; 265 1.1 riastrad p += m; 266 1.1 riastrad q += m; 267 1.1 riastrad nbytes -= m; 268 1.1 riastrad 269 1.1 riastrad if (C->i == 16) { 270 1.1 riastrad /* Finished a block; authenticate it. */ 271 1.4 riastrad aes_enc(C->enc, auth, auth, C->nr); 272 1.1 riastrad C->i = 0; 273 1.1 riastrad } else { 274 1.1 riastrad /* Didn't finish block, must be done with input. */ 275 1.1 riastrad KASSERT(nbytes == 0); 276 1.1 riastrad return; 277 1.1 riastrad } 278 1.1 riastrad } 279 1.1 riastrad 280 1.1 riastrad /* Process 16 bytes at a time. */ 281 1.2 riastrad if (nbytes - (nbytes % 16)) { 282 1.4 riastrad aes_ccm_dec1(C->enc, p, q, nbytes - (nbytes % 16), auth, 283 1.2 riastrad C->nr); 284 1.2 riastrad p += nbytes - (nbytes % 16); 285 1.2 riastrad q += nbytes - (nbytes % 16); 286 1.2 riastrad nbytes %= 16; 287 1.1 riastrad } 288 1.1 riastrad 289 1.1 riastrad /* Incorporate any <16-byte unit as a partial block. */ 290 1.1 riastrad if (nbytes) { 291 1.1 riastrad /* decrypt */ 292 1.1 riastrad aes_ccm_inc(C); 293 1.4 riastrad aes_enc(C->enc, ctr, C->out, C->nr); 294 1.1 riastrad xor(q, C->out, p, nbytes); 295 1.1 riastrad 296 1.1 riastrad /* authenticate */ 297 1.4 riastrad xor(auth, auth, q, nbytes); 298 1.1 riastrad 299 1.1 riastrad C->i = nbytes; 300 1.1 riastrad } 301 1.1 riastrad } 302 1.1 riastrad 303 1.1 riastrad void 304 1.5 rin #if defined(__m68k__) && __GNUC_PREREQ__(8, 0) 305 1.5 rin __attribute__((__optimize__("O0"))) 306 1.5 rin #endif 307 1.1 riastrad aes_ccm_tag(struct aes_ccm *C, void *out) 308 1.1 riastrad { 309 1.4 riastrad uint8_t *auth = C->authctr; 310 1.4 riastrad const uint8_t *ctr = C->authctr + 16; 311 1.1 riastrad 312 1.1 riastrad KASSERTMSG(C->mleft == 0, 313 1.1 riastrad "message too short: promised %zu bytes, processed %zu", 314 1.1 riastrad C->mlen, C->mlen - C->mleft); 315 1.1 riastrad 316 1.1 riastrad /* Zero-pad and munch up a partial block, if any. */ 317 1.1 riastrad if (C->i) 318 1.4 riastrad aes_enc(C->enc, auth, auth, C->nr); 319 1.1 riastrad 320 1.1 riastrad /* Zero the counter and generate a pad for the tag. */ 321 1.1 riastrad aes_ccm_zero_ctr(C); 322 1.4 riastrad aes_enc(C->enc, ctr, C->out, C->nr); 323 1.1 riastrad 324 1.1 riastrad /* Copy out as many bytes as requested. */ 325 1.4 riastrad xor(out, C->out, auth, C->M); 326 1.1 riastrad 327 1.1 riastrad C->i = ~0u; /* paranoia: prevent future misuse */ 328 1.1 riastrad } 329 1.1 riastrad 330 1.1 riastrad int 331 1.1 riastrad aes_ccm_verify(struct aes_ccm *C, const void *tag) 332 1.1 riastrad { 333 1.1 riastrad uint8_t expected[16]; 334 1.1 riastrad int result; 335 1.1 riastrad 336 1.1 riastrad aes_ccm_tag(C, expected); 337 1.1 riastrad result = consttime_memequal(tag, expected, C->M); 338 1.1 riastrad explicit_memset(expected, 0, sizeof expected); 339 1.1 riastrad 340 1.1 riastrad return result; 341 1.1 riastrad } 342 1.1 riastrad 343 1.1 riastrad /* RFC 3610, 8 */ 344 1.1 riastrad 345 1.1 riastrad static const uint8_t keyC[16] = { 346 1.1 riastrad 0xc0,0xc1,0xc2,0xc3, 0xc4,0xc5,0xc6,0xc7, 347 1.1 riastrad 0xc8,0xc9,0xca,0xcb, 0xcc,0xcd,0xce,0xcf, 348 1.1 riastrad }; 349 1.1 riastrad 350 1.1 riastrad static const uint8_t keyD[16] = { 351 1.1 riastrad 0xd7,0x82,0x8d,0x13, 0xb2,0xb0,0xbd,0xc3, 352 1.1 riastrad 0x25,0xa7,0x62,0x36, 0xdf,0x93,0xcc,0x6b, 353 1.1 riastrad }; 354 1.1 riastrad 355 1.1 riastrad static const uint8_t ptxt_seq[] = { 356 1.1 riastrad 0x00,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 357 1.1 riastrad 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, 358 1.1 riastrad 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 359 1.1 riastrad 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f, 360 1.1 riastrad 0x20, 361 1.1 riastrad }; 362 1.1 riastrad 363 1.1 riastrad static const uint8_t ptxt_rand[] = { 364 1.1 riastrad 0x6e,0x37,0xa6,0xef, 0x54,0x6d,0x95,0x5d, 365 1.1 riastrad 0x34,0xab,0x60,0x59, 0xab,0xf2,0x1c,0x0b, 366 1.1 riastrad 0x02,0xfe,0xb8,0x8f, 0x85,0x6d,0xf4,0xa3, 367 1.1 riastrad 0x73,0x81,0xbc,0xe3, 0xcc,0x12,0x85,0x17, 368 1.1 riastrad 0xd4, 369 1.1 riastrad }; 370 1.1 riastrad 371 1.1 riastrad static const struct { 372 1.1 riastrad const uint8_t *key; 373 1.1 riastrad size_t noncelen; 374 1.1 riastrad const uint8_t nonce[13]; 375 1.1 riastrad size_t adlen; 376 1.1 riastrad const uint8_t *ad; 377 1.1 riastrad size_t mlen; 378 1.1 riastrad const uint8_t *ptxt; 379 1.1 riastrad unsigned M; 380 1.1 riastrad const uint8_t tag[16]; 381 1.1 riastrad const uint8_t *ctxt; 382 1.1 riastrad } T[] = { 383 1.1 riastrad [0] = { /* Packet Vector #1, p. 11 */ 384 1.1 riastrad .key = keyC, 385 1.1 riastrad .nonce = { 386 1.1 riastrad 0x00,0x00,0x00,0x03, 0x02,0x01,0x00,0xa0, 387 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5, 388 1.1 riastrad }, 389 1.1 riastrad .adlen = 8, 390 1.1 riastrad .ad = ptxt_seq, 391 1.1 riastrad .mlen = 23, 392 1.1 riastrad .ptxt = ptxt_seq + 8, 393 1.1 riastrad .M = 8, 394 1.1 riastrad .tag = {0x17,0xe8,0xd1,0x2c,0xfd, 0xf9,0x26,0xe0}, 395 1.1 riastrad .ctxt = (const uint8_t[23]) { 396 1.1 riastrad 0x58,0x8c,0x97,0x9a, 0x61,0xc6,0x63,0xd2, 397 1.1 riastrad 0xf0,0x66,0xd0,0xc2, 0xc0,0xf9,0x89,0x80, 398 1.1 riastrad 0x6d,0x5f,0x6b,0x61, 0xda,0xc3,0x84, 399 1.1 riastrad }, 400 1.1 riastrad }, 401 1.1 riastrad [1] = { /* Packet Vector #2, p. 11 */ 402 1.1 riastrad .key = keyC, 403 1.1 riastrad .nonce = { 404 1.1 riastrad 0x00,0x00,0x00,0x04, 0x03,0x02,0x01,0xa0, 405 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5, 406 1.1 riastrad }, 407 1.1 riastrad .adlen = 8, 408 1.1 riastrad .ad = ptxt_seq, 409 1.1 riastrad .mlen = 24, 410 1.1 riastrad .ptxt = ptxt_seq + 8, 411 1.1 riastrad .M = 8, 412 1.1 riastrad .tag = {0xa0,0x91,0xd5,0x6e, 0x10,0x40,0x09,0x16}, 413 1.1 riastrad .ctxt = (const uint8_t[24]) { 414 1.1 riastrad 0x72,0xc9,0x1a,0x36, 0xe1,0x35,0xf8,0xcf, 415 1.1 riastrad 0x29,0x1c,0xa8,0x94, 0x08,0x5c,0x87,0xe3, 416 1.1 riastrad 0xcc,0x15,0xc4,0x39, 0xc9,0xe4,0x3a,0x3b, 417 1.1 riastrad }, 418 1.1 riastrad }, 419 1.1 riastrad [2] = { /* Packet Vector #3, p. 12 */ 420 1.1 riastrad .key = keyC, 421 1.1 riastrad .nonce = { 422 1.1 riastrad 0x00,0x00,0x00,0x05, 0x04,0x03,0x02,0xa0, 423 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5, 424 1.1 riastrad }, 425 1.1 riastrad .adlen = 8, 426 1.1 riastrad .ad = ptxt_seq, 427 1.1 riastrad .mlen = 25, 428 1.1 riastrad .ptxt = ptxt_seq + 8, 429 1.1 riastrad .M = 8, 430 1.1 riastrad .tag = {0x4a,0xda,0xa7,0x6f, 0xbd,0x9f,0xb0,0xc5}, 431 1.1 riastrad .ctxt = (const uint8_t[25]) { 432 1.1 riastrad 0x51,0xb1,0xe5,0xf4, 0x4a,0x19,0x7d,0x1d, 433 1.1 riastrad 0xa4,0x6b,0x0f,0x8e, 0x2d,0x28,0x2a,0xe8, 434 1.1 riastrad 0x71,0xe8,0x38,0xbb, 0x64,0xda,0x85,0x96, 435 1.1 riastrad 0x57, 436 1.1 riastrad }, 437 1.1 riastrad }, 438 1.1 riastrad [3] = { /* Packet Vector #4, p. 13 */ 439 1.1 riastrad .key = keyC, 440 1.1 riastrad .nonce = { 441 1.1 riastrad 0x00,0x00,0x00,0x06, 0x05,0x04,0x03,0xa0, 442 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5, 443 1.1 riastrad }, 444 1.1 riastrad .adlen = 12, 445 1.1 riastrad .ad = ptxt_seq, 446 1.1 riastrad .mlen = 19, 447 1.1 riastrad .ptxt = ptxt_seq + 12, 448 1.1 riastrad .M = 8, 449 1.1 riastrad .tag = {0x96,0xc8,0x61,0xb9, 0xc9,0xe6,0x1e,0xf1}, 450 1.1 riastrad .ctxt = (const uint8_t[19]) { 451 1.1 riastrad 0xa2,0x8c,0x68,0x65, 0x93,0x9a,0x9a,0x79, 452 1.1 riastrad 0xfa,0xaa,0x5c,0x4c, 0x2a,0x9d,0x4a,0x91, 453 1.1 riastrad 0xcd,0xac,0x8c, 454 1.1 riastrad }, 455 1.1 riastrad }, 456 1.1 riastrad [4] = { /* Packet Vector #5, p. 13 */ 457 1.1 riastrad .key = keyC, 458 1.1 riastrad .nonce = { 459 1.1 riastrad 0x00,0x00,0x00,0x07, 0x06,0x05,0x04,0xa0, 460 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5, 461 1.1 riastrad }, 462 1.1 riastrad .adlen = 12, 463 1.1 riastrad .ad = ptxt_seq, 464 1.1 riastrad .mlen = 20, 465 1.1 riastrad .ptxt = ptxt_seq + 12, 466 1.1 riastrad .M = 8, 467 1.1 riastrad .tag = {0x51,0xe8,0x3f,0x07, 0x7d,0x9c,0x2d,0x93}, 468 1.1 riastrad .ctxt = (const uint8_t[20]) { 469 1.1 riastrad 0xdc,0xf1,0xfb,0x7b, 0x5d,0x9e,0x23,0xfb, 470 1.1 riastrad 0x9d,0x4e,0x13,0x12, 0x53,0x65,0x8a,0xd8, 471 1.1 riastrad 0x6e,0xbd,0xca,0x3e, 472 1.1 riastrad }, 473 1.1 riastrad }, 474 1.1 riastrad [5] = { /* Packet Vector #6, p. 13 */ 475 1.1 riastrad .key = keyC, 476 1.1 riastrad .nonce = { 477 1.1 riastrad 0x00,0x00,0x00,0x08, 0x07,0x06,0x05,0xa0, 478 1.1 riastrad 0xa1,0xa2,0xa3,0xa4, 0xa5, 479 1.1 riastrad }, 480 1.1 riastrad .adlen = 12, 481 1.1 riastrad .ad = ptxt_seq, 482 1.1 riastrad .mlen = 21, 483 1.1 riastrad .ptxt = ptxt_seq + 12, 484 1.1 riastrad .M = 8, 485 1.1 riastrad .tag = {0x40,0x5a,0x04,0x43, 0xac,0x91,0xcb,0x94}, 486 1.1 riastrad .ctxt = (const uint8_t[21]) { 487 1.1 riastrad 0x6f,0xc1,0xb0,0x11, 0xf0,0x06,0x56,0x8b, 488 1.1 riastrad 0x51,0x71,0xa4,0x2d, 0x95,0x3d,0x46,0x9b, 489 1.1 riastrad 0x25,0x70,0xa4,0xbd, 0x87, 490 1.1 riastrad }, 491 1.1 riastrad }, 492 1.1 riastrad [6] = { /* Packet Vector #24 */ 493 1.1 riastrad .key = keyD, 494 1.1 riastrad .nonce = { 495 1.1 riastrad 0x00,0x8d,0x49,0x3b, 0x30,0xae,0x8b,0x3c, 496 1.1 riastrad 0x96,0x96,0x76,0x6c, 0xfa, 497 1.1 riastrad }, 498 1.1 riastrad .adlen = 12, 499 1.1 riastrad .ad = ptxt_rand, 500 1.1 riastrad .mlen = 21, 501 1.1 riastrad .ptxt = ptxt_rand + 12, 502 1.1 riastrad .M = 10, 503 1.1 riastrad .tag = {0x6d,0xce,0x9e,0x82, 0xef,0xa1,0x6d,0xa6, 0x20,0x59}, 504 1.1 riastrad .ctxt = (const uint8_t[21]) { 505 1.1 riastrad 0xf3,0x29,0x05,0xb8, 0x8a,0x64,0x1b,0x04, 506 1.1 riastrad 0xb9,0xc9,0xff,0xb5, 0x8c,0xc3,0x90,0x90, 507 1.1 riastrad 0x0f,0x3d,0xa1,0x2a, 0xb1, 508 1.1 riastrad }, 509 1.1 riastrad }, 510 1.1 riastrad }; 511 1.1 riastrad 512 1.1 riastrad int 513 1.1 riastrad aes_ccm_selftest(void) 514 1.1 riastrad { 515 1.1 riastrad const unsigned L = 2; 516 1.1 riastrad const unsigned noncelen = 13; 517 1.1 riastrad struct aesenc enc, *AE = &enc; 518 1.1 riastrad struct aes_ccm ccm, *C = &ccm; 519 1.1 riastrad uint8_t buf[33 + 2], *bufp = buf + 1; 520 1.1 riastrad uint8_t tag[16 + 2], *tagp = tag + 1; 521 1.1 riastrad unsigned i; 522 1.1 riastrad int result = 0; 523 1.1 riastrad 524 1.1 riastrad bufp[-1] = bufp[33] = 0x1a; 525 1.1 riastrad tagp[-1] = tagp[16] = 0x53; 526 1.1 riastrad 527 1.1 riastrad for (i = 0; i < __arraycount(T); i++) { 528 1.1 riastrad const unsigned nr = aes_setenckey128(AE, T[i].key); 529 1.1 riastrad 530 1.1 riastrad /* encrypt and authenticate */ 531 1.1 riastrad aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen, 532 1.1 riastrad T[i].ad, T[i].adlen, T[i].mlen); 533 1.1 riastrad aes_ccm_enc(C, T[i].ptxt, bufp, 1); 534 1.1 riastrad aes_ccm_enc(C, T[i].ptxt + 1, bufp + 1, 2); 535 1.1 riastrad aes_ccm_enc(C, T[i].ptxt + 3, bufp + 3, T[i].mlen - 4); 536 1.1 riastrad aes_ccm_enc(C, T[i].ptxt + T[i].mlen - 1, 537 1.1 riastrad bufp + T[i].mlen - 1, 1); 538 1.1 riastrad aes_ccm_tag(C, tagp); 539 1.1 riastrad if (memcmp(bufp, T[i].ctxt, T[i].mlen)) { 540 1.1 riastrad char name[32]; 541 1.1 riastrad snprintf(name, sizeof name, "%s: ctxt %u", __func__, 542 1.1 riastrad i); 543 1.1 riastrad hexdump(printf, name, bufp, T[i].mlen); 544 1.1 riastrad result = -1; 545 1.1 riastrad } 546 1.1 riastrad if (memcmp(tagp, T[i].tag, T[i].M)) { 547 1.1 riastrad char name[32]; 548 1.1 riastrad snprintf(name, sizeof name, "%s: tag %u", __func__, i); 549 1.1 riastrad hexdump(printf, name, tagp, T[i].M); 550 1.1 riastrad result = -1; 551 1.1 riastrad } 552 1.1 riastrad 553 1.1 riastrad /* decrypt and verify */ 554 1.1 riastrad aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen, 555 1.1 riastrad T[i].ad, T[i].adlen, T[i].mlen); 556 1.1 riastrad aes_ccm_dec(C, T[i].ctxt, bufp, 1); 557 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2); 558 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4); 559 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1, 560 1.1 riastrad bufp + T[i].mlen - 1, 1); 561 1.1 riastrad if (!aes_ccm_verify(C, T[i].tag)) { 562 1.1 riastrad printf("%s: verify %u failed\n", __func__, i); 563 1.1 riastrad result = -1; 564 1.1 riastrad } 565 1.1 riastrad if (memcmp(bufp, T[i].ptxt, T[i].mlen)) { 566 1.1 riastrad char name[32]; 567 1.1 riastrad snprintf(name, sizeof name, "%s: ptxt %u", __func__, 568 1.1 riastrad i); 569 1.1 riastrad hexdump(printf, name, bufp, T[i].mlen); 570 1.1 riastrad result = -1; 571 1.1 riastrad } 572 1.1 riastrad 573 1.1 riastrad /* decrypt and verify with a bit flipped */ 574 1.1 riastrad memcpy(tagp, T[i].tag, T[i].M); 575 1.1 riastrad tagp[0] ^= 0x80; 576 1.1 riastrad aes_ccm_init(C, nr, AE, L, T[i].M, T[i].nonce, noncelen, 577 1.1 riastrad T[i].ad, T[i].adlen, T[i].mlen); 578 1.1 riastrad aes_ccm_dec(C, T[i].ctxt, bufp, 1); 579 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 1, bufp + 1, 2); 580 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + 3, bufp + 3, T[i].mlen - 4); 581 1.1 riastrad aes_ccm_dec(C, T[i].ctxt + T[i].mlen - 1, 582 1.1 riastrad bufp + T[i].mlen - 1, 1); 583 1.1 riastrad if (aes_ccm_verify(C, tagp)) { 584 1.1 riastrad printf("%s: forgery %u succeeded\n", __func__, i); 585 1.1 riastrad result = -1; 586 1.1 riastrad } 587 1.1 riastrad } 588 1.1 riastrad 589 1.1 riastrad if (bufp[-1] != 0x1a || bufp[33] != 0x1a) { 590 1.1 riastrad printf("%s: buffer overrun\n", __func__); 591 1.1 riastrad result = -1; 592 1.1 riastrad } 593 1.1 riastrad if (tagp[-1] != 0x53 || tagp[16] != 0x53) { 594 1.1 riastrad printf("%s: tag overrun\n", __func__); 595 1.1 riastrad result = -1; 596 1.1 riastrad } 597 1.1 riastrad 598 1.1 riastrad return result; 599 1.1 riastrad } 600 1.1 riastrad 601 1.1 riastrad /* XXX provisional hack */ 602 1.1 riastrad #include <sys/module.h> 603 1.1 riastrad 604 1.3 riastrad MODULE(MODULE_CLASS_MISC, aes_ccm, "aes"); 605 1.1 riastrad 606 1.1 riastrad static int 607 1.1 riastrad aes_ccm_modcmd(modcmd_t cmd, void *opaque) 608 1.1 riastrad { 609 1.1 riastrad 610 1.1 riastrad switch (cmd) { 611 1.1 riastrad case MODULE_CMD_INIT: 612 1.1 riastrad if (aes_ccm_selftest()) 613 1.1 riastrad return EIO; 614 1.6 jmcneill aprint_debug("aes_ccm: self-test passed\n"); 615 1.1 riastrad return 0; 616 1.1 riastrad case MODULE_CMD_FINI: 617 1.1 riastrad return 0; 618 1.1 riastrad default: 619 1.1 riastrad return ENOTTY; 620 1.1 riastrad } 621 1.1 riastrad } 622