9125264ed98e6a950ab4bf34c5aa11bc5a85959d
[openssl.git] / crypto / aes / aes_ige.c
1 /*
2  * Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/cryptlib.h"
11
12 #include <openssl/aes.h>
13 #include "aes_locl.h"
14
15 #define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
16 typedef struct {
17     unsigned long data[N_WORDS];
18 } aes_block_t;
19
20 /* XXX: probably some better way to do this */
21 #if defined(__i386__) || defined(__x86_64__)
22 # define UNALIGNED_MEMOPS_ARE_FAST 1
23 #else
24 # define UNALIGNED_MEMOPS_ARE_FAST 0
25 #endif
26
27 #if UNALIGNED_MEMOPS_ARE_FAST
28 # define load_block(d, s)        (d) = *(const aes_block_t *)(s)
29 # define store_block(d, s)       *(aes_block_t *)(d) = (s)
30 #else
31 # define load_block(d, s)        memcpy((d).data, (s), AES_BLOCK_SIZE)
32 # define store_block(d, s)       memcpy((d), (s).data, AES_BLOCK_SIZE)
33 #endif
34
35 /* N.B. The IV for this mode is _twice_ the block size */
36
37 void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
38                      size_t length, const AES_KEY *key,
39                      unsigned char *ivec, const int enc)
40 {
41     size_t n;
42     size_t len = length;
43
44     OPENSSL_assert(in && out && key && ivec);
45     OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
46     OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
47
48     len = length / AES_BLOCK_SIZE;
49
50     if (AES_ENCRYPT == enc) {
51         if (in != out &&
52             (UNALIGNED_MEMOPS_ARE_FAST
53              || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
54              0)) {
55             aes_block_t *ivp = (aes_block_t *) ivec;
56             aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
57
58             while (len) {
59                 aes_block_t *inp = (aes_block_t *) in;
60                 aes_block_t *outp = (aes_block_t *) out;
61
62                 for (n = 0; n < N_WORDS; ++n)
63                     outp->data[n] = inp->data[n] ^ ivp->data[n];
64                 AES_encrypt((unsigned char *)outp->data,
65                             (unsigned char *)outp->data, key);
66                 for (n = 0; n < N_WORDS; ++n)
67                     outp->data[n] ^= iv2p->data[n];
68                 ivp = outp;
69                 iv2p = inp;
70                 --len;
71                 in += AES_BLOCK_SIZE;
72                 out += AES_BLOCK_SIZE;
73             }
74             memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
75             memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
76         } else {
77             aes_block_t tmp, tmp2;
78             aes_block_t iv;
79             aes_block_t iv2;
80
81             load_block(iv, ivec);
82             load_block(iv2, ivec + AES_BLOCK_SIZE);
83
84             while (len) {
85                 load_block(tmp, in);
86                 for (n = 0; n < N_WORDS; ++n)
87                     tmp2.data[n] = tmp.data[n] ^ iv.data[n];
88                 AES_encrypt((unsigned char *)tmp2.data,
89                             (unsigned char *)tmp2.data, key);
90                 for (n = 0; n < N_WORDS; ++n)
91                     tmp2.data[n] ^= iv2.data[n];
92                 store_block(out, tmp2);
93                 iv = tmp2;
94                 iv2 = tmp;
95                 --len;
96                 in += AES_BLOCK_SIZE;
97                 out += AES_BLOCK_SIZE;
98             }
99             memcpy(ivec, iv.data, AES_BLOCK_SIZE);
100             memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
101         }
102     } else {
103         if (in != out &&
104             (UNALIGNED_MEMOPS_ARE_FAST
105              || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
106              0)) {
107             aes_block_t *ivp = (aes_block_t *) ivec;
108             aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
109
110             while (len) {
111                 aes_block_t tmp;
112                 aes_block_t *inp = (aes_block_t *) in;
113                 aes_block_t *outp = (aes_block_t *) out;
114
115                 for (n = 0; n < N_WORDS; ++n)
116                     tmp.data[n] = inp->data[n] ^ iv2p->data[n];
117                 AES_decrypt((unsigned char *)tmp.data,
118                             (unsigned char *)outp->data, key);
119                 for (n = 0; n < N_WORDS; ++n)
120                     outp->data[n] ^= ivp->data[n];
121                 ivp = inp;
122                 iv2p = outp;
123                 --len;
124                 in += AES_BLOCK_SIZE;
125                 out += AES_BLOCK_SIZE;
126             }
127             memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
128             memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
129         } else {
130             aes_block_t tmp, tmp2;
131             aes_block_t iv;
132             aes_block_t iv2;
133
134             load_block(iv, ivec);
135             load_block(iv2, ivec + AES_BLOCK_SIZE);
136
137             while (len) {
138                 load_block(tmp, in);
139                 tmp2 = tmp;
140                 for (n = 0; n < N_WORDS; ++n)
141                     tmp.data[n] ^= iv2.data[n];
142                 AES_decrypt((unsigned char *)tmp.data,
143                             (unsigned char *)tmp.data, key);
144                 for (n = 0; n < N_WORDS; ++n)
145                     tmp.data[n] ^= iv.data[n];
146                 store_block(out, tmp);
147                 iv = tmp2;
148                 iv2 = tmp;
149                 --len;
150                 in += AES_BLOCK_SIZE;
151                 out += AES_BLOCK_SIZE;
152             }
153             memcpy(ivec, iv.data, AES_BLOCK_SIZE);
154             memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
155         }
156     }
157 }
158
159 /*
160  * Note that its effectively impossible to do biIGE in anything other
161  * than a single pass, so no provision is made for chaining.
162  */
163
164 /* N.B. The IV for this mode is _four times_ the block size */
165
166 void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
167                         size_t length, const AES_KEY *key,
168                         const AES_KEY *key2, const unsigned char *ivec,
169                         const int enc)
170 {
171     size_t n;
172     size_t len = length;
173     unsigned char tmp[AES_BLOCK_SIZE];
174     unsigned char tmp2[AES_BLOCK_SIZE];
175     unsigned char tmp3[AES_BLOCK_SIZE];
176     unsigned char prev[AES_BLOCK_SIZE];
177     const unsigned char *iv;
178     const unsigned char *iv2;
179
180     OPENSSL_assert(in && out && key && ivec);
181     OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
182     OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
183
184     if (AES_ENCRYPT == enc) {
185         /*
186          * XXX: Do a separate case for when in != out (strictly should check
187          * for overlap, too)
188          */
189
190         /* First the forward pass */
191         iv = ivec;
192         iv2 = ivec + AES_BLOCK_SIZE;
193         while (len >= AES_BLOCK_SIZE) {
194             for (n = 0; n < AES_BLOCK_SIZE; ++n)
195                 out[n] = in[n] ^ iv[n];
196             AES_encrypt(out, out, key);
197             for (n = 0; n < AES_BLOCK_SIZE; ++n)
198                 out[n] ^= iv2[n];
199             iv = out;
200             memcpy(prev, in, AES_BLOCK_SIZE);
201             iv2 = prev;
202             len -= AES_BLOCK_SIZE;
203             in += AES_BLOCK_SIZE;
204             out += AES_BLOCK_SIZE;
205         }
206
207         /* And now backwards */
208         iv = ivec + AES_BLOCK_SIZE * 2;
209         iv2 = ivec + AES_BLOCK_SIZE * 3;
210         len = length;
211         while (len >= AES_BLOCK_SIZE) {
212             out -= AES_BLOCK_SIZE;
213             /*
214              * XXX: reduce copies by alternating between buffers
215              */
216             memcpy(tmp, out, AES_BLOCK_SIZE);
217             for (n = 0; n < AES_BLOCK_SIZE; ++n)
218                 out[n] ^= iv[n];
219             /*
220              * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE);
221              */
222             AES_encrypt(out, out, key);
223             /*
224              * hexdump(stdout,"enc", out, AES_BLOCK_SIZE);
225              */
226             /*
227              * hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE);
228              */
229             for (n = 0; n < AES_BLOCK_SIZE; ++n)
230                 out[n] ^= iv2[n];
231             /*
232              * hexdump(stdout,"out", out, AES_BLOCK_SIZE);
233              */
234             iv = out;
235             memcpy(prev, tmp, AES_BLOCK_SIZE);
236             iv2 = prev;
237             len -= AES_BLOCK_SIZE;
238         }
239     } else {
240         /* First backwards */
241         iv = ivec + AES_BLOCK_SIZE * 2;
242         iv2 = ivec + AES_BLOCK_SIZE * 3;
243         in += length;
244         out += length;
245         while (len >= AES_BLOCK_SIZE) {
246             in -= AES_BLOCK_SIZE;
247             out -= AES_BLOCK_SIZE;
248             memcpy(tmp, in, AES_BLOCK_SIZE);
249             memcpy(tmp2, in, AES_BLOCK_SIZE);
250             for (n = 0; n < AES_BLOCK_SIZE; ++n)
251                 tmp[n] ^= iv2[n];
252             AES_decrypt(tmp, out, key);
253             for (n = 0; n < AES_BLOCK_SIZE; ++n)
254                 out[n] ^= iv[n];
255             memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
256             iv = tmp3;
257             iv2 = out;
258             len -= AES_BLOCK_SIZE;
259         }
260
261         /* And now forwards */
262         iv = ivec;
263         iv2 = ivec + AES_BLOCK_SIZE;
264         len = length;
265         while (len >= AES_BLOCK_SIZE) {
266             memcpy(tmp, out, AES_BLOCK_SIZE);
267             memcpy(tmp2, out, AES_BLOCK_SIZE);
268             for (n = 0; n < AES_BLOCK_SIZE; ++n)
269                 tmp[n] ^= iv2[n];
270             AES_decrypt(tmp, out, key);
271             for (n = 0; n < AES_BLOCK_SIZE; ++n)
272                 out[n] ^= iv[n];
273             memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
274             iv = tmp3;
275             iv2 = out;
276             len -= AES_BLOCK_SIZE;
277             in += AES_BLOCK_SIZE;
278             out += AES_BLOCK_SIZE;
279         }
280     }
281 }