Release 0.4.3-3maemo with patches to disable menus/actions, add ScrollArea and fix...
[keepassx] / src / crypto / aes_modes.c
1 /*\r
2  ---------------------------------------------------------------------------\r
3  Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.\r
4 \r
5  LICENSE TERMS\r
6 \r
7  The redistribution and use of this software (with or without changes)\r
8  is allowed without the payment of fees or royalties provided that:\r
9 \r
10   1. source code distributions include the above copyright notice, this\r
11      list of conditions and the following disclaimer;\r
12 \r
13   2. binary distributions include the above copyright notice, this list\r
14      of conditions and the following disclaimer in their documentation;\r
15 \r
16   3. the name of the copyright holder is not used to endorse products\r
17      built using this software without specific written permission.\r
18 \r
19  DISCLAIMER\r
20 \r
21  This software is provided 'as is' with no explicit or implied warranties\r
22  in respect of its properties, including, but not limited to, correctness\r
23  and/or fitness for purpose.\r
24  ---------------------------------------------------------------------------\r
25  Issue Date: 20/12/2007\r
26 \r
27  These subroutines implement multiple block AES modes for ECB, CBC, CFB,\r
28  OFB and CTR encryption,  The code provides support for the VIA Advanced\r
29  Cryptography Engine (ACE).\r
30 \r
31  NOTE: In the following subroutines, the AES contexts (ctx) must be\r
32  16 byte aligned if VIA ACE is being used\r
33 */\r
34 \r
35 #include <string.h>\r
36 #include <assert.h>\r
37 \r
38 #include "aesopt.h"\r
39 \r
40 #if defined( AES_MODES )\r
41 #if defined(__cplusplus)\r
42 extern "C"\r
43 {\r
44 #endif\r
45 \r
46 #if defined( _MSC_VER ) && ( _MSC_VER > 800 )\r
47 #pragma intrinsic(memcpy)\r
48 #endif\r
49 \r
50 #define BFR_BLOCKS      8\r
51 \r
52 /* These values are used to detect long word alignment in order to */\r
53 /* speed up some buffer operations. This facility may not work on  */\r
54 /* some machines so this define can be commented out if necessary  */\r
55 \r
56 #define FAST_BUFFER_OPERATIONS\r
57 \r
58 #define lp32(x)         ((uint_32t*)(x))\r
59 \r
60 #if defined( USE_VIA_ACE_IF_PRESENT )\r
61 \r
62 #include "aes_via_ace.h"\r
63 \r
64 #pragma pack(16)\r
65 \r
66 aligned_array(unsigned long,    enc_gen_table, 12, 16) =    NEH_ENC_GEN_DATA;\r
67 aligned_array(unsigned long,   enc_load_table, 12, 16) =   NEH_ENC_LOAD_DATA;\r
68 aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA;\r
69 aligned_array(unsigned long,    dec_gen_table, 12, 16) =    NEH_DEC_GEN_DATA;\r
70 aligned_array(unsigned long,   dec_load_table, 12, 16) =   NEH_DEC_LOAD_DATA;\r
71 aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA;\r
72 \r
73 /* NOTE: These control word macros must only be used after  */\r
74 /* a key has been set up because they depend on key size    */\r
75 \r
76 #if NEH_KEY_TYPE == NEH_LOAD\r
77 #define kd_adr(c)   ((uint_8t*)(c)->ks)\r
78 #elif NEH_KEY_TYPE == NEH_GENERATE\r
79 #define kd_adr(c)   ((uint_8t*)(c)->ks + (c)->inf.b[0])\r
80 #else\r
81 #define kd_adr(c)   ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0))\r
82 #endif\r
83 \r
84 #else\r
85 \r
86 #define aligned_array(type, name, no, stride) type name[no]\r
87 #define aligned_auto(type, name, no, stride)  type name[no]\r
88 \r
89 #endif\r
90 \r
91 #if defined( _MSC_VER ) && _MSC_VER > 1200\r
92 \r
93 #define via_cwd(cwd, ty, dir, len) \\r
94     unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4))\r
95 \r
96 #else\r
97 \r
98 #define via_cwd(cwd, ty, dir, len)              \\r
99     aligned_auto(unsigned long, cwd, 4, 16);    \\r
100     cwd[1] = cwd[2] = cwd[3] = 0;               \\r
101     cwd[0] = neh_##dir##_##ty##_key(len)\r
102 \r
103 #endif\r
104 \r
105 /* test the code for detecting and setting pointer alignment */\r
106 \r
107 AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */\r
108 {       uint_8t p[16];\r
109         uint_32t i, count_eq = 0, count_neq = 0;\r
110 \r
111         if(n < 4 || n > 16)\r
112                 return EXIT_FAILURE;\r
113 \r
114         for(i = 0; i < n; ++i)\r
115         {\r
116                 uint_8t *qf = ALIGN_FLOOR(p + i, n),\r
117                                 *qh =  ALIGN_CEIL(p + i, n);\r
118                 \r
119                 if(qh == qf)\r
120                         ++count_eq;\r
121                 else if(qh == qf + n)\r
122                         ++count_neq;\r
123                 else\r
124                         return EXIT_FAILURE;\r
125         }\r
126         return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS);\r
127 }\r
128 \r
129 AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1])\r
130 {\r
131     ctx->inf.b[2] = 0;\r
132     return EXIT_SUCCESS;\r
133 }\r
134 \r
135 AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf,\r
136                     int len, const aes_encrypt_ctx ctx[1])\r
137 {   int nb = len >> 4;\r
138 \r
139     if(len & (AES_BLOCK_SIZE - 1))\r
140         return EXIT_FAILURE;\r
141 \r
142 #if defined( USE_VIA_ACE_IF_PRESENT )\r
143 \r
144     if(ctx->inf.b[1] == 0xff)\r
145     {   uint_8t *ksp = (uint_8t*)(ctx->ks);\r
146         via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
147 \r
148         if(ALIGN_OFFSET( ctx, 16 ))\r
149             return EXIT_FAILURE;\r
150 \r
151         if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
152         {\r
153             via_ecb_op5(ksp,cwd,ibuf,obuf,nb);\r
154         }\r
155         else\r
156         {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
157             uint_8t *ip, *op;\r
158 \r
159             while(nb)\r
160             {\r
161                 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);\r
162 \r
163                 ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
164                 op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
165 \r
166                 if(ip != ibuf)\r
167                     memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
168 \r
169                 via_ecb_op5(ksp,cwd,ip,op,m);\r
170 \r
171                 if(op != obuf)\r
172                     memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
173 \r
174                 ibuf += m * AES_BLOCK_SIZE;\r
175                 obuf += m * AES_BLOCK_SIZE;\r
176                 nb -= m;\r
177             }\r
178         }\r
179 \r
180         return EXIT_SUCCESS;\r
181     }\r
182 \r
183 #endif\r
184 \r
185 #if !defined( ASSUME_VIA_ACE_PRESENT )\r
186     while(nb--)\r
187     {\r
188         if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)\r
189                         return EXIT_FAILURE;\r
190         ibuf += AES_BLOCK_SIZE;\r
191         obuf += AES_BLOCK_SIZE;\r
192     }\r
193 #endif\r
194     return EXIT_SUCCESS;\r
195 }\r
196 \r
197 AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf,\r
198                     int len, const aes_decrypt_ctx ctx[1])\r
199 {   int nb = len >> 4;\r
200 \r
201     if(len & (AES_BLOCK_SIZE - 1))\r
202         return EXIT_FAILURE;\r
203 \r
204 #if defined( USE_VIA_ACE_IF_PRESENT )\r
205 \r
206     if(ctx->inf.b[1] == 0xff)\r
207     {   uint_8t *ksp = kd_adr(ctx);\r
208         via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);\r
209 \r
210         if(ALIGN_OFFSET( ctx, 16 ))\r
211             return EXIT_FAILURE;\r
212 \r
213         if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
214         {\r
215             via_ecb_op5(ksp,cwd,ibuf,obuf,nb);\r
216         }\r
217         else\r
218         {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
219             uint_8t *ip, *op;\r
220 \r
221             while(nb)\r
222             {\r
223                 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);\r
224 \r
225                 ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
226                 op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
227 \r
228                 if(ip != ibuf)\r
229                     memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
230 \r
231                 via_ecb_op5(ksp,cwd,ip,op,m);\r
232 \r
233                 if(op != obuf)\r
234                     memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
235 \r
236                 ibuf += m * AES_BLOCK_SIZE;\r
237                 obuf += m * AES_BLOCK_SIZE;\r
238                 nb -= m;\r
239             }\r
240         }\r
241 \r
242         return EXIT_SUCCESS;\r
243     }\r
244 \r
245 #endif\r
246 \r
247 #if !defined( ASSUME_VIA_ACE_PRESENT )\r
248     while(nb--)\r
249     {\r
250         if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)\r
251                         return EXIT_FAILURE;\r
252         ibuf += AES_BLOCK_SIZE;\r
253         obuf += AES_BLOCK_SIZE;\r
254     }\r
255 #endif\r
256     return EXIT_SUCCESS;\r
257 }\r
258 \r
259 AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf,\r
260                     int len, unsigned char *iv, const aes_encrypt_ctx ctx[1])\r
261 {   int nb = len >> 4;\r
262 \r
263     if(len & (AES_BLOCK_SIZE - 1))\r
264         return EXIT_FAILURE;\r
265 \r
266 #if defined( USE_VIA_ACE_IF_PRESENT )\r
267 \r
268     if(ctx->inf.b[1] == 0xff)\r
269     {   uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
270         aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
271         via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
272 \r
273         if(ALIGN_OFFSET( ctx, 16 ))\r
274             return EXIT_FAILURE;\r
275 \r
276         if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
277         {\r
278             ivp = liv;\r
279             memcpy(liv, iv, AES_BLOCK_SIZE);\r
280         }\r
281 \r
282         if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))\r
283         {\r
284             via_cbc_op7(ksp,cwd,ibuf,obuf,nb,ivp,ivp);\r
285         }\r
286         else\r
287         {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
288             uint_8t *ip, *op;\r
289 \r
290             while(nb)\r
291             {\r
292                 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);\r
293 \r
294                 ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
295                 op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
296 \r
297                 if(ip != ibuf)\r
298                     memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
299 \r
300                 via_cbc_op7(ksp,cwd,ip,op,m,ivp,ivp);\r
301 \r
302                 if(op != obuf)\r
303                     memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
304 \r
305                 ibuf += m * AES_BLOCK_SIZE;\r
306                 obuf += m * AES_BLOCK_SIZE;\r
307                 nb -= m;\r
308             }\r
309         }\r
310 \r
311         if(iv != ivp)\r
312             memcpy(iv, ivp, AES_BLOCK_SIZE);\r
313 \r
314         return EXIT_SUCCESS;\r
315     }\r
316 \r
317 #endif\r
318 \r
319 #if !defined( ASSUME_VIA_ACE_PRESENT )\r
320 # ifdef FAST_BUFFER_OPERATIONS\r
321     if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))\r
322         while(nb--)\r
323         {\r
324             lp32(iv)[0] ^= lp32(ibuf)[0];\r
325             lp32(iv)[1] ^= lp32(ibuf)[1];\r
326             lp32(iv)[2] ^= lp32(ibuf)[2];\r
327             lp32(iv)[3] ^= lp32(ibuf)[3];\r
328             if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
329                                 return EXIT_FAILURE;\r
330             memcpy(obuf, iv, AES_BLOCK_SIZE);\r
331             ibuf += AES_BLOCK_SIZE;\r
332             obuf += AES_BLOCK_SIZE;\r
333         }\r
334     else\r
335 # endif\r
336         while(nb--)\r
337         {\r
338             iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1];\r
339             iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3];\r
340             iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5];\r
341             iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7];\r
342             iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9];\r
343             iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11];\r
344             iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13];\r
345             iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15];\r
346             if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
347                                 return EXIT_FAILURE;\r
348             memcpy(obuf, iv, AES_BLOCK_SIZE);\r
349             ibuf += AES_BLOCK_SIZE;\r
350             obuf += AES_BLOCK_SIZE;\r
351         }\r
352 #endif\r
353     return EXIT_SUCCESS;\r
354 }\r
355 \r
356 AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf,\r
357                     int len, unsigned char *iv, const aes_decrypt_ctx ctx[1])\r
358 {   unsigned char tmp[AES_BLOCK_SIZE];\r
359     int nb = len >> 4;\r
360 \r
361     if(len & (AES_BLOCK_SIZE - 1))\r
362         return EXIT_FAILURE;\r
363 \r
364 #if defined( USE_VIA_ACE_IF_PRESENT )\r
365 \r
366     if(ctx->inf.b[1] == 0xff)\r
367     {   uint_8t *ksp = kd_adr(ctx), *ivp = iv;\r
368         aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
369         via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);\r
370 \r
371         if(ALIGN_OFFSET( ctx, 16 ))\r
372             return EXIT_FAILURE;\r
373 \r
374         if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
375         {\r
376             ivp = liv;\r
377             memcpy(liv, iv, AES_BLOCK_SIZE);\r
378         }\r
379 \r
380         if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 ))\r
381         {\r
382             via_cbc_op6(ksp,cwd,ibuf,obuf,nb,ivp);\r
383         }\r
384         else\r
385         {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
386             uint_8t *ip, *op;\r
387 \r
388             while(nb)\r
389             {\r
390                 int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb);\r
391 \r
392                 ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
393                 op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
394 \r
395                 if(ip != ibuf)\r
396                     memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
397 \r
398                 via_cbc_op6(ksp,cwd,ip,op,m,ivp);\r
399 \r
400                 if(op != obuf)\r
401                     memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
402 \r
403                 ibuf += m * AES_BLOCK_SIZE;\r
404                 obuf += m * AES_BLOCK_SIZE;\r
405                 nb -= m;\r
406             }\r
407         }\r
408 \r
409         if(iv != ivp)\r
410             memcpy(iv, ivp, AES_BLOCK_SIZE);\r
411 \r
412         return EXIT_SUCCESS;\r
413     }\r
414 #endif\r
415 \r
416 #if !defined( ASSUME_VIA_ACE_PRESENT )\r
417 # ifdef FAST_BUFFER_OPERATIONS\r
418     if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))\r
419         while(nb--)\r
420         {\r
421             memcpy(tmp, ibuf, AES_BLOCK_SIZE);\r
422             if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)\r
423                                 return EXIT_FAILURE;\r
424             lp32(obuf)[0] ^= lp32(iv)[0];\r
425             lp32(obuf)[1] ^= lp32(iv)[1];\r
426             lp32(obuf)[2] ^= lp32(iv)[2];\r
427             lp32(obuf)[3] ^= lp32(iv)[3];\r
428             memcpy(iv, tmp, AES_BLOCK_SIZE);\r
429             ibuf += AES_BLOCK_SIZE;\r
430             obuf += AES_BLOCK_SIZE;\r
431         }\r
432     else\r
433 # endif\r
434         while(nb--)\r
435         {\r
436             memcpy(tmp, ibuf, AES_BLOCK_SIZE);\r
437             if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS)\r
438                                 return EXIT_FAILURE;\r
439             obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1];\r
440             obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3];\r
441             obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5];\r
442             obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7];\r
443             obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9];\r
444             obuf[10] ^= iv[10]; obuf[11] ^= iv[11];\r
445             obuf[12] ^= iv[12]; obuf[13] ^= iv[13];\r
446             obuf[14] ^= iv[14]; obuf[15] ^= iv[15];\r
447             memcpy(iv, tmp, AES_BLOCK_SIZE);\r
448             ibuf += AES_BLOCK_SIZE;\r
449             obuf += AES_BLOCK_SIZE;\r
450         }\r
451 #endif\r
452     return EXIT_SUCCESS;\r
453 }\r
454 \r
455 AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf,\r
456                     int len, unsigned char *iv, aes_encrypt_ctx ctx[1])\r
457 {   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;\r
458 \r
459     if(b_pos)           /* complete any partial block   */\r
460     {\r
461         while(b_pos < AES_BLOCK_SIZE && cnt < len)\r
462             *obuf++ = iv[b_pos++] ^= *ibuf++, cnt++;\r
463 \r
464         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
465     }\r
466 \r
467     if((nb = (len - cnt) >> 4) != 0)    /* process whole blocks */\r
468     {\r
469 #if defined( USE_VIA_ACE_IF_PRESENT )\r
470 \r
471         if(ctx->inf.b[1] == 0xff)\r
472         {   int m;\r
473             uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
474             aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
475             via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
476 \r
477             if(ALIGN_OFFSET( ctx, 16 ))\r
478                 return EXIT_FAILURE;\r
479 \r
480             if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
481             {\r
482                 ivp = liv;\r
483                 memcpy(liv, iv, AES_BLOCK_SIZE);\r
484             }\r
485 \r
486             if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
487             {\r
488                 via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);\r
489                 ibuf += nb * AES_BLOCK_SIZE;\r
490                 obuf += nb * AES_BLOCK_SIZE;\r
491                 cnt  += nb * AES_BLOCK_SIZE;\r
492             }\r
493             else    /* input, output or both are unaligned  */\r
494             {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
495                 uint_8t *ip, *op;\r
496 \r
497                 while(nb)\r
498                 {\r
499                     m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;\r
500 \r
501                     ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
502                     op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
503 \r
504                     if(ip != ibuf)\r
505                         memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
506 \r
507                     via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);\r
508 \r
509                     if(op != obuf)\r
510                         memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
511 \r
512                     ibuf += m * AES_BLOCK_SIZE;\r
513                     obuf += m * AES_BLOCK_SIZE;\r
514                     cnt  += m * AES_BLOCK_SIZE;\r
515                 }\r
516             }\r
517 \r
518             if(ivp != iv)\r
519                 memcpy(iv, ivp, AES_BLOCK_SIZE);\r
520         }\r
521 #else\r
522 # ifdef FAST_BUFFER_OPERATIONS\r
523         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))\r
524             while(cnt + AES_BLOCK_SIZE <= len)\r
525             {\r
526                 assert(b_pos == 0);\r
527                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
528                                         return EXIT_FAILURE;\r
529                 lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];\r
530                 lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];\r
531                 lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];\r
532                 lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];\r
533                 ibuf += AES_BLOCK_SIZE;\r
534                 obuf += AES_BLOCK_SIZE;\r
535                 cnt  += AES_BLOCK_SIZE;\r
536             }\r
537         else\r
538 # endif\r
539             while(cnt + AES_BLOCK_SIZE <= len)\r
540             {\r
541                 assert(b_pos == 0);\r
542                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
543                                         return EXIT_FAILURE;\r
544                 obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1];\r
545                 obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3];\r
546                 obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5];\r
547                 obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7];\r
548                 obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9];\r
549                 obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11];\r
550                 obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13];\r
551                 obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15];\r
552                 ibuf += AES_BLOCK_SIZE;\r
553                 obuf += AES_BLOCK_SIZE;\r
554                 cnt  += AES_BLOCK_SIZE;\r
555             }\r
556 #endif\r
557     }\r
558 \r
559     while(cnt < len)\r
560     {\r
561         if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
562                         return EXIT_FAILURE;\r
563 \r
564         while(cnt < len && b_pos < AES_BLOCK_SIZE)\r
565             *obuf++ = iv[b_pos++] ^= *ibuf++, cnt++;\r
566 \r
567         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
568     }\r
569 \r
570     ctx->inf.b[2] = b_pos;\r
571     return EXIT_SUCCESS;\r
572 }\r
573 \r
574 AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,\r
575                     int len, unsigned char *iv, aes_encrypt_ctx ctx[1])\r
576 {   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;\r
577 \r
578     if(b_pos)           /* complete any partial block   */\r
579     {   uint_8t t;\r
580 \r
581         while(b_pos < AES_BLOCK_SIZE && cnt < len)\r
582             t = *ibuf++, *obuf++ = t ^ iv[b_pos], iv[b_pos++] = t, cnt++;\r
583 \r
584         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
585     }\r
586 \r
587     if((nb = (len - cnt) >> 4) != 0)    /* process whole blocks */\r
588     {\r
589 #if defined( USE_VIA_ACE_IF_PRESENT )\r
590 \r
591         if(ctx->inf.b[1] == 0xff)\r
592         {   int m;\r
593             uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
594             aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
595             via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);\r
596 \r
597             if(ALIGN_OFFSET( ctx, 16 ))\r
598                 return EXIT_FAILURE;\r
599 \r
600             if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
601             {\r
602                 ivp = liv;\r
603                 memcpy(liv, iv, AES_BLOCK_SIZE);\r
604             }\r
605 \r
606             if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
607             {\r
608                 via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);\r
609                 ibuf += nb * AES_BLOCK_SIZE;\r
610                 obuf += nb * AES_BLOCK_SIZE;\r
611                 cnt  += nb * AES_BLOCK_SIZE;\r
612             }\r
613             else    /* input, output or both are unaligned  */\r
614             {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
615                 uint_8t *ip, *op;\r
616 \r
617                 while(nb)\r
618                 {\r
619                     m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;\r
620 \r
621                     ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
622                     op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
623 \r
624                     if(ip != ibuf)  /* input buffer is not aligned */\r
625                         memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
626 \r
627                     via_cfb_op6(ksp, cwd, ip, op, m, ivp);\r
628 \r
629                     if(op != obuf)  /* output buffer is not aligned */\r
630                         memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
631 \r
632                     ibuf += m * AES_BLOCK_SIZE;\r
633                     obuf += m * AES_BLOCK_SIZE;\r
634                     cnt  += m * AES_BLOCK_SIZE;\r
635                 }\r
636             }\r
637 \r
638             if(ivp != iv)\r
639                 memcpy(iv, ivp, AES_BLOCK_SIZE);\r
640         }\r
641 #else\r
642 # ifdef FAST_BUFFER_OPERATIONS\r
643         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 ))\r
644             while(cnt + AES_BLOCK_SIZE <= len)\r
645             {   uint_32t t;\r
646 \r
647                 assert(b_pos == 0);\r
648                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
649                                         return EXIT_FAILURE;\r
650                 t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;\r
651                 t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;\r
652                 t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;\r
653                 t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;\r
654                 ibuf += AES_BLOCK_SIZE;\r
655                 obuf += AES_BLOCK_SIZE;\r
656                 cnt  += AES_BLOCK_SIZE;\r
657             }\r
658         else\r
659 # endif\r
660             while(cnt + AES_BLOCK_SIZE <= len)\r
661             {   uint_8t t;\r
662 \r
663                 assert(b_pos == 0);\r
664                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
665                                         return EXIT_FAILURE;\r
666                 t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t;\r
667                 t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t;\r
668                 t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t;\r
669                 t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t;\r
670                 t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t;\r
671                 t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t;\r
672                 t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t;\r
673                 t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t;\r
674                 t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t;\r
675                 t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t;\r
676                 t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;\r
677                 t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;\r
678                 t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;\r
679                 t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;\r
680                 t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;\r
681                 t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;\r
682                 ibuf += AES_BLOCK_SIZE;\r
683                 obuf += AES_BLOCK_SIZE;\r
684                 cnt  += AES_BLOCK_SIZE;\r
685             }\r
686 #endif\r
687     }\r
688 \r
689     while(cnt < len)\r
690     {   uint_8t t;\r
691 \r
692         if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
693                         return EXIT_FAILURE;\r
694 \r
695         while(cnt < len && b_pos < AES_BLOCK_SIZE)\r
696             t = *ibuf++, *obuf++ = t ^ iv[b_pos], iv[b_pos++] = t, cnt++;\r
697 \r
698         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
699     }\r
700 \r
701     ctx->inf.b[2] = b_pos;\r
702     return EXIT_SUCCESS;\r
703 }\r
704 \r
705 AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,\r
706                     int len, unsigned char *iv, aes_encrypt_ctx ctx[1])\r
707 {   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;\r
708 \r
709     if(b_pos)           /* complete any partial block   */\r
710     {\r
711         while(b_pos < AES_BLOCK_SIZE && cnt < len)\r
712             *obuf++ = iv[b_pos++] ^ *ibuf++, cnt++;\r
713 \r
714         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
715     }\r
716 \r
717     if((nb = (len - cnt) >> 4) != 0)   /* process whole blocks */\r
718     {\r
719 #if defined( USE_VIA_ACE_IF_PRESENT )\r
720 \r
721         if(ctx->inf.b[1] == 0xff)\r
722         {   int m;\r
723             uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
724             aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
725             via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
726 \r
727             if(ALIGN_OFFSET( ctx, 16 ))\r
728                 return EXIT_FAILURE;\r
729 \r
730             if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
731             {\r
732                 ivp = liv;\r
733                 memcpy(liv, iv, AES_BLOCK_SIZE);\r
734             }\r
735 \r
736             if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
737             {\r
738                 via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);\r
739                 ibuf += nb * AES_BLOCK_SIZE;\r
740                 obuf += nb * AES_BLOCK_SIZE;\r
741                 cnt  += nb * AES_BLOCK_SIZE;\r
742             }\r
743             else    /* input, output or both are unaligned  */\r
744         {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
745             uint_8t *ip, *op;\r
746 \r
747                 while(nb)\r
748                 {\r
749                     m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;\r
750 \r
751                     ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
752                     op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
753 \r
754                     if(ip != ibuf)\r
755                         memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
756 \r
757                     via_ofb_op6(ksp, cwd, ip, op, m, ivp);\r
758 \r
759                     if(op != obuf)\r
760                         memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
761 \r
762                     ibuf += m * AES_BLOCK_SIZE;\r
763                     obuf += m * AES_BLOCK_SIZE;\r
764                     cnt  += m * AES_BLOCK_SIZE;\r
765                 }\r
766             }\r
767 \r
768             if(ivp != iv)\r
769                 memcpy(iv, ivp, AES_BLOCK_SIZE);\r
770         }\r
771 #else\r
772 # ifdef FAST_BUFFER_OPERATIONS\r
773         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))\r
774             while(cnt + AES_BLOCK_SIZE <= len)\r
775             {\r
776                 assert(b_pos == 0);\r
777                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
778                                         return EXIT_FAILURE;\r
779                 lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];\r
780                 lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];\r
781                 lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];\r
782                 lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];\r
783                 ibuf += AES_BLOCK_SIZE;\r
784                 obuf += AES_BLOCK_SIZE;\r
785                 cnt  += AES_BLOCK_SIZE;\r
786             }\r
787         else\r
788 # endif\r
789             while(cnt + AES_BLOCK_SIZE <= len)\r
790             {\r
791                 assert(b_pos == 0);\r
792                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
793                                         return EXIT_FAILURE;\r
794                 obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1];\r
795                 obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3];\r
796                 obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5];\r
797                 obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7];\r
798                 obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9];\r
799                 obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11];\r
800                 obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13];\r
801                 obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15];\r
802                 ibuf += AES_BLOCK_SIZE;\r
803                 obuf += AES_BLOCK_SIZE;\r
804                 cnt  += AES_BLOCK_SIZE;\r
805             }\r
806 #endif\r
807     }\r
808 \r
809     while(cnt < len)\r
810     {\r
811         if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
812                         return EXIT_FAILURE;\r
813 \r
814         while(cnt < len && b_pos < AES_BLOCK_SIZE)\r
815             *obuf++ = iv[b_pos++] ^ *ibuf++, cnt++;\r
816 \r
817         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
818     }\r
819 \r
820     ctx->inf.b[2] = b_pos;\r
821     return EXIT_SUCCESS;\r
822 }\r
823 \r
824 #define BFR_LENGTH  (BFR_BLOCKS * AES_BLOCK_SIZE)\r
825 \r
826 AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,\r
827             int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1])\r
828 {   uint_8t *ip;\r
829     int     i, blen, b_pos = (int)(ctx->inf.b[2]);\r
830 \r
831 #if defined( USE_VIA_ACE_IF_PRESENT )\r
832     aligned_auto(uint_8t, buf, BFR_LENGTH, 16);\r
833     if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 ))\r
834         return EXIT_FAILURE;\r
835 #else\r
836     uint_8t buf[BFR_LENGTH];\r
837 #endif\r
838 \r
839     if(b_pos)\r
840     {\r
841         memcpy(buf, cbuf, AES_BLOCK_SIZE);\r
842         if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)\r
843                         return EXIT_FAILURE;\r
844         while(b_pos < AES_BLOCK_SIZE && len)\r
845             *obuf++ = *ibuf++ ^ buf[b_pos++], --len;\r
846         if(len)\r
847             ctr_inc(cbuf), b_pos = 0;\r
848     }\r
849 \r
850     while(len)\r
851     {\r
852         blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;\r
853 \r
854         for(i = 0, ip = buf; i < (blen >> 4); ++i)\r
855         {\r
856             memcpy(ip, cbuf, AES_BLOCK_SIZE);\r
857             ctr_inc(cbuf);\r
858             ip += AES_BLOCK_SIZE;\r
859         }\r
860 \r
861         if(blen & (AES_BLOCK_SIZE - 1))\r
862             memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;\r
863 \r
864 #if defined( USE_VIA_ACE_IF_PRESENT )\r
865         if(ctx->inf.b[1] == 0xff)\r
866         {\r
867             via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
868             via_ecb_op5((ctx->ks),cwd,buf,buf,i);\r
869         }\r
870         else\r
871 #endif\r
872         if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)\r
873                         return EXIT_FAILURE;\r
874 \r
875         i = 0; ip = buf;\r
876 # ifdef FAST_BUFFER_OPERATIONS\r
877         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 ))\r
878             while(i + AES_BLOCK_SIZE <= blen)\r
879             {\r
880                 lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];\r
881                 lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];\r
882                 lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];\r
883                 lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];\r
884                 i += AES_BLOCK_SIZE;\r
885                 ip += AES_BLOCK_SIZE;\r
886                 ibuf += AES_BLOCK_SIZE;\r
887                 obuf += AES_BLOCK_SIZE;\r
888             }\r
889         else\r
890 #endif\r
891             while(i + AES_BLOCK_SIZE <= blen)\r
892             {\r
893                 obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1];\r
894                 obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3];\r
895                 obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5];\r
896                 obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7];\r
897                 obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9];\r
898                 obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11];\r
899                 obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13];\r
900                 obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15];\r
901                 i += AES_BLOCK_SIZE;\r
902                 ip += AES_BLOCK_SIZE;\r
903                 ibuf += AES_BLOCK_SIZE;\r
904                 obuf += AES_BLOCK_SIZE;\r
905             }\r
906 \r
907         while(i++ < blen)\r
908             *obuf++ = *ibuf++ ^ ip[b_pos++];\r
909     }\r
910 \r
911     ctx->inf.b[2] = b_pos;\r
912     return EXIT_SUCCESS;\r
913 }\r
914 \r
915 #if defined(__cplusplus)\r
916 }\r
917 #endif\r
918 #endif\r