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