1/* crypto/camellia/camellia_cbc.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#ifndef CAMELLIA_DEBUG
53# ifndef NDEBUG
54#  define NDEBUG
55# endif
56#endif
57#include <assert.h>
58#include <stdio.h>
59#include <string.h>
60
61#include <openssl/camellia.h>
62#include "cmll_locl.h"
63
64void Camellia_cbc_encrypt(const unsigned char *in, unsigned char *out,
65		     const unsigned long length, const CAMELLIA_KEY *key,
66		     unsigned char *ivec, const int enc) {
67
68	unsigned long n;
69	unsigned long len = length;
70	const unsigned char *iv = ivec;
71	union {	u32 t32[CAMELLIA_BLOCK_SIZE/sizeof(u32)];
72		u8  t8 [CAMELLIA_BLOCK_SIZE]; } tmp;
73	const union { long one; char little; } camellia_endian = {1};
74
75
76	assert(in && out && key && ivec);
77	assert((CAMELLIA_ENCRYPT == enc)||(CAMELLIA_DECRYPT == enc));
78
79	if(((size_t)in|(size_t)out|(size_t)ivec) % sizeof(u32) == 0)
80		{
81		if (CAMELLIA_ENCRYPT == enc)
82			{
83			while (len >= CAMELLIA_BLOCK_SIZE)
84				{
85				XOR4WORD2((u32 *)out,
86					(u32 *)in, (u32 *)iv);
87				if (camellia_endian.little)
88					SWAP4WORD((u32 *)out);
89				key->enc(key->rd_key, (u32 *)out);
90				if (camellia_endian.little)
91					SWAP4WORD((u32 *)out);
92				iv = out;
93				len -= CAMELLIA_BLOCK_SIZE;
94				in += CAMELLIA_BLOCK_SIZE;
95				out += CAMELLIA_BLOCK_SIZE;
96				}
97			if (len)
98				{
99				for(n=0; n < len; ++n)
100					out[n] = in[n] ^ iv[n];
101				for(n=len; n < CAMELLIA_BLOCK_SIZE; ++n)
102					out[n] = iv[n];
103				if (camellia_endian.little)
104					SWAP4WORD((u32 *)out);
105				key->enc(key->rd_key, (u32 *)out);
106				if (camellia_endian.little)
107					SWAP4WORD((u32 *)out);
108				iv = out;
109				}
110			memcpy(ivec,iv,CAMELLIA_BLOCK_SIZE);
111			}
112		else if (in != out)
113			{
114			while (len >= CAMELLIA_BLOCK_SIZE)
115				{
116				memcpy(out,in,CAMELLIA_BLOCK_SIZE);
117				if (camellia_endian.little)
118					SWAP4WORD((u32 *)out);
119				key->dec(key->rd_key,(u32 *)out);
120				if (camellia_endian.little)
121					SWAP4WORD((u32 *)out);
122				XOR4WORD((u32 *)out, (u32 *)iv);
123				iv = in;
124				len -= CAMELLIA_BLOCK_SIZE;
125				in  += CAMELLIA_BLOCK_SIZE;
126				out += CAMELLIA_BLOCK_SIZE;
127				}
128			if (len)
129				{
130				memcpy(tmp.t8, in, CAMELLIA_BLOCK_SIZE);
131				if (camellia_endian.little)
132					SWAP4WORD(tmp.t32);
133				key->dec(key->rd_key, tmp.t32);
134				if (camellia_endian.little)
135					SWAP4WORD(tmp.t32);
136				for(n=0; n < len; ++n)
137					out[n] = tmp.t8[n] ^ iv[n];
138				iv = in;
139				}
140			memcpy(ivec,iv,CAMELLIA_BLOCK_SIZE);
141			}
142		else /* in == out */
143			{
144			while (len >= CAMELLIA_BLOCK_SIZE)
145				{
146				memcpy(tmp.t8, in, CAMELLIA_BLOCK_SIZE);
147				if (camellia_endian.little)
148					SWAP4WORD((u32 *)out);
149				key->dec(key->rd_key, (u32 *)out);
150				if (camellia_endian.little)
151					SWAP4WORD((u32 *)out);
152				XOR4WORD((u32 *)out, (u32 *)ivec);
153				memcpy(ivec, tmp.t8, CAMELLIA_BLOCK_SIZE);
154				len -= CAMELLIA_BLOCK_SIZE;
155				in += CAMELLIA_BLOCK_SIZE;
156				out += CAMELLIA_BLOCK_SIZE;
157				}
158			if (len)
159				{
160				memcpy(tmp.t8, in, CAMELLIA_BLOCK_SIZE);
161				if (camellia_endian.little)
162					SWAP4WORD((u32 *)out);
163				key->dec(key->rd_key,(u32 *)out);
164				if (camellia_endian.little)
165					SWAP4WORD((u32 *)out);
166				for(n=0; n < len; ++n)
167					out[n] ^= ivec[n];
168				for(n=len; n < CAMELLIA_BLOCK_SIZE; ++n)
169					out[n] = tmp.t8[n];
170				memcpy(ivec, tmp.t8, CAMELLIA_BLOCK_SIZE);
171				}
172			}
173		}
174	else /* no aligned */
175		{
176		if (CAMELLIA_ENCRYPT == enc)
177			{
178			while (len >= CAMELLIA_BLOCK_SIZE)
179				{
180				for(n=0; n < CAMELLIA_BLOCK_SIZE; ++n)
181					tmp.t8[n] = in[n] ^ iv[n];
182				if (camellia_endian.little)
183					SWAP4WORD(tmp.t32);
184				key->enc(key->rd_key, tmp.t32);
185				if (camellia_endian.little)
186					SWAP4WORD(tmp.t32);
187				memcpy(out, tmp.t8, CAMELLIA_BLOCK_SIZE);
188				iv = out;
189				len -= CAMELLIA_BLOCK_SIZE;
190				in += CAMELLIA_BLOCK_SIZE;
191				out += CAMELLIA_BLOCK_SIZE;
192				}
193			if (len)
194				{
195				for(n=0; n < len; ++n)
196					tmp.t8[n] = in[n] ^ iv[n];
197				for(n=len; n < CAMELLIA_BLOCK_SIZE; ++n)
198					tmp.t8[n] = iv[n];
199				if (camellia_endian.little)
200					SWAP4WORD(tmp.t32);
201				key->enc(key->rd_key, tmp.t32);
202				if (camellia_endian.little)
203					SWAP4WORD(tmp.t32);
204				memcpy(out, tmp.t8, CAMELLIA_BLOCK_SIZE);
205				iv = out;
206				}
207			memcpy(ivec,iv,CAMELLIA_BLOCK_SIZE);
208			}
209		else if (in != out)
210			{
211			while (len >= CAMELLIA_BLOCK_SIZE)
212				{
213				memcpy(tmp.t8,in,CAMELLIA_BLOCK_SIZE);
214				if (camellia_endian.little)
215					SWAP4WORD(tmp.t32);
216				key->dec(key->rd_key,tmp.t32);
217				if (camellia_endian.little)
218					SWAP4WORD(tmp.t32);
219				for(n=0; n < CAMELLIA_BLOCK_SIZE; ++n)
220					out[n] = tmp.t8[n] ^ iv[n];
221				iv = in;
222				len -= CAMELLIA_BLOCK_SIZE;
223				in  += CAMELLIA_BLOCK_SIZE;
224				out += CAMELLIA_BLOCK_SIZE;
225				}
226			if (len)
227				{
228				memcpy(tmp.t8, in, CAMELLIA_BLOCK_SIZE);
229				if (camellia_endian.little)
230					SWAP4WORD(tmp.t32);
231				key->dec(key->rd_key, tmp.t32);
232				if (camellia_endian.little)
233					SWAP4WORD(tmp.t32);
234				for(n=0; n < len; ++n)
235					out[n] = tmp.t8[n] ^ iv[n];
236				iv = in;
237				}
238			memcpy(ivec,iv,CAMELLIA_BLOCK_SIZE);
239			}
240		else
241			{
242			while (len >= CAMELLIA_BLOCK_SIZE)
243				{
244				memcpy(tmp.t8, in, CAMELLIA_BLOCK_SIZE);
245				if (camellia_endian.little)
246					SWAP4WORD(tmp.t32);
247				key->dec(key->rd_key, tmp.t32);
248				if (camellia_endian.little)
249					SWAP4WORD(tmp.t32);
250				for(n=0; n < CAMELLIA_BLOCK_SIZE; ++n)
251					tmp.t8[n] ^= ivec[n];
252				memcpy(ivec, in, CAMELLIA_BLOCK_SIZE);
253				memcpy(out, tmp.t8, CAMELLIA_BLOCK_SIZE);
254				len -= CAMELLIA_BLOCK_SIZE;
255				in += CAMELLIA_BLOCK_SIZE;
256				out += CAMELLIA_BLOCK_SIZE;
257				}
258			if (len)
259				{
260				memcpy(tmp.t8, in, CAMELLIA_BLOCK_SIZE);
261				if (camellia_endian.little)
262					SWAP4WORD(tmp.t32);
263				key->dec(key->rd_key,tmp.t32);
264				if (camellia_endian.little)
265					SWAP4WORD(tmp.t32);
266				for(n=0; n < len; ++n)
267					tmp.t8[n] ^= ivec[n];
268				memcpy(ivec, in, CAMELLIA_BLOCK_SIZE);
269				memcpy(out,tmp.t8,len);
270				}
271			}
272		}
273}
274