Coverage Report

Created: 2025-04-22 06:18

/src/openssl/crypto/aes/aes_ige.c
Line
Count
Source (jump to first uncovered line)
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
0
# define UNALIGNED_MEMOPS_ARE_FAST 1
24
#else
25
# define UNALIGNED_MEMOPS_ARE_FAST 0
26
#endif
27
28
0
#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
0
# define load_block(d, s)        (d) = *(const aes_block_t *)(s)
39
0
# 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
0
{
52
0
    size_t n;
53
0
    size_t len = length / AES_BLOCK_SIZE;
54
55
0
    if (length == 0)
56
0
        return;
57
58
0
    OPENSSL_assert(in && out && key && ivec);
59
0
    OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
60
0
    OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
61
62
0
    if (AES_ENCRYPT == enc) {
63
0
        if (in != out &&
64
0
            (UNALIGNED_MEMOPS_ARE_FAST
65
0
             || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
66
0
             0)) {
67
0
            aes_block_t *ivp = (aes_block_t *) ivec;
68
0
            aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
69
70
0
            while (len) {
71
0
                aes_block_t *inp = (aes_block_t *) in;
72
0
                aes_block_t *outp = (aes_block_t *) out;
73
74
0
                for (n = 0; n < N_WORDS; ++n)
75
0
                    outp->data[n] = inp->data[n] ^ ivp->data[n];
76
0
                AES_encrypt((unsigned char *)outp->data,
77
0
                            (unsigned char *)outp->data, key);
78
0
                for (n = 0; n < N_WORDS; ++n)
79
0
                    outp->data[n] ^= iv2p->data[n];
80
0
                ivp = outp;
81
0
                iv2p = inp;
82
0
                --len;
83
0
                in += AES_BLOCK_SIZE;
84
0
                out += AES_BLOCK_SIZE;
85
0
            }
86
0
            memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
87
0
            memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
88
0
        } else {
89
0
            aes_block_t tmp, tmp2;
90
0
            aes_block_t iv;
91
0
            aes_block_t iv2;
92
93
0
            load_block(iv, ivec);
94
0
            load_block(iv2, ivec + AES_BLOCK_SIZE);
95
96
0
            while (len) {
97
0
                load_block(tmp, in);
98
0
                for (n = 0; n < N_WORDS; ++n)
99
0
                    tmp2.data[n] = tmp.data[n] ^ iv.data[n];
100
0
                AES_encrypt((unsigned char *)tmp2.data,
101
0
                            (unsigned char *)tmp2.data, key);
102
0
                for (n = 0; n < N_WORDS; ++n)
103
0
                    tmp2.data[n] ^= iv2.data[n];
104
0
                store_block(out, tmp2);
105
0
                iv = tmp2;
106
0
                iv2 = tmp;
107
0
                --len;
108
0
                in += AES_BLOCK_SIZE;
109
0
                out += AES_BLOCK_SIZE;
110
0
            }
111
0
            memcpy(ivec, iv.data, AES_BLOCK_SIZE);
112
0
            memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
113
0
        }
114
0
    } else {
115
0
        if (in != out &&
116
0
            (UNALIGNED_MEMOPS_ARE_FAST
117
0
             || ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
118
0
             0)) {
119
0
            aes_block_t *ivp = (aes_block_t *) ivec;
120
0
            aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
121
122
0
            while (len) {
123
0
                aes_block_t tmp;
124
0
                aes_block_t *inp = (aes_block_t *) in;
125
0
                aes_block_t *outp = (aes_block_t *) out;
126
127
0
                for (n = 0; n < N_WORDS; ++n)
128
0
                    tmp.data[n] = inp->data[n] ^ iv2p->data[n];
129
0
                AES_decrypt((unsigned char *)tmp.data,
130
0
                            (unsigned char *)outp->data, key);
131
0
                for (n = 0; n < N_WORDS; ++n)
132
0
                    outp->data[n] ^= ivp->data[n];
133
0
                ivp = inp;
134
0
                iv2p = outp;
135
0
                --len;
136
0
                in += AES_BLOCK_SIZE;
137
0
                out += AES_BLOCK_SIZE;
138
0
            }
139
0
            memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
140
0
            memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
141
0
        } else {
142
0
            aes_block_t tmp, tmp2;
143
0
            aes_block_t iv;
144
0
            aes_block_t iv2;
145
146
0
            load_block(iv, ivec);
147
0
            load_block(iv2, ivec + AES_BLOCK_SIZE);
148
149
0
            while (len) {
150
0
                load_block(tmp, in);
151
0
                tmp2 = tmp;
152
0
                for (n = 0; n < N_WORDS; ++n)
153
0
                    tmp.data[n] ^= iv2.data[n];
154
0
                AES_decrypt((unsigned char *)tmp.data,
155
0
                            (unsigned char *)tmp.data, key);
156
0
                for (n = 0; n < N_WORDS; ++n)
157
0
                    tmp.data[n] ^= iv.data[n];
158
0
                store_block(out, tmp);
159
0
                iv = tmp2;
160
0
                iv2 = tmp;
161
0
                --len;
162
0
                in += AES_BLOCK_SIZE;
163
0
                out += AES_BLOCK_SIZE;
164
0
            }
165
0
            memcpy(ivec, iv.data, AES_BLOCK_SIZE);
166
0
            memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
167
0
        }
168
0
    }
169
0
}
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
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
0
{
191
0
    size_t n;
192
0
    size_t len = length;
193
0
    unsigned char tmp[AES_BLOCK_SIZE];
194
0
    unsigned char tmp2[AES_BLOCK_SIZE];
195
0
    unsigned char tmp3[AES_BLOCK_SIZE];
196
0
    unsigned char prev[AES_BLOCK_SIZE];
197
0
    const unsigned char *iv;
198
0
    const unsigned char *iv2;
199
200
0
    OPENSSL_assert(in && out && key && ivec);
201
0
    OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
202
0
    OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
203
204
0
    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
0
        iv = ivec;
212
0
        iv2 = ivec + AES_BLOCK_SIZE;
213
0
        while (len >= AES_BLOCK_SIZE) {
214
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
215
0
                out[n] = in[n] ^ iv[n];
216
0
            AES_encrypt(out, out, key);
217
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
218
0
                out[n] ^= iv2[n];
219
0
            iv = out;
220
0
            memcpy(prev, in, AES_BLOCK_SIZE);
221
0
            iv2 = prev;
222
0
            len -= AES_BLOCK_SIZE;
223
0
            in += AES_BLOCK_SIZE;
224
0
            out += AES_BLOCK_SIZE;
225
0
        }
226
227
        /* And now backwards */
228
0
        iv = ivec + AES_BLOCK_SIZE * 2;
229
0
        iv2 = ivec + AES_BLOCK_SIZE * 3;
230
0
        len = length;
231
0
        while (len >= AES_BLOCK_SIZE) {
232
0
            out -= AES_BLOCK_SIZE;
233
            /*
234
             * XXX: reduce copies by alternating between buffers
235
             */
236
0
            memcpy(tmp, out, AES_BLOCK_SIZE);
237
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
238
0
                out[n] ^= iv[n];
239
            /*
240
             * hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE);
241
             */
242
0
            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
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
250
0
                out[n] ^= iv2[n];
251
            /*
252
             * hexdump(stdout,"out", out, AES_BLOCK_SIZE);
253
             */
254
0
            iv = out;
255
0
            memcpy(prev, tmp, AES_BLOCK_SIZE);
256
0
            iv2 = prev;
257
0
            len -= AES_BLOCK_SIZE;
258
0
        }
259
0
    } else {
260
        /* First backwards */
261
0
        iv = ivec + AES_BLOCK_SIZE * 2;
262
0
        iv2 = ivec + AES_BLOCK_SIZE * 3;
263
0
        in += length;
264
0
        out += length;
265
0
        while (len >= AES_BLOCK_SIZE) {
266
0
            in -= AES_BLOCK_SIZE;
267
0
            out -= AES_BLOCK_SIZE;
268
0
            memcpy(tmp, in, AES_BLOCK_SIZE);
269
0
            memcpy(tmp2, in, AES_BLOCK_SIZE);
270
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
271
0
                tmp[n] ^= iv2[n];
272
0
            AES_decrypt(tmp, out, key);
273
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
274
0
                out[n] ^= iv[n];
275
0
            memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
276
0
            iv = tmp3;
277
0
            iv2 = out;
278
0
            len -= AES_BLOCK_SIZE;
279
0
        }
280
281
        /* And now forwards */
282
0
        iv = ivec;
283
0
        iv2 = ivec + AES_BLOCK_SIZE;
284
0
        len = length;
285
0
        while (len >= AES_BLOCK_SIZE) {
286
0
            memcpy(tmp, out, AES_BLOCK_SIZE);
287
0
            memcpy(tmp2, out, AES_BLOCK_SIZE);
288
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
289
0
                tmp[n] ^= iv2[n];
290
0
            AES_decrypt(tmp, out, key);
291
0
            for (n = 0; n < AES_BLOCK_SIZE; ++n)
292
0
                out[n] ^= iv[n];
293
0
            memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
294
0
            iv = tmp3;
295
0
            iv2 = out;
296
0
            len -= AES_BLOCK_SIZE;
297
0
            in += AES_BLOCK_SIZE;
298
0
            out += AES_BLOCK_SIZE;
299
0
        }
300
0
    }
301
0
}