ccm128.c: minor optimization and bugfix in CRYPTO_ccm128_[en|de]crypt.
[openssl.git] / crypto / modes / ccm128.c
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
61 typedef struct {
62         union { u64 u[2]; u8 c[16]; } nonce, cmac;
63         u64 blocks;
64         block128_f block;
65         void *key;
66 } CCM128_CONTEXT;
67
68 /* First you setup M and L parameters and pass the key schedule */
69 void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
70         unsigned int M,unsigned int L,void *key,block128_f block)
71 {
72         memset(ctx->nonce.c,0,sizeof(ctx->nonce.c));
73         ctx->nonce.c[0] = ((u8)(L-1)&7) | (u8)(((M-2)/2)&7)<<3;
74         ctx->blocks = 0;
75         ctx->block = block;
76         ctx->key = key;
77 }
78
79 /* !!! Following interfaces are to be called *once* per packet !!! */
80
81 /* Then you setup per-message nonce and pass the length of the message */
82 int CRYPTO_ccm128_setiv(CCM128_CONTEXT *ctx,
83         const unsigned char *nonce,size_t nlen,size_t mlen)
84 {
85         unsigned int L = ctx->nonce.c[0]&7;     /* the L parameter */
86
87         if (nlen<(14-L)) return -1;             /* nonce is too short */
88
89         if (sizeof(mlen)==8 && L>=3) {
90                 ctx->nonce.c[8]  = (u8)(mlen>>(56%(sizeof(mlen)*8)));
91                 ctx->nonce.c[9]  = (u8)(mlen>>(48%(sizeof(mlen)*8)));
92                 ctx->nonce.c[10] = (u8)(mlen>>(40%(sizeof(mlen)*8)));
93                 ctx->nonce.c[11] = (u8)(mlen>>(32%(sizeof(mlen)*8)));
94         }
95         else
96                 *(u32*)(&ctx->nonce.c[8]) = 0;
97
98         ctx->nonce.c[12] = (u8)(mlen>>24);
99         ctx->nonce.c[13] = (u8)(mlen>>16);
100         ctx->nonce.c[14] = (u8)(mlen>>8);
101         ctx->nonce.c[15] = (u8)mlen;
102
103         ctx->nonce.c[0] &= ~0x40;       /* clear Adata flag */
104         memcpy(&ctx->nonce.c[1],nonce,14-L);
105
106         return 0;
107 }
108
109 /* Then you pass additional authentication data, this is optional */
110 void CRYPTO_ccm128_aad(CCM128_CONTEXT *ctx,
111         const unsigned char *aad,size_t alen)
112 {       unsigned int i;
113         block128_f block = ctx->block;
114
115         if (alen==0) return;
116
117         ctx->nonce.c[0] |= 0x40;        /* set Adata flag */
118         (*block)(ctx->nonce.c,ctx->cmac.c,ctx->key),
119         ctx->blocks++;
120
121         if (alen<(0x10000-0x100)) {
122                 ctx->cmac.c[0] ^= (u8)(alen>>8);
123                 ctx->cmac.c[1] ^= (u8)alen;
124                 i=2;
125         }
126         else if (sizeof(alen)==8 && alen>=(size_t)1<<32) {
127                 ctx->cmac.c[0] ^= 0xFF;
128                 ctx->cmac.c[1] ^= 0xFF;
129                 ctx->cmac.c[2] ^= (u8)(alen>>(56%(sizeof(alen)*8)));
130                 ctx->cmac.c[3] ^= (u8)(alen>>(48%(sizeof(alen)*8)));
131                 ctx->cmac.c[4] ^= (u8)(alen>>(40%(sizeof(alen)*8)));
132                 ctx->cmac.c[5] ^= (u8)(alen>>(32%(sizeof(alen)*8)));
133                 ctx->cmac.c[6] ^= (u8)(alen>>24);
134                 ctx->cmac.c[7] ^= (u8)(alen>>16);
135                 ctx->cmac.c[8] ^= (u8)(alen>>8);
136                 ctx->cmac.c[9] ^= (u8)alen;
137                 i=10;
138         }
139         else {
140                 ctx->cmac.c[0] ^= 0xFF;
141                 ctx->cmac.c[1] ^= 0xFE;
142                 ctx->cmac.c[2] ^= (u8)(alen>>24);
143                 ctx->cmac.c[3] ^= (u8)(alen>>16);
144                 ctx->cmac.c[4] ^= (u8)(alen>>8);
145                 ctx->cmac.c[5] ^= (u8)alen;
146                 i=6;
147         }
148
149         do {
150                 for(;i<16 && alen;++i,++aad,--alen)
151                         ctx->cmac.c[i] ^= *aad;
152                 (*block)(ctx->cmac.c,ctx->cmac.c,ctx->key),
153                 ctx->blocks++;
154                 i=0;
155         } while (alen);
156 }
157
158 /* Finally you encrypt or decrypt the message */
159
160 static void ctr128_inc(unsigned char *counter) {
161         unsigned int n=16;
162         u8  c;
163
164         do {
165                 --n;
166                 c = counter[n];
167                 ++c;
168                 counter[n] = c;
169                 if (c) return;
170         } while (n);
171 }
172
173 int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
174         const unsigned char *inp, unsigned char *out,
175         size_t len)
176 {
177         size_t          n;
178         unsigned int    i,L;
179         unsigned char   flags0 = ctx->nonce.c[0];
180         block128_f      block = ctx->block;
181         union { u64 u[2]; u8 c[16]; } scratch;
182
183         if (!(flags0&0x40))
184                 (*block)(ctx->nonce.c,ctx->cmac.c,ctx->key),
185                 ctx->blocks++;
186
187         ctx->nonce.c[0] = L = flags0&7;
188         for (n=0,i=15-L;i<15;++i) {
189                 n |= ctx->nonce.c[i];
190                 ctx->nonce.c[i]=0;
191                 n <<= 8;
192         }
193         n |= ctx->nonce.c[15];  /* reconstructed length */
194         ctx->nonce.c[15]=1;
195
196         if (n!=len) return -1;  /* length mismatch */
197
198         ctx->blocks += ((len+15)>>3)|1;
199         if (ctx->blocks > (U64(1)<<61)) return -2; /* too much data */
200
201         while (len>=16) {
202 #if defined(STRICT_ALIGNMENT)
203                 union { u64 u[2]; u8 c[16]; } temp;
204
205                 memcpy (temp.c,inp,16);
206                 ctx->cmac.u[0] ^= temp.u[0];
207                 ctx->cmac.u[1] ^= temp.u[1];
208 #else
209                 ctx->cmac.u[0] ^= ((u64*)inp)[0];
210                 ctx->cmac.u[1] ^= ((u64*)inp)[1];
211 #endif
212                 (*block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
213                 (*block)(ctx->nonce.c,scratch.c,ctx->key);
214                 ctr128_inc(ctx->nonce.c);
215 #if defined(STRICT_ALIGNMENT)
216                 temp.u[0] ^= scratch.u[0];
217                 temp.u[1] ^= scratch.u[1];
218                 memcpy(out,temp.c,16);
219 #else
220                 ((u64*)out)[0] = scratch.u[0]^((u64*)inp)[0];
221                 ((u64*)out)[1] = scratch.u[1]^((u64*)inp)[1];
222 #endif
223                 inp += 16;
224                 out += 16;
225                 len -= 16;
226         }
227
228         if (len) {
229                 for (i=0; i<len; ++i) ctx->cmac.c[i] ^= inp[i];
230                 (*block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
231                 (*block)(ctx->nonce.c,scratch.c,ctx->key);
232                 for (i=0; i<len; ++i) out[i] = scratch.c[i]^inp[i];
233         }
234
235         for (i=15-L;i<16;++i)
236                 ctx->nonce.c[i]=0;
237
238         (*block)(ctx->nonce.c,scratch.c,ctx->key);
239         ctx->cmac.u[0] ^= scratch.u[0];
240         ctx->cmac.u[1] ^= scratch.u[1];
241
242         ctx->nonce.c[0] = flags0;
243
244         return 0;
245 }
246
247 int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
248         const unsigned char *inp, unsigned char *out,
249         size_t len)
250 {
251         size_t          n;
252         unsigned int    i,L;
253         unsigned char   flags0 = ctx->nonce.c[0];
254         block128_f      block;
255         union { u64 u[2]; u8 c[16]; } scratch;
256
257         if (!(flags0&0x40))
258                 (*block)(ctx->nonce.c,ctx->cmac.c,ctx->key);
259
260         ctx->nonce.c[0] = L = flags0&7;
261         for (n=0,i=15-L;i<15;++i) {
262                 n |= ctx->nonce.c[i];
263                 ctx->nonce.c[i]=0;
264                 n <<= 8;
265         }
266         n |= ctx->nonce.c[15];  /* reconstructed length */
267         ctx->nonce.c[15]=1;
268
269         if (n!=len) return -1;
270
271         while (len>=16) {
272                 (*block)(ctx->nonce.c,scratch.c,ctx->key);
273                 ctr128_inc(ctx->nonce.c);
274 #if defined(STRICT_ALIGNMENT)
275                 memcpy (ctx->inp.c,inp,16);
276                 for (i=0; i<16/sizeof(size_t); ++i)
277                         ctx->cmac.s[i] ^= (scratch.s[i] ^= ctx->inp.s[i]);
278                 memcpy (out,scratch,16);
279 #else
280                 ctx->cmac.u[0] ^= (((u64*)out)[0] = scratch.u[0]^((u64*)inp)[0]);
281                 ctx->cmac.u[1] ^= (((u64*)out)[1] = scratch.u[1]^((u64*)inp)[1]);
282 #endif
283                 (*block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
284
285                 inp += 16;
286                 out += 16;
287                 len -= 16;
288         }
289
290         if (len) {
291                 (*block)(ctx->nonce.c,scratch.c,ctx->key);
292                 for (i=0; i<len; ++len)
293                         ctx->cmac.c[i] ^= (out[i] = scratch.c[i]^inp[i]);
294                 (*block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
295         }
296
297         for (i=15-L;i<16;++i)
298                 ctx->nonce.c[i]=0;
299
300         (*block)(ctx->nonce.c,scratch.c,ctx->key);
301         ctx->cmac.u[0] ^= scratch.u[0];
302         ctx->cmac.u[1] ^= scratch.u[1];
303
304         ctx->nonce.c[0] = flags0;
305
306         return 0;
307 }
308
309 size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx,unsigned char *tag,size_t len)
310 {       unsigned int M = (ctx->nonce.c[0]>>3)&7;        /* the M parameter */
311
312         M *= 2; M += 2;
313         if (len<M)      return 0;
314         memcpy(tag,ctx->cmac.c,M);
315         return M;
316 }