51119186de25b7d1d9ec268314bf72c021bb2713
[openssl.git] / crypto / aes / aes_ige.c
1 /*
2  * Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (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 /*
11  * AES_encrypt/AES_decrypt are deprecated - but we need to use them to implement
12  * these functions
13  */
14 #include "internal/deprecated.h"
15
16 #include "internal/cryptlib.h"
17
18 #include <openssl/aes.h>
19 #include "aes_local.h"
20
21 #define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
22 typedef struct {
23     unsigned long data[N_WORDS];
24 } aes_block_t;
25
26 /* XXX: probably some better way to do this */
27 #if defined(__i386__) || defined(__x86_64__)
28 # define UNALIGNED_MEMOPS_ARE_FAST 1
29 #else
30 # define UNALIGNED_MEMOPS_ARE_FAST 0
31 #endif
32
33 #if UNALIGNED_MEMOPS_ARE_FAST
34 # define load_block(d, s)        (d) = *(const aes_block_t *)(s)
35 # define store_block(d, s)       *(aes_block_t *)(d) = (s)
36 #else
37 # define load_block(d, s)        memcpy((d).data, (s), AES_BLOCK_SIZE)
38 # define store_block(d, s)       memcpy((d), (s).data, AES_BLOCK_SIZE)
39 #endif
40
41 /* N.B. The IV for this mode is _twice_ the block size */
42
43 /*  Use of this function is deprecated. */
44 void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
45                      size_t length, const AES_KEY *key,
46                      unsigned char *ivec, const int enc)
47 {
48     size_t n;
49     size_t len = length;
50
51     if (length == 0)
52         return;
53
54     OPENSSL_assert(in && out && key && ivec);
55     OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
56     OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
57
58     len = length / AES_BLOCK_SIZE;
59
60     if (AES_ENCRYPT == enc) {
61         if (in != out &&
62             (UNALIGNED_MEMOPS_ARE_FAST
63              || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
64              0)) {
65             aes_block_t *ivp = (aes_block_t *) ivec;
66             aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
67
68             while (len) {
69                 aes_block_t *inp = (aes_block_t *) in;
70                 aes_block_t *outp = (aes_block_t *) out;
71
72                 for (n = 0; n < N_WORDS; ++n)
73                     outp->data[n] = inp->data[n] ^ ivp->data[n];
74                 AES_encrypt((unsigned char *)outp->data,
75                             (unsigned char *)outp->data, key);
76                 for (n = 0; n < N_WORDS; ++n)
77                     outp->data[n] ^= iv2p->data[n];
78                 ivp = outp;
79                 iv2p = inp;
80                 --len;
81                 in += AES_BLOCK_SIZE;
82                 out += AES_BLOCK_SIZE;
83             }
84             memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
85             memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
86         } else {
87             aes_block_t tmp, tmp2;
88             aes_block_t iv;
89             aes_block_t iv2;
90
91             load_block(iv, ivec);
92             load_block(iv2, ivec + AES_BLOCK_SIZE);
93
94             while (len) {
95                 load_block(tmp, in);
96                 for (n = 0; n < N_WORDS; ++n)
97                     tmp2.data[n] = tmp.data[n] ^ iv.data[n];
98                 AES_encrypt((unsigned char *)tmp2.data,
99                             (unsigned char *)tmp2.data, key);
100                 for (n = 0; n < N_WORDS; ++n)
101                     tmp2.data[n] ^= iv2.data[n];
102                 store_block(out, tmp2);
103                 iv = tmp2;
104                 iv2 = tmp;
105                 --len;
106                 in += AES_BLOCK_SIZE;
107                 out += AES_BLOCK_SIZE;
108             }
109             memcpy(ivec, iv.data, AES_BLOCK_SIZE);
110             memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
111         }
112     } else {
113         if (in != out &&
114             (UNALIGNED_MEMOPS_ARE_FAST
115              || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
116              0)) {
117             aes_block_t *ivp = (aes_block_t *) ivec;
118             aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
119
120             while (len) {
121                 aes_block_t tmp;
122                 aes_block_t *inp = (aes_block_t *) in;
123                 aes_block_t *outp = (aes_block_t *) out;
124
125                 for (n = 0; n < N_WORDS; ++n)
126                     tmp.data[n] = inp->data[n] ^ iv2p->data[n];
127                 AES_decrypt((unsigned char *)tmp.data,
128                             (unsigned char *)outp->data, key);
129                 for (n = 0; n < N_WORDS; ++n)
130                     outp->data[n] ^= ivp->data[n];
131                 ivp = inp;
132                 iv2p = outp;
133                 --len;
134                 in += AES_BLOCK_SIZE;
135                 out += AES_BLOCK_SIZE;
136             }
137             memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
138             memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
139         } else {
140             aes_block_t tmp, tmp2;
141             aes_block_t iv;
142             aes_block_t iv2;
143
144             load_block(iv, ivec);
145             load_block(iv2, ivec + AES_BLOCK_SIZE);
146
147             while (len) {
148                 load_block(tmp, in);
149                 tmp2 = tmp;
150                 for (n = 0; n < N_WORDS; ++n)
151                     tmp.data[n] ^= iv2.data[n];
152                 AES_decrypt((unsigned char *)tmp.data,
153                             (unsigned char *)tmp.data, key);
154                 for (n = 0; n < N_WORDS; ++n)
155                     tmp.data[n] ^= iv.data[n];
156                 store_block(out, tmp);
157                 iv = tmp2;
158                 iv2 = tmp;
159                 --len;
160                 in += AES_BLOCK_SIZE;
161                 out += AES_BLOCK_SIZE;
162             }
163             memcpy(ivec, iv.data, AES_BLOCK_SIZE);
164             memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
165         }
166     }
167 }
168
169 /*
170  * Note that its effectively impossible to do biIGE in anything other
171  * than a single pass, so no provision is made for chaining.
172  *
173  * NB: The implementation of AES_bi_ige_encrypt has a bug. It is supposed to use
174  * 2 AES keys, but in fact only one is ever used. This bug has been present
175  * since this code was first implemented. It is believed to have minimal
176  * security impact in practice and has therefore not been fixed for backwards
177  * compatibility reasons.
178  *
179  * Use of this function is deprecated.
180  */
181
182 /* N.B. The IV for this mode is _four times_ the block size */
183
184 void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
185                         size_t length, const AES_KEY *key,
186                         const AES_KEY *key2, const unsigned char *ivec,
187                         const int enc)
188 {
189     size_t n;
190     size_t len = length;
191     unsigned char tmp[AES_BLOCK_SIZE];
192     unsigned char tmp2[AES_BLOCK_SIZE];
193     unsigned char tmp3[AES_BLOCK_SIZE];
194     unsigned char prev[AES_BLOCK_SIZE];
195     const unsigned char *iv;
196     const unsigned char *iv2;
197
198     OPENSSL_assert(in && out && key && ivec);
199     OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
200     OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
201
202     if (AES_ENCRYPT == enc) {
203         /*
204          * XXX: Do a separate case for when in != out (strictly should check
205          * for overlap, too)
206          */
207
208         /* First the forward pass */
209         iv = ivec;
210         iv2 = ivec + AES_BLOCK_SIZE;
211         while (len >= AES_BLOCK_SIZE) {
212             for (n = 0; n < AES_BLOCK_SIZE; ++n)
213                 out[n] = in[n] ^ iv[n];
214             AES_encrypt(out, out, key);
215             for (n = 0; n < AES_BLOCK_SIZE; ++n)
216                 out[n] ^= iv2[n];
217             iv = out;
218             memcpy(prev, in, AES_BLOCK_SIZE);
219             iv2 = prev;
220             len -= AES_BLOCK_SIZE;
221             in += AES_BLOCK_SIZE;
222             out += AES_BLOCK_SIZE;
223         }
224
225         /* And now backwards */
226         iv = ivec + AES_BLOCK_SIZE * 2;
227         iv2 = ivec + AES_BLOCK_SIZE * 3;
228         len = length;
229         while (len >= AES_BLOCK_SIZE) {
230             out -= AES_BLOCK_SIZE;
231             /*
232              * XXX: reduce copies by alternating between buffers
233              */
234             memcpy(tmp, out, AES_BLOCK_SIZE);
235             for (n = 0; n < AES_BLOCK_SIZE; ++n)
236                 out[n] ^= iv[n];
237             /*
238              * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE);
239              */
240             AES_encrypt(out, out, key);
241             /*
242              * hexdump(stdout,"enc", out, AES_BLOCK_SIZE);
243              */
244             /*
245              * hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE);
246              */
247             for (n = 0; n < AES_BLOCK_SIZE; ++n)
248                 out[n] ^= iv2[n];
249             /*
250              * hexdump(stdout,"out", out, AES_BLOCK_SIZE);
251              */
252             iv = out;
253             memcpy(prev, tmp, AES_BLOCK_SIZE);
254             iv2 = prev;
255             len -= AES_BLOCK_SIZE;
256         }
257     } else {
258         /* First backwards */
259         iv = ivec + AES_BLOCK_SIZE * 2;
260         iv2 = ivec + AES_BLOCK_SIZE * 3;
261         in += length;
262         out += length;
263         while (len >= AES_BLOCK_SIZE) {
264             in -= AES_BLOCK_SIZE;
265             out -= AES_BLOCK_SIZE;
266             memcpy(tmp, in, AES_BLOCK_SIZE);
267             memcpy(tmp2, in, 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         }
278
279         /* And now forwards */
280         iv = ivec;
281         iv2 = ivec + AES_BLOCK_SIZE;
282         len = length;
283         while (len >= AES_BLOCK_SIZE) {
284             memcpy(tmp, out, AES_BLOCK_SIZE);
285             memcpy(tmp2, out, AES_BLOCK_SIZE);
286             for (n = 0; n < AES_BLOCK_SIZE; ++n)
287                 tmp[n] ^= iv2[n];
288             AES_decrypt(tmp, out, key);
289             for (n = 0; n < AES_BLOCK_SIZE; ++n)
290                 out[n] ^= iv[n];
291             memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
292             iv = tmp3;
293             iv2 = out;
294             len -= AES_BLOCK_SIZE;
295             in += AES_BLOCK_SIZE;
296             out += AES_BLOCK_SIZE;
297         }
298     }
299 }