aes_ige.c revision 194206
1100384Speter/* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */
2100384Speter/* ====================================================================
3100384Speter * Copyright (c) 2006 The OpenSSL Project.  All rights reserved.
4100384Speter *
5100384Speter * Redistribution and use in source and binary forms, with or without
6100384Speter * modification, are permitted provided that the following conditions
7100384Speter * are met:
8100384Speter *
9100384Speter * 1. Redistributions of source code must retain the above copyright
10100384Speter *    notice, this list of conditions and the following disclaimer.
11100384Speter *
12100384Speter * 2. Redistributions in binary form must reproduce the above copyright
13100384Speter *    notice, this list of conditions and the following disclaimer in
14100384Speter *    the documentation and/or other materials provided with the
15100384Speter *    distribution.
16100384Speter *
17100384Speter * 3. All advertising materials mentioning features or use of this
18100384Speter *    software must display the following acknowledgment:
19100384Speter *    "This product includes software developed by the OpenSSL Project
20100384Speter *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21100384Speter *
22100384Speter * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23100384Speter *    endorse or promote products derived from this software without
24100384Speter *    prior written permission. For written permission, please contact
25100384Speter *    openssl-core@openssl.org.
26100384Speter *
27118031Sobrien * 5. Products derived from this software may not be called "OpenSSL"
28118031Sobrien *    nor may "OpenSSL" appear in their names without prior written
29118031Sobrien *    permission of the OpenSSL Project.
30104738Speter *
31191673Sjamie * 6. Redistributions of any form whatsoever must retain the following
32191673Sjamie *    acknowledgment:
33104738Speter *    "This product includes software developed by the OpenSSL Project
34100384Speter *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35100384Speter *
36162954Sphk * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37100384Speter * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38100384Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39100384Speter * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40100384Speter * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41185435Sbz * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42100384Speter * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43161343Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44100384Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45100384Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46100384Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47151909Sps * OF THE POSSIBILITY OF SUCH DAMAGE.
48100384Speter * ====================================================================
49100384Speter *
50100384Speter */
51100384Speter
52183044Sobrien#include "cryptlib.h"
53100384Speter
54100384Speter#include <openssl/aes.h>
55100384Speter#include "aes_locl.h"
56100384Speter
57100384Speter#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
58146950Spstypedef struct {
59100384Speter        unsigned long data[N_WORDS];
60100384Speter} aes_block_t;
61100384Speter
62100384Speter/* XXX: probably some better way to do this */
63100384Speter#if defined(__i386__) || defined(__x86_64__)
64100384Speter#define UNALIGNED_MEMOPS_ARE_FAST 1
65150883Sjhb#else
66113859Sjhb#define UNALIGNED_MEMOPS_ARE_FAST 0
67100384Speter#endif
68100384Speter
69100384Speter#if UNALIGNED_MEMOPS_ARE_FAST
70183044Sobrien#define load_block(d, s)        (d) = *(const aes_block_t *)(s)
71162551Sdavidxu#define store_block(d, s)       *(aes_block_t *)(d) = (s)
72100384Speter#else
73162551Sdavidxu#define load_block(d, s)        memcpy((d).data, (s), AES_BLOCK_SIZE)
74100384Speter#define store_block(d, s)       memcpy((d), (s).data, AES_BLOCK_SIZE)
75127140Sjhb#endif
76157285Sps
77174381Sjhb/* N.B. The IV for this mode is _twice_ the block size */
78174381Sjhb
79157285Spsvoid AES_ige_encrypt(const unsigned char *in, unsigned char *out,
80100384Speter					 const unsigned long length, const AES_KEY *key,
81191673Sjamie					 unsigned char *ivec, const int enc)
82191673Sjamie	{
83191673Sjamie	unsigned long n;
84191673Sjamie	unsigned long len;
85100384Speter
86100384Speter	OPENSSL_assert(in && out && key && ivec);
87100384Speter	OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
88100384Speter	OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
89100384Speter
90100384Speter	len = length / AES_BLOCK_SIZE;
91100384Speter
92100384Speter	if (AES_ENCRYPT == enc)
93151582Sps		{
94151582Sps		if (in != out &&
95183188Sobrien		    (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
96183188Sobrien			{
97119333Speter			aes_block_t *ivp = (aes_block_t *)ivec;
98119333Speter			aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
99174380Sjhb
100163018Sdavidxu			while (len)
101119333Speter				{
102100384Speter				aes_block_t *inp = (aes_block_t *)in;
103121719Speter				aes_block_t *outp = (aes_block_t *)out;
104121719Speter
105174377Sjhb				for(n=0 ; n < N_WORDS; ++n)
106121719Speter					outp->data[n] = inp->data[n] ^ ivp->data[n];
107121719Speter				AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key);
108174377Sjhb				for(n=0 ; n < N_WORDS; ++n)
109174377Sjhb					outp->data[n] ^= iv2p->data[n];
110174377Sjhb				ivp = outp;
111174377Sjhb				iv2p = inp;
112174377Sjhb				--len;
113174377Sjhb				in += AES_BLOCK_SIZE;
114121719Speter				out += AES_BLOCK_SIZE;
115174377Sjhb				}
116174377Sjhb			memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
117174377Sjhb			memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
118100384Speter			}
119119333Speter		else
120100384Speter			{
121127140Sjhb			aes_block_t tmp, tmp2;
122127140Sjhb			aes_block_t iv;
123136152Sjhb			aes_block_t iv2;
124100384Speter
125136152Sjhb			load_block(iv, ivec);
126136152Sjhb			load_block(iv2, ivec + AES_BLOCK_SIZE);
127136152Sjhb
128136152Sjhb			while (len)
129136152Sjhb				{
130100384Speter				load_block(tmp, in);
131100384Speter				for(n=0 ; n < N_WORDS; ++n)
132127140Sjhb					tmp2.data[n] = tmp.data[n] ^ iv.data[n];
133127140Sjhb				AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key);
134127140Sjhb				for(n=0 ; n < N_WORDS; ++n)
135100384Speter					tmp2.data[n] ^= iv2.data[n];
136100384Speter				store_block(out, tmp2);
137100384Speter				iv = tmp2;
138100384Speter				iv2 = tmp;
139100384Speter				--len;
140100384Speter				in += AES_BLOCK_SIZE;
141100384Speter				out += AES_BLOCK_SIZE;
142100384Speter				}
143100384Speter			memcpy(ivec, iv.data, AES_BLOCK_SIZE);
144100384Speter			memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
145100384Speter			}
146100384Speter		}
147100384Speter	else
148100384Speter		{
149100384Speter		if (in != out &&
150100384Speter		    (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0))
151127140Sjhb			{
152100384Speter			aes_block_t *ivp = (aes_block_t *)ivec;
153100384Speter			aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE);
154100384Speter
155100384Speter			while (len)
156128597Smarcel				{
157174526Sjhb				aes_block_t tmp;
158100384Speter				aes_block_t *inp = (aes_block_t *)in;
159100384Speter				aes_block_t *outp = (aes_block_t *)out;
160172003Sjhb
161174424Sscottl				for(n=0 ; n < N_WORDS; ++n)
162156266Sps					tmp.data[n] = inp->data[n] ^ iv2p->data[n];
163100384Speter				AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key);
164172003Sjhb				for(n=0 ; n < N_WORDS; ++n)
165100384Speter					outp->data[n] ^= ivp->data[n];
166100384Speter				ivp = inp;
167100384Speter				iv2p = outp;
168172003Sjhb				--len;
169174526Sjhb				in += AES_BLOCK_SIZE;
170100384Speter				out += AES_BLOCK_SIZE;
171100384Speter				}
172100384Speter			memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
173100384Speter			memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
174174526Sjhb			}
175174526Sjhb		else
176156266Sps			{
177156266Sps			aes_block_t tmp, tmp2;
178156266Sps			aes_block_t iv;
179156266Sps			aes_block_t iv2;
180174526Sjhb
181174526Sjhb			load_block(iv, ivec);
182156266Sps			load_block(iv2, ivec + AES_BLOCK_SIZE);
183156266Sps
184100384Speter			while (len)
185128597Smarcel				{
186100384Speter				load_block(tmp, in);
187128597Smarcel				tmp2 = tmp;
188100384Speter				for(n=0 ; n < N_WORDS; ++n)
189128260Speter					tmp.data[n] ^= iv2.data[n];
190100384Speter				AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key);
191147178Spjd				for(n=0 ; n < N_WORDS; ++n)
192147178Spjd					tmp.data[n] ^= iv.data[n];
193147178Spjd				store_block(out, tmp);
194100384Speter				iv = tmp2;
195100384Speter				iv2 = tmp;
196147178Spjd				--len;
197147178Spjd				in += AES_BLOCK_SIZE;
198147302Spjd				out += AES_BLOCK_SIZE;
199147302Spjd				}
200100384Speter			memcpy(ivec, iv.data, AES_BLOCK_SIZE);
201147178Spjd			memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
202147178Spjd			}
203174526Sjhb		}
204147178Spjd	}
205147178Spjd
206147178Spjd/*
207147178Spjd * Note that its effectively impossible to do biIGE in anything other
208100384Speter * than a single pass, so no provision is made for chaining.
209147178Spjd */
210100384Speter
211100384Speter/* N.B. The IV for this mode is _four times_ the block size */
212100384Speter
213128597Smarcelvoid AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
214100384Speter						const unsigned long length, const AES_KEY *key,
215100384Speter						const AES_KEY *key2, const unsigned char *ivec,
216119333Speter						const int enc)
217119333Speter	{
218100384Speter	unsigned long n;
219113859Sjhb	unsigned long len = length;
220113859Sjhb	unsigned char tmp[AES_BLOCK_SIZE];
221100384Speter	unsigned char tmp2[AES_BLOCK_SIZE];
222100384Speter	unsigned char tmp3[AES_BLOCK_SIZE];
223113859Sjhb	unsigned char prev[AES_BLOCK_SIZE];
224113859Sjhb	const unsigned char *iv;
225100384Speter	const unsigned char *iv2;
226100384Speter
227113859Sjhb	OPENSSL_assert(in && out && key && ivec);
228113859Sjhb	OPENSSL_assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc));
229113859Sjhb	OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);
230113859Sjhb
231113859Sjhb	if (AES_ENCRYPT == enc)
232113859Sjhb		{
233113859Sjhb		/* XXX: Do a separate case for when in != out (strictly should
234113859Sjhb		   check for overlap, too) */
235113859Sjhb
236113859Sjhb		/* First the forward pass */
237113859Sjhb		iv = ivec;
238113859Sjhb		iv2 = ivec + AES_BLOCK_SIZE;
239100384Speter		while (len >= AES_BLOCK_SIZE)
240100384Speter			{
241100384Speter			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
242100384Speter				out[n] = in[n] ^ iv[n];
243142059Sjhb			AES_encrypt(out, out, key);
244142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
245142059Sjhb				out[n] ^= iv2[n];
246142059Sjhb			iv = out;
247142059Sjhb			memcpy(prev, in, AES_BLOCK_SIZE);
248142059Sjhb			iv2 = prev;
249142059Sjhb			len -= AES_BLOCK_SIZE;
250100384Speter			in += AES_BLOCK_SIZE;
251142059Sjhb			out += AES_BLOCK_SIZE;
252142059Sjhb			}
253142059Sjhb
254100384Speter		/* And now backwards */
255100384Speter		iv = ivec + AES_BLOCK_SIZE*2;
256142059Sjhb		iv2 = ivec + AES_BLOCK_SIZE*3;
257142059Sjhb		len = length;
258142059Sjhb		while(len >= AES_BLOCK_SIZE)
259100384Speter			{
260142059Sjhb			out -= AES_BLOCK_SIZE;
261142059Sjhb			/* XXX: reduce copies by alternating between buffers */
262142059Sjhb			memcpy(tmp, out, AES_BLOCK_SIZE);
263142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
264147588Sjhb				out[n] ^= iv[n];
265147588Sjhb			/*			hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */
266142059Sjhb			AES_encrypt(out, out, key);
267142059Sjhb			/*			hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */
268142059Sjhb			/*			hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */
269142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
270142059Sjhb				out[n] ^= iv2[n];
271142059Sjhb			/*			hexdump(stdout,"out", out, AES_BLOCK_SIZE); */
272142059Sjhb			iv = out;
273142059Sjhb			memcpy(prev, tmp, AES_BLOCK_SIZE);
274142059Sjhb			iv2 = prev;
275177789Skib			len -= AES_BLOCK_SIZE;
276177789Skib			}
277177789Skib		}
278177789Skib	else
279177789Skib		{
280177789Skib		/* First backwards */
281177789Skib		iv = ivec + AES_BLOCK_SIZE*2;
282177789Skib		iv2 = ivec + AES_BLOCK_SIZE*3;
283177789Skib		in += length;
284142059Sjhb		out += length;
285142059Sjhb		while (len >= AES_BLOCK_SIZE)
286142059Sjhb			{
287142059Sjhb			in -= AES_BLOCK_SIZE;
288142059Sjhb			out -= AES_BLOCK_SIZE;
289142059Sjhb			memcpy(tmp, in, AES_BLOCK_SIZE);
290142059Sjhb			memcpy(tmp2, in, AES_BLOCK_SIZE);
291142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
292156440Sups				tmp[n] ^= iv2[n];
293142059Sjhb			AES_decrypt(tmp, out, key);
294142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
295142059Sjhb				out[n] ^= iv[n];
296142059Sjhb			memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
297142059Sjhb			iv = tmp3;
298142059Sjhb			iv2 = out;
299156440Sups			len -= AES_BLOCK_SIZE;
300156440Sups			}
301142059Sjhb
302142059Sjhb		/* And now forwards */
303142059Sjhb		iv = ivec;
304142059Sjhb		iv2 = ivec + AES_BLOCK_SIZE;
305100384Speter		len = length;
306142059Sjhb		while (len >= AES_BLOCK_SIZE)
307142059Sjhb			{
308142059Sjhb			memcpy(tmp, out, AES_BLOCK_SIZE);
309142059Sjhb			memcpy(tmp2, out, AES_BLOCK_SIZE);
310142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
311142059Sjhb				tmp[n] ^= iv2[n];
312142059Sjhb			AES_decrypt(tmp, out, key);
313142059Sjhb			for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
314142059Sjhb				out[n] ^= iv[n];
315100384Speter			memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
316100384Speter			iv = tmp3;
317156440Sups			iv2 = out;
318142059Sjhb			len -= AES_BLOCK_SIZE;
319142059Sjhb			in += AES_BLOCK_SIZE;
320142059Sjhb			out += AES_BLOCK_SIZE;
321142059Sjhb			}
322142059Sjhb		}
323142059Sjhb	}
324142059Sjhb