xref: /freebsd/sys/crypto/rijndael/rijndael-api-fst.c (revision 8f21478b6abf87c55b5393195cc981047ee94e99)
18f21478bSHajimu UMEMOTO /*	$KAME: rijndael-api-fst.c,v 1.18 2003/07/24 15:10:30 itojun Exp $	*/
2fe2869c8SKris Kennaway 
38f21478bSHajimu UMEMOTO /**
48f21478bSHajimu UMEMOTO  * rijndael-api-fst.c
5fe2869c8SKris Kennaway  *
68f21478bSHajimu UMEMOTO  * @version 2.9 (December 2000)
7fe2869c8SKris Kennaway  *
88f21478bSHajimu UMEMOTO  * Optimised ANSI C code for the Rijndael cipher (now AES)
9fe2869c8SKris Kennaway  *
108f21478bSHajimu UMEMOTO  * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
118f21478bSHajimu UMEMOTO  * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
128f21478bSHajimu UMEMOTO  * @author Paulo Barreto <paulo.barreto@terra.com.br>
138f21478bSHajimu UMEMOTO  *
148f21478bSHajimu UMEMOTO  * This code is hereby placed in the public domain.
158f21478bSHajimu UMEMOTO  *
168f21478bSHajimu UMEMOTO  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
178f21478bSHajimu UMEMOTO  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
188f21478bSHajimu UMEMOTO  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198f21478bSHajimu UMEMOTO  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
208f21478bSHajimu UMEMOTO  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
218f21478bSHajimu UMEMOTO  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
228f21478bSHajimu UMEMOTO  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
238f21478bSHajimu UMEMOTO  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
248f21478bSHajimu UMEMOTO  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
258f21478bSHajimu UMEMOTO  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
268f21478bSHajimu UMEMOTO  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278f21478bSHajimu UMEMOTO  *
288f21478bSHajimu UMEMOTO  * Acknowledgements:
298f21478bSHajimu UMEMOTO  *
308f21478bSHajimu UMEMOTO  * We are deeply indebted to the following people for their bug reports,
318f21478bSHajimu UMEMOTO  * fixes, and improvement suggestions to this implementation. Though we
328f21478bSHajimu UMEMOTO  * tried to list all contributions, we apologise in advance for any
338f21478bSHajimu UMEMOTO  * missing reference.
348f21478bSHajimu UMEMOTO  *
358f21478bSHajimu UMEMOTO  * Andrew Bales <Andrew.Bales@Honeywell.com>
368f21478bSHajimu UMEMOTO  * Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
378f21478bSHajimu UMEMOTO  * John Skodon <skodonj@webquill.com>
38fe2869c8SKris Kennaway  */
39fe2869c8SKris Kennaway 
40ad39da78SDavid E. O'Brien #include <sys/cdefs.h>
41ad39da78SDavid E. O'Brien __FBSDID("$FreeBSD$");
42ad39da78SDavid E. O'Brien 
43fe2869c8SKris Kennaway #include <sys/param.h>
4433841545SHajimu UMEMOTO #ifdef _KERNEL
4533841545SHajimu UMEMOTO #include <sys/systm.h>
4633841545SHajimu UMEMOTO #else
478f21478bSHajimu UMEMOTO #include <stdlib.h>
4833841545SHajimu UMEMOTO #include <string.h>
4933841545SHajimu UMEMOTO #endif
508f21478bSHajimu UMEMOTO 
518f21478bSHajimu UMEMOTO #include <crypto/rijndael/rijndael_local.h>
52fe2869c8SKris Kennaway #include <crypto/rijndael/rijndael-alg-fst.h>
53fe2869c8SKris Kennaway #include <crypto/rijndael/rijndael-api-fst.h>
5427da1009SPoul-Henning Kamp 
55fe2869c8SKris Kennaway int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) {
568f21478bSHajimu UMEMOTO 	u_int8_t cipherKey[RIJNDAEL_MAXKB];
57fe2869c8SKris Kennaway 
58fe2869c8SKris Kennaway 	if (key == NULL) {
59fe2869c8SKris Kennaway 		return BAD_KEY_INSTANCE;
60fe2869c8SKris Kennaway 	}
61fe2869c8SKris Kennaway 
62fe2869c8SKris Kennaway 	if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
63fe2869c8SKris Kennaway 		key->direction = direction;
64fe2869c8SKris Kennaway 	} else {
65fe2869c8SKris Kennaway 		return BAD_KEY_DIR;
66fe2869c8SKris Kennaway 	}
67fe2869c8SKris Kennaway 
68fe2869c8SKris Kennaway 	if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) {
69fe2869c8SKris Kennaway 		key->keyLen = keyLen;
70fe2869c8SKris Kennaway 	} else {
71fe2869c8SKris Kennaway 		return BAD_KEY_MAT;
72fe2869c8SKris Kennaway 	}
73fe2869c8SKris Kennaway 
74fe2869c8SKris Kennaway 	if (keyMaterial != NULL) {
758f21478bSHajimu UMEMOTO 		memcpy(key->keyMaterial, keyMaterial, keyLen/8);
76fe2869c8SKris Kennaway 	}
77fe2869c8SKris Kennaway 
78fe2869c8SKris Kennaway 	/* initialize key schedule: */
798f21478bSHajimu UMEMOTO 	memcpy(cipherKey, key->keyMaterial, keyLen/8);
808f21478bSHajimu UMEMOTO 	if (direction == DIR_ENCRYPT) {
818f21478bSHajimu UMEMOTO 		key->Nr = rijndaelKeySetupEnc(key->rk, cipherKey, keyLen);
828f21478bSHajimu UMEMOTO 	} else {
838f21478bSHajimu UMEMOTO 		key->Nr = rijndaelKeySetupDec(key->rk, cipherKey, keyLen);
84fe2869c8SKris Kennaway 	}
858f21478bSHajimu UMEMOTO 	rijndaelKeySetupEnc(key->ek, cipherKey, keyLen);
86fe2869c8SKris Kennaway 	return TRUE;
87fe2869c8SKris Kennaway }
88fe2869c8SKris Kennaway 
89fe2869c8SKris Kennaway int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) {
90fe2869c8SKris Kennaway 	if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
91fe2869c8SKris Kennaway 		cipher->mode = mode;
92fe2869c8SKris Kennaway 	} else {
93fe2869c8SKris Kennaway 		return BAD_CIPHER_MODE;
94fe2869c8SKris Kennaway 	}
95fe2869c8SKris Kennaway 	if (IV != NULL) {
968f21478bSHajimu UMEMOTO 		memcpy(cipher->IV, IV, RIJNDAEL_MAX_IV_SIZE);
97fe2869c8SKris Kennaway 	} else {
988f21478bSHajimu UMEMOTO 		memset(cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE);
99fe2869c8SKris Kennaway 	}
100fe2869c8SKris Kennaway 	return TRUE;
101fe2869c8SKris Kennaway }
102fe2869c8SKris Kennaway 
103fe2869c8SKris Kennaway int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
104fe2869c8SKris Kennaway 		BYTE *input, int inputLen, BYTE *outBuffer) {
1058f21478bSHajimu UMEMOTO 	int i, k, t, numBlocks;
1068f21478bSHajimu UMEMOTO 	u_int8_t block[16], *iv;
107fe2869c8SKris Kennaway 
108fe2869c8SKris Kennaway 	if (cipher == NULL ||
109fe2869c8SKris Kennaway 		key == NULL ||
110fe2869c8SKris Kennaway 		key->direction == DIR_DECRYPT) {
111fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
112fe2869c8SKris Kennaway 	}
113fe2869c8SKris Kennaway 	if (input == NULL || inputLen <= 0) {
114fe2869c8SKris Kennaway 		return 0; /* nothing to do */
115fe2869c8SKris Kennaway 	}
116fe2869c8SKris Kennaway 
117fe2869c8SKris Kennaway 	numBlocks = inputLen/128;
118fe2869c8SKris Kennaway 
119fe2869c8SKris Kennaway 	switch (cipher->mode) {
120fe2869c8SKris Kennaway 	case MODE_ECB:
121fe2869c8SKris Kennaway 		for (i = numBlocks; i > 0; i--) {
1228f21478bSHajimu UMEMOTO 			rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
123fe2869c8SKris Kennaway 			input += 16;
124fe2869c8SKris Kennaway 			outBuffer += 16;
125fe2869c8SKris Kennaway 		}
126fe2869c8SKris Kennaway 		break;
127fe2869c8SKris Kennaway 
128fe2869c8SKris Kennaway 	case MODE_CBC:
1298f21478bSHajimu UMEMOTO 		iv = cipher->IV;
1308f21478bSHajimu UMEMOTO 		for (i = numBlocks; i > 0; i--) {
1318f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[0] = ((u_int32_t*)input)[0] ^ ((u_int32_t*)iv)[0];
1328f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[1] = ((u_int32_t*)input)[1] ^ ((u_int32_t*)iv)[1];
1338f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[2] = ((u_int32_t*)input)[2] ^ ((u_int32_t*)iv)[2];
1348f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[3] = ((u_int32_t*)input)[3] ^ ((u_int32_t*)iv)[3];
1358f21478bSHajimu UMEMOTO 			rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
1368f21478bSHajimu UMEMOTO 			iv = outBuffer;
137fe2869c8SKris Kennaway 			input += 16;
138fe2869c8SKris Kennaway 			outBuffer += 16;
139fe2869c8SKris Kennaway 		}
140fe2869c8SKris Kennaway 		break;
141fe2869c8SKris Kennaway 
142fe2869c8SKris Kennaway     case MODE_CFB1:
1438f21478bSHajimu UMEMOTO 		iv = cipher->IV;
144fe2869c8SKris Kennaway         for (i = numBlocks; i > 0; i--) {
1458f21478bSHajimu UMEMOTO 			memcpy(outBuffer, input, 16);
146fe2869c8SKris Kennaway             for (k = 0; k < 128; k++) {
1478f21478bSHajimu UMEMOTO 				rijndaelEncrypt(key->ek, key->Nr, iv, block);
1488f21478bSHajimu UMEMOTO                 outBuffer[k >> 3] ^= (block[0] & 0x80U) >> (k & 7);
1498f21478bSHajimu UMEMOTO                 for (t = 0; t < 15; t++) {
1508f21478bSHajimu UMEMOTO                 	iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
151fe2869c8SKris Kennaway                 }
1528f21478bSHajimu UMEMOTO                	iv[15] = (iv[15] << 1) | ((outBuffer[k >> 3] >> (7 - (k & 7))) & 1);
1538f21478bSHajimu UMEMOTO             }
1548f21478bSHajimu UMEMOTO             outBuffer += 16;
1558f21478bSHajimu UMEMOTO             input += 16;
156fe2869c8SKris Kennaway         }
157fe2869c8SKris Kennaway         break;
158fe2869c8SKris Kennaway 
159fe2869c8SKris Kennaway 	default:
160fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
161fe2869c8SKris Kennaway 	}
162fe2869c8SKris Kennaway 
163fe2869c8SKris Kennaway 	return 128*numBlocks;
164fe2869c8SKris Kennaway }
165fe2869c8SKris Kennaway 
166fe2869c8SKris Kennaway /**
167fe2869c8SKris Kennaway  * Encrypt data partitioned in octets, using RFC 2040-like padding.
168fe2869c8SKris Kennaway  *
169fe2869c8SKris Kennaway  * @param   input           data to be encrypted (octet sequence)
170fe2869c8SKris Kennaway  * @param   inputOctets		input length in octets (not bits)
171fe2869c8SKris Kennaway  * @param   outBuffer       encrypted output data
172fe2869c8SKris Kennaway  *
173fe2869c8SKris Kennaway  * @return	length in octets (not bits) of the encrypted output buffer.
174fe2869c8SKris Kennaway  */
175fe2869c8SKris Kennaway int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
176fe2869c8SKris Kennaway 		BYTE *input, int inputOctets, BYTE *outBuffer) {
177fe2869c8SKris Kennaway 	int i, numBlocks, padLen;
1788f21478bSHajimu UMEMOTO 	u_int8_t block[16], *iv;
179fe2869c8SKris Kennaway 
180fe2869c8SKris Kennaway 	if (cipher == NULL ||
181fe2869c8SKris Kennaway 		key == NULL ||
182fe2869c8SKris Kennaway 		key->direction == DIR_DECRYPT) {
183fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
184fe2869c8SKris Kennaway 	}
185fe2869c8SKris Kennaway 	if (input == NULL || inputOctets <= 0) {
186fe2869c8SKris Kennaway 		return 0; /* nothing to do */
187fe2869c8SKris Kennaway 	}
188fe2869c8SKris Kennaway 
189fe2869c8SKris Kennaway 	numBlocks = inputOctets/16;
190fe2869c8SKris Kennaway 
191fe2869c8SKris Kennaway 	switch (cipher->mode) {
192fe2869c8SKris Kennaway 	case MODE_ECB:
193fe2869c8SKris Kennaway 		for (i = numBlocks; i > 0; i--) {
1948f21478bSHajimu UMEMOTO 			rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
195fe2869c8SKris Kennaway 			input += 16;
196fe2869c8SKris Kennaway 			outBuffer += 16;
197fe2869c8SKris Kennaway 		}
198fe2869c8SKris Kennaway 		padLen = 16 - (inputOctets - 16*numBlocks);
199eb159f5bSHajimu UMEMOTO 		if (padLen <= 0 || padLen > 16)
20027da1009SPoul-Henning Kamp 			return BAD_CIPHER_STATE;
2018f21478bSHajimu UMEMOTO 		memcpy(block, input, 16 - padLen);
2028f21478bSHajimu UMEMOTO 		memset(block + 16 - padLen, padLen, padLen);
2038f21478bSHajimu UMEMOTO 		rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
204fe2869c8SKris Kennaway 		break;
205fe2869c8SKris Kennaway 
206fe2869c8SKris Kennaway 	case MODE_CBC:
207fe2869c8SKris Kennaway 		iv = cipher->IV;
208fe2869c8SKris Kennaway 		for (i = numBlocks; i > 0; i--) {
2098f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[0] = ((u_int32_t*)input)[0] ^ ((u_int32_t*)iv)[0];
2108f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[1] = ((u_int32_t*)input)[1] ^ ((u_int32_t*)iv)[1];
2118f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[2] = ((u_int32_t*)input)[2] ^ ((u_int32_t*)iv)[2];
2128f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[3] = ((u_int32_t*)input)[3] ^ ((u_int32_t*)iv)[3];
2138f21478bSHajimu UMEMOTO 			rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
214fe2869c8SKris Kennaway 			iv = outBuffer;
215fe2869c8SKris Kennaway 			input += 16;
216fe2869c8SKris Kennaway 			outBuffer += 16;
217fe2869c8SKris Kennaway 		}
218fe2869c8SKris Kennaway 		padLen = 16 - (inputOctets - 16*numBlocks);
21966476d45SHajimu UMEMOTO 		if (padLen <= 0 || padLen > 16)
22027da1009SPoul-Henning Kamp 			return BAD_CIPHER_STATE;
221fe2869c8SKris Kennaway 		for (i = 0; i < 16 - padLen; i++) {
222fe2869c8SKris Kennaway 			block[i] = input[i] ^ iv[i];
223fe2869c8SKris Kennaway 		}
224fe2869c8SKris Kennaway 		for (i = 16 - padLen; i < 16; i++) {
225fe2869c8SKris Kennaway 			block[i] = (BYTE)padLen ^ iv[i];
226fe2869c8SKris Kennaway 		}
2278f21478bSHajimu UMEMOTO 		rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
228fe2869c8SKris Kennaway 		break;
229fe2869c8SKris Kennaway 
230fe2869c8SKris Kennaway 	default:
231fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
232fe2869c8SKris Kennaway 	}
233fe2869c8SKris Kennaway 
234fe2869c8SKris Kennaway 	return 16*(numBlocks + 1);
235fe2869c8SKris Kennaway }
236fe2869c8SKris Kennaway 
237fe2869c8SKris Kennaway int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
238fe2869c8SKris Kennaway 		BYTE *input, int inputLen, BYTE *outBuffer) {
2398f21478bSHajimu UMEMOTO 	int i, k, t, numBlocks;
2408f21478bSHajimu UMEMOTO 	u_int8_t block[16], *iv;
241fe2869c8SKris Kennaway 
242fe2869c8SKris Kennaway 	if (cipher == NULL ||
243fe2869c8SKris Kennaway 		key == NULL ||
244fe2869c8SKris Kennaway 		(cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
245fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
246fe2869c8SKris Kennaway 	}
247fe2869c8SKris Kennaway 	if (input == NULL || inputLen <= 0) {
248fe2869c8SKris Kennaway 		return 0; /* nothing to do */
249fe2869c8SKris Kennaway 	}
250fe2869c8SKris Kennaway 
251fe2869c8SKris Kennaway 	numBlocks = inputLen/128;
252fe2869c8SKris Kennaway 
253fe2869c8SKris Kennaway 	switch (cipher->mode) {
254fe2869c8SKris Kennaway 	case MODE_ECB:
255fe2869c8SKris Kennaway 		for (i = numBlocks; i > 0; i--) {
2568f21478bSHajimu UMEMOTO 			rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
257fe2869c8SKris Kennaway 			input += 16;
258fe2869c8SKris Kennaway 			outBuffer += 16;
259fe2869c8SKris Kennaway 		}
260fe2869c8SKris Kennaway 		break;
261fe2869c8SKris Kennaway 
262fe2869c8SKris Kennaway 	case MODE_CBC:
2638f21478bSHajimu UMEMOTO 		iv = cipher->IV;
264fe2869c8SKris Kennaway 		for (i = numBlocks; i > 0; i--) {
2658f21478bSHajimu UMEMOTO 			rijndaelDecrypt(key->rk, key->Nr, input, block);
2668f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[0] ^= ((u_int32_t*)iv)[0];
2678f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[1] ^= ((u_int32_t*)iv)[1];
2688f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[2] ^= ((u_int32_t*)iv)[2];
2698f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[3] ^= ((u_int32_t*)iv)[3];
2708f21478bSHajimu UMEMOTO 			memcpy(cipher->IV, input, 16);
2718f21478bSHajimu UMEMOTO 			memcpy(outBuffer, block, 16);
272fe2869c8SKris Kennaway 			input += 16;
273fe2869c8SKris Kennaway 			outBuffer += 16;
274fe2869c8SKris Kennaway 		}
275fe2869c8SKris Kennaway 		break;
276fe2869c8SKris Kennaway 
277fe2869c8SKris Kennaway     case MODE_CFB1:
2788f21478bSHajimu UMEMOTO 		iv = cipher->IV;
279fe2869c8SKris Kennaway         for (i = numBlocks; i > 0; i--) {
2808f21478bSHajimu UMEMOTO 			memcpy(outBuffer, input, 16);
281fe2869c8SKris Kennaway             for (k = 0; k < 128; k++) {
2828f21478bSHajimu UMEMOTO 				rijndaelEncrypt(key->ek, key->Nr, iv, block);
2838f21478bSHajimu UMEMOTO                 for (t = 0; t < 15; t++) {
2848f21478bSHajimu UMEMOTO                 	iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
285fe2869c8SKris Kennaway                 }
2868f21478bSHajimu UMEMOTO                	iv[15] = (iv[15] << 1) | ((input[k >> 3] >> (7 - (k & 7))) & 1);
2878f21478bSHajimu UMEMOTO                 outBuffer[k >> 3] ^= (block[0] & 0x80U) >> (k & 7);
2888f21478bSHajimu UMEMOTO             }
2898f21478bSHajimu UMEMOTO             outBuffer += 16;
2908f21478bSHajimu UMEMOTO             input += 16;
291fe2869c8SKris Kennaway         }
292fe2869c8SKris Kennaway         break;
293fe2869c8SKris Kennaway 
294fe2869c8SKris Kennaway 	default:
295fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
296fe2869c8SKris Kennaway 	}
297fe2869c8SKris Kennaway 
298fe2869c8SKris Kennaway 	return 128*numBlocks;
299fe2869c8SKris Kennaway }
300fe2869c8SKris Kennaway 
301fe2869c8SKris Kennaway int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
302fe2869c8SKris Kennaway 		BYTE *input, int inputOctets, BYTE *outBuffer) {
303fe2869c8SKris Kennaway 	int i, numBlocks, padLen;
3048f21478bSHajimu UMEMOTO 	u_int8_t block[16];
305fe2869c8SKris Kennaway 
306fe2869c8SKris Kennaway 	if (cipher == NULL ||
307fe2869c8SKris Kennaway 		key == NULL ||
308fe2869c8SKris Kennaway 		key->direction == DIR_ENCRYPT) {
309fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
310fe2869c8SKris Kennaway 	}
311fe2869c8SKris Kennaway 	if (input == NULL || inputOctets <= 0) {
312fe2869c8SKris Kennaway 		return 0; /* nothing to do */
313fe2869c8SKris Kennaway 	}
314fe2869c8SKris Kennaway 	if (inputOctets % 16 != 0) {
315fe2869c8SKris Kennaway 		return BAD_DATA;
316fe2869c8SKris Kennaway 	}
317fe2869c8SKris Kennaway 
318fe2869c8SKris Kennaway 	numBlocks = inputOctets/16;
319fe2869c8SKris Kennaway 
320fe2869c8SKris Kennaway 	switch (cipher->mode) {
321fe2869c8SKris Kennaway 	case MODE_ECB:
322fe2869c8SKris Kennaway 		/* all blocks but last */
323fe2869c8SKris Kennaway 		for (i = numBlocks - 1; i > 0; i--) {
3248f21478bSHajimu UMEMOTO 			rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
325fe2869c8SKris Kennaway 			input += 16;
326fe2869c8SKris Kennaway 			outBuffer += 16;
327fe2869c8SKris Kennaway 		}
328fe2869c8SKris Kennaway 		/* last block */
3298f21478bSHajimu UMEMOTO 		rijndaelDecrypt(key->rk, key->Nr, input, block);
330fe2869c8SKris Kennaway 		padLen = block[15];
331fe2869c8SKris Kennaway 		if (padLen >= 16) {
332fe2869c8SKris Kennaway 			return BAD_DATA;
333fe2869c8SKris Kennaway 		}
334fe2869c8SKris Kennaway 		for (i = 16 - padLen; i < 16; i++) {
335fe2869c8SKris Kennaway 			if (block[i] != padLen) {
336fe2869c8SKris Kennaway 				return BAD_DATA;
337fe2869c8SKris Kennaway 			}
338fe2869c8SKris Kennaway 		}
3398f21478bSHajimu UMEMOTO 		memcpy(outBuffer, block, 16 - padLen);
340fe2869c8SKris Kennaway 		break;
341fe2869c8SKris Kennaway 
342fe2869c8SKris Kennaway 	case MODE_CBC:
343fe2869c8SKris Kennaway 		/* all blocks but last */
344fe2869c8SKris Kennaway 		for (i = numBlocks - 1; i > 0; i--) {
3458f21478bSHajimu UMEMOTO 			rijndaelDecrypt(key->rk, key->Nr, input, block);
3468f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[0] ^= ((u_int32_t*)cipher->IV)[0];
3478f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[1] ^= ((u_int32_t*)cipher->IV)[1];
3488f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[2] ^= ((u_int32_t*)cipher->IV)[2];
3498f21478bSHajimu UMEMOTO 			((u_int32_t*)block)[3] ^= ((u_int32_t*)cipher->IV)[3];
3508f21478bSHajimu UMEMOTO 			memcpy(cipher->IV, input, 16);
3518f21478bSHajimu UMEMOTO 			memcpy(outBuffer, block, 16);
352fe2869c8SKris Kennaway 			input += 16;
353fe2869c8SKris Kennaway 			outBuffer += 16;
354fe2869c8SKris Kennaway 		}
355fe2869c8SKris Kennaway 		/* last block */
3568f21478bSHajimu UMEMOTO 		rijndaelDecrypt(key->rk, key->Nr, input, block);
3578f21478bSHajimu UMEMOTO 		((u_int32_t*)block)[0] ^= ((u_int32_t*)cipher->IV)[0];
3588f21478bSHajimu UMEMOTO 		((u_int32_t*)block)[1] ^= ((u_int32_t*)cipher->IV)[1];
3598f21478bSHajimu UMEMOTO 		((u_int32_t*)block)[2] ^= ((u_int32_t*)cipher->IV)[2];
3608f21478bSHajimu UMEMOTO 		((u_int32_t*)block)[3] ^= ((u_int32_t*)cipher->IV)[3];
361fe2869c8SKris Kennaway 		padLen = block[15];
362fe2869c8SKris Kennaway 		if (padLen <= 0 || padLen > 16) {
363fe2869c8SKris Kennaway 			return BAD_DATA;
364fe2869c8SKris Kennaway 		}
365fe2869c8SKris Kennaway 		for (i = 16 - padLen; i < 16; i++) {
366fe2869c8SKris Kennaway 			if (block[i] != padLen) {
367fe2869c8SKris Kennaway 				return BAD_DATA;
368fe2869c8SKris Kennaway 			}
369fe2869c8SKris Kennaway 		}
3708f21478bSHajimu UMEMOTO 		memcpy(outBuffer, block, 16 - padLen);
371fe2869c8SKris Kennaway 		break;
372fe2869c8SKris Kennaway 
373fe2869c8SKris Kennaway 	default:
374fe2869c8SKris Kennaway 		return BAD_CIPHER_STATE;
375fe2869c8SKris Kennaway 	}
376fe2869c8SKris Kennaway 
377fe2869c8SKris Kennaway 	return 16*numBlocks - padLen;
378fe2869c8SKris Kennaway }
379fe2869c8SKris Kennaway 
380