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