source: trunk/src/rijndael-api-fst.c

Last change on this file was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 9.6 KB
Line 
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#include "config_xor.h"
40
41#include <stdlib.h>
42#include <string.h>
43
44
45#ifdef SH_ENCRYPT
46
47#include "rijndael-api-fst.h"
48
49static void xor16(u8 *d, const u8 *a, const u8* b)
50{
51  size_t i;
52
53        for (i = 0; i < 4; i++) {
54                *d++ = *a++ ^ *b++;
55                *d++ = *a++ ^ *b++;
56                *d++ = *a++ ^ *b++;
57                *d++ = *a++ ^ *b++;
58        }
59}
60
61int
62rijndael_makeKey(keyInstance *key, BYTE direction, int keyLen,
63    const char *keyMaterial)
64{
65        u8 cipherKey[RIJNDAEL_MAXKB];
66        int i;
67
68        if (key == NULL) {
69                return BAD_KEY_INSTANCE;
70        }
71
72        if ((direction == DIR_ENCRYPT) || (direction == DIR_DECRYPT)) {
73                key->direction = direction;
74        } else {
75                return BAD_KEY_DIR;
76        }
77
78        if ((keyLen == 128) || (keyLen == 192) || (keyLen == 256)) {
79                key->keyLen = keyLen;
80        } else {
81                return BAD_KEY_MAT;
82        }
83
84        if (keyMaterial != NULL) {
85                char temp[RIJNDAEL_MAX_KEY_SIZE];
86                for (i = 0; i < key->keyLen/8; i++) {
87                  int t, j;
88                 
89                  t = *keyMaterial++;
90                  if ((t >= '0') && (t <= '9')) j = (t - '0') << 4;
91                  else if ((t >= 'a') && (t <= 'f')) j = (t - 'a' + 10) << 4; 
92                  else if ((t >= 'A') && (t <= 'F')) j = (t - 'A' + 10) << 4; 
93                  else return BAD_KEY_MAT;
94                 
95                  t = *keyMaterial++;
96                  if ((t >= '0') && (t <= '9')) j ^= (t - '0');
97                  else if ((t >= 'a') && (t <= 'f')) j ^= (t - 'a' + 10); 
98                  else if ((t >= 'A') && (t <= 'F')) j ^= (t - 'A' + 10); 
99                  else return BAD_KEY_MAT;
100                 
101                  temp[i] = (u8)j; 
102                }
103
104                /* memcpy(key->keyMaterial, keyMaterial, keyLen/8); */
105                memcpy(key->keyMaterial, temp, keyLen/8);
106        }
107
108        /* initialize key schedule: */
109        memcpy(cipherKey, key->keyMaterial, keyLen/8);
110        if (direction == DIR_ENCRYPT) {
111                key->Nr = rijndaelKeySetupEnc(key->rk, cipherKey, keyLen);
112        } else {
113                key->Nr = rijndaelKeySetupDec(key->rk, cipherKey, keyLen);
114        }
115        rijndaelKeySetupEnc(key->ek, cipherKey, keyLen);
116        return TRUE;
117}
118
119int
120rijndael_cipherInit(cipherInstance *cipher, BYTE mode, const char *IV)
121{
122        if ((mode == MODE_ECB) || (mode == MODE_CBC) || (mode == MODE_CFB1)) {
123                cipher->mode = mode;
124        } else {
125                return BAD_CIPHER_MODE;
126        }
127        if (IV != NULL) {
128                memcpy(cipher->IV, IV, RIJNDAEL_MAX_IV_SIZE);
129        } else {
130                memset(cipher->IV, 0, RIJNDAEL_MAX_IV_SIZE);
131        }
132        return TRUE;
133}
134
135int
136rijndael_blockEncrypt(cipherInstance *cipher, keyInstance *key,
137    const BYTE *input, int inputLen, BYTE *outBuffer)
138{
139        int i, k, t, numBlocks;
140        u8 block[16], *iv;
141
142        if (cipher == NULL ||
143                key == NULL ||
144                key->direction == DIR_DECRYPT) {
145                return BAD_CIPHER_STATE;
146        }
147        if (input == NULL || inputLen <= 0) {
148                return 0; /* nothing to do */
149        }
150
151        numBlocks = inputLen/128;
152
153        switch (cipher->mode) {
154        case MODE_ECB:
155                for (i = numBlocks; i > 0; i--) {
156                        rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
157                        input += 16;
158                        outBuffer += 16;
159                }
160                break;
161
162        case MODE_CBC:
163                iv = (u8 *)cipher->IV;
164                for (i = numBlocks; i > 0; i--) {
165                        xor16(block, input, iv);
166                        rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
167                        iv = outBuffer;
168                        input += 16;
169                        outBuffer += 16;
170                }
171                break;
172
173        case MODE_CFB1:
174                iv = (u8 *)cipher->IV;
175                for (i = numBlocks; i > 0; i--) {
176                        memcpy(outBuffer, input, 16);
177                        for (k = 0; k < 128; k++) {
178                                rijndaelEncrypt(key->ek, key->Nr, iv, block);
179                                outBuffer[k >> 3] ^=
180                                    (block[0] & 0x80U) >> (k & 7);
181                                for (t = 0; t < 15; t++) {
182                                        iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
183                                }
184                                iv[15] = (iv[15] << 1) |
185                                    ((outBuffer[k >> 3] >> (7 - (k & 7))) & 1);
186                        }
187                        outBuffer += 16;
188                        input += 16;
189                }
190                break;
191
192        default:
193                return BAD_CIPHER_STATE;
194        }
195
196        return 128 * numBlocks;
197}
198
199/**
200 * Encrypt data partitioned in octets, using RFC 2040-like padding.
201 *
202 * @param   input           data to be encrypted (octet sequence)
203 * @param   inputOctets         input length in octets (not bits)
204 * @param   outBuffer       encrypted output data
205 *
206 * @return      length in octets (not bits) of the encrypted output buffer.
207 */
208int
209rijndael_padEncrypt(cipherInstance *cipher, keyInstance *key,
210    const BYTE *input, int inputOctets, BYTE *outBuffer)
211{
212        int i, numBlocks, padLen;
213        u8 block[16], *iv;
214
215        if (cipher == NULL ||
216                key == NULL ||
217                key->direction == DIR_DECRYPT) {
218                return BAD_CIPHER_STATE;
219        }
220        if (input == NULL || inputOctets <= 0) {
221                return 0; /* nothing to do */
222        }
223
224        numBlocks = inputOctets / 16;
225
226        switch (cipher->mode) {
227        case MODE_ECB:
228                for (i = numBlocks; i > 0; i--) {
229                        rijndaelEncrypt(key->rk, key->Nr, input, outBuffer);
230                        input += 16;
231                        outBuffer += 16;
232                }
233                padLen = 16 - (inputOctets - 16*numBlocks);
234                memcpy(block, input, 16 - padLen);
235                memset(block + 16 - padLen, padLen, padLen);
236                rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
237                break;
238
239        case MODE_CBC:
240                iv = (u8 *)cipher->IV;
241                for (i = numBlocks; i > 0; i--) {
242                        xor16(block, input, iv);
243                        rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
244                        iv = outBuffer;
245                        input += 16;
246                        outBuffer += 16;
247                }
248                padLen = 16 - (inputOctets - 16*numBlocks);
249                for (i = 0; i < 16 - padLen; i++) {
250                        block[i] = input[i] ^ iv[i];
251                }
252                for (i = 16 - padLen; i < 16; i++) {
253                        block[i] = (BYTE)padLen ^ iv[i];
254                }
255                rijndaelEncrypt(key->rk, key->Nr, block, outBuffer);
256                break;
257
258        default:
259                return BAD_CIPHER_STATE;
260        }
261
262        return 16 * (numBlocks + 1);
263}
264
265int
266rijndael_blockDecrypt(cipherInstance *cipher, keyInstance *key,
267    const BYTE *input, int inputLen, BYTE *outBuffer)
268{
269        int i, k, t, numBlocks;
270        u8 block[16], *iv;
271
272        if (cipher == NULL ||
273                key == NULL ||
274                (cipher->mode != MODE_CFB1 && key->direction == DIR_ENCRYPT)) {
275                return BAD_CIPHER_STATE;
276        }
277        if (input == NULL || inputLen <= 0) {
278                return 0; /* nothing to do */
279        }
280
281        numBlocks = inputLen/128;
282
283        switch (cipher->mode) {
284        case MODE_ECB:
285                for (i = numBlocks; i > 0; i--) {
286                        rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
287                        input += 16;
288                        outBuffer += 16;
289                }
290                break;
291
292        case MODE_CBC:
293                iv = (u8 *)cipher->IV;
294                for (i = numBlocks; i > 0; i--) {
295                        rijndaelDecrypt(key->rk, key->Nr, input, block);
296                        xor16(block, block, iv);
297                        if (numBlocks > 1)
298                          memcpy(cipher->IV, input, 16);
299                        memcpy(outBuffer, block, 16);
300                        input += 16;
301                        outBuffer += 16;
302                }
303                break;
304
305    case MODE_CFB1:
306                iv = (u8 *)cipher->IV;
307                for (i = numBlocks; i > 0; i--) {
308                        memcpy(outBuffer, input, 16);
309                        for (k = 0; k < 128; k++) {
310                                rijndaelEncrypt(key->ek, key->Nr, iv, block);
311                                for (t = 0; t < 15; t++) {
312                                        iv[t] = (iv[t] << 1) | (iv[t + 1] >> 7);
313                                }
314                                iv[15] = (iv[15] << 1) |
315                                    ((input[k >> 3] >> (7 - (k & 7))) & 1);
316                                outBuffer[k >> 3] ^= (block[0] & 0x80U) >>
317                                    (k & 7);
318                        }
319                        outBuffer += 16;
320                        input += 16;
321                }
322                break;
323
324        default:
325                return BAD_CIPHER_STATE;
326        }
327
328        return 128 * numBlocks;
329}
330
331int
332rijndael_padDecrypt(cipherInstance *cipher, keyInstance *key,
333    const BYTE *input, int inputOctets, BYTE *outBuffer)
334{
335        int i, numBlocks, padLen;
336        u8 block[16], *iv;
337
338        if (cipher == NULL ||
339                key == NULL ||
340                key->direction == DIR_ENCRYPT) {
341                return BAD_CIPHER_STATE;
342        }
343        if (input == NULL || inputOctets <= 0) {
344                return 0; /* nothing to do */
345        }
346        if (inputOctets % 16 != 0) {
347                return BAD_DATA;
348        }
349
350        numBlocks = inputOctets/16;
351
352        switch (cipher->mode) {
353        case MODE_ECB:
354                /* all blocks but last */
355                for (i = numBlocks - 1; i > 0; i--) {
356                        rijndaelDecrypt(key->rk, key->Nr, input, outBuffer);
357                        input += 16;
358                        outBuffer += 16;
359                }
360                /* last block */
361                rijndaelDecrypt(key->rk, key->Nr, input, block);
362                padLen = block[15];
363                if (padLen >= 16) {
364                        return BAD_DATA;
365                }
366                for (i = 16 - padLen; i < 16; i++) {
367                        if (block[i] != padLen) {
368                                return BAD_DATA;
369                        }
370                }
371                memcpy(outBuffer, block, 16 - padLen);
372                break;
373
374        case MODE_CBC:
375                iv = (u8 *)cipher->IV;
376                /* all blocks but last */
377                for (i = numBlocks - 1; i > 0; i--) {
378                        rijndaelDecrypt(key->rk, key->Nr, input, block);
379                        xor16(block, block, iv);
380                        memcpy(cipher->IV, input, 16);
381                        memcpy(outBuffer, block, 16);
382                        input += 16;
383                        outBuffer += 16;
384                }
385                /* last block */
386                rijndaelDecrypt(key->rk, key->Nr, input, block);
387                xor16(block, block, iv);
388                padLen = block[15];
389                if (padLen <= 0 || padLen > 16) {
390                        return BAD_DATA;
391                }
392                for (i = 16 - padLen; i < 16; i++) {
393                        if (block[i] != padLen) {
394                                return BAD_DATA;
395                        }
396                }
397                memcpy(outBuffer, block, 16 - padLen);
398                break;
399
400        default:
401                return BAD_CIPHER_STATE;
402        }
403
404        return 16 * numBlocks - padLen;
405}
406
407#endif
Note: See TracBrowser for help on using the repository browser.