1/* $NetBSD: rijndael-api-fst.c,v 1.24 2011/05/14 16:46:55 jmmv Exp $ */
2
3/**
4 * rijndael-api-fst.c
5 *
6 * @version 2.9 (December 2000)
7 *
8 * Optimised ANSI C code for the Rijndael cipher (now AES)
9 *
10 * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
11 * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
12 * @author Paulo Barreto <paulo.barreto@terra.com.br>
13 *
14 * This code is hereby placed in the public domain.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * Acknowledgements:
29 *
30 * We are deeply indebted to the following people for their bug reports,
31 * fixes, and improvement suggestions to this implementation. Though we
32 * tried to list all contributions, we apologise in advance for any
33 * missing reference.
34 *
35 * Andrew Bales <Andrew.Bales@Honeywell.com>
36 * Markus Friedl <markus.friedl@informatik.uni-erlangen.de>
37 * John Skodon <skodonj@webquill.com>
38 */
39
40#include <sys/cdefs.h>
41__KERNEL_RCSID(0, "$NetBSD: rijndael-api-fst.c,v 1.24 2011/05/14 16:46:55 jmmv Exp $");
42
43#include <sys/param.h>
44#ifdef _KERNEL
45#include <sys/systm.h>
46#else
47#include <stdlib.h>
48#include <string.h>
49#endif
50
51#include <crypto/rijndael/rijndael_local.h>
52#include <crypto/rijndael/rijndael-alg-fst.h>
53#include <crypto/rijndael/rijndael-api-fst.h>
54
55static void xor16(uint8_t *d, const uint8_t *a, const uint8_t* b)
56{
57 for (size_t i = 0; i < 4; i++) {
58 *d++ = *a++ ^ *b++;
59 *d++ = *a++ ^ *b++;
60 *d++ = *a++ ^ *b++;
61 *d++ = *a++ ^ *b++;
62 }
63}
64
65int
66rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen,
67 const char *keyMaterial)
68{
69 u_int8_t cipherKey[RIJNDAEL_MAXKB];
70
71 if (key == NULL) {
72 return BAD_KEY_INSTANCE;
73 }
74
75 if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
76 key->direction = direction;
77 } else {
78 return BAD_KEY_DIR;
79 }
80
81 if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) {
82 key->keyLen = keyLen;
83 } else {
84 return BAD_KEY_MAT;
85 }
86
87 if (keyMaterial != NULL) {
88 memcpy(key->keyMaterial, keyMaterial, keyLen/8);
89 }
90
91 /* initialize key schedule: */
92 memcpy(cipherKey, key->keyMaterial, keyLen/8);
93 if (direction == DIR_ENCRYPT) {
94 key->Nr = rijndaelKeySetupEnc(key->rk, cipherKey, keyLen);
95 } else {
96 key->Nr = rijndaelKeySetupDec(key->rk, cipherKey, keyLen);
97 }
98 rijndaelKeySetupEnc(key->ek, cipherKey, keyLen);
99 return TRUE;
100}
101
102int
103rijndael_cipherInit(cipherInstance *cipher, BYTE mode, const char *IV)
104{
105 if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
106 cipher->mode = mode;
107 } else {
108 return BAD_CIPHER_MODE;
109 }
110 if (IV != NULL) {
111 memcpy(cipher->IV, IV, RIJNDAEL_MAX_IV_SIZE);
112 } else {
113 memset(cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE);
114 }
115 return TRUE;
116}
117
118int
119rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
120 const BYTE *input, int inputLen, BYTE *outBuffer)
121{
122 int i, k, t, numBlocks;
123 u_int8_t block[16], *iv;
124
125 if (cipher == NULL ||
126 key == NULL ||
127 key->direction == DIR_DECRYPT) {
128 return BAD_CIPHER_STATE;
129 }
130 if (input == NULL || inputLen <= 0) {
131 return 0; /* nothing to do */
132 }
133
134 numBlocks = inputLen/128;
135
136 switch (cipher->mode) {
137 case MODE_ECB:
138 for (i = numBlocks; i > 0; i--) {
139 rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
140 input += 16;
141 outBuffer += 16;
142 }
143 break;
144
145 case MODE_CBC:
146 iv = (u_int8_t *)cipher->IV;
147 for (i = numBlocks; i > 0; i--) {
148 xor16(block, input, iv);
149 rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
150 iv = outBuffer;
151 input += 16;
152 outBuffer += 16;
153 }
154 break;
155
156 case MODE_CFB1:
157 iv = (u_int8_t *)cipher->IV;
158 for (i = numBlocks; i > 0; i--) {
159 memcpy(outBuffer, input, 16);
160 for (k = 0; k < 128; k++) {
161 rijndaelEncrypt(key->ek, key->Nr, iv, block);
162 outBuffer[k >> 3] ^=
163 (block[0] & 0x80U) >> (k & 7);
164 for (t = 0; t < 15; t++) {
165 iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
166 }
167 iv[15] = (iv[15] << 1) |
168 ((outBuffer[k >> 3] >> (7 - (k & 7))) & 1);
169 }
170 outBuffer += 16;
171 input += 16;
172 }
173 break;
174
175 default:
176 return BAD_CIPHER_STATE;
177 }
178
179 return 128 * numBlocks;
180}
181
182/**
183 * Encrypt data partitioned in octets, using RFC 2040-like padding.
184 *
185 * @param input data to be encrypted (octet sequence)
186 * @param inputOctets input length in octets (not bits)
187 * @param outBuffer encrypted output data
188 *
189 * @return length in octets (not bits) of the encrypted output buffer.
190 */
191int
192rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
193 const BYTE *input, int inputOctets, BYTE *outBuffer)
194{
195 int i, numBlocks, padLen;
196 u_int8_t block[16], *iv;
197
198 if (cipher == NULL ||
199 key == NULL ||
200 key->direction == DIR_DECRYPT) {
201 return BAD_CIPHER_STATE;
202 }
203 if (input == NULL || inputOctets <= 0) {
204 return 0; /* nothing to do */
205 }
206
207 numBlocks = inputOctets / 16;
208
209 switch (cipher->mode) {
210 case MODE_ECB:
211 for (i = numBlocks; i > 0; i--) {
212 rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
213 input += 16;
214 outBuffer += 16;
215 }
216 padLen = 16 - (inputOctets - 16*numBlocks);
217 memcpy(block, input, 16 - padLen);
218 memset(block + 16 - padLen, padLen, padLen);
219 rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
220 break;
221
222 case MODE_CBC:
223 iv = (u_int8_t *)cipher->IV;
224 for (i = numBlocks; i > 0; i--) {
225 xor16(block, input, iv);
226 rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
227 iv = outBuffer;
228 input += 16;
229 outBuffer += 16;
230 }
231 padLen = 16 - (inputOctets - 16*numBlocks);
232 for (i = 0; i < 16 - padLen; i++) {
233 block[i] = input[i] ^ iv[i];
234 }
235 for (i = 16 - padLen; i < 16; i++) {
236 block[i] = (BYTE)padLen ^ iv[i];
237 }
238 rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
239 break;
240
241 default:
242 return BAD_CIPHER_STATE;
243 }
244
245 return 16 * (numBlocks + 1);
246}
247
248int
249rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
250 const BYTE *input, int inputLen, BYTE *outBuffer)
251{
252 int i, k, t, numBlocks;
253 u_int8_t block[16], *iv;
254
255 if (cipher == NULL ||
256 key == NULL ||
257 (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
258 return BAD_CIPHER_STATE;
259 }
260 if (input == NULL || inputLen <= 0) {
261 return 0; /* nothing to do */
262 }
263
264 numBlocks = inputLen/128;
265
266 switch (cipher->mode) {
267 case MODE_ECB:
268 for (i = numBlocks; i > 0; i--) {
269 rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
270 input += 16;
271 outBuffer += 16;
272 }
273 break;
274
275 case MODE_CBC:
276 iv = (u_int8_t *)cipher->IV;
277 for (i = numBlocks; i > 0; i--) {
278 rijndaelDecrypt(key->rk, key->Nr, input, block);
279 xor16(block, block, iv);
280 memcpy(cipher->IV, input, 16);
281 memcpy(outBuffer, block, 16);
282 input += 16;
283 outBuffer += 16;
284 }
285 break;
286
287 case MODE_CFB1:
288 iv = (u_int8_t *)cipher->IV;
289 for (i = numBlocks; i > 0; i--) {
290 memcpy(outBuffer, input, 16);
291 for (k = 0; k < 128; k++) {
292 rijndaelEncrypt(key->ek, key->Nr, iv, block);
293 for (t = 0; t < 15; t++) {
294 iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
295 }
296 iv[15] = (iv[15] << 1) |
297 ((input[k >> 3] >> (7 - (k & 7))) & 1);
298 outBuffer[k >> 3] ^= (block[0] & 0x80U) >>
299 (k & 7);
300 }
301 outBuffer += 16;
302 input += 16;
303 }
304 break;
305
306 default:
307 return BAD_CIPHER_STATE;
308 }
309
310 return 128 * numBlocks;
311}
312
313int
314rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
315 const BYTE *input, int inputOctets, BYTE *outBuffer)
316{
317 int i, numBlocks, padLen;
318 u_int8_t block[16], *iv;
319
320 if (cipher == NULL ||
321 key == NULL ||
322 key->direction == DIR_ENCRYPT) {
323 return BAD_CIPHER_STATE;
324 }
325 if (input == NULL || inputOctets <= 0) {
326 return 0; /* nothing to do */
327 }
328 if (inputOctets % 16 != 0) {
329 return BAD_DATA;
330 }
331
332 numBlocks = inputOctets/16;
333
334 switch (cipher->mode) {
335 case MODE_ECB:
336 /* all blocks but last */
337 for (i = numBlocks - 1; i > 0; i--) {
338 rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
339 input += 16;
340 outBuffer += 16;
341 }
342 /* last block */
343 rijndaelDecrypt(key->rk, key->Nr, input, block);
344 padLen = block[15];
345 if (padLen >= 16) {
346 return BAD_DATA;
347 }
348 for (i = 16 - padLen; i < 16; i++) {
349 if (block[i] != padLen) {
350 return BAD_DATA;
351 }
352 }
353 memcpy(outBuffer, block, 16 - padLen);
354 break;
355
356 case MODE_CBC:
357 iv = (u_int8_t *)cipher->IV;
358 /* all blocks but last */
359 for (i = numBlocks - 1; i > 0; i--) {
360 rijndaelDecrypt(key->rk, key->Nr, input, block);
361 xor16(block, block, iv);
362 memcpy(cipher->IV, input, 16);
363 memcpy(outBuffer, block, 16);
364 input += 16;
365 outBuffer += 16;
366 }
367 /* last block */
368 rijndaelDecrypt(key->rk, key->Nr, input, block);
369 xor16(block, block, iv);
370 padLen = block[15];
371 if (padLen <= 0 || padLen > 16) {
372 return BAD_DATA;
373 }
374 for (i = 16 - padLen; i < 16; i++) {
375 if (block[i] != padLen) {
376 return BAD_DATA;
377 }
378 }
379 memcpy(outBuffer, block, 16 - padLen);
380 break;
381
382 default:
383 return BAD_CIPHER_STATE;
384 }
385
386 return 16 * numBlocks - padLen;
387}
388