OSDN Git Service

Modify dialog messages for saving an encryption status.
[ffftp/ffftp.git] / 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         {\r
463             *obuf++ = (iv[b_pos++] ^= *ibuf++);\r
464             cnt++;\r
465         }\r
466 \r
467         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
468     }\r
469 \r
470     if((nb = (len - cnt) >> 4) != 0)    /* process whole blocks */\r
471     {\r
472 #if defined( USE_VIA_ACE_IF_PRESENT )\r
473 \r
474         if(ctx->inf.b[1] == 0xff)\r
475         {   int m;\r
476             uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
477             aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
478             via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
479 \r
480             if(ALIGN_OFFSET( ctx, 16 ))\r
481                 return EXIT_FAILURE;\r
482 \r
483             if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
484             {\r
485                 ivp = liv;\r
486                 memcpy(liv, iv, AES_BLOCK_SIZE);\r
487             }\r
488 \r
489             if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
490             {\r
491                 via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp);\r
492                 ibuf += nb * AES_BLOCK_SIZE;\r
493                 obuf += nb * AES_BLOCK_SIZE;\r
494                 cnt  += nb * AES_BLOCK_SIZE;\r
495             }\r
496             else    /* input, output or both are unaligned  */\r
497             {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
498                 uint_8t *ip, *op;\r
499 \r
500                 while(nb)\r
501                 {\r
502                     m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;\r
503 \r
504                     ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
505                     op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
506 \r
507                     if(ip != ibuf)\r
508                         memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
509 \r
510                     via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp);\r
511 \r
512                     if(op != obuf)\r
513                         memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
514 \r
515                     ibuf += m * AES_BLOCK_SIZE;\r
516                     obuf += m * AES_BLOCK_SIZE;\r
517                     cnt  += m * AES_BLOCK_SIZE;\r
518                 }\r
519             }\r
520 \r
521             if(ivp != iv)\r
522                 memcpy(iv, ivp, AES_BLOCK_SIZE);\r
523         }\r
524 #else\r
525 # ifdef FAST_BUFFER_OPERATIONS\r
526         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))\r
527             while(cnt + AES_BLOCK_SIZE <= len)\r
528             {\r
529                 assert(b_pos == 0);\r
530                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
531                                         return EXIT_FAILURE;\r
532                 lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0];\r
533                 lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1];\r
534                 lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2];\r
535                 lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3];\r
536                 ibuf += AES_BLOCK_SIZE;\r
537                 obuf += AES_BLOCK_SIZE;\r
538                 cnt  += AES_BLOCK_SIZE;\r
539             }\r
540         else\r
541 # endif\r
542             while(cnt + AES_BLOCK_SIZE <= len)\r
543             {\r
544                 assert(b_pos == 0);\r
545                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
546                                         return EXIT_FAILURE;\r
547                 obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1];\r
548                 obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3];\r
549                 obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5];\r
550                 obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7];\r
551                 obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9];\r
552                 obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11];\r
553                 obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13];\r
554                 obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15];\r
555                 ibuf += AES_BLOCK_SIZE;\r
556                 obuf += AES_BLOCK_SIZE;\r
557                 cnt  += AES_BLOCK_SIZE;\r
558             }\r
559 #endif\r
560     }\r
561 \r
562     while(cnt < len)\r
563     {\r
564         if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
565                         return EXIT_FAILURE;\r
566 \r
567         while(cnt < len && b_pos < AES_BLOCK_SIZE)\r
568         {\r
569             *obuf++ = (iv[b_pos++] ^= *ibuf++);\r
570             cnt++;\r
571         }\r
572 \r
573         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
574     }\r
575 \r
576     ctx->inf.b[2] = (uint_8t)b_pos;\r
577     return EXIT_SUCCESS;\r
578 }\r
579 \r
580 AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf,\r
581                     int len, unsigned char *iv, aes_encrypt_ctx ctx[1])\r
582 {   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;\r
583 \r
584     if(b_pos)           /* complete any partial block   */\r
585     {   uint_8t t;\r
586 \r
587         while(b_pos < AES_BLOCK_SIZE && cnt < len)\r
588         {\r
589             t = *ibuf++;\r
590             *obuf++ = t ^ iv[b_pos];\r
591             iv[b_pos++] = t;\r
592             cnt++;\r
593         }\r
594 \r
595         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
596     }\r
597 \r
598     if((nb = (len - cnt) >> 4) != 0)    /* process whole blocks */\r
599     {\r
600 #if defined( USE_VIA_ACE_IF_PRESENT )\r
601 \r
602         if(ctx->inf.b[1] == 0xff)\r
603         {   int m;\r
604             uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
605             aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
606             via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192);\r
607 \r
608             if(ALIGN_OFFSET( ctx, 16 ))\r
609                 return EXIT_FAILURE;\r
610 \r
611             if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
612             {\r
613                 ivp = liv;\r
614                 memcpy(liv, iv, AES_BLOCK_SIZE);\r
615             }\r
616 \r
617             if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
618             {\r
619                 via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp);\r
620                 ibuf += nb * AES_BLOCK_SIZE;\r
621                 obuf += nb * AES_BLOCK_SIZE;\r
622                 cnt  += nb * AES_BLOCK_SIZE;\r
623             }\r
624             else    /* input, output or both are unaligned  */\r
625             {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
626                 uint_8t *ip, *op;\r
627 \r
628                 while(nb)\r
629                 {\r
630                     m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;\r
631 \r
632                     ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
633                     op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
634 \r
635                     if(ip != ibuf)  /* input buffer is not aligned */\r
636                         memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
637 \r
638                     via_cfb_op6(ksp, cwd, ip, op, m, ivp);\r
639 \r
640                     if(op != obuf)  /* output buffer is not aligned */\r
641                         memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
642 \r
643                     ibuf += m * AES_BLOCK_SIZE;\r
644                     obuf += m * AES_BLOCK_SIZE;\r
645                     cnt  += m * AES_BLOCK_SIZE;\r
646                 }\r
647             }\r
648 \r
649             if(ivp != iv)\r
650                 memcpy(iv, ivp, AES_BLOCK_SIZE);\r
651         }\r
652 #else\r
653 # ifdef FAST_BUFFER_OPERATIONS\r
654         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 ))\r
655             while(cnt + AES_BLOCK_SIZE <= len)\r
656             {   uint_32t t;\r
657 \r
658                 assert(b_pos == 0);\r
659                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
660                                         return EXIT_FAILURE;\r
661                 t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t;\r
662                 t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t;\r
663                 t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t;\r
664                 t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t;\r
665                 ibuf += AES_BLOCK_SIZE;\r
666                 obuf += AES_BLOCK_SIZE;\r
667                 cnt  += AES_BLOCK_SIZE;\r
668             }\r
669         else\r
670 # endif\r
671             while(cnt + AES_BLOCK_SIZE <= len)\r
672             {   uint_8t t;\r
673 \r
674                 assert(b_pos == 0);\r
675                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
676                                         return EXIT_FAILURE;\r
677                 t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t;\r
678                 t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t;\r
679                 t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t;\r
680                 t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t;\r
681                 t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t;\r
682                 t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t;\r
683                 t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t;\r
684                 t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t;\r
685                 t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t;\r
686                 t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t;\r
687                 t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t;\r
688                 t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t;\r
689                 t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t;\r
690                 t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t;\r
691                 t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t;\r
692                 t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t;\r
693                 ibuf += AES_BLOCK_SIZE;\r
694                 obuf += AES_BLOCK_SIZE;\r
695                 cnt  += AES_BLOCK_SIZE;\r
696             }\r
697 #endif\r
698     }\r
699 \r
700     while(cnt < len)\r
701     {   uint_8t t;\r
702 \r
703         if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
704                         return EXIT_FAILURE;\r
705 \r
706         while(cnt < len && b_pos < AES_BLOCK_SIZE)\r
707         {\r
708             t = *ibuf++;\r
709             *obuf++ = t ^ iv[b_pos];\r
710             iv[b_pos++] = t;\r
711             cnt++;\r
712         }\r
713 \r
714         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
715     }\r
716 \r
717     ctx->inf.b[2] = (uint_8t)b_pos;\r
718     return EXIT_SUCCESS;\r
719 }\r
720 \r
721 AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf,\r
722                     int len, unsigned char *iv, aes_encrypt_ctx ctx[1])\r
723 {   int cnt = 0, b_pos = (int)ctx->inf.b[2], nb;\r
724 \r
725     if(b_pos)           /* complete any partial block   */\r
726     {\r
727         while(b_pos < AES_BLOCK_SIZE && cnt < len)\r
728         {\r
729             *obuf++ = iv[b_pos++] ^ *ibuf++;\r
730             cnt++;\r
731         }\r
732 \r
733         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
734     }\r
735 \r
736     if((nb = (len - cnt) >> 4) != 0)   /* process whole blocks */\r
737     {\r
738 #if defined( USE_VIA_ACE_IF_PRESENT )\r
739 \r
740         if(ctx->inf.b[1] == 0xff)\r
741         {   int m;\r
742             uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv;\r
743             aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16);\r
744             via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
745 \r
746             if(ALIGN_OFFSET( ctx, 16 ))\r
747                 return EXIT_FAILURE;\r
748 \r
749             if(ALIGN_OFFSET( iv, 16 ))   /* ensure an aligned iv */\r
750             {\r
751                 ivp = liv;\r
752                 memcpy(liv, iv, AES_BLOCK_SIZE);\r
753             }\r
754 \r
755             if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ))\r
756             {\r
757                 via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp);\r
758                 ibuf += nb * AES_BLOCK_SIZE;\r
759                 obuf += nb * AES_BLOCK_SIZE;\r
760                 cnt  += nb * AES_BLOCK_SIZE;\r
761             }\r
762             else    /* input, output or both are unaligned  */\r
763         {   aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16);\r
764             uint_8t *ip, *op;\r
765 \r
766                 while(nb)\r
767                 {\r
768                     m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m;\r
769 \r
770                     ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf);\r
771                     op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf);\r
772 \r
773                     if(ip != ibuf)\r
774                         memcpy(buf, ibuf, m * AES_BLOCK_SIZE);\r
775 \r
776                     via_ofb_op6(ksp, cwd, ip, op, m, ivp);\r
777 \r
778                     if(op != obuf)\r
779                         memcpy(obuf, buf, m * AES_BLOCK_SIZE);\r
780 \r
781                     ibuf += m * AES_BLOCK_SIZE;\r
782                     obuf += m * AES_BLOCK_SIZE;\r
783                     cnt  += m * AES_BLOCK_SIZE;\r
784                 }\r
785             }\r
786 \r
787             if(ivp != iv)\r
788                 memcpy(iv, ivp, AES_BLOCK_SIZE);\r
789         }\r
790 #else\r
791 # ifdef FAST_BUFFER_OPERATIONS\r
792         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 ))\r
793             while(cnt + AES_BLOCK_SIZE <= len)\r
794             {\r
795                 assert(b_pos == 0);\r
796                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
797                                         return EXIT_FAILURE;\r
798                 lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0];\r
799                 lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1];\r
800                 lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2];\r
801                 lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3];\r
802                 ibuf += AES_BLOCK_SIZE;\r
803                 obuf += AES_BLOCK_SIZE;\r
804                 cnt  += AES_BLOCK_SIZE;\r
805             }\r
806         else\r
807 # endif\r
808             while(cnt + AES_BLOCK_SIZE <= len)\r
809             {\r
810                 assert(b_pos == 0);\r
811                 if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
812                                         return EXIT_FAILURE;\r
813                 obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1];\r
814                 obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3];\r
815                 obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5];\r
816                 obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7];\r
817                 obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9];\r
818                 obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11];\r
819                 obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13];\r
820                 obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15];\r
821                 ibuf += AES_BLOCK_SIZE;\r
822                 obuf += AES_BLOCK_SIZE;\r
823                 cnt  += AES_BLOCK_SIZE;\r
824             }\r
825 #endif\r
826     }\r
827 \r
828     while(cnt < len)\r
829     {\r
830         if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)\r
831                         return EXIT_FAILURE;\r
832 \r
833         while(cnt < len && b_pos < AES_BLOCK_SIZE)\r
834         {\r
835             *obuf++ = iv[b_pos++] ^ *ibuf++;\r
836             cnt++;\r
837         }\r
838 \r
839         b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos);\r
840     }\r
841 \r
842     ctx->inf.b[2] = (uint_8t)b_pos;\r
843     return EXIT_SUCCESS;\r
844 }\r
845 \r
846 #define BFR_LENGTH  (BFR_BLOCKS * AES_BLOCK_SIZE)\r
847 \r
848 AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf,\r
849             int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1])\r
850 {   unsigned char   *ip;\r
851     int             i, blen, b_pos = (int)(ctx->inf.b[2]);\r
852 \r
853 #if defined( USE_VIA_ACE_IF_PRESENT )\r
854     aligned_auto(uint_8t, buf, BFR_LENGTH, 16);\r
855     if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 ))\r
856         return EXIT_FAILURE;\r
857 #else\r
858     uint_8t buf[BFR_LENGTH];\r
859 #endif\r
860 \r
861     if(b_pos)\r
862     {\r
863         memcpy(buf, cbuf, AES_BLOCK_SIZE);\r
864         if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)\r
865                         return EXIT_FAILURE;\r
866 \r
867         while(b_pos < AES_BLOCK_SIZE && len)\r
868         {\r
869             *obuf++ = *ibuf++ ^ buf[b_pos++];\r
870             --len;\r
871         }\r
872 \r
873         if(len)\r
874             ctr_inc(cbuf), b_pos = 0;\r
875     }\r
876 \r
877     while(len)\r
878     {\r
879         blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen;\r
880 \r
881         for(i = 0, ip = buf; i < (blen >> 4); ++i)\r
882         {\r
883             memcpy(ip, cbuf, AES_BLOCK_SIZE);\r
884             ctr_inc(cbuf);\r
885             ip += AES_BLOCK_SIZE;\r
886         }\r
887 \r
888         if(blen & (AES_BLOCK_SIZE - 1))\r
889             memcpy(ip, cbuf, AES_BLOCK_SIZE), i++;\r
890 \r
891 #if defined( USE_VIA_ACE_IF_PRESENT )\r
892         if(ctx->inf.b[1] == 0xff)\r
893         {\r
894             via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192);\r
895             via_ecb_op5((ctx->ks), cwd, buf, buf, i);\r
896         }\r
897         else\r
898 #endif\r
899         if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS)\r
900                         return EXIT_FAILURE;\r
901 \r
902         i = 0; ip = buf;\r
903 # ifdef FAST_BUFFER_OPERATIONS\r
904         if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 ))\r
905             while(i + AES_BLOCK_SIZE <= blen)\r
906             {\r
907                 lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0];\r
908                 lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1];\r
909                 lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2];\r
910                 lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3];\r
911                 i += AES_BLOCK_SIZE;\r
912                 ip += AES_BLOCK_SIZE;\r
913                 ibuf += AES_BLOCK_SIZE;\r
914                 obuf += AES_BLOCK_SIZE;\r
915             }\r
916         else\r
917 #endif\r
918             while(i + AES_BLOCK_SIZE <= blen)\r
919             {\r
920                 obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1];\r
921                 obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3];\r
922                 obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5];\r
923                 obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7];\r
924                 obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9];\r
925                 obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11];\r
926                 obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13];\r
927                 obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15];\r
928                 i += AES_BLOCK_SIZE;\r
929                 ip += AES_BLOCK_SIZE;\r
930                 ibuf += AES_BLOCK_SIZE;\r
931                 obuf += AES_BLOCK_SIZE;\r
932             }\r
933 \r
934         while(i++ < blen)\r
935             *obuf++ = *ibuf++ ^ ip[b_pos++];\r
936     }\r
937 \r
938     ctx->inf.b[2] = (uint_8t)b_pos;\r
939     return EXIT_SUCCESS;\r
940 }\r
941 \r
942 #if defined(__cplusplus)\r
943 }\r
944 #endif\r
945 #endif\r