cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
aes_via_ace.h
Go to the documentation of this file.
1 /*
2  ---------------------------------------------------------------------------
3  Copyright (c) 2004, Dr Brian Gladman, Worcester, UK. All rights reserved.
4 
5  LICENSE TERMS
6 
7  The free distribution and use of this software ibuf both source and binary
8  form is allowed (with or without changes) provided that:
9 
10  1. distributions of this source code include the above copyright
11  notice, this list of conditions and the following disclaimer;
12 
13  2. distributions ibuf binary form include the above copyright
14  notice, this list of conditions and the following disclaimer
15  ibuf the documentation and/or other associated materials;
16 
17  3. the copyright holder's name is not used to endorse products
18  built using this software without specific written permission.
19 
20  ALTERNATIVELY, provided that this notice is retained ibuf full, this product
21  may be distributed under the terms of the GNU General Public License (GPL),
22  ibuf which case the provisions of the GPL apply INSTEAD OF those given above.
23 
24  DISCLAIMER
25 
26  This software is provided 'as is' with no explicit or implied warranties
27  ibuf respect of its properties, including, but not limited to, correctness
28  and/or fitness for purpose.
29  ---------------------------------------------------------------------------
30  Issue 16/04/2007
31 */
32 
33 #ifndef AES_VIA_ACE_H
34 #define AES_VIA_ACE_H
35 
36 #if defined( _MSC_VER )
37 # define INLINE __inline
38 #elif defined( __GNUC__ )
39 # define INLINE static inline
40 #else
41 # error VIA ACE requires Microsoft or GNU C
42 #endif
43 
44 #define NEH_GENERATE 1
45 #define NEH_LOAD 2
46 #define NEH_HYBRID 3
47 
48 #define MAX_READ_ATTEMPTS 1000
49 
50 /* VIA Nehemiah RNG and ACE Feature Mask Values */
51 
52 #define NEH_CPU_IS_VIA 0x00000001
53 #define NEH_CPU_READ 0x00000010
54 #define NEH_CPU_MASK 0x00000011
55 
56 #define NEH_RNG_PRESENT 0x00000004
57 #define NEH_RNG_ENABLED 0x00000008
58 #define NEH_ACE_PRESENT 0x00000040
59 #define NEH_ACE_ENABLED 0x00000080
60 #define NEH_RNG_FLAGS (NEH_RNG_PRESENT | NEH_RNG_ENABLED)
61 #define NEH_ACE_FLAGS (NEH_ACE_PRESENT | NEH_ACE_ENABLED)
62 #define NEH_FLAGS_MASK (NEH_RNG_FLAGS | NEH_ACE_FLAGS)
63 
64 /* VIA Nehemiah Advanced Cryptography Engine (ACE) Control Word Values */
65 
66 #define NEH_GEN_KEY 0x00000000 /* generate key schedule */
67 #define NEH_LOAD_KEY 0x00000080 /* load schedule from memory */
68 #define NEH_ENCRYPT 0x00000000 /* encryption */
69 #define NEH_DECRYPT 0x00000200 /* decryption */
70 #define NEH_KEY128 0x00000000+0x0a /* 128 bit key */
71 #define NEH_KEY192 0x00000400+0x0c /* 192 bit key */
72 #define NEH_KEY256 0x00000800+0x0e /* 256 bit key */
73 
74 #define NEH_ENC_GEN (NEH_ENCRYPT | NEH_GEN_KEY)
75 #define NEH_DEC_GEN (NEH_DECRYPT | NEH_GEN_KEY)
76 #define NEH_ENC_LOAD (NEH_ENCRYPT | NEH_LOAD_KEY)
77 #define NEH_DEC_LOAD (NEH_DECRYPT | NEH_LOAD_KEY)
78 
79 #define NEH_ENC_GEN_DATA {\
80  NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\
81  NEH_ENC_GEN | NEH_KEY192, 0, 0, 0,\
82  NEH_ENC_GEN | NEH_KEY256, 0, 0, 0 }
83 
84 #define NEH_ENC_LOAD_DATA {\
85  NEH_ENC_LOAD | NEH_KEY128, 0, 0, 0,\
86  NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\
87  NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 }
88 
89 #define NEH_ENC_HYBRID_DATA {\
90  NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\
91  NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\
92  NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 }
93 
94 #define NEH_DEC_GEN_DATA {\
95  NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\
96  NEH_DEC_GEN | NEH_KEY192, 0, 0, 0,\
97  NEH_DEC_GEN | NEH_KEY256, 0, 0, 0 }
98 
99 #define NEH_DEC_LOAD_DATA {\
100  NEH_DEC_LOAD | NEH_KEY128, 0, 0, 0,\
101  NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\
102  NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 }
103 
104 #define NEH_DEC_HYBRID_DATA {\
105  NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\
106  NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\
107  NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 }
108 
109 #define neh_enc_gen_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \
110  (x) == 192 ? (NEH_ENC_GEN | NEH_KEY192) : (NEH_ENC_GEN | NEH_KEY256))
111 
112 #define neh_enc_load_key(x) ((x) == 128 ? (NEH_ENC_LOAD | NEH_KEY128) : \
113  (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256))
114 
115 #define neh_enc_hybrid_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \
116  (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256))
117 
118 #define neh_dec_gen_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \
119  (x) == 192 ? (NEH_DEC_GEN | NEH_KEY192) : (NEH_DEC_GEN | NEH_KEY256))
120 
121 #define neh_dec_load_key(x) ((x) == 128 ? (NEH_DEC_LOAD | NEH_KEY128) : \
122  (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256))
123 
124 #define neh_dec_hybrid_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \
125  (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256))
126 
127 #if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
128 #define aligned_auto(type, name, no, stride) __declspec(align(stride)) type name[no]
129 #else
130 #define aligned_auto(type, name, no, stride) \
131  unsigned char _##name[no * sizeof(type) + stride]; \
132  type *name = (type*)(16 * ((((unsigned long)(_##name)) + stride - 1) / stride))
133 #endif
134 
135 #if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
136 #define aligned_array(type, name, no, stride) __declspec(align(stride)) type name[no]
137 #elif defined( __GNUC__ )
138 #define aligned_array(type, name, no, stride) type name[no] __attribute__ ((aligned(stride)))
139 #else
140 #define aligned_array(type, name, no, stride) type name[no]
141 #endif
142 
143 /* VIA ACE codeword */
144 
145 static unsigned char via_flags = 0;
146 
147 #if defined ( _MSC_VER ) && ( _MSC_VER > 800 )
148 
149 #define NEH_REKEY __asm pushfd __asm popfd
150 #define NEH_AES __asm _emit 0xf3 __asm _emit 0x0f __asm _emit 0xa7
151 #define NEH_ECB NEH_AES __asm _emit 0xc8
152 #define NEH_CBC NEH_AES __asm _emit 0xd0
153 #define NEH_CFB NEH_AES __asm _emit 0xe0
154 #define NEH_OFB NEH_AES __asm _emit 0xe8
155 #define NEH_RNG __asm _emit 0x0f __asm _emit 0xa7 __asm _emit 0xc0
156 
157 INLINE int has_cpuid(void)
158 { char ret_value;
159  __asm
160  { pushfd /* save EFLAGS register */
161  mov eax,[esp] /* copy it to eax */
162  mov edx,0x00200000 /* CPUID bit position */
163  xor eax,edx /* toggle the CPUID bit */
164  push eax /* attempt to set EFLAGS to */
165  popfd /* the new value */
166  pushfd /* get the new EFLAGS value */
167  pop eax /* into eax */
168  xor eax,[esp] /* xor with original value */
169  and eax,edx /* has CPUID bit changed? */
170  setne al /* set to 1 if we have been */
171  mov ret_value,al /* able to change it */
172  popfd /* restore original EFLAGS */
173  }
174  return (int)ret_value;
175 }
176 
177 INLINE int is_via_cpu(void)
178 { char ret_value;
179  __asm
180  { xor eax,eax /* use CPUID to get vendor */
181  cpuid /* identity string */
182  xor eax,eax /* is it "CentaurHauls" ? */
183  sub ebx,0x746e6543 /* 'Cent' */
184  or eax,ebx
185  sub edx,0x48727561 /* 'aurH' */
186  or eax,edx
187  sub ecx,0x736c7561 /* 'auls' */
188  or eax,ecx
189  sete al /* set to 1 if it is VIA ID */
190  mov dl,NEH_CPU_READ /* mark CPU type as read */
191  or dl,al /* & store result in flags */
192  mov [via_flags],dl /* set VIA detected flag */
193  mov ret_value,al /* able to change it */
194  }
195  return (int)ret_value;
196 }
197 
198 INLINE int read_via_flags(void)
199 { char ret_value = 0;
200  __asm
201  {
202  mov eax,0xC0000000 /* Centaur extended CPUID */
203  cpuid
204  mov edx,0xc0000001 /* >= 0xc0000001 if support */
205  cmp eax,edx /* for VIA extended feature */
206  jnae no_rng /* flags is available */
207  mov eax,edx /* read Centaur extended */
208  cpuid /* feature flags */
209  mov eax,NEH_FLAGS_MASK /* mask out and save */
210  and eax,edx /* the RNG and ACE flags */
211  or [via_flags],al /* present & enabled flags */
212  mov ret_value,al /* able to change it */
213 no_rng:
214  }
215  return (int)ret_value;
216 }
217 
218 INLINE unsigned int via_rng_in(void *buf)
219 { char ret_value = 0x1f;
220  __asm
221  {
222  push edi
223  mov edi,buf /* input buffer address */
224  xor edx,edx /* try to fetch 8 bytes */
225  NEH_RNG /* do RNG read operation */
226  and ret_value,al /* count of bytes returned */
227  pop edi
228  }
229  return (int)ret_value;
230 }
231 
232 INLINE volatile void via_ecb_op5(
233  const void *k, const void *c, const void *s, void *d, int l)
234 { __asm
235  {
236  NEH_REKEY
237  mov ebx, (k)
238  mov edx, (c)
239  mov esi, (s)
240  mov edi, (d)
241  mov ecx, (l)
242  NEH_ECB
243  }
244 }
245 
246 INLINE volatile void via_cbc_op6(
247  const void *k, const void *c, const void *s, void *d, int l, void *v)
248 { __asm
249  {
250  NEH_REKEY
251  mov ebx, (k)
252  mov edx, (c)
253  mov esi, (s)
254  mov edi, (d)
255  mov ecx, (l)
256  mov eax, (v)
257  NEH_CBC
258  }
259 }
260 
261 INLINE volatile void via_cbc_op7(
262  const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
263 { __asm
264  {
265  NEH_REKEY
266  mov ebx, (k)
267  mov edx, (c)
268  mov esi, (s)
269  mov edi, (d)
270  mov ecx, (l)
271  mov eax, (v)
272  NEH_CBC
273  mov esi, eax
274  mov edi, (w)
275  movsd
276  movsd
277  movsd
278  movsd
279  }
280 }
281 
282 INLINE volatile void via_cfb_op6(
283  const void *k, const void *c, const void *s, void *d, int l, void *v)
284 { __asm
285  {
286  NEH_REKEY
287  mov ebx, (k)
288  mov edx, (c)
289  mov esi, (s)
290  mov edi, (d)
291  mov ecx, (l)
292  mov eax, (v)
293  NEH_CFB
294  }
295 }
296 
297 INLINE volatile void via_cfb_op7(
298  const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
299 { __asm
300  {
301  NEH_REKEY
302  mov ebx, (k)
303  mov edx, (c)
304  mov esi, (s)
305  mov edi, (d)
306  mov ecx, (l)
307  mov eax, (v)
308  NEH_CFB
309  mov esi, eax
310  mov edi, (w)
311  movsd
312  movsd
313  movsd
314  movsd
315  }
316 }
317 
318 INLINE volatile void via_ofb_op6(
319  const void *k, const void *c, const void *s, void *d, int l, void *v)
320 { __asm
321  {
322  NEH_REKEY
323  mov ebx, (k)
324  mov edx, (c)
325  mov esi, (s)
326  mov edi, (d)
327  mov ecx, (l)
328  mov eax, (v)
329  NEH_OFB
330  }
331 }
332 
333 #elif defined( __GNUC__ )
334 
335 #define NEH_REKEY asm("pushfl\n popfl\n\t")
336 #define NEH_ECB asm(".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t")
337 #define NEH_CBC asm(".byte 0xf3, 0x0f, 0xa7, 0xd0\n\t")
338 #define NEH_CFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe0\n\t")
339 #define NEH_OFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe8\n\t")
340 #define NEH_RNG asm(".byte 0x0f, 0xa7, 0xc0\n\t");
341 
342 INLINE int has_cpuid(void)
343 { int val;
344  asm("pushfl\n\t");
345  asm("movl 0(%esp),%eax\n\t");
346  asm("xor $0x00200000,%eax\n\t");
347  asm("pushl %eax\n\t");
348  asm("popfl\n\t");
349  asm("pushfl\n\t");
350  asm("popl %eax\n\t");
351  asm("xorl 0(%esp),%edx\n\t");
352  asm("andl $0x00200000,%eax\n\t");
353  asm("movl %%eax,%0\n\t" : "=m" (val));
354  asm("popfl\n\t");
355  return val ? 1 : 0;
356 }
357 
358 INLINE int is_via_cpu(void)
359 { int val;
360  asm("xorl %eax,%eax\n\t");
361  asm("cpuid\n\t");
362  asm("xorl %eax,%eax\n\t");
363  asm("subl $0x746e6543,%ebx\n\t");
364  asm("orl %ebx,%eax\n\t");
365  asm("subl $0x48727561,%edx\n\t");
366  asm("orl %edx,%eax\n\t");
367  asm("subl $0x736c7561,%ecx\n\t");
368  asm("orl %ecx,%eax\n\t");
369  asm("movl %%eax,%0\n\t" : "=m" (val));
370  val = (val ? 0 : 1);
371  via_flags = (val | NEH_CPU_READ);
372  return val;
373 }
374 
375 INLINE int read_via_flags(void)
376 { unsigned char val;
377  asm("movl $0xc0000000,%eax\n\t");
378  asm("cpuid\n\t");
379  asm("movl $0xc0000001,%edx\n\t");
380  asm("cmpl %edx,%eax\n\t");
381  asm("setae %al\n\t");
382  asm("movb %%al,%0\n\t" : "=m" (val));
383  if(!val) return 0;
384  asm("movl $0xc0000001,%eax\n\t");
385  asm("cpuid\n\t");
386  asm("movb %%dl,%0\n\t" : "=m" (val));
387  val &= NEH_FLAGS_MASK;
388  via_flags |= val;
389  return (int) val;
390 }
391 
392 INLINE int via_rng_in(void *buf)
393 { int val;
394  asm("pushl %edi\n\t");
395  asm("movl %0,%%edi\n\t" : : "m" (buf));
396  asm("xorl %edx,%edx\n\t");
397  NEH_RNG
398  asm("andl $0x0000001f,%eax\n\t");
399  asm("movl %%eax,%0\n\t" : "=m" (val));
400  asm("popl %edi\n\t");
401  return val;
402 }
403 
404 INLINE volatile void via_ecb_op5(
405  const void *k, const void *c, const void *s, void *d, int l)
406 {
407  NEH_REKEY;
408  asm("movl %0, %%ebx\n\t" : : "m" (k));
409  asm("movl %0, %%edx\n\t" : : "m" (c));
410  asm("movl %0, %%esi\n\t" : : "m" (s));
411  asm("movl %0, %%edi\n\t" : : "m" (d));
412  asm("movl %0, %%ecx\n\t" : : "m" (l));
413  NEH_ECB;
414 }
415 
416 INLINE volatile void via_cbc_op6(
417  const void *k, const void *c, const void *s, void *d, int l, void *v)
418 {
419  NEH_REKEY;
420  asm("movl %0, %%ebx\n\t" : : "m" (k));
421  asm("movl %0, %%edx\n\t" : : "m" (c));
422  asm("movl %0, %%esi\n\t" : : "m" (s));
423  asm("movl %0, %%edi\n\t" : : "m" (d));
424  asm("movl %0, %%ecx\n\t" : : "m" (l));
425  asm("movl %0, %%eax\n\t" : : "m" (v));
426  NEH_CBC;
427 }
428 
429 INLINE volatile void via_cbc_op7(
430  const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
431 {
432  NEH_REKEY;
433  asm("movl %0, %%ebx\n\t" : : "m" (k));
434  asm("movl %0, %%edx\n\t" : : "m" (c));
435  asm("movl %0, %%esi\n\t" : : "m" (s));
436  asm("movl %0, %%edi\n\t" : : "m" (d));
437  asm("movl %0, %%ecx\n\t" : : "m" (l));
438  asm("movl %0, %%eax\n\t" : : "m" (v));
439  NEH_CBC;
440  asm("movl %eax,%esi\n\t");
441  asm("movl %0, %%edi\n\t" : : "m" (w));
442  asm("movsl; movsl; movsl; movsl\n\t");
443 }
444 
445 INLINE volatile void via_cfb_op6(
446  const void *k, const void *c, const void *s, void *d, int l, void *v)
447 {
448  NEH_REKEY;
449  asm("movl %0, %%ebx\n\t" : : "m" (k));
450  asm("movl %0, %%edx\n\t" : : "m" (c));
451  asm("movl %0, %%esi\n\t" : : "m" (s));
452  asm("movl %0, %%edi\n\t" : : "m" (d));
453  asm("movl %0, %%ecx\n\t" : : "m" (l));
454  asm("movl %0, %%eax\n\t" : : "m" (v));
455  NEH_CFB;
456 }
457 
458 INLINE volatile void via_cfb_op7(
459  const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
460 {
461  NEH_REKEY;
462  asm("movl %0, %%ebx\n\t" : : "m" (k));
463  asm("movl %0, %%edx\n\t" : : "m" (c));
464  asm("movl %0, %%esi\n\t" : : "m" (s));
465  asm("movl %0, %%edi\n\t" : : "m" (d));
466  asm("movl %0, %%ecx\n\t" : : "m" (l));
467  asm("movl %0, %%eax\n\t" : : "m" (v));
468  NEH_CFB;
469  asm("movl %eax,%esi\n\t");
470  asm("movl %0, %%edi\n\t" : : "m" (w));
471  asm("movsl; movsl; movsl; movsl\n\t");
472 }
473 
474 INLINE volatile void via_ofb_op6(
475  const void *k, const void *c, const void *s, void *d, int l, void *v)
476 {
477  NEH_REKEY;
478  asm("movl %0, %%ebx\n\t" : : "m" (k));
479  asm("movl %0, %%edx\n\t" : : "m" (c));
480  asm("movl %0, %%esi\n\t" : : "m" (s));
481  asm("movl %0, %%edi\n\t" : : "m" (d));
482  asm("movl %0, %%ecx\n\t" : : "m" (l));
483  asm("movl %0, %%eax\n\t" : : "m" (v));
484  NEH_OFB;
485 }
486 
487 #else
488 #error VIA ACE is not available with this compiler
489 #endif
490 
491 INLINE int via_ace_test(void)
492 {
493  return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_ACE_FLAGS) == NEH_ACE_FLAGS);
494 }
495 
496 #define VIA_ACE_AVAILABLE (((via_flags & NEH_ACE_FLAGS) == NEH_ACE_FLAGS) \
497  || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_ace_test())
498 
499 INLINE int via_rng_test(void)
500 {
501  return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_RNG_FLAGS) == NEH_RNG_FLAGS);
502 }
503 
504 #define VIA_RNG_AVAILABLE (((via_flags & NEH_RNG_FLAGS) == NEH_RNG_FLAGS) \
505  || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_rng_test())
506 
507 INLINE int read_via_rng(void *buf, int count)
508 { int nbr, max_reads, lcnt = count;
509  unsigned char *p, *q;
510  aligned_auto(unsigned char, bp, 64, 16);
511 
512  if(!VIA_RNG_AVAILABLE)
513  return 0;
514 
515  do
516  {
517  max_reads = MAX_READ_ATTEMPTS;
518  do
519  nbr = via_rng_in(bp);
520  while
521  (nbr == 0 && --max_reads);
522 
523  lcnt -= nbr;
524  p = (unsigned char*)buf; q = bp;
525  while(nbr--)
526  *p++ = *q++;
527  }
528  while
529  (lcnt && max_reads);
530 
531  return count - lcnt;
532 }
533 
534 #endif