xref: /minix3/crypto/external/bsd/openssl/dist/engines/e_padlock.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*-
2ebfedea0SLionel Sambuc  * Support for VIA PadLock Advanced Cryptography Engine (ACE)
3ebfedea0SLionel Sambuc  * Written by Michal Ludvig <michal@logix.cz>
4ebfedea0SLionel Sambuc  *            http://www.logix.cz/michal
5ebfedea0SLionel Sambuc  *
6ebfedea0SLionel Sambuc  * Big thanks to Andy Polyakov for a help with optimization,
7ebfedea0SLionel Sambuc  * assembler fixes, port to MS Windows and a lot of other
8ebfedea0SLionel Sambuc  * valuable work on this engine!
9ebfedea0SLionel Sambuc  */
10ebfedea0SLionel Sambuc 
11ebfedea0SLionel Sambuc /* ====================================================================
12ebfedea0SLionel Sambuc  * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
13ebfedea0SLionel Sambuc  *
14ebfedea0SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
15ebfedea0SLionel Sambuc  * modification, are permitted provided that the following conditions
16ebfedea0SLionel Sambuc  * are met:
17ebfedea0SLionel Sambuc  *
18ebfedea0SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
19ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
20ebfedea0SLionel Sambuc  *
21ebfedea0SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
22ebfedea0SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in
23ebfedea0SLionel Sambuc  *    the documentation and/or other materials provided with the
24ebfedea0SLionel Sambuc  *    distribution.
25ebfedea0SLionel Sambuc  *
26ebfedea0SLionel Sambuc  * 3. All advertising materials mentioning features or use of this
27ebfedea0SLionel Sambuc  *    software must display the following acknowledgment:
28ebfedea0SLionel Sambuc  *    "This product includes software developed by the OpenSSL Project
29ebfedea0SLionel Sambuc  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
30ebfedea0SLionel Sambuc  *
31ebfedea0SLionel Sambuc  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
32ebfedea0SLionel Sambuc  *    endorse or promote products derived from this software without
33ebfedea0SLionel Sambuc  *    prior written permission. For written permission, please contact
34ebfedea0SLionel Sambuc  *    licensing@OpenSSL.org.
35ebfedea0SLionel Sambuc  *
36ebfedea0SLionel Sambuc  * 5. Products derived from this software may not be called "OpenSSL"
37ebfedea0SLionel Sambuc  *    nor may "OpenSSL" appear in their names without prior written
38ebfedea0SLionel Sambuc  *    permission of the OpenSSL Project.
39ebfedea0SLionel Sambuc  *
40ebfedea0SLionel Sambuc  * 6. Redistributions of any form whatsoever must retain the following
41ebfedea0SLionel Sambuc  *    acknowledgment:
42ebfedea0SLionel Sambuc  *    "This product includes software developed by the OpenSSL Project
43ebfedea0SLionel Sambuc  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
44ebfedea0SLionel Sambuc  *
45ebfedea0SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
46ebfedea0SLionel Sambuc  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47ebfedea0SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
48ebfedea0SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
49ebfedea0SLionel Sambuc  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50ebfedea0SLionel Sambuc  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
51ebfedea0SLionel Sambuc  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52ebfedea0SLionel Sambuc  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53ebfedea0SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
54ebfedea0SLionel Sambuc  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55ebfedea0SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
56ebfedea0SLionel Sambuc  * OF THE POSSIBILITY OF SUCH DAMAGE.
57ebfedea0SLionel Sambuc  * ====================================================================
58ebfedea0SLionel Sambuc  *
59ebfedea0SLionel Sambuc  * This product includes cryptographic software written by Eric Young
60ebfedea0SLionel Sambuc  * (eay@cryptsoft.com).  This product includes software written by Tim
61ebfedea0SLionel Sambuc  * Hudson (tjh@cryptsoft.com).
62ebfedea0SLionel Sambuc  *
63ebfedea0SLionel Sambuc  */
64ebfedea0SLionel Sambuc 
65ebfedea0SLionel Sambuc #include <stdio.h>
66ebfedea0SLionel Sambuc #include <string.h>
67ebfedea0SLionel Sambuc 
68ebfedea0SLionel Sambuc #include <openssl/opensslconf.h>
69ebfedea0SLionel Sambuc #include <openssl/crypto.h>
70ebfedea0SLionel Sambuc #include <openssl/dso.h>
71ebfedea0SLionel Sambuc #include <openssl/engine.h>
72ebfedea0SLionel Sambuc #include <openssl/evp.h>
73ebfedea0SLionel Sambuc #ifndef OPENSSL_NO_AES
74ebfedea0SLionel Sambuc # include <openssl/aes.h>
75ebfedea0SLionel Sambuc #endif
76ebfedea0SLionel Sambuc #include <openssl/rand.h>
77ebfedea0SLionel Sambuc #include <openssl/err.h>
78ebfedea0SLionel Sambuc 
79ebfedea0SLionel Sambuc #ifndef OPENSSL_NO_HW
80ebfedea0SLionel Sambuc # ifndef OPENSSL_NO_HW_PADLOCK
81ebfedea0SLionel Sambuc 
82ebfedea0SLionel Sambuc /* Attempt to have a single source for both 0.9.7 and 0.9.8 :-) */
83ebfedea0SLionel Sambuc #  if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
84ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_DYNAMIC_ENGINE
85ebfedea0SLionel Sambuc #    define DYNAMIC_ENGINE
86ebfedea0SLionel Sambuc #   endif
87ebfedea0SLionel Sambuc #  elif (OPENSSL_VERSION_NUMBER >= 0x00907000L)
88ebfedea0SLionel Sambuc #   ifdef ENGINE_DYNAMIC_SUPPORT
89ebfedea0SLionel Sambuc #    define DYNAMIC_ENGINE
90ebfedea0SLionel Sambuc #   endif
91ebfedea0SLionel Sambuc #  else
92ebfedea0SLionel Sambuc #   error "Only OpenSSL >= 0.9.7 is supported"
93ebfedea0SLionel Sambuc #  endif
94ebfedea0SLionel Sambuc 
95*0a6a1f1dSLionel Sambuc /*
96*0a6a1f1dSLionel Sambuc  * VIA PadLock AES is available *ONLY* on some x86 CPUs. Not only that it
97*0a6a1f1dSLionel Sambuc  * doesn't exist elsewhere, but it even can't be compiled on other platforms!
98*0a6a1f1dSLionel Sambuc  *
99*0a6a1f1dSLionel Sambuc  * In addition, because of the heavy use of inline assembler, compiler choice
100*0a6a1f1dSLionel Sambuc  * is limited to GCC and Microsoft C.
101*0a6a1f1dSLionel Sambuc  */
102ebfedea0SLionel Sambuc #  undef COMPILE_HW_PADLOCK
103ebfedea0SLionel Sambuc #  if !defined(I386_ONLY) && !defined(OPENSSL_NO_INLINE_ASM)
104ebfedea0SLionel Sambuc #   if (defined(__GNUC__) && (defined(__i386__) || defined(__i386))) || \
105ebfedea0SLionel Sambuc      (defined(_MSC_VER) && defined(_M_IX86))
106ebfedea0SLionel Sambuc #    define COMPILE_HW_PADLOCK
107ebfedea0SLionel Sambuc #   endif
108ebfedea0SLionel Sambuc #  endif
109ebfedea0SLionel Sambuc 
110ebfedea0SLionel Sambuc #  ifdef OPENSSL_NO_DYNAMIC_ENGINE
111ebfedea0SLionel Sambuc #   ifdef COMPILE_HW_PADLOCK
112ebfedea0SLionel Sambuc static ENGINE *ENGINE_padlock(void);
113ebfedea0SLionel Sambuc #   endif
114ebfedea0SLionel Sambuc 
ENGINE_load_padlock(void)115ebfedea0SLionel Sambuc void ENGINE_load_padlock(void)
116ebfedea0SLionel Sambuc {
117ebfedea0SLionel Sambuc /* On non-x86 CPUs it just returns. */
118ebfedea0SLionel Sambuc #   ifdef COMPILE_HW_PADLOCK
119ebfedea0SLionel Sambuc     ENGINE *toadd = ENGINE_padlock();
120*0a6a1f1dSLionel Sambuc     if (!toadd)
121*0a6a1f1dSLionel Sambuc         return;
122ebfedea0SLionel Sambuc     ENGINE_add(toadd);
123ebfedea0SLionel Sambuc     ENGINE_free(toadd);
124ebfedea0SLionel Sambuc     ERR_clear_error();
125ebfedea0SLionel Sambuc #   endif
126ebfedea0SLionel Sambuc }
127ebfedea0SLionel Sambuc 
128ebfedea0SLionel Sambuc #  endif
129ebfedea0SLionel Sambuc 
130ebfedea0SLionel Sambuc #  ifdef COMPILE_HW_PADLOCK
131*0a6a1f1dSLionel Sambuc /*
132*0a6a1f1dSLionel Sambuc  * We do these includes here to avoid header problems on platforms that do
133*0a6a1f1dSLionel Sambuc  * not have the VIA padlock anyway...
134*0a6a1f1dSLionel Sambuc  */
135ebfedea0SLionel Sambuc #   include <stdlib.h>
136ebfedea0SLionel Sambuc #   ifdef _WIN32
137ebfedea0SLionel Sambuc #    include <malloc.h>
138ebfedea0SLionel Sambuc #    ifndef alloca
139ebfedea0SLionel Sambuc #     define alloca _alloca
140ebfedea0SLionel Sambuc #    endif
141ebfedea0SLionel Sambuc #   elif defined(__GNUC__)
142ebfedea0SLionel Sambuc #    ifndef alloca
143ebfedea0SLionel Sambuc #     define alloca(s) __builtin_alloca(s)
144ebfedea0SLionel Sambuc #    endif
145ebfedea0SLionel Sambuc #   endif
146ebfedea0SLionel Sambuc 
147ebfedea0SLionel Sambuc /* Function for ENGINE detection and control */
148ebfedea0SLionel Sambuc static int padlock_available(void);
149ebfedea0SLionel Sambuc static int padlock_init(ENGINE *e);
150ebfedea0SLionel Sambuc 
151ebfedea0SLionel Sambuc /* RNG Stuff */
152ebfedea0SLionel Sambuc static RAND_METHOD padlock_rand;
153ebfedea0SLionel Sambuc 
154ebfedea0SLionel Sambuc /* Cipher Stuff */
155ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_AES
156*0a6a1f1dSLionel Sambuc static int padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
157*0a6a1f1dSLionel Sambuc                            const int **nids, int nid);
158ebfedea0SLionel Sambuc #   endif
159ebfedea0SLionel Sambuc 
160ebfedea0SLionel Sambuc /* Engine names */
161ebfedea0SLionel Sambuc static const char *padlock_id = "padlock";
162ebfedea0SLionel Sambuc static char padlock_name[100];
163ebfedea0SLionel Sambuc 
164ebfedea0SLionel Sambuc /* Available features */
165ebfedea0SLionel Sambuc static int padlock_use_ace = 0; /* Advanced Cryptography Engine */
166ebfedea0SLionel Sambuc static int padlock_use_rng = 0; /* Random Number Generator */
167ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_AES
168ebfedea0SLionel Sambuc static int padlock_aes_align_required = 1;
169ebfedea0SLionel Sambuc #   endif
170ebfedea0SLionel Sambuc 
171ebfedea0SLionel Sambuc /* ===== Engine "management" functions ===== */
172ebfedea0SLionel Sambuc 
173ebfedea0SLionel Sambuc /* Prepare the ENGINE structure for registration */
padlock_bind_helper(ENGINE * e)174*0a6a1f1dSLionel Sambuc static int padlock_bind_helper(ENGINE *e)
175ebfedea0SLionel Sambuc {
176ebfedea0SLionel Sambuc     /* Check available features */
177ebfedea0SLionel Sambuc     padlock_available();
178ebfedea0SLionel Sambuc 
179*0a6a1f1dSLionel Sambuc #   if 1                        /* disable RNG for now, see commentary in
180*0a6a1f1dSLionel Sambuc                                  * vicinity of RNG code */
181ebfedea0SLionel Sambuc     padlock_use_rng = 0;
182ebfedea0SLionel Sambuc #   endif
183ebfedea0SLionel Sambuc 
184ebfedea0SLionel Sambuc     /* Generate a nice engine name with available features */
185ebfedea0SLionel Sambuc     BIO_snprintf(padlock_name, sizeof(padlock_name),
186ebfedea0SLionel Sambuc                  "VIA PadLock (%s, %s)",
187ebfedea0SLionel Sambuc                  padlock_use_rng ? "RNG" : "no-RNG",
188ebfedea0SLionel Sambuc                  padlock_use_ace ? "ACE" : "no-ACE");
189ebfedea0SLionel Sambuc 
190ebfedea0SLionel Sambuc     /* Register everything or return with an error */
191ebfedea0SLionel Sambuc     if (!ENGINE_set_id(e, padlock_id) ||
192ebfedea0SLionel Sambuc         !ENGINE_set_name(e, padlock_name) ||
193ebfedea0SLionel Sambuc         !ENGINE_set_init_function(e, padlock_init) ||
194ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_AES
195ebfedea0SLionel Sambuc         (padlock_use_ace && !ENGINE_set_ciphers(e, padlock_ciphers)) ||
196ebfedea0SLionel Sambuc #   endif
197ebfedea0SLionel Sambuc         (padlock_use_rng && !ENGINE_set_RAND(e, &padlock_rand))) {
198ebfedea0SLionel Sambuc         return 0;
199ebfedea0SLionel Sambuc     }
200ebfedea0SLionel Sambuc 
201ebfedea0SLionel Sambuc     /* Everything looks good */
202ebfedea0SLionel Sambuc     return 1;
203ebfedea0SLionel Sambuc }
204ebfedea0SLionel Sambuc 
205ebfedea0SLionel Sambuc #   ifdef OPENSSL_NO_DYNAMIC_ENGINE
206ebfedea0SLionel Sambuc 
207ebfedea0SLionel Sambuc /* Constructor */
ENGINE_padlock(void)208*0a6a1f1dSLionel Sambuc static ENGINE *ENGINE_padlock(void)
209ebfedea0SLionel Sambuc {
210ebfedea0SLionel Sambuc     ENGINE *eng = ENGINE_new();
211ebfedea0SLionel Sambuc 
212ebfedea0SLionel Sambuc     if (!eng) {
213ebfedea0SLionel Sambuc         return NULL;
214ebfedea0SLionel Sambuc     }
215ebfedea0SLionel Sambuc 
216ebfedea0SLionel Sambuc     if (!padlock_bind_helper(eng)) {
217ebfedea0SLionel Sambuc         ENGINE_free(eng);
218ebfedea0SLionel Sambuc         return NULL;
219ebfedea0SLionel Sambuc     }
220ebfedea0SLionel Sambuc 
221ebfedea0SLionel Sambuc     return eng;
222ebfedea0SLionel Sambuc }
223ebfedea0SLionel Sambuc 
224ebfedea0SLionel Sambuc #   endif
225ebfedea0SLionel Sambuc 
226ebfedea0SLionel Sambuc /* Check availability of the engine */
padlock_init(ENGINE * e)227*0a6a1f1dSLionel Sambuc static int padlock_init(ENGINE *e)
228ebfedea0SLionel Sambuc {
229ebfedea0SLionel Sambuc     return (padlock_use_rng || padlock_use_ace);
230ebfedea0SLionel Sambuc }
231ebfedea0SLionel Sambuc 
232*0a6a1f1dSLionel Sambuc /*
233*0a6a1f1dSLionel Sambuc  * This stuff is needed if this ENGINE is being compiled into a
234*0a6a1f1dSLionel Sambuc  * self-contained shared-library.
235ebfedea0SLionel Sambuc  */
236ebfedea0SLionel Sambuc #   ifdef DYNAMIC_ENGINE
padlock_bind_fn(ENGINE * e,const char * id)237*0a6a1f1dSLionel Sambuc static int padlock_bind_fn(ENGINE *e, const char *id)
238ebfedea0SLionel Sambuc {
239ebfedea0SLionel Sambuc     if (id && (strcmp(id, padlock_id) != 0)) {
240ebfedea0SLionel Sambuc         return 0;
241ebfedea0SLionel Sambuc     }
242ebfedea0SLionel Sambuc 
243ebfedea0SLionel Sambuc     if (!padlock_bind_helper(e)) {
244ebfedea0SLionel Sambuc         return 0;
245ebfedea0SLionel Sambuc     }
246ebfedea0SLionel Sambuc 
247ebfedea0SLionel Sambuc     return 1;
248ebfedea0SLionel Sambuc }
249ebfedea0SLionel Sambuc 
250ebfedea0SLionel Sambuc IMPLEMENT_DYNAMIC_CHECK_FN()
251ebfedea0SLionel Sambuc     IMPLEMENT_DYNAMIC_BIND_FN(padlock_bind_fn)
252ebfedea0SLionel Sambuc #   endif                       /* DYNAMIC_ENGINE */
253ebfedea0SLionel Sambuc /* ===== Here comes the "real" engine ===== */
254ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_AES
255ebfedea0SLionel Sambuc /* Some AES-related constants */
256ebfedea0SLionel Sambuc #    define AES_BLOCK_SIZE          16
257ebfedea0SLionel Sambuc #    define AES_KEY_SIZE_128        16
258ebfedea0SLionel Sambuc #    define AES_KEY_SIZE_192        24
259ebfedea0SLionel Sambuc #    define AES_KEY_SIZE_256        32
260*0a6a1f1dSLionel Sambuc     /*
261*0a6a1f1dSLionel Sambuc      * Here we store the status information relevant to the current context.
262ebfedea0SLionel Sambuc      */
263*0a6a1f1dSLionel Sambuc     /*
264*0a6a1f1dSLionel Sambuc      * BIG FAT WARNING: Inline assembler in PADLOCK_XCRYPT_ASM() depends on
265*0a6a1f1dSLionel Sambuc      * the order of items in this structure.  Don't blindly modify, reorder,
266*0a6a1f1dSLionel Sambuc      * etc!
267*0a6a1f1dSLionel Sambuc      */
268*0a6a1f1dSLionel Sambuc struct padlock_cipher_data {
269ebfedea0SLionel Sambuc     unsigned char iv[AES_BLOCK_SIZE]; /* Initialization vector */
270*0a6a1f1dSLionel Sambuc     union {
271*0a6a1f1dSLionel Sambuc         unsigned int pad[4];
272ebfedea0SLionel Sambuc         struct {
273ebfedea0SLionel Sambuc             int rounds:4;
274ebfedea0SLionel Sambuc             int dgst:1;         /* n/a in C3 */
275ebfedea0SLionel Sambuc             int align:1;        /* n/a in C3 */
276ebfedea0SLionel Sambuc             int ciphr:1;        /* n/a in C3 */
277ebfedea0SLionel Sambuc             unsigned int keygen:1;
278ebfedea0SLionel Sambuc             int interm:1;
279ebfedea0SLionel Sambuc             unsigned int encdec:1;
280ebfedea0SLionel Sambuc             int ksize:2;
281ebfedea0SLionel Sambuc         } b;
282ebfedea0SLionel Sambuc     } cword;                    /* Control word */
283ebfedea0SLionel Sambuc     AES_KEY ks;                 /* Encryption key */
284ebfedea0SLionel Sambuc };
285ebfedea0SLionel Sambuc 
286ebfedea0SLionel Sambuc /*
287ebfedea0SLionel Sambuc  * Essentially this variable belongs in thread local storage.
288ebfedea0SLionel Sambuc  * Having this variable global on the other hand can only cause
289ebfedea0SLionel Sambuc  * few bogus key reloads [if any at all on single-CPU system],
290ebfedea0SLionel Sambuc  * so we accept the penatly...
291ebfedea0SLionel Sambuc  */
292ebfedea0SLionel Sambuc static volatile struct padlock_cipher_data *padlock_saved_context;
293ebfedea0SLionel Sambuc #   endif
294ebfedea0SLionel Sambuc 
295*0a6a1f1dSLionel Sambuc /*-
296ebfedea0SLionel Sambuc  * =======================================================
297ebfedea0SLionel Sambuc  * Inline assembler section(s).
298ebfedea0SLionel Sambuc  * =======================================================
299ebfedea0SLionel Sambuc  * Order of arguments is chosen to facilitate Windows port
300ebfedea0SLionel Sambuc  * using __fastcall calling convention. If you wish to add
301ebfedea0SLionel Sambuc  * more routines, keep in mind that first __fastcall
302ebfedea0SLionel Sambuc  * argument is passed in %ecx and second - in %edx.
303ebfedea0SLionel Sambuc  * =======================================================
304ebfedea0SLionel Sambuc  */
305ebfedea0SLionel Sambuc #   if defined(__GNUC__) && __GNUC__>=2
306ebfedea0SLionel Sambuc /*
307ebfedea0SLionel Sambuc  * As for excessive "push %ebx"/"pop %ebx" found all over.
308ebfedea0SLionel Sambuc  * When generating position-independent code GCC won't let
309ebfedea0SLionel Sambuc  * us use "b" in assembler templates nor even respect "ebx"
310ebfedea0SLionel Sambuc  * in "clobber description." Therefore the trouble...
311ebfedea0SLionel Sambuc  */
312ebfedea0SLionel Sambuc 
313*0a6a1f1dSLionel Sambuc /*
314*0a6a1f1dSLionel Sambuc  * Helper function - check if a CPUID instruction is available on this CPU
315*0a6a1f1dSLionel Sambuc  */
padlock_insn_cpuid_available(void)316*0a6a1f1dSLionel Sambuc static int padlock_insn_cpuid_available(void)
317ebfedea0SLionel Sambuc {
318ebfedea0SLionel Sambuc     int result = -1;
319ebfedea0SLionel Sambuc 
320*0a6a1f1dSLionel Sambuc     /*
321*0a6a1f1dSLionel Sambuc      * We're checking if the bit #21 of EFLAGS can be toggled. If yes =
322*0a6a1f1dSLionel Sambuc      * CPUID is available.
323*0a6a1f1dSLionel Sambuc      */
324*0a6a1f1dSLionel Sambuc     asm volatile ("pushf\n"
325ebfedea0SLionel Sambuc                   "popl %%eax\n"
326ebfedea0SLionel Sambuc                   "xorl $0x200000, %%eax\n"
327ebfedea0SLionel Sambuc                   "movl %%eax, %%ecx\n"
328ebfedea0SLionel Sambuc                   "andl $0x200000, %%ecx\n"
329ebfedea0SLionel Sambuc                   "pushl %%eax\n"
330ebfedea0SLionel Sambuc                   "popf\n"
331ebfedea0SLionel Sambuc                   "pushf\n"
332ebfedea0SLionel Sambuc                   "popl %%eax\n"
333ebfedea0SLionel Sambuc                   "andl $0x200000, %%eax\n"
334ebfedea0SLionel Sambuc                   "xorl %%eax, %%ecx\n"
335*0a6a1f1dSLionel Sambuc                   "movl %%ecx, %0\n":"=r" (result)::"eax", "ecx");
336ebfedea0SLionel Sambuc 
337ebfedea0SLionel Sambuc     return (result == 0);
338ebfedea0SLionel Sambuc }
339ebfedea0SLionel Sambuc 
340*0a6a1f1dSLionel Sambuc /*
341*0a6a1f1dSLionel Sambuc  * Load supported features of the CPU to see if the PadLock is available.
342*0a6a1f1dSLionel Sambuc  */
padlock_available(void)343*0a6a1f1dSLionel Sambuc static int padlock_available(void)
344ebfedea0SLionel Sambuc {
345ebfedea0SLionel Sambuc     char vendor_string[16];
346ebfedea0SLionel Sambuc     unsigned int eax, edx;
347ebfedea0SLionel Sambuc 
348ebfedea0SLionel Sambuc     /* First check if the CPUID instruction is available at all... */
349ebfedea0SLionel Sambuc     if (!padlock_insn_cpuid_available())
350ebfedea0SLionel Sambuc         return 0;
351ebfedea0SLionel Sambuc 
352ebfedea0SLionel Sambuc     /* Are we running on the Centaur (VIA) CPU? */
353ebfedea0SLionel Sambuc     eax = 0x00000000;
354ebfedea0SLionel Sambuc     vendor_string[12] = 0;
355*0a6a1f1dSLionel Sambuc     asm volatile ("pushl  %%ebx\n"
356ebfedea0SLionel Sambuc                   "cpuid\n"
357ebfedea0SLionel Sambuc                   "movl   %%ebx,(%%edi)\n"
358ebfedea0SLionel Sambuc                   "movl   %%edx,4(%%edi)\n"
359ebfedea0SLionel Sambuc                   "movl   %%ecx,8(%%edi)\n"
360*0a6a1f1dSLionel Sambuc                   "popl   %%ebx":"+a" (eax):"D"(vendor_string):"ecx", "edx");
361ebfedea0SLionel Sambuc     if (strcmp(vendor_string, "CentaurHauls") != 0)
362ebfedea0SLionel Sambuc         return 0;
363ebfedea0SLionel Sambuc 
364ebfedea0SLionel Sambuc     /* Check for Centaur Extended Feature Flags presence */
365ebfedea0SLionel Sambuc     eax = 0xC0000000;
366*0a6a1f1dSLionel Sambuc     asm volatile ("pushl %%ebx; cpuid; popl %%ebx":"+a" (eax)::"ecx", "edx");
367ebfedea0SLionel Sambuc     if (eax < 0xC0000001)
368ebfedea0SLionel Sambuc         return 0;
369ebfedea0SLionel Sambuc 
370ebfedea0SLionel Sambuc     /* Read the Centaur Extended Feature Flags */
371ebfedea0SLionel Sambuc     eax = 0xC0000001;
372*0a6a1f1dSLionel Sambuc     asm volatile ("pushl %%ebx; cpuid; popl %%ebx":"+a" (eax),
373*0a6a1f1dSLionel Sambuc                   "=d"(edx)::"ecx");
374ebfedea0SLionel Sambuc 
375ebfedea0SLionel Sambuc     /* Fill up some flags */
376ebfedea0SLionel Sambuc     padlock_use_ace = ((edx & (0x3 << 6)) == (0x3 << 6));
377ebfedea0SLionel Sambuc     padlock_use_rng = ((edx & (0x3 << 2)) == (0x3 << 2));
378ebfedea0SLionel Sambuc 
379ebfedea0SLionel Sambuc     return padlock_use_ace + padlock_use_rng;
380ebfedea0SLionel Sambuc }
381ebfedea0SLionel Sambuc 
382ebfedea0SLionel Sambuc #    ifndef OPENSSL_NO_AES
383*0a6a1f1dSLionel Sambuc #     ifndef AES_ASM
384ebfedea0SLionel Sambuc /* Our own htonl()/ntohl() */
padlock_bswapl(AES_KEY * ks)385*0a6a1f1dSLionel Sambuc static inline void padlock_bswapl(AES_KEY *ks)
386ebfedea0SLionel Sambuc {
387ebfedea0SLionel Sambuc     size_t i = sizeof(ks->rd_key) / sizeof(ks->rd_key[0]);
388ebfedea0SLionel Sambuc     unsigned int *key = ks->rd_key;
389ebfedea0SLionel Sambuc 
390ebfedea0SLionel Sambuc     while (i--) {
391ebfedea0SLionel Sambuc         asm volatile ("bswapl %0":"+r" (*key));
392ebfedea0SLionel Sambuc         key++;
393ebfedea0SLionel Sambuc     }
394ebfedea0SLionel Sambuc }
395ebfedea0SLionel Sambuc #     endif
396*0a6a1f1dSLionel Sambuc #    endif
397ebfedea0SLionel Sambuc 
398*0a6a1f1dSLionel Sambuc /*
399*0a6a1f1dSLionel Sambuc  * Force key reload from memory to the CPU microcode. Loading EFLAGS from the
400*0a6a1f1dSLionel Sambuc  * stack clears EFLAGS[30] which does the trick.
401*0a6a1f1dSLionel Sambuc  */
padlock_reload_key(void)402*0a6a1f1dSLionel Sambuc static inline void padlock_reload_key(void)
403ebfedea0SLionel Sambuc {
404ebfedea0SLionel Sambuc     asm volatile ("pushfl; popfl");
405ebfedea0SLionel Sambuc }
406ebfedea0SLionel Sambuc 
407ebfedea0SLionel Sambuc #    ifndef OPENSSL_NO_AES
408ebfedea0SLionel Sambuc /*
409ebfedea0SLionel Sambuc  * This is heuristic key context tracing. At first one
410ebfedea0SLionel Sambuc  * believes that one should use atomic swap instructions,
411ebfedea0SLionel Sambuc  * but it's not actually necessary. Point is that if
412ebfedea0SLionel Sambuc  * padlock_saved_context was changed by another thread
413ebfedea0SLionel Sambuc  * after we've read it and before we compare it with cdata,
414ebfedea0SLionel Sambuc  * our key *shall* be reloaded upon thread context switch
415ebfedea0SLionel Sambuc  * and we are therefore set in either case...
416ebfedea0SLionel Sambuc  */
padlock_verify_context(struct padlock_cipher_data * cdata)417*0a6a1f1dSLionel Sambuc static inline void padlock_verify_context(struct padlock_cipher_data *cdata)
418ebfedea0SLionel Sambuc {
419*0a6a1f1dSLionel Sambuc     asm volatile ("pushfl\n"
420ebfedea0SLionel Sambuc                   "       btl     $30,(%%esp)\n"
421ebfedea0SLionel Sambuc                   "       jnc     1f\n"
422ebfedea0SLionel Sambuc                   "       cmpl    %2,%1\n"
423ebfedea0SLionel Sambuc                   "       je      1f\n"
424ebfedea0SLionel Sambuc                   "       popfl\n"
425ebfedea0SLionel Sambuc                   "       subl    $4,%%esp\n"
426ebfedea0SLionel Sambuc                   "1:     addl    $4,%%esp\n"
427*0a6a1f1dSLionel Sambuc                   "       movl    %2,%0":"+m" (padlock_saved_context)
428ebfedea0SLionel Sambuc                   :"r"(padlock_saved_context), "r"(cdata):"cc");
429ebfedea0SLionel Sambuc }
430ebfedea0SLionel Sambuc 
431ebfedea0SLionel Sambuc /* Template for padlock_xcrypt_* modes */
432*0a6a1f1dSLionel Sambuc /*
433*0a6a1f1dSLionel Sambuc  * BIG FAT WARNING: The offsets used with 'leal' instructions describe items
434*0a6a1f1dSLionel Sambuc  * of the 'padlock_cipher_data' structure.
435ebfedea0SLionel Sambuc  */
436ebfedea0SLionel Sambuc #     define PADLOCK_XCRYPT_ASM(name,rep_xcrypt)     \
437ebfedea0SLionel Sambuc static inline void *name(size_t cnt,            \
438ebfedea0SLionel Sambuc         struct padlock_cipher_data *cdata,      \
439ebfedea0SLionel Sambuc         void *out, const void *inp)             \
440ebfedea0SLionel Sambuc {       void *iv;                               \
441ebfedea0SLionel Sambuc         asm volatile ( "pushl   %%ebx\n"        \
442ebfedea0SLionel Sambuc                 "       leal    16(%0),%%edx\n" \
443ebfedea0SLionel Sambuc                 "       leal    32(%0),%%ebx\n" \
444ebfedea0SLionel Sambuc                         rep_xcrypt "\n"         \
445ebfedea0SLionel Sambuc                 "       popl    %%ebx"          \
446ebfedea0SLionel Sambuc                 : "=a"(iv), "=c"(cnt), "=D"(out), "=S"(inp) \
447ebfedea0SLionel Sambuc                 : "0"(cdata), "1"(cnt), "2"(out), "3"(inp)  \
448ebfedea0SLionel Sambuc                 : "edx", "cc", "memory");       \
449ebfedea0SLionel Sambuc         return iv;                              \
450ebfedea0SLionel Sambuc }
451ebfedea0SLionel Sambuc 
452ebfedea0SLionel Sambuc /* Generate all functions with appropriate opcodes */
453*0a6a1f1dSLionel Sambuc /* rep xcryptecb */
454*0a6a1f1dSLionel Sambuc PADLOCK_XCRYPT_ASM(padlock_xcrypt_ecb, ".byte 0xf3,0x0f,0xa7,0xc8")
455*0a6a1f1dSLionel Sambuc /* rep xcryptcbc */
456*0a6a1f1dSLionel Sambuc     PADLOCK_XCRYPT_ASM(padlock_xcrypt_cbc, ".byte 0xf3,0x0f,0xa7,0xd0")
457*0a6a1f1dSLionel Sambuc /* rep xcryptcfb */
458*0a6a1f1dSLionel Sambuc     PADLOCK_XCRYPT_ASM(padlock_xcrypt_cfb, ".byte 0xf3,0x0f,0xa7,0xe0")
459*0a6a1f1dSLionel Sambuc /* rep xcryptofb */
460*0a6a1f1dSLionel Sambuc     PADLOCK_XCRYPT_ASM(padlock_xcrypt_ofb, ".byte 0xf3,0x0f,0xa7,0xe8")
461ebfedea0SLionel Sambuc #    endif
462ebfedea0SLionel Sambuc /* The RNG call itself */
padlock_xstore(void * addr,unsigned int edx_in)463*0a6a1f1dSLionel Sambuc static inline unsigned int padlock_xstore(void *addr, unsigned int edx_in)
464ebfedea0SLionel Sambuc {
465ebfedea0SLionel Sambuc     unsigned int eax_out;
466ebfedea0SLionel Sambuc 
467ebfedea0SLionel Sambuc     asm volatile (".byte 0x0f,0xa7,0xc0" /* xstore */
468ebfedea0SLionel Sambuc                   :"=a" (eax_out), "=m"(*(unsigned *)addr)
469ebfedea0SLionel Sambuc                   :"D"(addr), "d"(edx_in)
470ebfedea0SLionel Sambuc         );
471ebfedea0SLionel Sambuc 
472ebfedea0SLionel Sambuc     return eax_out;
473ebfedea0SLionel Sambuc }
474ebfedea0SLionel Sambuc 
475*0a6a1f1dSLionel Sambuc /*
476*0a6a1f1dSLionel Sambuc  * Why not inline 'rep movsd'? I failed to find information on what value in
477*0a6a1f1dSLionel Sambuc  * Direction Flag one can expect and consequently have to apply
478*0a6a1f1dSLionel Sambuc  * "better-safe-than-sorry" approach and assume "undefined." I could
479*0a6a1f1dSLionel Sambuc  * explicitly clear it and restore the original value upon return from
480*0a6a1f1dSLionel Sambuc  * padlock_aes_cipher, but it's presumably too much trouble for too little
481*0a6a1f1dSLionel Sambuc  * gain... In case you wonder 'rep xcrypt*' instructions above are *not*
482*0a6a1f1dSLionel Sambuc  * affected by the Direction Flag and pointers advance toward larger
483*0a6a1f1dSLionel Sambuc  * addresses unconditionally.
484ebfedea0SLionel Sambuc  */
padlock_memcpy(void * dst,const void * src,size_t n)485*0a6a1f1dSLionel Sambuc static inline unsigned char *padlock_memcpy(void *dst, const void *src,
486*0a6a1f1dSLionel Sambuc                                             size_t n)
487ebfedea0SLionel Sambuc {
488ebfedea0SLionel Sambuc     long *d = dst;
489ebfedea0SLionel Sambuc     const long *s = src;
490ebfedea0SLionel Sambuc 
491ebfedea0SLionel Sambuc     n /= sizeof(*d);
492*0a6a1f1dSLionel Sambuc     do {
493*0a6a1f1dSLionel Sambuc         *d++ = *s++;
494*0a6a1f1dSLionel Sambuc     } while (--n);
495ebfedea0SLionel Sambuc 
496ebfedea0SLionel Sambuc     return dst;
497ebfedea0SLionel Sambuc }
498ebfedea0SLionel Sambuc 
499ebfedea0SLionel Sambuc #   elif defined(_MSC_VER)
500ebfedea0SLionel Sambuc /*
501ebfedea0SLionel Sambuc  * Unlike GCC these are real functions. In order to minimize impact
502ebfedea0SLionel Sambuc  * on performance we adhere to __fastcall calling convention in
503ebfedea0SLionel Sambuc  * order to get two first arguments passed through %ecx and %edx.
504ebfedea0SLionel Sambuc  * Which kind of suits very well, as instructions in question use
505ebfedea0SLionel Sambuc  * both %ecx and %edx as input:-)
506ebfedea0SLionel Sambuc  */
507ebfedea0SLionel Sambuc #    define REP_XCRYPT(code)                \
508ebfedea0SLionel Sambuc         _asm _emit 0xf3                 \
509ebfedea0SLionel Sambuc         _asm _emit 0x0f _asm _emit 0xa7 \
510ebfedea0SLionel Sambuc         _asm _emit code
511ebfedea0SLionel Sambuc 
512*0a6a1f1dSLionel Sambuc /*
513*0a6a1f1dSLionel Sambuc  * BIG FAT WARNING: The offsets used with 'lea' instructions describe items
514*0a6a1f1dSLionel Sambuc  * of the 'padlock_cipher_data' structure.
515ebfedea0SLionel Sambuc  */
516ebfedea0SLionel Sambuc #    define PADLOCK_XCRYPT_ASM(name,code)   \
517ebfedea0SLionel Sambuc static void * __fastcall                \
518ebfedea0SLionel Sambuc         name (size_t cnt, void *cdata,  \
519ebfedea0SLionel Sambuc         void *outp, const void *inp)    \
520ebfedea0SLionel Sambuc {       _asm    mov     eax,edx         \
521ebfedea0SLionel Sambuc         _asm    lea     edx,[eax+16]    \
522ebfedea0SLionel Sambuc         _asm    lea     ebx,[eax+32]    \
523ebfedea0SLionel Sambuc         _asm    mov     edi,outp        \
524ebfedea0SLionel Sambuc         _asm    mov     esi,inp         \
525ebfedea0SLionel Sambuc         REP_XCRYPT(code)                \
526ebfedea0SLionel Sambuc }
527ebfedea0SLionel Sambuc 
528ebfedea0SLionel Sambuc PADLOCK_XCRYPT_ASM(padlock_xcrypt_ecb,0xc8)
529ebfedea0SLionel Sambuc PADLOCK_XCRYPT_ASM(padlock_xcrypt_cbc,0xd0)
530ebfedea0SLionel Sambuc PADLOCK_XCRYPT_ASM(padlock_xcrypt_cfb,0xe0)
531ebfedea0SLionel Sambuc PADLOCK_XCRYPT_ASM(padlock_xcrypt_ofb,0xe8)
532ebfedea0SLionel Sambuc 
padlock_xstore(void * outp,unsigned int code)533*0a6a1f1dSLionel Sambuc static int __fastcall padlock_xstore(void *outp, unsigned int code)
534*0a6a1f1dSLionel Sambuc {
535*0a6a1f1dSLionel Sambuc     _asm    mov edi,ecx
536ebfedea0SLionel Sambuc     _asm _emit 0x0f _asm _emit 0xa7 _asm _emit 0xc0
537ebfedea0SLionel Sambuc }
538ebfedea0SLionel Sambuc 
padlock_reload_key(void)539*0a6a1f1dSLionel Sambuc static void __fastcall padlock_reload_key(void)
540*0a6a1f1dSLionel Sambuc {
541*0a6a1f1dSLionel Sambuc     _asm pushfd
542*0a6a1f1dSLionel Sambuc     _asm popfd
543*0a6a1f1dSLionel Sambuc }
544ebfedea0SLionel Sambuc 
padlock_verify_context(void * cdata)545*0a6a1f1dSLionel Sambuc static void __fastcall padlock_verify_context(void *cdata)
546*0a6a1f1dSLionel Sambuc {
547*0a6a1f1dSLionel Sambuc     _asm    {
548ebfedea0SLionel Sambuc         pushfd
549ebfedea0SLionel Sambuc         bt  DWORD PTR[esp],30
550ebfedea0SLionel Sambuc         jnc skip
551ebfedea0SLionel Sambuc         cmp ecx,padlock_saved_context
552ebfedea0SLionel Sambuc         je  skip
553ebfedea0SLionel Sambuc         popfd
554ebfedea0SLionel Sambuc         sub esp,4
555ebfedea0SLionel Sambuc     skip:   add esp,4
556ebfedea0SLionel Sambuc         mov padlock_saved_context,ecx
557ebfedea0SLionel Sambuc     }
558ebfedea0SLionel Sambuc }
559ebfedea0SLionel Sambuc 
560ebfedea0SLionel Sambuc static int
padlock_available(void)561ebfedea0SLionel Sambuc padlock_available(void)
562*0a6a1f1dSLionel Sambuc {
563*0a6a1f1dSLionel Sambuc     _asm    {
564ebfedea0SLionel Sambuc         pushfd
565ebfedea0SLionel Sambuc         pop eax
566ebfedea0SLionel Sambuc         mov ecx,eax
567ebfedea0SLionel Sambuc         xor eax,1<<21
568ebfedea0SLionel Sambuc         push    eax
569ebfedea0SLionel Sambuc         popfd
570ebfedea0SLionel Sambuc         pushfd
571ebfedea0SLionel Sambuc         pop eax
572ebfedea0SLionel Sambuc         xor eax,ecx
573ebfedea0SLionel Sambuc         bt  eax,21
574ebfedea0SLionel Sambuc         jnc noluck
575ebfedea0SLionel Sambuc         mov eax,0
576ebfedea0SLionel Sambuc         cpuid
577ebfedea0SLionel Sambuc         xor eax,eax
578ebfedea0SLionel Sambuc         cmp ebx,'tneC'
579ebfedea0SLionel Sambuc         jne noluck
580ebfedea0SLionel Sambuc         cmp edx,'Hrua'
581ebfedea0SLionel Sambuc         jne noluck
582ebfedea0SLionel Sambuc         cmp ecx,'slua'
583ebfedea0SLionel Sambuc         jne noluck
584ebfedea0SLionel Sambuc         mov eax,0xC0000000
585ebfedea0SLionel Sambuc         cpuid
586ebfedea0SLionel Sambuc         mov edx,eax
587ebfedea0SLionel Sambuc         xor eax,eax
588ebfedea0SLionel Sambuc         cmp edx,0xC0000001
589ebfedea0SLionel Sambuc         jb  noluck
590ebfedea0SLionel Sambuc         mov eax,0xC0000001
591ebfedea0SLionel Sambuc         cpuid
592ebfedea0SLionel Sambuc         xor eax,eax
593ebfedea0SLionel Sambuc         bt  edx,6
594ebfedea0SLionel Sambuc         jnc skip_a
595ebfedea0SLionel Sambuc         bt  edx,7
596ebfedea0SLionel Sambuc         jnc skip_a
597ebfedea0SLionel Sambuc         mov padlock_use_ace,1
598ebfedea0SLionel Sambuc         inc eax
599ebfedea0SLionel Sambuc     skip_a: bt  edx,2
600ebfedea0SLionel Sambuc         jnc skip_r
601ebfedea0SLionel Sambuc         bt  edx,3
602ebfedea0SLionel Sambuc         jnc skip_r
603ebfedea0SLionel Sambuc         mov padlock_use_rng,1
604ebfedea0SLionel Sambuc         inc eax
605ebfedea0SLionel Sambuc     skip_r:
606ebfedea0SLionel Sambuc     noluck:
607ebfedea0SLionel Sambuc     }
608ebfedea0SLionel Sambuc }
609ebfedea0SLionel Sambuc 
padlock_bswapl(void * key)610*0a6a1f1dSLionel Sambuc static void __fastcall padlock_bswapl(void *key)
611*0a6a1f1dSLionel Sambuc {
612*0a6a1f1dSLionel Sambuc     _asm    {
613ebfedea0SLionel Sambuc         pushfd
614ebfedea0SLionel Sambuc         cld
615ebfedea0SLionel Sambuc         mov esi,ecx
616ebfedea0SLionel Sambuc         mov edi,ecx
617ebfedea0SLionel Sambuc         mov ecx,60
618ebfedea0SLionel Sambuc     up: lodsd
619ebfedea0SLionel Sambuc         bswap   eax
620ebfedea0SLionel Sambuc         stosd
621ebfedea0SLionel Sambuc         loop    up
622ebfedea0SLionel Sambuc         popfd
623ebfedea0SLionel Sambuc     }
624ebfedea0SLionel Sambuc }
625ebfedea0SLionel Sambuc 
626*0a6a1f1dSLionel Sambuc /*
627*0a6a1f1dSLionel Sambuc  * MS actually specifies status of Direction Flag and compiler even manages
628*0a6a1f1dSLionel Sambuc  * to compile following as 'rep movsd' all by itself...
629ebfedea0SLionel Sambuc  */
630ebfedea0SLionel Sambuc #    define padlock_memcpy(o,i,n) ((unsigned char *)memcpy((o),(i),(n)&~3U))
631ebfedea0SLionel Sambuc #   endif
632ebfedea0SLionel Sambuc /* ===== AES encryption/decryption ===== */
633ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_AES
634ebfedea0SLionel Sambuc #    if defined(NID_aes_128_cfb128) && ! defined (NID_aes_128_cfb)
635ebfedea0SLionel Sambuc #     define NID_aes_128_cfb NID_aes_128_cfb128
636ebfedea0SLionel Sambuc #    endif
637ebfedea0SLionel Sambuc #    if defined(NID_aes_128_ofb128) && ! defined (NID_aes_128_ofb)
638ebfedea0SLionel Sambuc #     define NID_aes_128_ofb NID_aes_128_ofb128
639ebfedea0SLionel Sambuc #    endif
640ebfedea0SLionel Sambuc #    if defined(NID_aes_192_cfb128) && ! defined (NID_aes_192_cfb)
641ebfedea0SLionel Sambuc #     define NID_aes_192_cfb NID_aes_192_cfb128
642ebfedea0SLionel Sambuc #    endif
643ebfedea0SLionel Sambuc #    if defined(NID_aes_192_ofb128) && ! defined (NID_aes_192_ofb)
644ebfedea0SLionel Sambuc #     define NID_aes_192_ofb NID_aes_192_ofb128
645ebfedea0SLionel Sambuc #    endif
646ebfedea0SLionel Sambuc #    if defined(NID_aes_256_cfb128) && ! defined (NID_aes_256_cfb)
647ebfedea0SLionel Sambuc #     define NID_aes_256_cfb NID_aes_256_cfb128
648ebfedea0SLionel Sambuc #    endif
649ebfedea0SLionel Sambuc #    if defined(NID_aes_256_ofb128) && ! defined (NID_aes_256_ofb)
650ebfedea0SLionel Sambuc #     define NID_aes_256_ofb NID_aes_256_ofb128
651ebfedea0SLionel Sambuc #    endif
652*0a6a1f1dSLionel Sambuc /*
653*0a6a1f1dSLionel Sambuc  * List of supported ciphers.
654*0a6a1f1dSLionel Sambuc  */ static int padlock_cipher_nids[] = {
655ebfedea0SLionel Sambuc     NID_aes_128_ecb,
656ebfedea0SLionel Sambuc     NID_aes_128_cbc,
657ebfedea0SLionel Sambuc     NID_aes_128_cfb,
658ebfedea0SLionel Sambuc     NID_aes_128_ofb,
659ebfedea0SLionel Sambuc 
660ebfedea0SLionel Sambuc     NID_aes_192_ecb,
661ebfedea0SLionel Sambuc     NID_aes_192_cbc,
662ebfedea0SLionel Sambuc     NID_aes_192_cfb,
663ebfedea0SLionel Sambuc     NID_aes_192_ofb,
664ebfedea0SLionel Sambuc 
665ebfedea0SLionel Sambuc     NID_aes_256_ecb,
666ebfedea0SLionel Sambuc     NID_aes_256_cbc,
667ebfedea0SLionel Sambuc     NID_aes_256_cfb,
668ebfedea0SLionel Sambuc     NID_aes_256_ofb,
669ebfedea0SLionel Sambuc };
670*0a6a1f1dSLionel Sambuc 
671ebfedea0SLionel Sambuc static int padlock_cipher_nids_num = (sizeof(padlock_cipher_nids) /
672ebfedea0SLionel Sambuc                                       sizeof(padlock_cipher_nids[0]));
673ebfedea0SLionel Sambuc 
674ebfedea0SLionel Sambuc /* Function prototypes ... */
675ebfedea0SLionel Sambuc static int padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
676ebfedea0SLionel Sambuc                                 const unsigned char *iv, int enc);
677ebfedea0SLionel Sambuc static int padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
678ebfedea0SLionel Sambuc                               const unsigned char *in, size_t nbytes);
679ebfedea0SLionel Sambuc 
680ebfedea0SLionel Sambuc #    define NEAREST_ALIGNED(ptr) ( (unsigned char *)(ptr) +         \
681ebfedea0SLionel Sambuc         ( (0x10 - ((size_t)(ptr) & 0x0F)) & 0x0F )      )
682ebfedea0SLionel Sambuc #    define ALIGNED_CIPHER_DATA(ctx) ((struct padlock_cipher_data *)\
683ebfedea0SLionel Sambuc         NEAREST_ALIGNED(ctx->cipher_data))
684ebfedea0SLionel Sambuc 
685ebfedea0SLionel Sambuc #    define EVP_CIPHER_block_size_ECB       AES_BLOCK_SIZE
686ebfedea0SLionel Sambuc #    define EVP_CIPHER_block_size_CBC       AES_BLOCK_SIZE
687ebfedea0SLionel Sambuc #    define EVP_CIPHER_block_size_OFB       1
688ebfedea0SLionel Sambuc #    define EVP_CIPHER_block_size_CFB       1
689ebfedea0SLionel Sambuc 
690*0a6a1f1dSLionel Sambuc /*
691*0a6a1f1dSLionel Sambuc  * Declaring so many ciphers by hand would be a pain. Instead introduce a bit
692*0a6a1f1dSLionel Sambuc  * of preprocessor magic :-)
693*0a6a1f1dSLionel Sambuc  */
694ebfedea0SLionel Sambuc #    define DECLARE_AES_EVP(ksize,lmode,umode)      \
695ebfedea0SLionel Sambuc static const EVP_CIPHER padlock_aes_##ksize##_##lmode = {       \
696ebfedea0SLionel Sambuc         NID_aes_##ksize##_##lmode,              \
697ebfedea0SLionel Sambuc         EVP_CIPHER_block_size_##umode,  \
698ebfedea0SLionel Sambuc         AES_KEY_SIZE_##ksize,           \
699ebfedea0SLionel Sambuc         AES_BLOCK_SIZE,                 \
700ebfedea0SLionel Sambuc         0 | EVP_CIPH_##umode##_MODE,    \
701ebfedea0SLionel Sambuc         padlock_aes_init_key,           \
702ebfedea0SLionel Sambuc         padlock_aes_cipher,             \
703ebfedea0SLionel Sambuc         NULL,                           \
704ebfedea0SLionel Sambuc         sizeof(struct padlock_cipher_data) + 16,        \
705ebfedea0SLionel Sambuc         EVP_CIPHER_set_asn1_iv,         \
706ebfedea0SLionel Sambuc         EVP_CIPHER_get_asn1_iv,         \
707ebfedea0SLionel Sambuc         NULL,                           \
708ebfedea0SLionel Sambuc         NULL                            \
709ebfedea0SLionel Sambuc }
710ebfedea0SLionel Sambuc 
711ebfedea0SLionel Sambuc DECLARE_AES_EVP(128, ecb, ECB);
712ebfedea0SLionel Sambuc DECLARE_AES_EVP(128, cbc, CBC);
713ebfedea0SLionel Sambuc DECLARE_AES_EVP(128, cfb, CFB);
714ebfedea0SLionel Sambuc DECLARE_AES_EVP(128, ofb, OFB);
715ebfedea0SLionel Sambuc 
716ebfedea0SLionel Sambuc DECLARE_AES_EVP(192, ecb, ECB);
717ebfedea0SLionel Sambuc DECLARE_AES_EVP(192, cbc, CBC);
718ebfedea0SLionel Sambuc DECLARE_AES_EVP(192, cfb, CFB);
719ebfedea0SLionel Sambuc DECLARE_AES_EVP(192, ofb, OFB);
720ebfedea0SLionel Sambuc 
721ebfedea0SLionel Sambuc DECLARE_AES_EVP(256, ecb, ECB);
722ebfedea0SLionel Sambuc DECLARE_AES_EVP(256, cbc, CBC);
723ebfedea0SLionel Sambuc DECLARE_AES_EVP(256, cfb, CFB);
724ebfedea0SLionel Sambuc DECLARE_AES_EVP(256, ofb, OFB);
725ebfedea0SLionel Sambuc 
726ebfedea0SLionel Sambuc static int
padlock_ciphers(ENGINE * e,const EVP_CIPHER ** cipher,const int ** nids,int nid)727*0a6a1f1dSLionel Sambuc padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher, const int **nids,
728*0a6a1f1dSLionel Sambuc                 int nid)
729ebfedea0SLionel Sambuc {
730ebfedea0SLionel Sambuc     /* No specific cipher => return a list of supported nids ... */
731ebfedea0SLionel Sambuc     if (!cipher) {
732ebfedea0SLionel Sambuc         *nids = padlock_cipher_nids;
733ebfedea0SLionel Sambuc         return padlock_cipher_nids_num;
734ebfedea0SLionel Sambuc     }
735ebfedea0SLionel Sambuc 
736ebfedea0SLionel Sambuc     /* ... or the requested "cipher" otherwise */
737ebfedea0SLionel Sambuc     switch (nid) {
738ebfedea0SLionel Sambuc     case NID_aes_128_ecb:
739ebfedea0SLionel Sambuc         *cipher = &padlock_aes_128_ecb;
740ebfedea0SLionel Sambuc         break;
741ebfedea0SLionel Sambuc     case NID_aes_128_cbc:
742ebfedea0SLionel Sambuc         *cipher = &padlock_aes_128_cbc;
743ebfedea0SLionel Sambuc         break;
744ebfedea0SLionel Sambuc     case NID_aes_128_cfb:
745ebfedea0SLionel Sambuc         *cipher = &padlock_aes_128_cfb;
746ebfedea0SLionel Sambuc         break;
747ebfedea0SLionel Sambuc     case NID_aes_128_ofb:
748ebfedea0SLionel Sambuc         *cipher = &padlock_aes_128_ofb;
749ebfedea0SLionel Sambuc         break;
750ebfedea0SLionel Sambuc 
751ebfedea0SLionel Sambuc     case NID_aes_192_ecb:
752ebfedea0SLionel Sambuc         *cipher = &padlock_aes_192_ecb;
753ebfedea0SLionel Sambuc         break;
754ebfedea0SLionel Sambuc     case NID_aes_192_cbc:
755ebfedea0SLionel Sambuc         *cipher = &padlock_aes_192_cbc;
756ebfedea0SLionel Sambuc         break;
757ebfedea0SLionel Sambuc     case NID_aes_192_cfb:
758ebfedea0SLionel Sambuc         *cipher = &padlock_aes_192_cfb;
759ebfedea0SLionel Sambuc         break;
760ebfedea0SLionel Sambuc     case NID_aes_192_ofb:
761ebfedea0SLionel Sambuc         *cipher = &padlock_aes_192_ofb;
762ebfedea0SLionel Sambuc         break;
763ebfedea0SLionel Sambuc 
764ebfedea0SLionel Sambuc     case NID_aes_256_ecb:
765ebfedea0SLionel Sambuc         *cipher = &padlock_aes_256_ecb;
766ebfedea0SLionel Sambuc         break;
767ebfedea0SLionel Sambuc     case NID_aes_256_cbc:
768ebfedea0SLionel Sambuc         *cipher = &padlock_aes_256_cbc;
769ebfedea0SLionel Sambuc         break;
770ebfedea0SLionel Sambuc     case NID_aes_256_cfb:
771ebfedea0SLionel Sambuc         *cipher = &padlock_aes_256_cfb;
772ebfedea0SLionel Sambuc         break;
773ebfedea0SLionel Sambuc     case NID_aes_256_ofb:
774ebfedea0SLionel Sambuc         *cipher = &padlock_aes_256_ofb;
775ebfedea0SLionel Sambuc         break;
776ebfedea0SLionel Sambuc 
777ebfedea0SLionel Sambuc     default:
778ebfedea0SLionel Sambuc         /* Sorry, we don't support this NID */
779ebfedea0SLionel Sambuc         *cipher = NULL;
780ebfedea0SLionel Sambuc         return 0;
781ebfedea0SLionel Sambuc     }
782ebfedea0SLionel Sambuc 
783ebfedea0SLionel Sambuc     return 1;
784ebfedea0SLionel Sambuc }
785ebfedea0SLionel Sambuc 
786ebfedea0SLionel Sambuc /* Prepare the encryption key for PadLock usage */
787ebfedea0SLionel Sambuc static int
padlock_aes_init_key(EVP_CIPHER_CTX * ctx,const unsigned char * key,const unsigned char * iv,int enc)788ebfedea0SLionel Sambuc padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
789ebfedea0SLionel Sambuc                      const unsigned char *iv, int enc)
790ebfedea0SLionel Sambuc {
791ebfedea0SLionel Sambuc     struct padlock_cipher_data *cdata;
792ebfedea0SLionel Sambuc     int key_len = EVP_CIPHER_CTX_key_length(ctx) * 8;
793ebfedea0SLionel Sambuc 
794*0a6a1f1dSLionel Sambuc     if (key == NULL)
795*0a6a1f1dSLionel Sambuc         return 0;               /* ERROR */
796ebfedea0SLionel Sambuc 
797ebfedea0SLionel Sambuc     cdata = ALIGNED_CIPHER_DATA(ctx);
798ebfedea0SLionel Sambuc     memset(cdata, 0, sizeof(struct padlock_cipher_data));
799ebfedea0SLionel Sambuc 
800ebfedea0SLionel Sambuc     /* Prepare Control word. */
801ebfedea0SLionel Sambuc     if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE)
802ebfedea0SLionel Sambuc         cdata->cword.b.encdec = 0;
803ebfedea0SLionel Sambuc     else
804ebfedea0SLionel Sambuc         cdata->cword.b.encdec = (ctx->encrypt == 0);
805ebfedea0SLionel Sambuc     cdata->cword.b.rounds = 10 + (key_len - 128) / 32;
806ebfedea0SLionel Sambuc     cdata->cword.b.ksize = (key_len - 128) / 64;
807ebfedea0SLionel Sambuc 
808ebfedea0SLionel Sambuc     switch (key_len) {
809ebfedea0SLionel Sambuc     case 128:
810*0a6a1f1dSLionel Sambuc         /*
811*0a6a1f1dSLionel Sambuc          * PadLock can generate an extended key for AES128 in hardware
812*0a6a1f1dSLionel Sambuc          */
813ebfedea0SLionel Sambuc         memcpy(cdata->ks.rd_key, key, AES_KEY_SIZE_128);
814ebfedea0SLionel Sambuc         cdata->cword.b.keygen = 0;
815ebfedea0SLionel Sambuc         break;
816ebfedea0SLionel Sambuc 
817ebfedea0SLionel Sambuc     case 192:
818ebfedea0SLionel Sambuc     case 256:
819*0a6a1f1dSLionel Sambuc         /*
820*0a6a1f1dSLionel Sambuc          * Generate an extended AES key in software. Needed for AES192/AES256
821*0a6a1f1dSLionel Sambuc          */
822*0a6a1f1dSLionel Sambuc         /*
823*0a6a1f1dSLionel Sambuc          * Well, the above applies to Stepping 8 CPUs and is listed as
824*0a6a1f1dSLionel Sambuc          * hardware errata. They most likely will fix it at some point and
825*0a6a1f1dSLionel Sambuc          * then a check for stepping would be due here.
826*0a6a1f1dSLionel Sambuc          */
827ebfedea0SLionel Sambuc         if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB_MODE ||
828*0a6a1f1dSLionel Sambuc             EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE || enc)
829ebfedea0SLionel Sambuc             AES_set_encrypt_key(key, key_len, &cdata->ks);
830ebfedea0SLionel Sambuc         else
831ebfedea0SLionel Sambuc             AES_set_decrypt_key(key, key_len, &cdata->ks);
832ebfedea0SLionel Sambuc #    ifndef AES_ASM
833*0a6a1f1dSLionel Sambuc         /*
834*0a6a1f1dSLionel Sambuc          * OpenSSL C functions use byte-swapped extended key.
835*0a6a1f1dSLionel Sambuc          */
836ebfedea0SLionel Sambuc         padlock_bswapl(&cdata->ks);
837ebfedea0SLionel Sambuc #    endif
838ebfedea0SLionel Sambuc         cdata->cword.b.keygen = 1;
839ebfedea0SLionel Sambuc         break;
840ebfedea0SLionel Sambuc 
841ebfedea0SLionel Sambuc     default:
842ebfedea0SLionel Sambuc         /* ERROR */
843ebfedea0SLionel Sambuc         return 0;
844ebfedea0SLionel Sambuc     }
845ebfedea0SLionel Sambuc 
846ebfedea0SLionel Sambuc     /*
847ebfedea0SLionel Sambuc      * This is done to cover for cases when user reuses the
848ebfedea0SLionel Sambuc      * context for new key. The catch is that if we don't do
849ebfedea0SLionel Sambuc      * this, padlock_eas_cipher might proceed with old key...
850ebfedea0SLionel Sambuc      */
851ebfedea0SLionel Sambuc     padlock_reload_key();
852ebfedea0SLionel Sambuc 
853ebfedea0SLionel Sambuc     return 1;
854ebfedea0SLionel Sambuc }
855ebfedea0SLionel Sambuc 
856*0a6a1f1dSLionel Sambuc /*-
857ebfedea0SLionel Sambuc  * Simplified version of padlock_aes_cipher() used when
858ebfedea0SLionel Sambuc  * 1) both input and output buffers are at aligned addresses.
859ebfedea0SLionel Sambuc  * or when
860ebfedea0SLionel Sambuc  * 2) running on a newer CPU that doesn't require aligned buffers.
861ebfedea0SLionel Sambuc  */
862ebfedea0SLionel Sambuc static int
padlock_aes_cipher_omnivorous(EVP_CIPHER_CTX * ctx,unsigned char * out_arg,const unsigned char * in_arg,size_t nbytes)863ebfedea0SLionel Sambuc padlock_aes_cipher_omnivorous(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
864ebfedea0SLionel Sambuc                               const unsigned char *in_arg, size_t nbytes)
865ebfedea0SLionel Sambuc {
866ebfedea0SLionel Sambuc     struct padlock_cipher_data *cdata;
867ebfedea0SLionel Sambuc     void *iv;
868ebfedea0SLionel Sambuc 
869ebfedea0SLionel Sambuc     cdata = ALIGNED_CIPHER_DATA(ctx);
870ebfedea0SLionel Sambuc     padlock_verify_context(cdata);
871ebfedea0SLionel Sambuc 
872ebfedea0SLionel Sambuc     switch (EVP_CIPHER_CTX_mode(ctx)) {
873ebfedea0SLionel Sambuc     case EVP_CIPH_ECB_MODE:
874ebfedea0SLionel Sambuc         padlock_xcrypt_ecb(nbytes / AES_BLOCK_SIZE, cdata, out_arg, in_arg);
875ebfedea0SLionel Sambuc         break;
876ebfedea0SLionel Sambuc 
877ebfedea0SLionel Sambuc     case EVP_CIPH_CBC_MODE:
878ebfedea0SLionel Sambuc         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
879*0a6a1f1dSLionel Sambuc         iv = padlock_xcrypt_cbc(nbytes / AES_BLOCK_SIZE, cdata, out_arg,
880*0a6a1f1dSLionel Sambuc                                 in_arg);
881ebfedea0SLionel Sambuc         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
882ebfedea0SLionel Sambuc         break;
883ebfedea0SLionel Sambuc 
884ebfedea0SLionel Sambuc     case EVP_CIPH_CFB_MODE:
885ebfedea0SLionel Sambuc         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
886*0a6a1f1dSLionel Sambuc         iv = padlock_xcrypt_cfb(nbytes / AES_BLOCK_SIZE, cdata, out_arg,
887*0a6a1f1dSLionel Sambuc                                 in_arg);
888ebfedea0SLionel Sambuc         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
889ebfedea0SLionel Sambuc         break;
890ebfedea0SLionel Sambuc 
891ebfedea0SLionel Sambuc     case EVP_CIPH_OFB_MODE:
892ebfedea0SLionel Sambuc         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
893ebfedea0SLionel Sambuc         padlock_xcrypt_ofb(nbytes / AES_BLOCK_SIZE, cdata, out_arg, in_arg);
894ebfedea0SLionel Sambuc         memcpy(ctx->iv, cdata->iv, AES_BLOCK_SIZE);
895ebfedea0SLionel Sambuc         break;
896ebfedea0SLionel Sambuc 
897ebfedea0SLionel Sambuc     default:
898ebfedea0SLionel Sambuc         return 0;
899ebfedea0SLionel Sambuc     }
900ebfedea0SLionel Sambuc 
901ebfedea0SLionel Sambuc     memset(cdata->iv, 0, AES_BLOCK_SIZE);
902ebfedea0SLionel Sambuc 
903ebfedea0SLionel Sambuc     return 1;
904ebfedea0SLionel Sambuc }
905ebfedea0SLionel Sambuc 
906ebfedea0SLionel Sambuc #    ifndef  PADLOCK_CHUNK
907ebfedea0SLionel Sambuc #     define PADLOCK_CHUNK  512 /* Must be a power of 2 larger than 16 */
908ebfedea0SLionel Sambuc #    endif
909ebfedea0SLionel Sambuc #    if PADLOCK_CHUNK<16 || PADLOCK_CHUNK&(PADLOCK_CHUNK-1)
910ebfedea0SLionel Sambuc #     error "insane PADLOCK_CHUNK..."
911ebfedea0SLionel Sambuc #    endif
912ebfedea0SLionel Sambuc 
913*0a6a1f1dSLionel Sambuc /*
914*0a6a1f1dSLionel Sambuc  * Re-align the arguments to 16-Bytes boundaries and run the encryption
915*0a6a1f1dSLionel Sambuc  * function itself. This function is not AES-specific.
916*0a6a1f1dSLionel Sambuc  */
917ebfedea0SLionel Sambuc static int
padlock_aes_cipher(EVP_CIPHER_CTX * ctx,unsigned char * out_arg,const unsigned char * in_arg,size_t nbytes)918ebfedea0SLionel Sambuc padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
919ebfedea0SLionel Sambuc                    const unsigned char *in_arg, size_t nbytes)
920ebfedea0SLionel Sambuc {
921ebfedea0SLionel Sambuc     struct padlock_cipher_data *cdata;
922ebfedea0SLionel Sambuc     const void *inp;
923ebfedea0SLionel Sambuc     unsigned char *out, *tofree;
924ebfedea0SLionel Sambuc     void *iv;
925ebfedea0SLionel Sambuc     int inp_misaligned, out_misaligned, realign_in_loop;
926ebfedea0SLionel Sambuc     size_t chunk, allocated = 0;
927ebfedea0SLionel Sambuc 
928*0a6a1f1dSLionel Sambuc     /*
929*0a6a1f1dSLionel Sambuc      * ctx->num is maintained in byte-oriented modes, such as CFB and OFB...
930*0a6a1f1dSLionel Sambuc      */
931ebfedea0SLionel Sambuc     if ((chunk = ctx->num)) {   /* borrow chunk variable */
932ebfedea0SLionel Sambuc         unsigned char *ivp = ctx->iv;
933ebfedea0SLionel Sambuc 
934ebfedea0SLionel Sambuc         switch (EVP_CIPHER_CTX_mode(ctx)) {
935ebfedea0SLionel Sambuc         case EVP_CIPH_CFB_MODE:
936ebfedea0SLionel Sambuc             if (chunk >= AES_BLOCK_SIZE)
937ebfedea0SLionel Sambuc                 return 0;       /* bogus value */
938ebfedea0SLionel Sambuc 
939ebfedea0SLionel Sambuc             if (ctx->encrypt)
940ebfedea0SLionel Sambuc                 while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
941ebfedea0SLionel Sambuc                     ivp[chunk] = *(out_arg++) = *(in_arg++) ^ ivp[chunk];
942ebfedea0SLionel Sambuc                     chunk++, nbytes--;
943*0a6a1f1dSLionel Sambuc             } else
944*0a6a1f1dSLionel Sambuc                 while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
945ebfedea0SLionel Sambuc                     unsigned char c = *(in_arg++);
946ebfedea0SLionel Sambuc                     *(out_arg++) = c ^ ivp[chunk];
947ebfedea0SLionel Sambuc                     ivp[chunk++] = c, nbytes--;
948ebfedea0SLionel Sambuc                 }
949ebfedea0SLionel Sambuc 
950ebfedea0SLionel Sambuc             ctx->num = chunk % AES_BLOCK_SIZE;
951ebfedea0SLionel Sambuc             break;
952ebfedea0SLionel Sambuc         case EVP_CIPH_OFB_MODE:
953ebfedea0SLionel Sambuc             if (chunk >= AES_BLOCK_SIZE)
954ebfedea0SLionel Sambuc                 return 0;       /* bogus value */
955ebfedea0SLionel Sambuc 
956ebfedea0SLionel Sambuc             while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
957ebfedea0SLionel Sambuc                 *(out_arg++) = *(in_arg++) ^ ivp[chunk];
958ebfedea0SLionel Sambuc                 chunk++, nbytes--;
959ebfedea0SLionel Sambuc             }
960ebfedea0SLionel Sambuc 
961ebfedea0SLionel Sambuc             ctx->num = chunk % AES_BLOCK_SIZE;
962ebfedea0SLionel Sambuc             break;
963ebfedea0SLionel Sambuc         }
964ebfedea0SLionel Sambuc     }
965ebfedea0SLionel Sambuc 
966ebfedea0SLionel Sambuc     if (nbytes == 0)
967ebfedea0SLionel Sambuc         return 1;
968ebfedea0SLionel Sambuc #    if 0
969ebfedea0SLionel Sambuc     if (nbytes % AES_BLOCK_SIZE)
970ebfedea0SLionel Sambuc         return 0;               /* are we expected to do tail processing? */
971ebfedea0SLionel Sambuc #    else
972*0a6a1f1dSLionel Sambuc     /*
973*0a6a1f1dSLionel Sambuc      * nbytes is always multiple of AES_BLOCK_SIZE in ECB and CBC modes and
974*0a6a1f1dSLionel Sambuc      * arbitrary value in byte-oriented modes, such as CFB and OFB...
975*0a6a1f1dSLionel Sambuc      */
976ebfedea0SLionel Sambuc #    endif
977ebfedea0SLionel Sambuc 
978*0a6a1f1dSLionel Sambuc     /*
979*0a6a1f1dSLionel Sambuc      * VIA promises CPUs that won't require alignment in the future. For now
980*0a6a1f1dSLionel Sambuc      * padlock_aes_align_required is initialized to 1 and the condition is
981*0a6a1f1dSLionel Sambuc      * never met...
982*0a6a1f1dSLionel Sambuc      */
983*0a6a1f1dSLionel Sambuc     /*
984*0a6a1f1dSLionel Sambuc      * C7 core is capable to manage unaligned input in non-ECB[!] mode, but
985*0a6a1f1dSLionel Sambuc      * performance penalties appear to be approximately same as for software
986*0a6a1f1dSLionel Sambuc      * alignment below or ~3x. They promise to improve it in the future, but
987*0a6a1f1dSLionel Sambuc      * for now we can just as well pretend that it can only handle aligned
988*0a6a1f1dSLionel Sambuc      * input...
989*0a6a1f1dSLionel Sambuc      */
990ebfedea0SLionel Sambuc     if (!padlock_aes_align_required && (nbytes % AES_BLOCK_SIZE) == 0)
991ebfedea0SLionel Sambuc         return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
992ebfedea0SLionel Sambuc 
993ebfedea0SLionel Sambuc     inp_misaligned = (((size_t)in_arg) & 0x0F);
994ebfedea0SLionel Sambuc     out_misaligned = (((size_t)out_arg) & 0x0F);
995ebfedea0SLionel Sambuc 
996*0a6a1f1dSLionel Sambuc     /*
997*0a6a1f1dSLionel Sambuc      * Note that even if output is aligned and input not, I still prefer to
998*0a6a1f1dSLionel Sambuc      * loop instead of copy the whole input and then encrypt in one stroke.
999*0a6a1f1dSLionel Sambuc      * This is done in order to improve L1 cache utilization...
1000*0a6a1f1dSLionel Sambuc      */
1001ebfedea0SLionel Sambuc     realign_in_loop = out_misaligned | inp_misaligned;
1002ebfedea0SLionel Sambuc 
1003ebfedea0SLionel Sambuc     if (!realign_in_loop && (nbytes % AES_BLOCK_SIZE) == 0)
1004ebfedea0SLionel Sambuc         return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
1005ebfedea0SLionel Sambuc 
1006ebfedea0SLionel Sambuc     /* this takes one "if" out of the loops */
1007ebfedea0SLionel Sambuc     chunk = nbytes;
1008ebfedea0SLionel Sambuc     chunk %= PADLOCK_CHUNK;
1009*0a6a1f1dSLionel Sambuc     if (chunk == 0)
1010*0a6a1f1dSLionel Sambuc         chunk = PADLOCK_CHUNK;
1011ebfedea0SLionel Sambuc 
1012ebfedea0SLionel Sambuc     if (out_misaligned) {
1013ebfedea0SLionel Sambuc         /* optmize for small input */
1014ebfedea0SLionel Sambuc         allocated = (chunk < nbytes ? PADLOCK_CHUNK : nbytes);
1015ebfedea0SLionel Sambuc         tofree = malloc(0x10 + allocated);
1016ebfedea0SLionel Sambuc         if (tofree == NULL)
1017ebfedea0SLionel Sambuc             return 0;
1018ebfedea0SLionel Sambuc         out = NEAREST_ALIGNED(tofree);
1019*0a6a1f1dSLionel Sambuc     } else {
1020ebfedea0SLionel Sambuc         out = out_arg;
1021ebfedea0SLionel Sambuc         tofree = NULL;
1022ebfedea0SLionel Sambuc     }
1023ebfedea0SLionel Sambuc 
1024ebfedea0SLionel Sambuc     cdata = ALIGNED_CIPHER_DATA(ctx);
1025ebfedea0SLionel Sambuc     padlock_verify_context(cdata);
1026ebfedea0SLionel Sambuc 
1027ebfedea0SLionel Sambuc     switch (EVP_CIPHER_CTX_mode(ctx)) {
1028ebfedea0SLionel Sambuc     case EVP_CIPH_ECB_MODE:
1029ebfedea0SLionel Sambuc         do {
1030ebfedea0SLionel Sambuc             if (inp_misaligned)
1031ebfedea0SLionel Sambuc                 inp = padlock_memcpy(out, in_arg, chunk);
1032ebfedea0SLionel Sambuc             else
1033ebfedea0SLionel Sambuc                 inp = in_arg;
1034ebfedea0SLionel Sambuc             in_arg += chunk;
1035ebfedea0SLionel Sambuc 
1036ebfedea0SLionel Sambuc             padlock_xcrypt_ecb(chunk / AES_BLOCK_SIZE, cdata, out, inp);
1037ebfedea0SLionel Sambuc 
1038ebfedea0SLionel Sambuc             if (out_misaligned)
1039ebfedea0SLionel Sambuc                 out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
1040ebfedea0SLionel Sambuc             else
1041ebfedea0SLionel Sambuc                 out = out_arg += chunk;
1042ebfedea0SLionel Sambuc 
1043ebfedea0SLionel Sambuc             nbytes -= chunk;
1044ebfedea0SLionel Sambuc             chunk = PADLOCK_CHUNK;
1045ebfedea0SLionel Sambuc         } while (nbytes);
1046ebfedea0SLionel Sambuc         break;
1047ebfedea0SLionel Sambuc 
1048ebfedea0SLionel Sambuc     case EVP_CIPH_CBC_MODE:
1049ebfedea0SLionel Sambuc         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
1050ebfedea0SLionel Sambuc         goto cbc_shortcut;
1051ebfedea0SLionel Sambuc         do {
1052ebfedea0SLionel Sambuc             if (iv != cdata->iv)
1053ebfedea0SLionel Sambuc                 memcpy(cdata->iv, iv, AES_BLOCK_SIZE);
1054ebfedea0SLionel Sambuc             chunk = PADLOCK_CHUNK;
1055ebfedea0SLionel Sambuc  cbc_shortcut:                 /* optimize for small input */
1056ebfedea0SLionel Sambuc             if (inp_misaligned)
1057ebfedea0SLionel Sambuc                 inp = padlock_memcpy(out, in_arg, chunk);
1058ebfedea0SLionel Sambuc             else
1059ebfedea0SLionel Sambuc                 inp = in_arg;
1060ebfedea0SLionel Sambuc             in_arg += chunk;
1061ebfedea0SLionel Sambuc 
1062ebfedea0SLionel Sambuc             iv = padlock_xcrypt_cbc(chunk / AES_BLOCK_SIZE, cdata, out, inp);
1063ebfedea0SLionel Sambuc 
1064ebfedea0SLionel Sambuc             if (out_misaligned)
1065ebfedea0SLionel Sambuc                 out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
1066ebfedea0SLionel Sambuc             else
1067ebfedea0SLionel Sambuc                 out = out_arg += chunk;
1068ebfedea0SLionel Sambuc 
1069ebfedea0SLionel Sambuc         } while (nbytes -= chunk);
1070ebfedea0SLionel Sambuc         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
1071ebfedea0SLionel Sambuc         break;
1072ebfedea0SLionel Sambuc 
1073ebfedea0SLionel Sambuc     case EVP_CIPH_CFB_MODE:
1074ebfedea0SLionel Sambuc         memcpy(iv = cdata->iv, ctx->iv, AES_BLOCK_SIZE);
1075ebfedea0SLionel Sambuc         chunk &= ~(AES_BLOCK_SIZE - 1);
1076*0a6a1f1dSLionel Sambuc         if (chunk)
1077*0a6a1f1dSLionel Sambuc             goto cfb_shortcut;
1078*0a6a1f1dSLionel Sambuc         else
1079*0a6a1f1dSLionel Sambuc             goto cfb_skiploop;
1080ebfedea0SLionel Sambuc         do {
1081ebfedea0SLionel Sambuc             if (iv != cdata->iv)
1082ebfedea0SLionel Sambuc                 memcpy(cdata->iv, iv, AES_BLOCK_SIZE);
1083ebfedea0SLionel Sambuc             chunk = PADLOCK_CHUNK;
1084ebfedea0SLionel Sambuc  cfb_shortcut:                 /* optimize for small input */
1085ebfedea0SLionel Sambuc             if (inp_misaligned)
1086ebfedea0SLionel Sambuc                 inp = padlock_memcpy(out, in_arg, chunk);
1087ebfedea0SLionel Sambuc             else
1088ebfedea0SLionel Sambuc                 inp = in_arg;
1089ebfedea0SLionel Sambuc             in_arg += chunk;
1090ebfedea0SLionel Sambuc 
1091ebfedea0SLionel Sambuc             iv = padlock_xcrypt_cfb(chunk / AES_BLOCK_SIZE, cdata, out, inp);
1092ebfedea0SLionel Sambuc 
1093ebfedea0SLionel Sambuc             if (out_misaligned)
1094ebfedea0SLionel Sambuc                 out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
1095ebfedea0SLionel Sambuc             else
1096ebfedea0SLionel Sambuc                 out = out_arg += chunk;
1097ebfedea0SLionel Sambuc 
1098ebfedea0SLionel Sambuc             nbytes -= chunk;
1099ebfedea0SLionel Sambuc         } while (nbytes >= AES_BLOCK_SIZE);
1100ebfedea0SLionel Sambuc 
1101ebfedea0SLionel Sambuc  cfb_skiploop:
1102ebfedea0SLionel Sambuc         if (nbytes) {
1103ebfedea0SLionel Sambuc             unsigned char *ivp = cdata->iv;
1104ebfedea0SLionel Sambuc 
1105ebfedea0SLionel Sambuc             if (iv != ivp) {
1106ebfedea0SLionel Sambuc                 memcpy(ivp, iv, AES_BLOCK_SIZE);
1107ebfedea0SLionel Sambuc                 iv = ivp;
1108ebfedea0SLionel Sambuc             }
1109ebfedea0SLionel Sambuc             ctx->num = nbytes;
1110ebfedea0SLionel Sambuc             if (cdata->cword.b.encdec) {
1111ebfedea0SLionel Sambuc                 cdata->cword.b.encdec = 0;
1112ebfedea0SLionel Sambuc                 padlock_reload_key();
1113ebfedea0SLionel Sambuc                 padlock_xcrypt_ecb(1, cdata, ivp, ivp);
1114ebfedea0SLionel Sambuc                 cdata->cword.b.encdec = 1;
1115ebfedea0SLionel Sambuc                 padlock_reload_key();
1116ebfedea0SLionel Sambuc                 while (nbytes) {
1117ebfedea0SLionel Sambuc                     unsigned char c = *(in_arg++);
1118ebfedea0SLionel Sambuc                     *(out_arg++) = c ^ *ivp;
1119ebfedea0SLionel Sambuc                     *(ivp++) = c, nbytes--;
1120ebfedea0SLionel Sambuc                 }
1121*0a6a1f1dSLionel Sambuc             } else {
1122*0a6a1f1dSLionel Sambuc                 padlock_reload_key();
1123ebfedea0SLionel Sambuc                 padlock_xcrypt_ecb(1, cdata, ivp, ivp);
1124ebfedea0SLionel Sambuc                 padlock_reload_key();
1125ebfedea0SLionel Sambuc                 while (nbytes) {
1126ebfedea0SLionel Sambuc                     *ivp = *(out_arg++) = *(in_arg++) ^ *ivp;
1127ebfedea0SLionel Sambuc                     ivp++, nbytes--;
1128ebfedea0SLionel Sambuc                 }
1129ebfedea0SLionel Sambuc             }
1130ebfedea0SLionel Sambuc         }
1131ebfedea0SLionel Sambuc 
1132ebfedea0SLionel Sambuc         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
1133ebfedea0SLionel Sambuc         break;
1134ebfedea0SLionel Sambuc 
1135ebfedea0SLionel Sambuc     case EVP_CIPH_OFB_MODE:
1136ebfedea0SLionel Sambuc         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
1137ebfedea0SLionel Sambuc         chunk &= ~(AES_BLOCK_SIZE - 1);
1138*0a6a1f1dSLionel Sambuc         if (chunk)
1139*0a6a1f1dSLionel Sambuc             do {
1140ebfedea0SLionel Sambuc                 if (inp_misaligned)
1141ebfedea0SLionel Sambuc                     inp = padlock_memcpy(out, in_arg, chunk);
1142ebfedea0SLionel Sambuc                 else
1143ebfedea0SLionel Sambuc                     inp = in_arg;
1144ebfedea0SLionel Sambuc                 in_arg += chunk;
1145ebfedea0SLionel Sambuc 
1146ebfedea0SLionel Sambuc                 padlock_xcrypt_ofb(chunk / AES_BLOCK_SIZE, cdata, out, inp);
1147ebfedea0SLionel Sambuc 
1148ebfedea0SLionel Sambuc                 if (out_misaligned)
1149ebfedea0SLionel Sambuc                     out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
1150ebfedea0SLionel Sambuc                 else
1151ebfedea0SLionel Sambuc                     out = out_arg += chunk;
1152ebfedea0SLionel Sambuc 
1153ebfedea0SLionel Sambuc                 nbytes -= chunk;
1154ebfedea0SLionel Sambuc                 chunk = PADLOCK_CHUNK;
1155ebfedea0SLionel Sambuc             } while (nbytes >= AES_BLOCK_SIZE);
1156ebfedea0SLionel Sambuc 
1157ebfedea0SLionel Sambuc         if (nbytes) {
1158ebfedea0SLionel Sambuc             unsigned char *ivp = cdata->iv;
1159ebfedea0SLionel Sambuc 
1160ebfedea0SLionel Sambuc             ctx->num = nbytes;
1161ebfedea0SLionel Sambuc             padlock_reload_key(); /* empirically found */
1162ebfedea0SLionel Sambuc             padlock_xcrypt_ecb(1, cdata, ivp, ivp);
1163ebfedea0SLionel Sambuc             padlock_reload_key(); /* empirically found */
1164ebfedea0SLionel Sambuc             while (nbytes) {
1165ebfedea0SLionel Sambuc                 *(out_arg++) = *(in_arg++) ^ *ivp;
1166ebfedea0SLionel Sambuc                 ivp++, nbytes--;
1167ebfedea0SLionel Sambuc             }
1168ebfedea0SLionel Sambuc         }
1169ebfedea0SLionel Sambuc 
1170ebfedea0SLionel Sambuc         memcpy(ctx->iv, cdata->iv, AES_BLOCK_SIZE);
1171ebfedea0SLionel Sambuc         break;
1172ebfedea0SLionel Sambuc 
1173ebfedea0SLionel Sambuc     default:
1174ebfedea0SLionel Sambuc         free(tofree);
1175ebfedea0SLionel Sambuc         return 0;
1176ebfedea0SLionel Sambuc     }
1177ebfedea0SLionel Sambuc 
1178ebfedea0SLionel Sambuc     /* Clean the realign buffer if it was used */
1179ebfedea0SLionel Sambuc     if (out_misaligned) {
1180ebfedea0SLionel Sambuc         volatile unsigned long *p = (void *)out;
1181ebfedea0SLionel Sambuc         size_t n = allocated / sizeof(*p);
1182*0a6a1f1dSLionel Sambuc         while (n--)
1183*0a6a1f1dSLionel Sambuc             *p++ = 0;
1184ebfedea0SLionel Sambuc     }
1185ebfedea0SLionel Sambuc 
1186ebfedea0SLionel Sambuc     memset(cdata->iv, 0, AES_BLOCK_SIZE);
1187ebfedea0SLionel Sambuc     free(tofree);
1188ebfedea0SLionel Sambuc 
1189ebfedea0SLionel Sambuc     return 1;
1190ebfedea0SLionel Sambuc }
1191ebfedea0SLionel Sambuc 
1192ebfedea0SLionel Sambuc #   endif                       /* OPENSSL_NO_AES */
1193ebfedea0SLionel Sambuc 
1194ebfedea0SLionel Sambuc /* ===== Random Number Generator ===== */
1195ebfedea0SLionel Sambuc /*
1196ebfedea0SLionel Sambuc  * This code is not engaged. The reason is that it does not comply
1197ebfedea0SLionel Sambuc  * with recommendations for VIA RNG usage for secure applications
1198ebfedea0SLionel Sambuc  * (posted at http://www.via.com.tw/en/viac3/c3.jsp) nor does it
1199ebfedea0SLionel Sambuc  * provide meaningful error control...
1200ebfedea0SLionel Sambuc  */
1201*0a6a1f1dSLionel Sambuc /*
1202*0a6a1f1dSLionel Sambuc  * Wrapper that provides an interface between the API and the raw PadLock
1203*0a6a1f1dSLionel Sambuc  * RNG
1204*0a6a1f1dSLionel Sambuc  */
padlock_rand_bytes(unsigned char * output,int count)1205*0a6a1f1dSLionel Sambuc static int padlock_rand_bytes(unsigned char *output, int count)
1206ebfedea0SLionel Sambuc {
1207ebfedea0SLionel Sambuc     unsigned int eax, buf;
1208ebfedea0SLionel Sambuc 
1209ebfedea0SLionel Sambuc     while (count >= 8) {
1210ebfedea0SLionel Sambuc         eax = padlock_xstore(output, 0);
1211*0a6a1f1dSLionel Sambuc         if (!(eax & (1 << 6)))
1212*0a6a1f1dSLionel Sambuc             return 0;           /* RNG disabled */
1213ebfedea0SLionel Sambuc         /* this ---vv--- covers DC bias, Raw Bits and String Filter */
1214*0a6a1f1dSLionel Sambuc         if (eax & (0x1F << 10))
1215*0a6a1f1dSLionel Sambuc             return 0;
1216*0a6a1f1dSLionel Sambuc         if ((eax & 0x1F) == 0)
1217*0a6a1f1dSLionel Sambuc             continue;           /* no data, retry... */
1218*0a6a1f1dSLionel Sambuc         if ((eax & 0x1F) != 8)
1219*0a6a1f1dSLionel Sambuc             return 0;           /* fatal failure...  */
1220ebfedea0SLionel Sambuc         output += 8;
1221ebfedea0SLionel Sambuc         count -= 8;
1222ebfedea0SLionel Sambuc     }
1223ebfedea0SLionel Sambuc     while (count > 0) {
1224ebfedea0SLionel Sambuc         eax = padlock_xstore(&buf, 3);
1225*0a6a1f1dSLionel Sambuc         if (!(eax & (1 << 6)))
1226*0a6a1f1dSLionel Sambuc             return 0;           /* RNG disabled */
1227ebfedea0SLionel Sambuc         /* this ---vv--- covers DC bias, Raw Bits and String Filter */
1228*0a6a1f1dSLionel Sambuc         if (eax & (0x1F << 10))
1229*0a6a1f1dSLionel Sambuc             return 0;
1230*0a6a1f1dSLionel Sambuc         if ((eax & 0x1F) == 0)
1231*0a6a1f1dSLionel Sambuc             continue;           /* no data, retry... */
1232*0a6a1f1dSLionel Sambuc         if ((eax & 0x1F) != 1)
1233*0a6a1f1dSLionel Sambuc             return 0;           /* fatal failure...  */
1234ebfedea0SLionel Sambuc         *output++ = (unsigned char)buf;
1235ebfedea0SLionel Sambuc         count--;
1236ebfedea0SLionel Sambuc     }
1237ebfedea0SLionel Sambuc     *(volatile unsigned int *)&buf = 0;
1238ebfedea0SLionel Sambuc 
1239ebfedea0SLionel Sambuc     return 1;
1240ebfedea0SLionel Sambuc }
1241ebfedea0SLionel Sambuc 
1242ebfedea0SLionel Sambuc /* Dummy but necessary function */
padlock_rand_status(void)1243*0a6a1f1dSLionel Sambuc static int padlock_rand_status(void)
1244ebfedea0SLionel Sambuc {
1245ebfedea0SLionel Sambuc     return 1;
1246ebfedea0SLionel Sambuc }
1247ebfedea0SLionel Sambuc 
1248ebfedea0SLionel Sambuc /* Prepare structure for registration */
1249ebfedea0SLionel Sambuc static RAND_METHOD padlock_rand = {
1250ebfedea0SLionel Sambuc     NULL,                       /* seed */
1251ebfedea0SLionel Sambuc     padlock_rand_bytes,         /* bytes */
1252ebfedea0SLionel Sambuc     NULL,                       /* cleanup */
1253ebfedea0SLionel Sambuc     NULL,                       /* add */
1254ebfedea0SLionel Sambuc     padlock_rand_bytes,         /* pseudorand */
1255ebfedea0SLionel Sambuc     padlock_rand_status,        /* rand status */
1256ebfedea0SLionel Sambuc };
1257ebfedea0SLionel Sambuc 
1258ebfedea0SLionel Sambuc #  else                         /* !COMPILE_HW_PADLOCK */
1259ebfedea0SLionel Sambuc #   ifndef OPENSSL_NO_DYNAMIC_ENGINE
1260ebfedea0SLionel Sambuc OPENSSL_EXPORT
1261ebfedea0SLionel Sambuc     int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
1262ebfedea0SLionel Sambuc OPENSSL_EXPORT
bind_engine(ENGINE * e,const char * id,const dynamic_fns * fns)1263*0a6a1f1dSLionel Sambuc     int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
1264*0a6a1f1dSLionel Sambuc {
1265*0a6a1f1dSLionel Sambuc     return 0;
1266*0a6a1f1dSLionel Sambuc }
1267*0a6a1f1dSLionel Sambuc 
1268ebfedea0SLionel Sambuc IMPLEMENT_DYNAMIC_CHECK_FN()
1269ebfedea0SLionel Sambuc #   endif
1270ebfedea0SLionel Sambuc #  endif                        /* COMPILE_HW_PADLOCK */
1271ebfedea0SLionel Sambuc # endif                         /* !OPENSSL_NO_HW_PADLOCK */
1272ebfedea0SLionel Sambuc #endif                          /* !OPENSSL_NO_HW */
1273