f8f4ba57753ff945e796bb235be43d47abfb2361
[openssl.git] / crypto / aes / aes_ige.c
1 /* ====================================================================
2  * Copyright (c) 2006 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
51 #include "internal/cryptlib.h"
52
53 #include <openssl/aes.h>
54 #include "aes_locl.h"
55
56 #define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
57 typedef struct {
58     unsigned long data[N_WORDS];
59 } aes_block_t;
60
61 /* XXX: probably some better way to do this */
62 #if defined(__i386__) || defined(__x86_64__)
63 # define UNALIGNED_MEMOPS_ARE_FAST 1
64 #else
65 # define UNALIGNED_MEMOPS_ARE_FAST 0
66 #endif
67
68 #if UNALIGNED_MEMOPS_ARE_FAST
69 # define load_block(d, s)        (d) = *(const aes_block_t *)(s)
70 # define store_block(d, s)       *(aes_block_t *)(d) = (s)
71 #else
72 # define load_block(d, s)        memcpy((d).data, (s), AES_BLOCK_SIZE)
73 # define store_block(d, s)       memcpy((d), (s).data, AES_BLOCK_SIZE)
74 #endif
75
76 /* N.B. The IV for this mode is _twice_ the block size */
77
78 void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
79                      size_t length, const AES_KEY *key,
80                      unsigned char *ivec, const int enc)
81 {
82     size_t n;
83     size_t len = length;
84
85     OPENSSL_assert(in && out && key && ivec);
86     OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
87     OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
88
89     len = length / AES_BLOCK_SIZE;
90
91     if (AES_ENCRYPT == enc) {
92         if (in != out &&
93             (UNALIGNED_MEMOPS_ARE_FAST
94              || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
95              0)) {
96             aes_block_t *ivp = (aes_block_t *) ivec;
97             aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
98
99             while (len) {
100                 aes_block_t *inp = (aes_block_t *) in;
101                 aes_block_t *outp = (aes_block_t *) out;
102
103                 for (n = 0; n < N_WORDS; ++n)
104                     outp->data[n] = inp->data[n] ^ ivp->data[n];
105                 AES_encrypt((unsigned char *)outp->data,
106                             (unsigned char *)outp->data, key);
107                 for (n = 0; n < N_WORDS; ++n)
108                     outp->data[n] ^= iv2p->data[n];
109                 ivp = outp;
110                 iv2p = inp;
111                 --len;
112                 in += AES_BLOCK_SIZE;
113                 out += AES_BLOCK_SIZE;
114             }
115             memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
116             memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
117         } else {
118             aes_block_t tmp, tmp2;
119             aes_block_t iv;
120             aes_block_t iv2;
121
122             load_block(iv, ivec);
123             load_block(iv2, ivec + AES_BLOCK_SIZE);
124
125             while (len) {
126                 load_block(tmp, in);
127                 for (n = 0; n < N_WORDS; ++n)
128                     tmp2.data[n] = tmp.data[n] ^ iv.data[n];
129                 AES_encrypt((unsigned char *)tmp2.data,
130                             (unsigned char *)tmp2.data, key);
131                 for (n = 0; n < N_WORDS; ++n)
132                     tmp2.data[n] ^= iv2.data[n];
133                 store_block(out, tmp2);
134                 iv = tmp2;
135                 iv2 = tmp;
136                 --len;
137                 in += AES_BLOCK_SIZE;
138                 out += AES_BLOCK_SIZE;
139             }
140             memcpy(ivec, iv.data, AES_BLOCK_SIZE);
141             memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
142         }
143     } else {
144         if (in != out &&
145             (UNALIGNED_MEMOPS_ARE_FAST
146              || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
147              0)) {
148             aes_block_t *ivp = (aes_block_t *) ivec;
149             aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
150
151             while (len) {
152                 aes_block_t tmp;
153                 aes_block_t *inp = (aes_block_t *) in;
154                 aes_block_t *outp = (aes_block_t *) out;
155
156                 for (n = 0; n < N_WORDS; ++n)
157                     tmp.data[n] = inp->data[n] ^ iv2p->data[n];
158                 AES_decrypt((unsigned char *)tmp.data,
159                             (unsigned char *)outp->data, key);
160                 for (n = 0; n < N_WORDS; ++n)
161                     outp->data[n] ^= ivp->data[n];
162                 ivp = inp;
163                 iv2p = outp;
164                 --len;
165                 in += AES_BLOCK_SIZE;
166                 out += AES_BLOCK_SIZE;
167             }
168             memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
169             memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
170         } else {
171             aes_block_t tmp, tmp2;
172             aes_block_t iv;
173             aes_block_t iv2;
174
175             load_block(iv, ivec);
176             load_block(iv2, ivec + AES_BLOCK_SIZE);
177
178             while (len) {
179                 load_block(tmp, in);
180                 tmp2 = tmp;
181                 for (n = 0; n < N_WORDS; ++n)
182                     tmp.data[n] ^= iv2.data[n];
183                 AES_decrypt((unsigned char *)tmp.data,
184                             (unsigned char *)tmp.data, key);
185                 for (n = 0; n < N_WORDS; ++n)
186                     tmp.data[n] ^= iv.data[n];
187                 store_block(out, tmp);
188                 iv = tmp2;
189                 iv2 = tmp;
190                 --len;
191                 in += AES_BLOCK_SIZE;
192                 out += AES_BLOCK_SIZE;
193             }
194             memcpy(ivec, iv.data, AES_BLOCK_SIZE);
195             memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
196         }
197     }
198 }
199
200 /*
201  * Note that its effectively impossible to do biIGE in anything other
202  * than a single pass, so no provision is made for chaining.
203  */
204
205 /* N.B. The IV for this mode is _four times_ the block size */
206
207 void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
208                         size_t length, const AES_KEY *key,
209                         const AES_KEY *key2, const unsigned char *ivec,
210                         const int enc)
211 {
212     size_t n;
213     size_t len = length;
214     unsigned char tmp[AES_BLOCK_SIZE];
215     unsigned char tmp2[AES_BLOCK_SIZE];
216     unsigned char tmp3[AES_BLOCK_SIZE];
217     unsigned char prev[AES_BLOCK_SIZE];
218     const unsigned char *iv;
219     const unsigned char *iv2;
220
221     OPENSSL_assert(in && out && key && ivec);
222     OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
223     OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
224
225     if (AES_ENCRYPT == enc) {
226         /*
227          * XXX: Do a separate case for when in != out (strictly should check
228          * for overlap, too)
229          */
230
231         /* First the forward pass */
232         iv = ivec;
233         iv2 = ivec + AES_BLOCK_SIZE;
234         while (len >= AES_BLOCK_SIZE) {
235             for (n = 0; n < AES_BLOCK_SIZE; ++n)
236                 out[n] = in[n] ^ iv[n];
237             AES_encrypt(out, out, key);
238             for (n = 0; n < AES_BLOCK_SIZE; ++n)
239                 out[n] ^= iv2[n];
240             iv = out;
241             memcpy(prev, in, AES_BLOCK_SIZE);
242             iv2 = prev;
243             len -= AES_BLOCK_SIZE;
244             in += AES_BLOCK_SIZE;
245             out += AES_BLOCK_SIZE;
246         }
247
248         /* And now backwards */
249         iv = ivec + AES_BLOCK_SIZE * 2;
250         iv2 = ivec + AES_BLOCK_SIZE * 3;
251         len = length;
252         while (len >= AES_BLOCK_SIZE) {
253             out -= AES_BLOCK_SIZE;
254             /*
255              * XXX: reduce copies by alternating between buffers
256              */
257             memcpy(tmp, out, AES_BLOCK_SIZE);
258             for (n = 0; n < AES_BLOCK_SIZE; ++n)
259                 out[n] ^= iv[n];
260             /*
261              * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE);
262              */
263             AES_encrypt(out, out, key);
264             /*
265              * hexdump(stdout,"enc", out, AES_BLOCK_SIZE);
266              */
267             /*
268              * hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE);
269              */
270             for (n = 0; n < AES_BLOCK_SIZE; ++n)
271                 out[n] ^= iv2[n];
272             /*
273              * hexdump(stdout,"out", out, AES_BLOCK_SIZE);
274              */
275             iv = out;
276             memcpy(prev, tmp, AES_BLOCK_SIZE);
277             iv2 = prev;
278             len -= AES_BLOCK_SIZE;
279         }
280     } else {
281         /* First backwards */
282         iv = ivec + AES_BLOCK_SIZE * 2;
283         iv2 = ivec + AES_BLOCK_SIZE * 3;
284         in += length;
285         out += length;
286         while (len >= AES_BLOCK_SIZE) {
287             in -= AES_BLOCK_SIZE;
288             out -= AES_BLOCK_SIZE;
289             memcpy(tmp, in, AES_BLOCK_SIZE);
290             memcpy(tmp2, in, AES_BLOCK_SIZE);
291             for (n = 0; n < AES_BLOCK_SIZE; ++n)
292                 tmp[n] ^= iv2[n];
293             AES_decrypt(tmp, out, key);
294             for (n = 0; n < AES_BLOCK_SIZE; ++n)
295                 out[n] ^= iv[n];
296             memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
297             iv = tmp3;
298             iv2 = out;
299             len -= AES_BLOCK_SIZE;
300         }
301
302         /* And now forwards */
303         iv = ivec;
304         iv2 = ivec + AES_BLOCK_SIZE;
305         len = length;
306         while (len >= AES_BLOCK_SIZE) {
307             memcpy(tmp, out, AES_BLOCK_SIZE);
308             memcpy(tmp2, out, AES_BLOCK_SIZE);
309             for (n = 0; n < AES_BLOCK_SIZE; ++n)
310                 tmp[n] ^= iv2[n];
311             AES_decrypt(tmp, out, key);
312             for (n = 0; n < AES_BLOCK_SIZE; ++n)
313                 out[n] ^= iv[n];
314             memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
315             iv = tmp3;
316             iv2 = out;
317             len -= AES_BLOCK_SIZE;
318             in += AES_BLOCK_SIZE;
319             out += AES_BLOCK_SIZE;
320         }
321     }
322 }