/src/libressl/crypto/modes/ccm128.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: ccm128.c,v 1.5 2019/05/08 14:18:25 tb Exp $ */ |
2 | | /* ==================================================================== |
3 | | * Copyright (c) 2011 The OpenSSL Project. All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * |
9 | | * 1. Redistributions of source code must retain the above copyright |
10 | | * notice, this list of conditions and the following disclaimer. |
11 | | * |
12 | | * 2. Redistributions in binary form must reproduce the above copyright |
13 | | * notice, this list of conditions and the following disclaimer in |
14 | | * the documentation and/or other materials provided with the |
15 | | * distribution. |
16 | | * |
17 | | * 3. All advertising materials mentioning features or use of this |
18 | | * software must display the following acknowledgment: |
19 | | * "This product includes software developed by the OpenSSL Project |
20 | | * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" |
21 | | * |
22 | | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
23 | | * endorse or promote products derived from this software without |
24 | | * prior written permission. For written permission, please contact |
25 | | * openssl-core@openssl.org. |
26 | | * |
27 | | * 5. Products derived from this software may not be called "OpenSSL" |
28 | | * nor may "OpenSSL" appear in their names without prior written |
29 | | * permission of the OpenSSL Project. |
30 | | * |
31 | | * 6. Redistributions of any form whatsoever must retain the following |
32 | | * acknowledgment: |
33 | | * "This product includes software developed by the OpenSSL Project |
34 | | * for use in the OpenSSL Toolkit (http://www.openssl.org/)" |
35 | | * |
36 | | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
37 | | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
38 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
39 | | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
40 | | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
41 | | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
42 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
43 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
44 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
45 | | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
46 | | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
47 | | * OF THE POSSIBILITY OF SUCH DAMAGE. |
48 | | * ==================================================================== |
49 | | */ |
50 | | |
51 | | #include <openssl/crypto.h> |
52 | | #include "modes_lcl.h" |
53 | | #include <string.h> |
54 | | |
55 | | #ifndef MODES_DEBUG |
56 | | # ifndef NDEBUG |
57 | | # define NDEBUG |
58 | | # endif |
59 | | #endif |
60 | | |
61 | | /* First you setup M and L parameters and pass the key schedule. |
62 | | * This is called once per session setup... */ |
63 | | void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, |
64 | | unsigned int M,unsigned int L,void *key,block128_f block) |
65 | 0 | { |
66 | 0 | memset(ctx->nonce.c,0,sizeof(ctx->nonce.c)); |
67 | 0 | ctx->nonce.c[0] = ((u8)(L-1)&7) | (u8)(((M-2)/2)&7)<<3; |
68 | 0 | ctx->blocks = 0; |
69 | 0 | ctx->block = block; |
70 | 0 | ctx->key = key; |
71 | 0 | } |
72 | | |
73 | | /* !!! Following interfaces are to be called *once* per packet !!! */ |
74 | | |
75 | | /* Then you setup per-message nonce and pass the length of the message */ |
76 | | int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx, |
77 | | const unsigned char *nonce,size_t nlen,size_t mlen) |
78 | 0 | { |
79 | 0 | unsigned int L = ctx->nonce.c[0]&7; /* the L parameter */ |
80 | |
|
81 | 0 | if (nlen<(14-L)) return -1; /* nonce is too short */ |
82 | | |
83 | 0 | if (sizeof(mlen)==8 && L>=3) { |
84 | 0 | ctx->nonce.c[8] = (u8)(mlen>>(56%(sizeof(mlen)*8))); |
85 | 0 | ctx->nonce.c[9] = (u8)(mlen>>(48%(sizeof(mlen)*8))); |
86 | 0 | ctx->nonce.c[10] = (u8)(mlen>>(40%(sizeof(mlen)*8))); |
87 | 0 | ctx->nonce.c[11] = (u8)(mlen>>(32%(sizeof(mlen)*8))); |
88 | 0 | } |
89 | 0 | else |
90 | 0 | ctx->nonce.u[1] = 0; |
91 | |
|
92 | 0 | ctx->nonce.c[12] = (u8)(mlen>>24); |
93 | 0 | ctx->nonce.c[13] = (u8)(mlen>>16); |
94 | 0 | ctx->nonce.c[14] = (u8)(mlen>>8); |
95 | 0 | ctx->nonce.c[15] = (u8)mlen; |
96 | |
|
97 | 0 | ctx->nonce.c[0] &= ~0x40; /* clear Adata flag */ |
98 | 0 | memcpy(&ctx->nonce.c[1],nonce,14-L); |
99 | |
|
100 | 0 | return 0; |
101 | 0 | } |
102 | | |
103 | | /* Then you pass additional authentication data, this is optional */ |
104 | | void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx, |
105 | | const unsigned char *aad,size_t alen) |
106 | 0 | { unsigned int i; |
107 | 0 | block128_f block = ctx->block; |
108 | |
|
109 | 0 | if (alen==0) return; |
110 | | |
111 | 0 | ctx->nonce.c[0] |= 0x40; /* set Adata flag */ |
112 | 0 | (*block)(ctx->nonce.c,ctx->cmac.c,ctx->key), |
113 | 0 | ctx->blocks++; |
114 | |
|
115 | 0 | if (alen<(0x10000-0x100)) { |
116 | 0 | ctx->cmac.c[0] ^= (u8)(alen>>8); |
117 | 0 | ctx->cmac.c[1] ^= (u8)alen; |
118 | 0 | i=2; |
119 | 0 | } |
120 | 0 | else if (sizeof(alen)==8 && alen>=(size_t)1<<(32%(sizeof(alen)*8))) { |
121 | 0 | ctx->cmac.c[0] ^= 0xFF; |
122 | 0 | ctx->cmac.c[1] ^= 0xFF; |
123 | 0 | ctx->cmac.c[2] ^= (u8)(alen>>(56%(sizeof(alen)*8))); |
124 | 0 | ctx->cmac.c[3] ^= (u8)(alen>>(48%(sizeof(alen)*8))); |
125 | 0 | ctx->cmac.c[4] ^= (u8)(alen>>(40%(sizeof(alen)*8))); |
126 | 0 | ctx->cmac.c[5] ^= (u8)(alen>>(32%(sizeof(alen)*8))); |
127 | 0 | ctx->cmac.c[6] ^= (u8)(alen>>24); |
128 | 0 | ctx->cmac.c[7] ^= (u8)(alen>>16); |
129 | 0 | ctx->cmac.c[8] ^= (u8)(alen>>8); |
130 | 0 | ctx->cmac.c[9] ^= (u8)alen; |
131 | 0 | i=10; |
132 | 0 | } |
133 | 0 | else { |
134 | 0 | ctx->cmac.c[0] ^= 0xFF; |
135 | 0 | ctx->cmac.c[1] ^= 0xFE; |
136 | 0 | ctx->cmac.c[2] ^= (u8)(alen>>24); |
137 | 0 | ctx->cmac.c[3] ^= (u8)(alen>>16); |
138 | 0 | ctx->cmac.c[4] ^= (u8)(alen>>8); |
139 | 0 | ctx->cmac.c[5] ^= (u8)alen; |
140 | 0 | i=6; |
141 | 0 | } |
142 | |
|
143 | 0 | do { |
144 | 0 | for(;i<16 && alen;++i,++aad,--alen) |
145 | 0 | ctx->cmac.c[i] ^= *aad; |
146 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,ctx->key), |
147 | 0 | ctx->blocks++; |
148 | 0 | i=0; |
149 | 0 | } while (alen); |
150 | 0 | } |
151 | | |
152 | | /* Finally you encrypt or decrypt the message */ |
153 | | |
154 | | /* counter part of nonce may not be larger than L*8 bits, |
155 | | * L is not larger than 8, therefore 64-bit counter... */ |
156 | 0 | static void ctr64_inc(unsigned char *counter) { |
157 | 0 | unsigned int n=8; |
158 | 0 | u8 c; |
159 | |
|
160 | 0 | counter += 8; |
161 | 0 | do { |
162 | 0 | --n; |
163 | 0 | c = counter[n]; |
164 | 0 | ++c; |
165 | 0 | counter[n] = c; |
166 | 0 | if (c) return; |
167 | 0 | } while (n); |
168 | 0 | } |
169 | | |
170 | | int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx, |
171 | | const unsigned char *inp, unsigned char *out, |
172 | | size_t len) |
173 | 0 | { |
174 | 0 | size_t n; |
175 | 0 | unsigned int i,L; |
176 | 0 | unsigned char flags0 = ctx->nonce.c[0]; |
177 | 0 | block128_f block = ctx->block; |
178 | 0 | void * key = ctx->key; |
179 | 0 | union { u64 u[2]; u8 c[16]; } scratch; |
180 | |
|
181 | 0 | if (!(flags0&0x40)) |
182 | 0 | (*block)(ctx->nonce.c,ctx->cmac.c,key), |
183 | 0 | ctx->blocks++; |
184 | |
|
185 | 0 | ctx->nonce.c[0] = L = flags0&7; |
186 | 0 | for (n=0,i=15-L;i<15;++i) { |
187 | 0 | n |= ctx->nonce.c[i]; |
188 | 0 | ctx->nonce.c[i]=0; |
189 | 0 | n <<= 8; |
190 | 0 | } |
191 | 0 | n |= ctx->nonce.c[15]; /* reconstructed length */ |
192 | 0 | ctx->nonce.c[15]=1; |
193 | |
|
194 | 0 | if (n!=len) return -1; /* length mismatch */ |
195 | | |
196 | 0 | ctx->blocks += ((len+15)>>3)|1; |
197 | 0 | if (ctx->blocks > (U64(1)<<61)) return -2; /* too much data */ |
198 | | |
199 | 0 | while (len>=16) { |
200 | | #ifdef __STRICT_ALIGNMENT |
201 | | union { u64 u[2]; u8 c[16]; } temp; |
202 | | |
203 | | memcpy (temp.c,inp,16); |
204 | | ctx->cmac.u[0] ^= temp.u[0]; |
205 | | ctx->cmac.u[1] ^= temp.u[1]; |
206 | | #else |
207 | 0 | ctx->cmac.u[0] ^= ((u64*)inp)[0]; |
208 | 0 | ctx->cmac.u[1] ^= ((u64*)inp)[1]; |
209 | 0 | #endif |
210 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,key); |
211 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
212 | 0 | ctr64_inc(ctx->nonce.c); |
213 | | #ifdef __STRICT_ALIGNMENT |
214 | | temp.u[0] ^= scratch.u[0]; |
215 | | temp.u[1] ^= scratch.u[1]; |
216 | | memcpy(out,temp.c,16); |
217 | | #else |
218 | 0 | ((u64*)out)[0] = scratch.u[0]^((u64*)inp)[0]; |
219 | 0 | ((u64*)out)[1] = scratch.u[1]^((u64*)inp)[1]; |
220 | 0 | #endif |
221 | 0 | inp += 16; |
222 | 0 | out += 16; |
223 | 0 | len -= 16; |
224 | 0 | } |
225 | |
|
226 | 0 | if (len) { |
227 | 0 | for (i=0; i<len; ++i) ctx->cmac.c[i] ^= inp[i]; |
228 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,key); |
229 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
230 | 0 | for (i=0; i<len; ++i) out[i] = scratch.c[i]^inp[i]; |
231 | 0 | } |
232 | |
|
233 | 0 | for (i=15-L;i<16;++i) |
234 | 0 | ctx->nonce.c[i]=0; |
235 | |
|
236 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
237 | 0 | ctx->cmac.u[0] ^= scratch.u[0]; |
238 | 0 | ctx->cmac.u[1] ^= scratch.u[1]; |
239 | |
|
240 | 0 | ctx->nonce.c[0] = flags0; |
241 | |
|
242 | 0 | return 0; |
243 | 0 | } |
244 | | |
245 | | int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx, |
246 | | const unsigned char *inp, unsigned char *out, |
247 | | size_t len) |
248 | 0 | { |
249 | 0 | size_t n; |
250 | 0 | unsigned int i,L; |
251 | 0 | unsigned char flags0 = ctx->nonce.c[0]; |
252 | 0 | block128_f block = ctx->block; |
253 | 0 | void * key = ctx->key; |
254 | 0 | union { u64 u[2]; u8 c[16]; } scratch; |
255 | |
|
256 | 0 | if (!(flags0&0x40)) |
257 | 0 | (*block)(ctx->nonce.c,ctx->cmac.c,key); |
258 | |
|
259 | 0 | ctx->nonce.c[0] = L = flags0&7; |
260 | 0 | for (n=0,i=15-L;i<15;++i) { |
261 | 0 | n |= ctx->nonce.c[i]; |
262 | 0 | ctx->nonce.c[i]=0; |
263 | 0 | n <<= 8; |
264 | 0 | } |
265 | 0 | n |= ctx->nonce.c[15]; /* reconstructed length */ |
266 | 0 | ctx->nonce.c[15]=1; |
267 | |
|
268 | 0 | if (n!=len) return -1; |
269 | | |
270 | 0 | while (len>=16) { |
271 | | #ifdef __STRICT_ALIGNMENT |
272 | | union { u64 u[2]; u8 c[16]; } temp; |
273 | | #endif |
274 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
275 | 0 | ctr64_inc(ctx->nonce.c); |
276 | | #ifdef __STRICT_ALIGNMENT |
277 | | memcpy (temp.c,inp,16); |
278 | | ctx->cmac.u[0] ^= (scratch.u[0] ^= temp.u[0]); |
279 | | ctx->cmac.u[1] ^= (scratch.u[1] ^= temp.u[1]); |
280 | | memcpy (out,scratch.c,16); |
281 | | #else |
282 | 0 | ctx->cmac.u[0] ^= (((u64*)out)[0] = scratch.u[0]^((u64*)inp)[0]); |
283 | 0 | ctx->cmac.u[1] ^= (((u64*)out)[1] = scratch.u[1]^((u64*)inp)[1]); |
284 | 0 | #endif |
285 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,key); |
286 | |
|
287 | 0 | inp += 16; |
288 | 0 | out += 16; |
289 | 0 | len -= 16; |
290 | 0 | } |
291 | |
|
292 | 0 | if (len) { |
293 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
294 | 0 | for (i=0; i<len; ++i) |
295 | 0 | ctx->cmac.c[i] ^= (out[i] = scratch.c[i]^inp[i]); |
296 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,key); |
297 | 0 | } |
298 | |
|
299 | 0 | for (i=15-L;i<16;++i) |
300 | 0 | ctx->nonce.c[i]=0; |
301 | |
|
302 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
303 | 0 | ctx->cmac.u[0] ^= scratch.u[0]; |
304 | 0 | ctx->cmac.u[1] ^= scratch.u[1]; |
305 | |
|
306 | 0 | ctx->nonce.c[0] = flags0; |
307 | |
|
308 | 0 | return 0; |
309 | 0 | } |
310 | | |
311 | | static void ctr64_add (unsigned char *counter,size_t inc) |
312 | 0 | { size_t n=8, val=0; |
313 | |
|
314 | 0 | counter += 8; |
315 | 0 | do { |
316 | 0 | --n; |
317 | 0 | val += counter[n] + (inc&0xff); |
318 | 0 | counter[n] = (unsigned char)val; |
319 | 0 | val >>= 8; /* carry bit */ |
320 | 0 | inc >>= 8; |
321 | 0 | } while(n && (inc || val)); |
322 | 0 | } |
323 | | |
324 | | int CRYPTO_ccm128_encrypt_ccm64(CCM128_CONTEXT *ctx, |
325 | | const unsigned char *inp, unsigned char *out, |
326 | | size_t len,ccm128_f stream) |
327 | 0 | { |
328 | 0 | size_t n; |
329 | 0 | unsigned int i,L; |
330 | 0 | unsigned char flags0 = ctx->nonce.c[0]; |
331 | 0 | block128_f block = ctx->block; |
332 | 0 | void * key = ctx->key; |
333 | 0 | union { u64 u[2]; u8 c[16]; } scratch; |
334 | |
|
335 | 0 | if (!(flags0&0x40)) |
336 | 0 | (*block)(ctx->nonce.c,ctx->cmac.c,key), |
337 | 0 | ctx->blocks++; |
338 | |
|
339 | 0 | ctx->nonce.c[0] = L = flags0&7; |
340 | 0 | for (n=0,i=15-L;i<15;++i) { |
341 | 0 | n |= ctx->nonce.c[i]; |
342 | 0 | ctx->nonce.c[i]=0; |
343 | 0 | n <<= 8; |
344 | 0 | } |
345 | 0 | n |= ctx->nonce.c[15]; /* reconstructed length */ |
346 | 0 | ctx->nonce.c[15]=1; |
347 | |
|
348 | 0 | if (n!=len) return -1; /* length mismatch */ |
349 | | |
350 | 0 | ctx->blocks += ((len+15)>>3)|1; |
351 | 0 | if (ctx->blocks > (U64(1)<<61)) return -2; /* too much data */ |
352 | | |
353 | 0 | if ((n=len/16)) { |
354 | 0 | (*stream)(inp,out,n,key,ctx->nonce.c,ctx->cmac.c); |
355 | 0 | n *= 16; |
356 | 0 | inp += n; |
357 | 0 | out += n; |
358 | 0 | len -= n; |
359 | 0 | if (len) ctr64_add(ctx->nonce.c,n/16); |
360 | 0 | } |
361 | |
|
362 | 0 | if (len) { |
363 | 0 | for (i=0; i<len; ++i) ctx->cmac.c[i] ^= inp[i]; |
364 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,key); |
365 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
366 | 0 | for (i=0; i<len; ++i) out[i] = scratch.c[i]^inp[i]; |
367 | 0 | } |
368 | |
|
369 | 0 | for (i=15-L;i<16;++i) |
370 | 0 | ctx->nonce.c[i]=0; |
371 | |
|
372 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
373 | 0 | ctx->cmac.u[0] ^= scratch.u[0]; |
374 | 0 | ctx->cmac.u[1] ^= scratch.u[1]; |
375 | |
|
376 | 0 | ctx->nonce.c[0] = flags0; |
377 | |
|
378 | 0 | return 0; |
379 | 0 | } |
380 | | |
381 | | int CRYPTO_ccm128_decrypt_ccm64(CCM128_CONTEXT *ctx, |
382 | | const unsigned char *inp, unsigned char *out, |
383 | | size_t len,ccm128_f stream) |
384 | 0 | { |
385 | 0 | size_t n; |
386 | 0 | unsigned int i,L; |
387 | 0 | unsigned char flags0 = ctx->nonce.c[0]; |
388 | 0 | block128_f block = ctx->block; |
389 | 0 | void * key = ctx->key; |
390 | 0 | union { u64 u[2]; u8 c[16]; } scratch; |
391 | |
|
392 | 0 | if (!(flags0&0x40)) |
393 | 0 | (*block)(ctx->nonce.c,ctx->cmac.c,key); |
394 | |
|
395 | 0 | ctx->nonce.c[0] = L = flags0&7; |
396 | 0 | for (n=0,i=15-L;i<15;++i) { |
397 | 0 | n |= ctx->nonce.c[i]; |
398 | 0 | ctx->nonce.c[i]=0; |
399 | 0 | n <<= 8; |
400 | 0 | } |
401 | 0 | n |= ctx->nonce.c[15]; /* reconstructed length */ |
402 | 0 | ctx->nonce.c[15]=1; |
403 | |
|
404 | 0 | if (n!=len) return -1; |
405 | | |
406 | 0 | if ((n=len/16)) { |
407 | 0 | (*stream)(inp,out,n,key,ctx->nonce.c,ctx->cmac.c); |
408 | 0 | n *= 16; |
409 | 0 | inp += n; |
410 | 0 | out += n; |
411 | 0 | len -= n; |
412 | 0 | if (len) ctr64_add(ctx->nonce.c,n/16); |
413 | 0 | } |
414 | |
|
415 | 0 | if (len) { |
416 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
417 | 0 | for (i=0; i<len; ++i) |
418 | 0 | ctx->cmac.c[i] ^= (out[i] = scratch.c[i]^inp[i]); |
419 | 0 | (*block)(ctx->cmac.c,ctx->cmac.c,key); |
420 | 0 | } |
421 | |
|
422 | 0 | for (i=15-L;i<16;++i) |
423 | 0 | ctx->nonce.c[i]=0; |
424 | |
|
425 | 0 | (*block)(ctx->nonce.c,scratch.c,key); |
426 | 0 | ctx->cmac.u[0] ^= scratch.u[0]; |
427 | 0 | ctx->cmac.u[1] ^= scratch.u[1]; |
428 | |
|
429 | 0 | ctx->nonce.c[0] = flags0; |
430 | |
|
431 | 0 | return 0; |
432 | 0 | } |
433 | | |
434 | | size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx,unsigned char *tag,size_t len) |
435 | 0 | { unsigned int M = (ctx->nonce.c[0]>>3)&7; /* the M parameter */ |
436 | |
|
437 | 0 | M *= 2; M += 2; |
438 | 0 | if (len != M) return 0; |
439 | 0 | memcpy(tag,ctx->cmac.c,M); |
440 | 0 | return M; |
441 | 0 | } |