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