Branch data Line data Source code
1 : : /* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */
2 : : /* ====================================================================
3 : : * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions
7 : : * are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : *
12 : : * 2. Redistributions in binary form must reproduce the above copyright
13 : : * notice, this list of conditions and the following disclaimer in
14 : : * the documentation and/or other materials provided with the
15 : : * distribution.
16 : : *
17 : : * 3. All advertising materials mentioning features or use of this
18 : : * software must display the following acknowledgment:
19 : : * "This product includes software developed by the OpenSSL Project
20 : : * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21 : : *
22 : : * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 : : * endorse or promote products derived from this software without
24 : : * prior written permission. For written permission, please contact
25 : : * openssl-core@openssl.org.
26 : : *
27 : : * 5. Products derived from this software may not be called "OpenSSL"
28 : : * nor may "OpenSSL" appear in their names without prior written
29 : : * permission of the OpenSSL Project.
30 : : *
31 : : * 6. Redistributions of any form whatsoever must retain the following
32 : : * acknowledgment:
33 : : * "This product includes software developed by the OpenSSL Project
34 : : * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35 : : *
36 : : * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 : : * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 : : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 : : * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 : : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 : : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 : : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 : : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 : : * OF THE POSSIBILITY OF SUCH DAMAGE.
48 : : * ====================================================================
49 : : *
50 : : */
51 : :
52 : : #include "cryptlib.h"
53 : :
54 : : #include <openssl/aes.h>
55 : : #include "aes_locl.h"
56 : :
57 : : #define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
58 : : typedef struct {
59 : : unsigned long data[N_WORDS];
60 : : } aes_block_t;
61 : :
62 : : /* XXX: probably some better way to do this */
63 : : #if defined(__i386__) || defined(__x86_64__)
64 : : #define UNALIGNED_MEMOPS_ARE_FAST 1
65 : : #else
66 : : #define UNALIGNED_MEMOPS_ARE_FAST 0
67 : : #endif
68 : :
69 : : #if UNALIGNED_MEMOPS_ARE_FAST
70 : : #define load_block(d, s) (d) = *(const aes_block_t *)(s)
71 : : #define store_block(d, s) *(aes_block_t *)(d) = (s)
72 : : #else
73 : : #define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE)
74 : : #define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE)
75 : : #endif
76 : :
77 : : /* N.B. The IV for this mode is _twice_ the block size */
78 : :
79 : 21 : void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
80 : : size_t length, const AES_KEY *key,
81 : : unsigned char *ivec, const int enc)
82 : : {
83 : : size_t n;
84 : 21 : size_t len = length;
85 : :
86 [ + - ][ - + ]: 21 : OPENSSL_assert(in && out && key && ivec);
87 [ - + ]: 21 : OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
88 [ - + ]: 21 : OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
89 : :
90 : 21 : len = length / AES_BLOCK_SIZE;
91 : :
92 [ + + ]: 21 : if (AES_ENCRYPT == enc)
93 : : {
94 [ + + ]: 11 : if (in != out &&
95 : : (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
96 : : {
97 : 10 : aes_block_t *ivp = (aes_block_t *)ivec;
98 : 10 : aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
99 : :
100 [ + + ]: 2596 : while (len)
101 : : {
102 : : aes_block_t *inp = (aes_block_t *)in;
103 : : aes_block_t *outp = (aes_block_t *)out;
104 : :
105 [ + + ]: 7758 : for(n=0 ; n < N_WORDS; ++n)
106 : 5172 : outp->data[n] = inp->data[n] ^ ivp->data[n];
107 : 2586 : AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key);
108 [ + + ]: 7758 : for(n=0 ; n < N_WORDS; ++n)
109 : 5172 : outp->data[n] ^= iv2p->data[n];
110 : 2586 : ivp = outp;
111 : 2586 : iv2p = inp;
112 : 2586 : --len;
113 : 2586 : in += AES_BLOCK_SIZE;
114 : 2586 : out += AES_BLOCK_SIZE;
115 : : }
116 : 10 : memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
117 : 10 : memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
118 : : }
119 : : else
120 : : {
121 : : aes_block_t tmp, tmp2;
122 : : aes_block_t iv;
123 : : aes_block_t iv2;
124 : :
125 : 1 : load_block(iv, ivec);
126 : 1 : load_block(iv2, ivec + AES_BLOCK_SIZE);
127 : :
128 [ + + ]: 3 : while (len)
129 : : {
130 : 2 : load_block(tmp, in);
131 [ + + ]: 6 : for(n=0 ; n < N_WORDS; ++n)
132 : 4 : tmp2.data[n] = tmp.data[n] ^ iv.data[n];
133 : 2 : AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key);
134 [ + + ]: 6 : for(n=0 ; n < N_WORDS; ++n)
135 : 4 : tmp2.data[n] ^= iv2.data[n];
136 : 2 : store_block(out, tmp2);
137 : 2 : iv = tmp2;
138 : 2 : iv2 = tmp;
139 : 2 : --len;
140 : 2 : in += AES_BLOCK_SIZE;
141 : 2 : out += AES_BLOCK_SIZE;
142 : : }
143 : : memcpy(ivec, iv.data, AES_BLOCK_SIZE);
144 : 1 : memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
145 : : }
146 : : }
147 : : else
148 : : {
149 [ + + ]: 10 : if (in != out &&
150 : : (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
151 : : {
152 : 9 : aes_block_t *ivp = (aes_block_t *)ivec;
153 : 9 : aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
154 : :
155 [ + + ]: 2595 : while (len)
156 : : {
157 : : aes_block_t tmp;
158 : : aes_block_t *inp = (aes_block_t *)in;
159 : : aes_block_t *outp = (aes_block_t *)out;
160 : :
161 [ + + ]: 7758 : for(n=0 ; n < N_WORDS; ++n)
162 : 5172 : tmp.data[n] = inp->data[n] ^ iv2p->data[n];
163 : 2586 : AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key);
164 [ + + ]: 7758 : for(n=0 ; n < N_WORDS; ++n)
165 : 5172 : outp->data[n] ^= ivp->data[n];
166 : 2586 : ivp = inp;
167 : 2586 : iv2p = outp;
168 : 2586 : --len;
169 : 2586 : in += AES_BLOCK_SIZE;
170 : 2586 : out += AES_BLOCK_SIZE;
171 : : }
172 : 9 : memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
173 : 9 : memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
174 : : }
175 : : else
176 : : {
177 : : aes_block_t tmp, tmp2;
178 : : aes_block_t iv;
179 : : aes_block_t iv2;
180 : :
181 : 1 : load_block(iv, ivec);
182 : 1 : load_block(iv2, ivec + AES_BLOCK_SIZE);
183 : :
184 [ + + ]: 3 : while (len)
185 : : {
186 : 2 : load_block(tmp, in);
187 : 2 : tmp2 = tmp;
188 [ + + ]: 6 : for(n=0 ; n < N_WORDS; ++n)
189 : 4 : tmp.data[n] ^= iv2.data[n];
190 : 2 : AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key);
191 [ + + ]: 6 : for(n=0 ; n < N_WORDS; ++n)
192 : 4 : tmp.data[n] ^= iv.data[n];
193 : 2 : store_block(out, tmp);
194 : 2 : iv = tmp2;
195 : 2 : iv2 = tmp;
196 : 2 : --len;
197 : 2 : in += AES_BLOCK_SIZE;
198 : 2 : out += AES_BLOCK_SIZE;
199 : : }
200 : : memcpy(ivec, iv.data, AES_BLOCK_SIZE);
201 : 1 : memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
202 : : }
203 : : }
204 : 21 : }
205 : :
206 : : /*
207 : : * Note that its effectively impossible to do biIGE in anything other
208 : : * than a single pass, so no provision is made for chaining.
209 : : */
210 : :
211 : : /* N.B. The IV for this mode is _four times_ the block size */
212 : :
213 : 4 : void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
214 : : size_t length, const AES_KEY *key,
215 : : const AES_KEY *key2, const unsigned char *ivec,
216 : : const int enc)
217 : : {
218 : : size_t n;
219 : 4 : size_t len = length;
220 : : unsigned char tmp[AES_BLOCK_SIZE];
221 : : unsigned char tmp2[AES_BLOCK_SIZE];
222 : : unsigned char tmp3[AES_BLOCK_SIZE];
223 : : unsigned char prev[AES_BLOCK_SIZE];
224 : : const unsigned char *iv;
225 : : const unsigned char *iv2;
226 : :
227 [ + - ][ - + ]: 4 : OPENSSL_assert(in && out && key && ivec);
228 [ - + ]: 4 : OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
229 [ - + ]: 4 : OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
230 : :
231 [ + + ]: 4 : if (AES_ENCRYPT == enc)
232 : : {
233 : : /* XXX: Do a separate case for when in != out (strictly should
234 : : check for overlap, too) */
235 : :
236 : : /* First the forward pass */
237 : 3 : iv = ivec;
238 : 3 : iv2 = ivec + AES_BLOCK_SIZE;
239 [ + + ]: 17 : while (len >= AES_BLOCK_SIZE)
240 : : {
241 [ + + ]: 238 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
242 : 224 : out[n] = in[n] ^ iv[n];
243 : 14 : AES_encrypt(out, out, key);
244 [ + + ]: 238 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
245 : 224 : out[n] ^= iv2[n];
246 : 14 : iv = out;
247 : : memcpy(prev, in, AES_BLOCK_SIZE);
248 : 14 : iv2 = prev;
249 : 14 : len -= AES_BLOCK_SIZE;
250 : 14 : in += AES_BLOCK_SIZE;
251 : 14 : out += AES_BLOCK_SIZE;
252 : : }
253 : :
254 : : /* And now backwards */
255 : 3 : iv = ivec + AES_BLOCK_SIZE*2;
256 : 3 : iv2 = ivec + AES_BLOCK_SIZE*3;
257 : 3 : len = length;
258 [ + + ]: 17 : while(len >= AES_BLOCK_SIZE)
259 : : {
260 : 14 : out -= AES_BLOCK_SIZE;
261 : : /* XXX: reduce copies by alternating between buffers */
262 : : memcpy(tmp, out, AES_BLOCK_SIZE);
263 [ + + ]: 238 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
264 : 224 : out[n] ^= iv[n];
265 : : /* hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */
266 : 14 : AES_encrypt(out, out, key);
267 : : /* hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */
268 : : /* hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */
269 [ + + ]: 238 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
270 : 224 : out[n] ^= iv2[n];
271 : : /* hexdump(stdout,"out", out, AES_BLOCK_SIZE); */
272 : 14 : iv = out;
273 : : memcpy(prev, tmp, AES_BLOCK_SIZE);
274 : 14 : iv2 = prev;
275 : 14 : len -= AES_BLOCK_SIZE;
276 : : }
277 : : }
278 : : else
279 : : {
280 : : /* First backwards */
281 : 1 : iv = ivec + AES_BLOCK_SIZE*2;
282 : 1 : iv2 = ivec + AES_BLOCK_SIZE*3;
283 : 1 : in += length;
284 : 1 : out += length;
285 [ + + ]: 9 : while (len >= AES_BLOCK_SIZE)
286 : : {
287 : 8 : in -= AES_BLOCK_SIZE;
288 : 8 : out -= AES_BLOCK_SIZE;
289 : : memcpy(tmp, in, AES_BLOCK_SIZE);
290 : : memcpy(tmp2, in, AES_BLOCK_SIZE);
291 [ + + ]: 136 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
292 : 128 : tmp[n] ^= iv2[n];
293 : 8 : AES_decrypt(tmp, out, key);
294 [ + + ]: 136 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
295 : 128 : out[n] ^= iv[n];
296 : : memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
297 : 8 : iv = tmp3;
298 : 8 : iv2 = out;
299 : 8 : len -= AES_BLOCK_SIZE;
300 : : }
301 : :
302 : : /* And now forwards */
303 : 1 : iv = ivec;
304 : 1 : iv2 = ivec + AES_BLOCK_SIZE;
305 : 1 : len = length;
306 [ + + ]: 9 : while (len >= AES_BLOCK_SIZE)
307 : : {
308 : : memcpy(tmp, out, AES_BLOCK_SIZE);
309 : : memcpy(tmp2, out, AES_BLOCK_SIZE);
310 [ + + ]: 136 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
311 : 128 : tmp[n] ^= iv2[n];
312 : 8 : AES_decrypt(tmp, out, key);
313 [ + + ]: 136 : for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
314 : 128 : out[n] ^= iv[n];
315 : : memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
316 : 8 : iv = tmp3;
317 : 8 : iv2 = out;
318 : 8 : len -= AES_BLOCK_SIZE;
319 : 8 : in += AES_BLOCK_SIZE;
320 : 8 : out += AES_BLOCK_SIZE;
321 : : }
322 : : }
323 : 4 : }
|