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