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 | |
55 | static 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 | |
65 | int |
66 | rijndael_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 | |
102 | int |
103 | rijndael_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 | |
118 | int |
119 | rijndael_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 | */ |
191 | int |
192 | rijndael_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 | |
248 | int |
249 | rijndael_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 | |
313 | int |
314 | rijndael_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 | |