2 ---------------------------------------------------------------------------
\r
3 Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
\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
10 1. source code distributions include the above copyright notice, this
\r
11 list of conditions and the following disclaimer;
\r
13 2. binary distributions include the above copyright notice, this list
\r
14 of conditions and the following disclaimer in their documentation;
\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
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/20077
\r
28 #ifndef AES_VIA_ACE_H
\r
29 #define AES_VIA_ACE_H
\r
31 #if defined( _MSC_VER )
\r
32 # define INLINE __inline
\r
33 #elif defined( __GNUC__ )
\r
34 # define INLINE static inline
\r
36 # error VIA ACE requires Microsoft or GNU C
\r
39 #define NEH_GENERATE 1
\r
41 #define NEH_HYBRID 3
\r
43 #define MAX_READ_ATTEMPTS 1000
\r
45 /* VIA Nehemiah RNG and ACE Feature Mask Values */
\r
47 #define NEH_CPU_IS_VIA 0x00000001
\r
48 #define NEH_CPU_READ 0x00000010
\r
49 #define NEH_CPU_MASK 0x00000011
\r
51 #define NEH_RNG_PRESENT 0x00000004
\r
52 #define NEH_RNG_ENABLED 0x00000008
\r
53 #define NEH_ACE_PRESENT 0x00000040
\r
54 #define NEH_ACE_ENABLED 0x00000080
\r
55 #define NEH_RNG_FLAGS (NEH_RNG_PRESENT | NEH_RNG_ENABLED)
\r
56 #define NEH_ACE_FLAGS (NEH_ACE_PRESENT | NEH_ACE_ENABLED)
\r
57 #define NEH_FLAGS_MASK (NEH_RNG_FLAGS | NEH_ACE_FLAGS)
\r
59 /* VIA Nehemiah Advanced Cryptography Engine (ACE) Control Word Values */
\r
61 #define NEH_GEN_KEY 0x00000000 /* generate key schedule */
\r
62 #define NEH_LOAD_KEY 0x00000080 /* load schedule from memory */
\r
63 #define NEH_ENCRYPT 0x00000000 /* encryption */
\r
64 #define NEH_DECRYPT 0x00000200 /* decryption */
\r
65 #define NEH_KEY128 0x00000000+0x0a /* 128 bit key */
\r
66 #define NEH_KEY192 0x00000400+0x0c /* 192 bit key */
\r
67 #define NEH_KEY256 0x00000800+0x0e /* 256 bit key */
\r
69 #define NEH_ENC_GEN (NEH_ENCRYPT | NEH_GEN_KEY)
\r
70 #define NEH_DEC_GEN (NEH_DECRYPT | NEH_GEN_KEY)
\r
71 #define NEH_ENC_LOAD (NEH_ENCRYPT | NEH_LOAD_KEY)
\r
72 #define NEH_DEC_LOAD (NEH_DECRYPT | NEH_LOAD_KEY)
\r
74 #define NEH_ENC_GEN_DATA {\
\r
75 NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\
\r
76 NEH_ENC_GEN | NEH_KEY192, 0, 0, 0,\
\r
77 NEH_ENC_GEN | NEH_KEY256, 0, 0, 0 }
\r
79 #define NEH_ENC_LOAD_DATA {\
\r
80 NEH_ENC_LOAD | NEH_KEY128, 0, 0, 0,\
\r
81 NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\
\r
82 NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 }
\r
84 #define NEH_ENC_HYBRID_DATA {\
\r
85 NEH_ENC_GEN | NEH_KEY128, 0, 0, 0,\
\r
86 NEH_ENC_LOAD | NEH_KEY192, 0, 0, 0,\
\r
87 NEH_ENC_LOAD | NEH_KEY256, 0, 0, 0 }
\r
89 #define NEH_DEC_GEN_DATA {\
\r
90 NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\
\r
91 NEH_DEC_GEN | NEH_KEY192, 0, 0, 0,\
\r
92 NEH_DEC_GEN | NEH_KEY256, 0, 0, 0 }
\r
94 #define NEH_DEC_LOAD_DATA {\
\r
95 NEH_DEC_LOAD | NEH_KEY128, 0, 0, 0,\
\r
96 NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\
\r
97 NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 }
\r
99 #define NEH_DEC_HYBRID_DATA {\
\r
100 NEH_DEC_GEN | NEH_KEY128, 0, 0, 0,\
\r
101 NEH_DEC_LOAD | NEH_KEY192, 0, 0, 0,\
\r
102 NEH_DEC_LOAD | NEH_KEY256, 0, 0, 0 }
\r
104 #define neh_enc_gen_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \
\r
105 (x) == 192 ? (NEH_ENC_GEN | NEH_KEY192) : (NEH_ENC_GEN | NEH_KEY256))
\r
107 #define neh_enc_load_key(x) ((x) == 128 ? (NEH_ENC_LOAD | NEH_KEY128) : \
\r
108 (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256))
\r
110 #define neh_enc_hybrid_key(x) ((x) == 128 ? (NEH_ENC_GEN | NEH_KEY128) : \
\r
111 (x) == 192 ? (NEH_ENC_LOAD | NEH_KEY192) : (NEH_ENC_LOAD | NEH_KEY256))
\r
113 #define neh_dec_gen_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \
\r
114 (x) == 192 ? (NEH_DEC_GEN | NEH_KEY192) : (NEH_DEC_GEN | NEH_KEY256))
\r
116 #define neh_dec_load_key(x) ((x) == 128 ? (NEH_DEC_LOAD | NEH_KEY128) : \
\r
117 (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256))
\r
119 #define neh_dec_hybrid_key(x) ((x) == 128 ? (NEH_DEC_GEN | NEH_KEY128) : \
\r
120 (x) == 192 ? (NEH_DEC_LOAD | NEH_KEY192) : (NEH_DEC_LOAD | NEH_KEY256))
\r
122 #if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
\r
123 #define aligned_auto(type, name, no, stride) __declspec(align(stride)) type name[no]
\r
125 #define aligned_auto(type, name, no, stride) \
\r
126 unsigned char _##name[no * sizeof(type) + stride]; \
\r
127 type *name = (type*)(16 * ((((unsigned long)(_##name)) + stride - 1) / stride))
\r
130 #if defined( _MSC_VER ) && ( _MSC_VER > 1200 )
\r
131 #define aligned_array(type, name, no, stride) __declspec(align(stride)) type name[no]
\r
132 #elif defined( __GNUC__ )
\r
133 #define aligned_array(type, name, no, stride) type name[no] __attribute__ ((aligned(stride)))
\r
135 #define aligned_array(type, name, no, stride) type name[no]
\r
138 /* VIA ACE codeword */
\r
140 static unsigned char via_flags = 0;
\r
142 #if defined ( _MSC_VER ) && ( _MSC_VER > 800 )
\r
144 #define NEH_REKEY __asm pushfd __asm popfd
\r
145 #define NEH_AES __asm _emit 0xf3 __asm _emit 0x0f __asm _emit 0xa7
\r
146 #define NEH_ECB NEH_AES __asm _emit 0xc8
\r
147 #define NEH_CBC NEH_AES __asm _emit 0xd0
\r
148 #define NEH_CFB NEH_AES __asm _emit 0xe0
\r
149 #define NEH_OFB NEH_AES __asm _emit 0xe8
\r
150 #define NEH_RNG __asm _emit 0x0f __asm _emit 0xa7 __asm _emit 0xc0
\r
152 INLINE int has_cpuid(void)
\r
155 { pushfd /* save EFLAGS register */
\r
156 mov eax,[esp] /* copy it to eax */
\r
157 mov edx,0x00200000 /* CPUID bit position */
\r
158 xor eax,edx /* toggle the CPUID bit */
\r
159 push eax /* attempt to set EFLAGS to */
\r
160 popfd /* the new value */
\r
161 pushfd /* get the new EFLAGS value */
\r
162 pop eax /* into eax */
\r
163 xor eax,[esp] /* xor with original value */
\r
164 and eax,edx /* has CPUID bit changed? */
\r
165 setne al /* set to 1 if we have been */
\r
166 mov ret_value,al /* able to change it */
\r
167 popfd /* restore original EFLAGS */
\r
169 return (int)ret_value;
\r
172 INLINE int is_via_cpu(void)
\r
175 { xor eax,eax /* use CPUID to get vendor */
\r
176 cpuid /* identity string */
\r
177 xor eax,eax /* is it "CentaurHauls" ? */
\r
178 sub ebx,0x746e6543 /* 'Cent' */
\r
180 sub edx,0x48727561 /* 'aurH' */
\r
182 sub ecx,0x736c7561 /* 'auls' */
\r
184 sete al /* set to 1 if it is VIA ID */
\r
185 mov dl,NEH_CPU_READ /* mark CPU type as read */
\r
186 or dl,al /* & store result in flags */
\r
187 mov [via_flags],dl /* set VIA detected flag */
\r
188 mov ret_value,al /* able to change it */
\r
190 return (int)ret_value;
\r
193 INLINE int read_via_flags(void)
\r
194 { char ret_value = 0;
\r
197 mov eax,0xC0000000 /* Centaur extended CPUID */
\r
199 mov edx,0xc0000001 /* >= 0xc0000001 if support */
\r
200 cmp eax,edx /* for VIA extended feature */
\r
201 jnae no_rng /* flags is available */
\r
202 mov eax,edx /* read Centaur extended */
\r
203 cpuid /* feature flags */
\r
204 mov eax,NEH_FLAGS_MASK /* mask out and save */
\r
205 and eax,edx /* the RNG and ACE flags */
\r
206 or [via_flags],al /* present & enabled flags */
\r
207 mov ret_value,al /* able to change it */
\r
210 return (int)ret_value;
\r
213 INLINE unsigned int via_rng_in(void *buf)
\r
214 { char ret_value = 0x1f;
\r
218 mov edi,buf /* input buffer address */
\r
219 xor edx,edx /* try to fetch 8 bytes */
\r
220 NEH_RNG /* do RNG read operation */
\r
221 and ret_value,al /* count of bytes returned */
\r
224 return (int)ret_value;
\r
227 INLINE void via_ecb_op5(
\r
228 const void *k, const void *c, const void *s, void *d, int l)
\r
241 INLINE void via_cbc_op6(
\r
242 const void *k, const void *c, const void *s, void *d, int l, void *v)
\r
256 INLINE void via_cbc_op7(
\r
257 const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
\r
277 INLINE void via_cfb_op6(
\r
278 const void *k, const void *c, const void *s, void *d, int l, void *v)
\r
292 INLINE void via_cfb_op7(
\r
293 const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
\r
313 INLINE void via_ofb_op6(
\r
314 const void *k, const void *c, const void *s, void *d, int l, void *v)
\r
328 #elif defined( __GNUC__ )
\r
330 #define NEH_REKEY asm("pushfl\n popfl\n\t")
\r
331 #define NEH_ECB asm(".byte 0xf3, 0x0f, 0xa7, 0xc8\n\t")
\r
332 #define NEH_CBC asm(".byte 0xf3, 0x0f, 0xa7, 0xd0\n\t")
\r
333 #define NEH_CFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe0\n\t")
\r
334 #define NEH_OFB asm(".byte 0xf3, 0x0f, 0xa7, 0xe8\n\t")
\r
335 #define NEH_RNG asm(".byte 0x0f, 0xa7, 0xc0\n\t");
\r
337 INLINE int has_cpuid(void)
\r
340 asm("movl 0(%esp),%eax\n\t");
\r
341 asm("xor $0x00200000,%eax\n\t");
\r
342 asm("pushl %eax\n\t");
\r
345 asm("popl %eax\n\t");
\r
346 asm("xorl 0(%esp),%edx\n\t");
\r
347 asm("andl $0x00200000,%eax\n\t");
\r
348 asm("movl %%eax,%0\n\t" : "=m" (val));
\r
350 return val ? 1 : 0;
\r
353 INLINE int is_via_cpu(void)
\r
355 asm("xorl %eax,%eax\n\t");
\r
357 asm("xorl %eax,%eax\n\t");
\r
358 asm("subl $0x746e6543,%ebx\n\t");
\r
359 asm("orl %ebx,%eax\n\t");
\r
360 asm("subl $0x48727561,%edx\n\t");
\r
361 asm("orl %edx,%eax\n\t");
\r
362 asm("subl $0x736c7561,%ecx\n\t");
\r
363 asm("orl %ecx,%eax\n\t");
\r
364 asm("movl %%eax,%0\n\t" : "=m" (val));
\r
365 val = (val ? 0 : 1);
\r
366 via_flags = (val | NEH_CPU_READ);
\r
370 INLINE int read_via_flags(void)
\r
371 { unsigned char val;
\r
372 asm("movl $0xc0000000,%eax\n\t");
\r
374 asm("movl $0xc0000001,%edx\n\t");
\r
375 asm("cmpl %edx,%eax\n\t");
\r
376 asm("setae %al\n\t");
\r
377 asm("movb %%al,%0\n\t" : "=m" (val));
\r
379 asm("movl $0xc0000001,%eax\n\t");
\r
381 asm("movb %%dl,%0\n\t" : "=m" (val));
\r
382 val &= NEH_FLAGS_MASK;
\r
387 INLINE int via_rng_in(void *buf)
\r
389 asm("pushl %edi\n\t");
\r
390 asm("movl %0,%%edi\n\t" : : "m" (buf));
\r
391 asm("xorl %edx,%edx\n\t");
\r
393 asm("andl $0x0000001f,%eax\n\t");
\r
394 asm("movl %%eax,%0\n\t" : "=m" (val));
\r
395 asm("popl %edi\n\t");
\r
399 INLINE volatile void via_ecb_op5(
\r
400 const void *k, const void *c, const void *s, void *d, int l)
\r
403 asm("movl %0, %%ebx\n\t" : : "m" (k));
\r
404 asm("movl %0, %%edx\n\t" : : "m" (c));
\r
405 asm("movl %0, %%esi\n\t" : : "m" (s));
\r
406 asm("movl %0, %%edi\n\t" : : "m" (d));
\r
407 asm("movl %0, %%ecx\n\t" : : "m" (l));
\r
411 INLINE volatile void via_cbc_op6(
\r
412 const void *k, const void *c, const void *s, void *d, int l, void *v)
\r
415 asm("movl %0, %%ebx\n\t" : : "m" (k));
\r
416 asm("movl %0, %%edx\n\t" : : "m" (c));
\r
417 asm("movl %0, %%esi\n\t" : : "m" (s));
\r
418 asm("movl %0, %%edi\n\t" : : "m" (d));
\r
419 asm("movl %0, %%ecx\n\t" : : "m" (l));
\r
420 asm("movl %0, %%eax\n\t" : : "m" (v));
\r
424 INLINE volatile void via_cbc_op7(
\r
425 const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
\r
428 asm("movl %0, %%ebx\n\t" : : "m" (k));
\r
429 asm("movl %0, %%edx\n\t" : : "m" (c));
\r
430 asm("movl %0, %%esi\n\t" : : "m" (s));
\r
431 asm("movl %0, %%edi\n\t" : : "m" (d));
\r
432 asm("movl %0, %%ecx\n\t" : : "m" (l));
\r
433 asm("movl %0, %%eax\n\t" : : "m" (v));
\r
435 asm("movl %eax,%esi\n\t");
\r
436 asm("movl %0, %%edi\n\t" : : "m" (w));
\r
437 asm("movsl; movsl; movsl; movsl\n\t");
\r
440 INLINE volatile void via_cfb_op6(
\r
441 const void *k, const void *c, const void *s, void *d, int l, void *v)
\r
444 asm("movl %0, %%ebx\n\t" : : "m" (k));
\r
445 asm("movl %0, %%edx\n\t" : : "m" (c));
\r
446 asm("movl %0, %%esi\n\t" : : "m" (s));
\r
447 asm("movl %0, %%edi\n\t" : : "m" (d));
\r
448 asm("movl %0, %%ecx\n\t" : : "m" (l));
\r
449 asm("movl %0, %%eax\n\t" : : "m" (v));
\r
453 INLINE volatile void via_cfb_op7(
\r
454 const void *k, const void *c, const void *s, void *d, int l, void *v, void *w)
\r
457 asm("movl %0, %%ebx\n\t" : : "m" (k));
\r
458 asm("movl %0, %%edx\n\t" : : "m" (c));
\r
459 asm("movl %0, %%esi\n\t" : : "m" (s));
\r
460 asm("movl %0, %%edi\n\t" : : "m" (d));
\r
461 asm("movl %0, %%ecx\n\t" : : "m" (l));
\r
462 asm("movl %0, %%eax\n\t" : : "m" (v));
\r
464 asm("movl %eax,%esi\n\t");
\r
465 asm("movl %0, %%edi\n\t" : : "m" (w));
\r
466 asm("movsl; movsl; movsl; movsl\n\t");
\r
469 INLINE volatile void via_ofb_op6(
\r
470 const void *k, const void *c, const void *s, void *d, int l, void *v)
\r
473 asm("movl %0, %%ebx\n\t" : : "m" (k));
\r
474 asm("movl %0, %%edx\n\t" : : "m" (c));
\r
475 asm("movl %0, %%esi\n\t" : : "m" (s));
\r
476 asm("movl %0, %%edi\n\t" : : "m" (d));
\r
477 asm("movl %0, %%ecx\n\t" : : "m" (l));
\r
478 asm("movl %0, %%eax\n\t" : : "m" (v));
\r
483 #error VIA ACE is not available with this compiler
\r
486 INLINE int via_ace_test(void)
\r
488 return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_ACE_FLAGS) == NEH_ACE_FLAGS);
\r
491 #define VIA_ACE_AVAILABLE (((via_flags & NEH_ACE_FLAGS) == NEH_ACE_FLAGS) \
\r
492 || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_ace_test())
\r
494 INLINE int via_rng_test(void)
\r
496 return has_cpuid() && is_via_cpu() && ((read_via_flags() & NEH_RNG_FLAGS) == NEH_RNG_FLAGS);
\r
499 #define VIA_RNG_AVAILABLE (((via_flags & NEH_RNG_FLAGS) == NEH_RNG_FLAGS) \
\r
500 || (via_flags & NEH_CPU_READ) && (via_flags & NEH_CPU_IS_VIA) || via_rng_test())
\r
502 INLINE int read_via_rng(void *buf, int count)
\r
503 { int nbr, max_reads, lcnt = count;
\r
504 unsigned char *p, *q;
\r
505 aligned_auto(unsigned char, bp, 64, 16);
\r
507 if(!VIA_RNG_AVAILABLE)
\r
512 max_reads = MAX_READ_ATTEMPTS;
\r
514 nbr = via_rng_in(bp);
\r
516 (nbr == 0 && --max_reads);
\r
519 p = (unsigned char*)buf; q = bp;
\r
524 (lcnt && max_reads);
\r
526 return count - lcnt;
\r