• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*	$NetBSD: rijndael-api-fst.c,v 1.4 2006/09/09 16:22:36 manu Exp $	*/
2 
3 /*	$KAME: rijndael-api-fst.c,v 1.8 2002/11/18 23:32:54 itojun Exp $	*/
4 
5 /*
6  * rijndael-api-fst.c   v2.3   April '2000
7  *
8  * Optimised ANSI C code
9  *
10  * authors: v1.0: Antoon Bosselaers
11  *          v2.0: Vincent Rijmen
12  *          v2.1: Vincent Rijmen
13  *          v2.2: Vincent Rijmen
14  *          v2.3: Paulo Barreto
15  *          v2.4: Vincent Rijmen
16  *
17  * This code is placed in the public domain.
18  */
19 
20 #include "config.h"
21 
22 #include <sys/param.h>
23 #include <sys/types.h>
24 #ifdef _KERNEL
25 #include <sys/time.h>
26 #include <sys/systm.h>
27 #else
28 #include <string.h>
29 #endif
30 #include <crypto/rijndael/rijndael-alg-fst.h>
31 #include <crypto/rijndael/rijndael-api-fst.h>
32 #include <crypto/rijndael/rijndael_local.h>
33 
34 #include <err.h>
35 #define bcopy(a, b, c) memcpy(b, a, c)
36 #define bzero(a, b) memset(a, 0, b)
37 #define panic(a) err(1, (a))
38 
rijndael_makeKey(keyInstance * key,BYTE direction,int keyLen,char * keyMaterial)39 int rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial) {
40 	word8 k[MAXKC][4];
41 	int i;
42 	char *keyMat;
43 
44 	if (key == NULL) {
45 		return BAD_KEY_INSTANCE;
46 	}
47 
48 	if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
49 		key->direction = direction;
50 	} else {
51 		return BAD_KEY_DIR;
52 	}
53 
54 	if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) {
55 		key->keyLen = keyLen;
56 	} else {
57 		return BAD_KEY_MAT;
58 	}
59 
60 	if (keyMaterial != NULL) {
61 		bcopy(keyMaterial, key->keyMaterial, keyLen/8);
62 	}
63 
64 	key->ROUNDS = keyLen/32 + 6;
65 
66 	/* initialize key schedule: */
67 	keyMat = key->keyMaterial;
68 	for (i = 0; i < key->keyLen/8; i++) {
69 		k[i >> 2][i & 3] = (word8)keyMat[i];
70 	}
71 	rijndaelKeySched(k, key->keySched, key->ROUNDS);
72 	if (direction == DIR_DECRYPT) {
73 		rijndaelKeyEncToDec(key->keySched, key->ROUNDS);
74 	}
75 
76 	return TRUE;
77 }
78 
rijndael_cipherInit(cipherInstance * cipher,BYTE mode,char * IV)79 int rijndael_cipherInit(cipherInstance *cipher, BYTE mode, char *IV) {
80 	if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
81 		cipher->mode = mode;
82 	} else {
83 		return BAD_CIPHER_MODE;
84 	}
85 	if (IV != NULL) {
86 		bcopy(IV, cipher->IV, MAX_IV_SIZE);
87 	} else {
88 		bzero(cipher->IV, MAX_IV_SIZE);
89 	}
90 	return TRUE;
91 }
92 
rijndael_blockEncrypt(cipherInstance * cipher,keyInstance * key,BYTE * input,int inputLen,BYTE * outBuffer)93 int rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
94 		BYTE *input, int inputLen, BYTE *outBuffer) {
95 	int i, k, numBlocks;
96 	word8 block[16], iv[4][4];
97 
98 	if (cipher == NULL ||
99 		key == NULL ||
100 		key->direction == DIR_DECRYPT) {
101 		return BAD_CIPHER_STATE;
102 	}
103 	if (input == NULL || inputLen <= 0) {
104 		return 0; /* nothing to do */
105 	}
106 
107 	numBlocks = inputLen/128;
108 
109 	switch (cipher->mode) {
110 	case MODE_ECB:
111 		for (i = numBlocks; i > 0; i--) {
112 			rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS);
113 			input += 16;
114 			outBuffer += 16;
115 		}
116 		break;
117 
118 	case MODE_CBC:
119 #if 1 /*STRICT_ALIGN*/
120 		bcopy(cipher->IV, block, 16);
121 		bcopy(input, iv, 16);
122 		((word32*)block)[0] ^= ((word32*)iv)[0];
123 		((word32*)block)[1] ^= ((word32*)iv)[1];
124 		((word32*)block)[2] ^= ((word32*)iv)[2];
125 		((word32*)block)[3] ^= ((word32*)iv)[3];
126 #else
127 		((word32*)block)[0] = ((word32*)cipher->IV)[0] ^ ((word32*)input)[0];
128 		((word32*)block)[1] = ((word32*)cipher->IV)[1] ^ ((word32*)input)[1];
129 		((word32*)block)[2] = ((word32*)cipher->IV)[2] ^ ((word32*)input)[2];
130 		((word32*)block)[3] = ((word32*)cipher->IV)[3] ^ ((word32*)input)[3];
131 #endif
132 		rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
133 		input += 16;
134 		for (i = numBlocks - 1; i > 0; i--) {
135 #if 1 /*STRICT_ALIGN*/
136 			bcopy(outBuffer, block, 16);
137 			bcopy(input, iv, 16);
138 			((word32*)block)[0] ^= ((word32*)iv)[0];
139 			((word32*)block)[1] ^= ((word32*)iv)[1];
140 			((word32*)block)[2] ^= ((word32*)iv)[2];
141 			((word32*)block)[3] ^= ((word32*)iv)[3];
142 #else
143 			((word32*)block)[0] = ((word32*)outBuffer)[0] ^ ((word32*)input)[0];
144 			((word32*)block)[1] = ((word32*)outBuffer)[1] ^ ((word32*)input)[1];
145 			((word32*)block)[2] = ((word32*)outBuffer)[2] ^ ((word32*)input)[2];
146 			((word32*)block)[3] = ((word32*)outBuffer)[3] ^ ((word32*)input)[3];
147 #endif
148 			outBuffer += 16;
149 			rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
150 			input += 16;
151 		}
152 		break;
153 
154 	case MODE_CFB1:
155 #if 1 /*STRICT_ALIGN*/
156 		bcopy(cipher->IV, iv, 16);
157 #else  /* !STRICT_ALIGN */
158 		*((word32*)iv[0]) = *((word32*)(cipher->IV   ));
159 		*((word32*)iv[1]) = *((word32*)(cipher->IV+ 4));
160 		*((word32*)iv[2]) = *((word32*)(cipher->IV+ 8));
161 		*((word32*)iv[3]) = *((word32*)(cipher->IV+12));
162 #endif /* ?STRICT_ALIGN */
163 		for (i = numBlocks; i > 0; i--) {
164 			for (k = 0; k < 128; k++) {
165 				*((word32*) block    ) = *((word32*)iv[0]);
166 				*((word32*)(block+ 4)) = *((word32*)iv[1]);
167 				*((word32*)(block+ 8)) = *((word32*)iv[2]);
168 				*((word32*)(block+12)) = *((word32*)iv[3]);
169 				rijndaelEncrypt(block, block, key->keySched, key->ROUNDS);
170 				outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7);
171 				iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7);
172 				iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7);
173 				iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7);
174 				iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7);
175 				iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7);
176 				iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7);
177 				iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7);
178 				iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7);
179 				iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7);
180 				iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7);
181 				iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7);
182 				iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7);
183 				iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7);
184 				iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7);
185 				iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7);
186 				iv[3][3] = (iv[3][3] << 1) | ((outBuffer[k/8] >> (7-(k&7))) & 1);
187 			}
188 		}
189 		break;
190 
191 	default:
192 		return BAD_CIPHER_STATE;
193 	}
194 
195 	return 128*numBlocks;
196 }
197 
198 /**
199  * Encrypt data partitioned in octets, using RFC 2040-like padding.
200  *
201  * @param   input           data to be encrypted (octet sequence)
202  * @param   inputOctets		input length in octets (not bits)
203  * @param   outBuffer       encrypted output data
204  *
205  * @return	length in octets (not bits) of the encrypted output buffer.
206  */
rijndael_padEncrypt(cipherInstance * cipher,keyInstance * key,BYTE * input,int inputOctets,BYTE * outBuffer)207 int rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
208 		BYTE *input, int inputOctets, BYTE *outBuffer) {
209 	int i, numBlocks, padLen;
210 	word8 block[16], *iv, *cp;
211 
212 	if (cipher == NULL ||
213 		key == NULL ||
214 		key->direction == DIR_DECRYPT) {
215 		return BAD_CIPHER_STATE;
216 	}
217 	if (input == NULL || inputOctets <= 0) {
218 		return 0; /* nothing to do */
219 	}
220 
221 	numBlocks = inputOctets/16;
222 
223 	switch (cipher->mode) {
224 	case MODE_ECB:
225 		for (i = numBlocks; i > 0; i--) {
226 			rijndaelEncrypt(input, outBuffer, key->keySched, key->ROUNDS);
227 			input += 16;
228 			outBuffer += 16;
229 		}
230 		padLen = 16 - (inputOctets - 16*numBlocks);
231 		if (padLen <= 0 || padLen > 16)
232 			panic("rijndael_padEncrypt(ECB)");
233 		bcopy(input, block, 16 - padLen);
234 		for (cp = block + 16 - padLen; cp < block + 16; cp++)
235 			*cp = padLen;
236 		rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
237 		break;
238 
239 	case MODE_CBC:
240 		iv = cipher->IV;
241 		for (i = numBlocks; i > 0; i--) {
242 			((word32*)block)[0] = ((word32*)input)[0] ^ ((word32*)iv)[0];
243 			((word32*)block)[1] = ((word32*)input)[1] ^ ((word32*)iv)[1];
244 			((word32*)block)[2] = ((word32*)input)[2] ^ ((word32*)iv)[2];
245 			((word32*)block)[3] = ((word32*)input)[3] ^ ((word32*)iv)[3];
246 			rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
247 			iv = outBuffer;
248 			input += 16;
249 			outBuffer += 16;
250 		}
251 		padLen = 16 - (inputOctets - 16*numBlocks);
252 		if (padLen <= 0 || padLen > 16)
253 			panic("rijndael_padEncrypt(CBC)");
254 		for (i = 0; i < 16 - padLen; i++) {
255 			block[i] = input[i] ^ iv[i];
256 		}
257 		for (i = 16 - padLen; i < 16; i++) {
258 			block[i] = (BYTE)padLen ^ iv[i];
259 		}
260 		rijndaelEncrypt(block, outBuffer, key->keySched, key->ROUNDS);
261 		break;
262 
263 	default:
264 		return BAD_CIPHER_STATE;
265 	}
266 
267 	return 16*(numBlocks + 1);
268 }
269 
rijndael_blockDecrypt(cipherInstance * cipher,keyInstance * key,BYTE * input,int inputLen,BYTE * outBuffer)270 int rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
271 		BYTE *input, int inputLen, BYTE *outBuffer) {
272 	int i, k, numBlocks;
273 	word8 block[16], iv[4][4];
274 
275 	if (cipher == NULL ||
276 		key == NULL ||
277 		(cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
278 		return BAD_CIPHER_STATE;
279 	}
280 	if (input == NULL || inputLen <= 0) {
281 		return 0; /* nothing to do */
282 	}
283 
284 	numBlocks = inputLen/128;
285 
286 	switch (cipher->mode) {
287 	case MODE_ECB:
288 		for (i = numBlocks; i > 0; i--) {
289 			rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS);
290 			input += 16;
291 			outBuffer += 16;
292 		}
293 		break;
294 
295 	case MODE_CBC:
296 #if 1 /*STRICT_ALIGN */
297 		bcopy(cipher->IV, iv, 16);
298 #else
299 		*((word32*)iv[0]) = *((word32*)(cipher->IV   ));
300 		*((word32*)iv[1]) = *((word32*)(cipher->IV+ 4));
301 		*((word32*)iv[2]) = *((word32*)(cipher->IV+ 8));
302 		*((word32*)iv[3]) = *((word32*)(cipher->IV+12));
303 #endif
304 		for (i = numBlocks; i > 0; i--) {
305 			rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
306 			((word32*)block)[0] ^= *((word32*)iv[0]);
307 			((word32*)block)[1] ^= *((word32*)iv[1]);
308 			((word32*)block)[2] ^= *((word32*)iv[2]);
309 			((word32*)block)[3] ^= *((word32*)iv[3]);
310 #if 1 /*STRICT_ALIGN*/
311 			bcopy(input, iv, 16);
312 			bcopy(block, outBuffer, 16);
313 #else
314 			*((word32*)iv[0]) = ((word32*)input)[0]; ((word32*)outBuffer)[0] = ((word32*)block)[0];
315 			*((word32*)iv[1]) = ((word32*)input)[1]; ((word32*)outBuffer)[1] = ((word32*)block)[1];
316 			*((word32*)iv[2]) = ((word32*)input)[2]; ((word32*)outBuffer)[2] = ((word32*)block)[2];
317 			*((word32*)iv[3]) = ((word32*)input)[3]; ((word32*)outBuffer)[3] = ((word32*)block)[3];
318 #endif
319 			input += 16;
320 			outBuffer += 16;
321 		}
322 		break;
323 
324 	case MODE_CFB1:
325 #if 1 /*STRICT_ALIGN */
326 		bcopy(cipher->IV, iv, 16);
327 #else
328 		*((word32*)iv[0]) = *((word32*)(cipher->IV));
329 		*((word32*)iv[1]) = *((word32*)(cipher->IV+ 4));
330 		*((word32*)iv[2]) = *((word32*)(cipher->IV+ 8));
331 		*((word32*)iv[3]) = *((word32*)(cipher->IV+12));
332 #endif
333 		for (i = numBlocks; i > 0; i--) {
334 			for (k = 0; k < 128; k++) {
335 				*((word32*) block    ) = *((word32*)iv[0]);
336 				*((word32*)(block+ 4)) = *((word32*)iv[1]);
337 				*((word32*)(block+ 8)) = *((word32*)iv[2]);
338 				*((word32*)(block+12)) = *((word32*)iv[3]);
339 				rijndaelEncrypt(block, block, key->keySched, key->ROUNDS);
340 				iv[0][0] = (iv[0][0] << 1) | (iv[0][1] >> 7);
341 				iv[0][1] = (iv[0][1] << 1) | (iv[0][2] >> 7);
342 				iv[0][2] = (iv[0][2] << 1) | (iv[0][3] >> 7);
343 				iv[0][3] = (iv[0][3] << 1) | (iv[1][0] >> 7);
344 				iv[1][0] = (iv[1][0] << 1) | (iv[1][1] >> 7);
345 				iv[1][1] = (iv[1][1] << 1) | (iv[1][2] >> 7);
346 				iv[1][2] = (iv[1][2] << 1) | (iv[1][3] >> 7);
347 				iv[1][3] = (iv[1][3] << 1) | (iv[2][0] >> 7);
348 				iv[2][0] = (iv[2][0] << 1) | (iv[2][1] >> 7);
349 				iv[2][1] = (iv[2][1] << 1) | (iv[2][2] >> 7);
350 				iv[2][2] = (iv[2][2] << 1) | (iv[2][3] >> 7);
351 				iv[2][3] = (iv[2][3] << 1) | (iv[3][0] >> 7);
352 				iv[3][0] = (iv[3][0] << 1) | (iv[3][1] >> 7);
353 				iv[3][1] = (iv[3][1] << 1) | (iv[3][2] >> 7);
354 				iv[3][2] = (iv[3][2] << 1) | (iv[3][3] >> 7);
355 				iv[3][3] = (iv[3][3] << 1) | ((input[k/8] >> (7-(k&7))) & 1);
356 				outBuffer[k/8] ^= (block[0] & 0x80) >> (k & 7);
357 			}
358 		}
359 		break;
360 
361 	default:
362 		return BAD_CIPHER_STATE;
363 	}
364 
365 	return 128*numBlocks;
366 }
367 
rijndael_padDecrypt(cipherInstance * cipher,keyInstance * key,BYTE * input,int inputOctets,BYTE * outBuffer)368 int rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
369 		BYTE *input, int inputOctets, BYTE *outBuffer) {
370 	int i, numBlocks, padLen;
371 	word8 block[16];
372 	word32 iv[4];
373 
374 	if (cipher == NULL ||
375 		key == NULL ||
376 		key->direction == DIR_ENCRYPT) {
377 		return BAD_CIPHER_STATE;
378 	}
379 	if (input == NULL || inputOctets <= 0) {
380 		return 0; /* nothing to do */
381 	}
382 	if (inputOctets % 16 != 0) {
383 		return BAD_DATA;
384 	}
385 
386 	numBlocks = inputOctets/16;
387 
388 	switch (cipher->mode) {
389 	case MODE_ECB:
390 		/* all blocks but last */
391 		for (i = numBlocks - 1; i > 0; i--) {
392 			rijndaelDecrypt(input, outBuffer, key->keySched, key->ROUNDS);
393 			input += 16;
394 			outBuffer += 16;
395 		}
396 		/* last block */
397 		rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
398 		padLen = block[15];
399 		if (padLen >= 16) {
400 			return BAD_DATA;
401 		}
402 		for (i = 16 - padLen; i < 16; i++) {
403 			if (block[i] != padLen) {
404 				return BAD_DATA;
405 			}
406 		}
407 		bcopy(block, outBuffer, 16 - padLen);
408 		break;
409 
410 	case MODE_CBC:
411 		bcopy(cipher->IV, iv, 16);
412 		/* all blocks but last */
413 		for (i = numBlocks - 1; i > 0; i--) {
414 			rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
415 			((word32*)block)[0] ^= iv[0];
416 			((word32*)block)[1] ^= iv[1];
417 			((word32*)block)[2] ^= iv[2];
418 			((word32*)block)[3] ^= iv[3];
419 			bcopy(input, iv, 16);
420 			bcopy(block, outBuffer, 16);
421 			input += 16;
422 			outBuffer += 16;
423 		}
424 		/* last block */
425 		rijndaelDecrypt(input, block, key->keySched, key->ROUNDS);
426 		((word32*)block)[0] ^= iv[0];
427 		((word32*)block)[1] ^= iv[1];
428 		((word32*)block)[2] ^= iv[2];
429 		((word32*)block)[3] ^= iv[3];
430 		padLen = block[15];
431 		if (padLen <= 0 || padLen > 16) {
432 			return BAD_DATA;
433 		}
434 		for (i = 16 - padLen; i < 16; i++) {
435 			if (block[i] != padLen) {
436 				return BAD_DATA;
437 			}
438 		}
439 		bcopy(block, outBuffer, 16 - padLen);
440 		break;
441 
442 	default:
443 		return BAD_CIPHER_STATE;
444 	}
445 
446 	return 16*numBlocks - padLen;
447 }
448 
449 #ifdef INTERMEDIATE_VALUE_KAT
450 /**
451  *	cipherUpdateRounds:
452  *
453  *	Encrypts/Decrypts exactly one full block a specified number of rounds.
454  *	Only used in the Intermediate Value Known Answer Test.
455  *
456  *	Returns:
457  *		TRUE - on success
458  *		BAD_CIPHER_STATE - cipher in bad state (e.g., not initialized)
459  */
rijndael_cipherUpdateRounds(cipherInstance * cipher,keyInstance * key,BYTE * input,int inputLen,BYTE * outBuffer,int rounds)460 int rijndael_cipherUpdateRounds(cipherInstance *cipher, keyInstance *key,
461 		BYTE *input, int inputLen, BYTE *outBuffer, int rounds) {
462 	int j;
463 	word8 block[4][4];
464 
465 	if (cipher == NULL || key == NULL) {
466 		return BAD_CIPHER_STATE;
467 	}
468 
469 	for (j = 3; j >= 0; j--) {
470 		/* parse input stream into rectangular array */
471   		*((word32*)block[j]) = *((word32*)(input+4*j));
472 	}
473 
474 	switch (key->direction) {
475 	case DIR_ENCRYPT:
476 		rijndaelEncryptRound(block, key->keySched, key->ROUNDS, rounds);
477 		break;
478 
479 	case DIR_DECRYPT:
480 		rijndaelDecryptRound(block, key->keySched, key->ROUNDS, rounds);
481 		break;
482 
483 	default:
484 		return BAD_KEY_DIR;
485 	}
486 
487 	for (j = 3; j >= 0; j--) {
488 		/* parse rectangular array into output ciphertext bytes */
489 		*((word32*)(outBuffer+4*j)) = *((word32*)block[j]);
490 	}
491 
492 	return TRUE;
493 }
494 #endif /* INTERMEDIATE_VALUE_KAT */
495