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