dc42b480bdc01c8eda703f2df620944e8de75dc9
[oweals/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 { u8 c[16]; size_t s[16/sizeof(size_t)]; } nonce, cmac,
63                                                          scratch, inp;
64         u64 blocks;
65         block128_f block;
66         void *key;
67 } CCM128_CONTEXT;
68
69 /* First you setup M and L parameters and pass the key schedule */
70 void CRYPTO_ccm128_init(CCM128_CONTEXT *ctx,
71         unsigned int M,unsigned int L,void *key)
72 {
73         memset(ctx->nonce.c,0,sizeof(ctx->nonce.c));
74         ctx->nonce.c[0] = ((u8)(L-1)&7) | (u8)(((M-2)/2)&7)<<3;
75         ctx->blocks = 0;
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                 *((size_t *)&ctx->nonce.s[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
114         if (alen==0) return;
115
116         ctx->nonce.c[0] |= 0x40;        /* set Adata flag */
117         (*ctx->block)(ctx->nonce.c,ctx->cmac.c,ctx->key),
118         ctx->blocks++;
119
120         if (alen<(0x10000-0x100)) {
121                 ctx->cmac.c[0] ^= (u8)(alen>>8);
122                 ctx->cmac.c[1] ^= (u8)alen;
123                 i=2;
124         }
125         else if (sizeof(alen)==8 && alen>=(size_t)1<<32) {
126                 ctx->cmac.c[0] ^= 0xFF;
127                 ctx->cmac.c[1] ^= 0xFF;
128                 ctx->cmac.c[2] ^= (u8)(alen>>(56%(sizeof(alen)*8)));
129                 ctx->cmac.c[3] ^= (u8)(alen>>(48%(sizeof(alen)*8)));
130                 ctx->cmac.c[4] ^= (u8)(alen>>(40%(sizeof(alen)*8)));
131                 ctx->cmac.c[5] ^= (u8)(alen>>(32%(sizeof(alen)*8)));
132                 ctx->cmac.c[6] ^= (u8)(alen>>24);
133                 ctx->cmac.c[7] ^= (u8)(alen>>16);
134                 ctx->cmac.c[8] ^= (u8)(alen>>8);
135                 ctx->cmac.c[9] ^= (u8)alen;
136                 i=10;
137         }
138         else {
139                 ctx->cmac.c[0] ^= 0xFF;
140                 ctx->cmac.c[1] ^= 0xFE;
141                 ctx->cmac.c[2] ^= (u8)(alen>>24);
142                 ctx->cmac.c[3] ^= (u8)(alen>>16);
143                 ctx->cmac.c[4] ^= (u8)(alen>>8);
144                 ctx->cmac.c[5] ^= (u8)alen;
145                 i=6;
146         }
147
148         do {
149                 for(;i<16 && alen;++i,++aad,--alen)
150                         ctx->cmac.c[i] ^= *aad;
151                 (*ctx->block)(ctx->cmac.c,ctx->cmac.c,ctx->key),
152                 ctx->blocks++;
153                 i=0;
154         } while (alen);
155 }
156
157 /* Finally you encrypt or decrypt the message */
158
159 static void ctr128_inc(unsigned char *counter) {
160         unsigned int n=16;
161         u8  c;
162
163         do {
164                 --n;
165                 c = counter[n];
166                 ++c;
167                 counter[n] = c;
168                 if (c) return;
169         } while (n);
170 }
171
172 int CRYPTO_ccm128_encrypt(CCM128_CONTEXT *ctx,
173         const unsigned char *inp, unsigned char *out,
174         size_t len)
175 {
176         size_t          n;
177         unsigned int    i;
178         unsigned char   flags = ctx->nonce.c[0];
179
180         if (!(flags&0x40))
181                 (*ctx->block)(ctx->nonce.c,ctx->cmac.c,ctx->key),
182                 ctx->blocks++;
183
184         flags &= 7;     /* extract the L parameter */
185         for (n=0,i=15-flags;i<15;++i) {
186                 n |= ctx->nonce.c[i]; ctx->nonce.c[i]=0;
187                 n <<= 8;
188         }
189         n |= ctx->nonce.c[15];  /* reconstructed length */
190         ctx->nonce.c[15]=1;
191
192         if (n!=len) return -1;  /* length mismatch */
193
194         ctx->blocks += ((len+15)>>3)|1;
195         if (ctx->blocks > (U64(1)<<61)) return -2; /* too much data */
196
197         while (len>=16) {
198 #if defined(STRICT_ALIGNMENT)
199                 memcpy (ctx->inp.c,inp,16);
200                 for (i=0; i<16/sizeof(size_t); ++i)
201                         ctx->cmac.s[i] ^= ctx->inp.s[i];
202 #else
203                 for (i=0; i<16/sizeof(size_t); ++i)
204                         ctx->cmac.s[i] ^= ((size_t*)inp)[i];
205 #endif
206                 (*ctx->block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
207                 (*ctx->block)(ctx->nonce.c,ctx->scratch.c,ctx->key);
208                 ctr128_inc(ctx->nonce.c);
209 #if defined(STRICT_ALIGNMENT)
210                 for (i=0; i<16/sizeof(size_t); ++i)
211                         ctx->inp.s[i] ^= ctx->scratch.s[i];
212                 memcpy(out,ctx->inp.c,16);
213 #else
214                 for (i=0; i<16/sizeof(size_t); ++i)
215                         ((size_t*)out)[i] = ctx->scratch.s[i]^((size_t*)inp)[i];
216 #endif
217                 inp += 16;
218                 out += 16;
219                 len -= 16;
220         }
221
222         if (len) {
223                 for (i=0; i<len; ++i) ctx->cmac.c[i] ^= inp[i];
224                 (*ctx->block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
225                 (*ctx->block)(ctx->nonce.c,ctx->scratch.c,ctx->key);
226                 for (i=0; i<len; ++i) out[i] = ctx->scratch.c[i]^inp[i];
227         }
228
229         for (i=15-flags;i<16;++i)
230                 ctx->nonce.c[i]=0;
231
232         (*ctx->block)(ctx->nonce.c,ctx->scratch.c,ctx->key);
233         for (i=0; i<16/sizeof(size_t); ++i)
234                 ctx->cmac.s[i] ^= ctx->scratch.s[i];
235
236         return 0;
237 }
238
239 int CRYPTO_ccm128_decrypt(CCM128_CONTEXT *ctx,
240         const unsigned char *inp, unsigned char *out,
241         size_t len)
242 {
243         size_t          n;
244         unsigned int    i;
245         unsigned char   flags = ctx->nonce.c[0];
246
247         if (!(flags&0x40))
248                 (*ctx->block)(ctx->nonce.c,ctx->cmac.c,ctx->key);
249
250         flags &= 7;     /* extract the L parameter */
251         for (n=0,i=15-flags;i<15;++i) {
252                 n |= ctx->nonce.c[i]; ctx->nonce.c[i]=0;
253                 n <<= 8;
254         }
255         n |= ctx->nonce.c[15];  /* reconstructed length */
256         ctx->nonce.c[15]=1;
257
258         if (n!=len) return -1;
259
260         while (len>=16) {
261                 (*ctx->block)(ctx->nonce.c,ctx->scratch.c,ctx->key);
262                 ctr128_inc(ctx->nonce.c);
263 #if defined(STRICT_ALIGNMENT)
264                 memcpy (ctx->inp.c,inp,16);
265                 for (i=0; i<16/sizeof(size_t); ++i)
266                         ctx->cmac.s[i] ^= (ctx->scratch.s[i] ^= ctx->inp.s[i]);
267                 memcpy (out,ctx->scratch,16);
268 #else
269                 for (i=0; i<16/sizeof(size_t); ++i)
270                         ctx->cmac.s[i] ^= ((size_t*)out)[i] = ctx->scratch.s[i]^((size_t*)inp)[i];
271 #endif
272                 (*ctx->block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
273
274                 inp += 16;
275                 out += 16;
276                 len -= 16;
277         }
278
279         if (len) {
280                 (*ctx->block)(ctx->nonce.c,ctx->scratch.c,ctx->key);
281                 for (i=0; i<len; ++len)
282                         ctx->cmac.c[i] ^= (out[i] = ctx->scratch.c[i]^inp[i]);
283                 (*ctx->block)(ctx->cmac.c,ctx->cmac.c,ctx->key);
284         }
285
286         for (i=15-flags;i<16;++i)
287                 ctx->nonce.c[i]=0;
288
289         (*ctx->block)(ctx->nonce.c,ctx->scratch.c,ctx->key);
290         for (i=0; i<16/sizeof(size_t); ++i)
291                 ctx->cmac.s[i] ^= ctx->scratch.s[i];
292
293         return 0;
294 }
295
296 size_t CRYPTO_ccm128_tag(CCM128_CONTEXT *ctx,unsigned char *tag,size_t len)
297 {       unsigned int M = (ctx->nonce.c[0]>>3)&7;        /* the M parameter */
298
299         M *= 2; M += 2;
300         if (len<M)      return 0;
301         memcpy(tag,ctx->cmac.c,M);
302         return M;
303 }