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