xref: /freebsd/crypto/openssl/engines/e_padlock.c (revision 6f9291ce)
16f9291ceSJung-uk Kim /*-
21f13597dSJung-uk Kim  * Support for VIA PadLock Advanced Cryptography Engine (ACE)
31f13597dSJung-uk Kim  * Written by Michal Ludvig <michal@logix.cz>
41f13597dSJung-uk Kim  *            http://www.logix.cz/michal
51f13597dSJung-uk Kim  *
61f13597dSJung-uk Kim  * Big thanks to Andy Polyakov for a help with optimization,
71f13597dSJung-uk Kim  * assembler fixes, port to MS Windows and a lot of other
81f13597dSJung-uk Kim  * valuable work on this engine!
91f13597dSJung-uk Kim  */
101f13597dSJung-uk Kim 
111f13597dSJung-uk Kim /* ====================================================================
121f13597dSJung-uk Kim  * Copyright (c) 1999-2001 The OpenSSL Project.  All rights reserved.
131f13597dSJung-uk Kim  *
141f13597dSJung-uk Kim  * Redistribution and use in source and binary forms, with or without
151f13597dSJung-uk Kim  * modification, are permitted provided that the following conditions
161f13597dSJung-uk Kim  * are met:
171f13597dSJung-uk Kim  *
181f13597dSJung-uk Kim  * 1. Redistributions of source code must retain the above copyright
191f13597dSJung-uk Kim  *    notice, this list of conditions and the following disclaimer.
201f13597dSJung-uk Kim  *
211f13597dSJung-uk Kim  * 2. Redistributions in binary form must reproduce the above copyright
221f13597dSJung-uk Kim  *    notice, this list of conditions and the following disclaimer in
231f13597dSJung-uk Kim  *    the documentation and/or other materials provided with the
241f13597dSJung-uk Kim  *    distribution.
251f13597dSJung-uk Kim  *
261f13597dSJung-uk Kim  * 3. All advertising materials mentioning features or use of this
271f13597dSJung-uk Kim  *    software must display the following acknowledgment:
281f13597dSJung-uk Kim  *    "This product includes software developed by the OpenSSL Project
291f13597dSJung-uk Kim  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
301f13597dSJung-uk Kim  *
311f13597dSJung-uk Kim  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
321f13597dSJung-uk Kim  *    endorse or promote products derived from this software without
331f13597dSJung-uk Kim  *    prior written permission. For written permission, please contact
341f13597dSJung-uk Kim  *    licensing@OpenSSL.org.
351f13597dSJung-uk Kim  *
361f13597dSJung-uk Kim  * 5. Products derived from this software may not be called "OpenSSL"
371f13597dSJung-uk Kim  *    nor may "OpenSSL" appear in their names without prior written
381f13597dSJung-uk Kim  *    permission of the OpenSSL Project.
391f13597dSJung-uk Kim  *
401f13597dSJung-uk Kim  * 6. Redistributions of any form whatsoever must retain the following
411f13597dSJung-uk Kim  *    acknowledgment:
421f13597dSJung-uk Kim  *    "This product includes software developed by the OpenSSL Project
431f13597dSJung-uk Kim  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
441f13597dSJung-uk Kim  *
451f13597dSJung-uk Kim  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
461f13597dSJung-uk Kim  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
471f13597dSJung-uk Kim  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
481f13597dSJung-uk Kim  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
491f13597dSJung-uk Kim  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
501f13597dSJung-uk Kim  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
511f13597dSJung-uk Kim  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
521f13597dSJung-uk Kim  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
531f13597dSJung-uk Kim  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
541f13597dSJung-uk Kim  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
551f13597dSJung-uk Kim  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
561f13597dSJung-uk Kim  * OF THE POSSIBILITY OF SUCH DAMAGE.
571f13597dSJung-uk Kim  * ====================================================================
581f13597dSJung-uk Kim  *
591f13597dSJung-uk Kim  * This product includes cryptographic software written by Eric Young
601f13597dSJung-uk Kim  * (eay@cryptsoft.com).  This product includes software written by Tim
611f13597dSJung-uk Kim  * Hudson (tjh@cryptsoft.com).
621f13597dSJung-uk Kim  *
631f13597dSJung-uk Kim  */
641f13597dSJung-uk Kim 
651f13597dSJung-uk Kim #include <stdio.h>
661f13597dSJung-uk Kim #include <string.h>
671f13597dSJung-uk Kim 
681f13597dSJung-uk Kim #include <openssl/opensslconf.h>
691f13597dSJung-uk Kim #include <openssl/crypto.h>
701f13597dSJung-uk Kim #include <openssl/dso.h>
711f13597dSJung-uk Kim #include <openssl/engine.h>
721f13597dSJung-uk Kim #include <openssl/evp.h>
731f13597dSJung-uk Kim #ifndef OPENSSL_NO_AES
741f13597dSJung-uk Kim # include <openssl/aes.h>
751f13597dSJung-uk Kim #endif
761f13597dSJung-uk Kim #include <openssl/rand.h>
771f13597dSJung-uk Kim #include <openssl/err.h>
781f13597dSJung-uk Kim 
791f13597dSJung-uk Kim #ifndef OPENSSL_NO_HW
801f13597dSJung-uk Kim # ifndef OPENSSL_NO_HW_PADLOCK
811f13597dSJung-uk Kim 
821f13597dSJung-uk Kim /* Attempt to have a single source for both 0.9.7 and 0.9.8 :-) */
831f13597dSJung-uk Kim #  if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
841f13597dSJung-uk Kim #   ifndef OPENSSL_NO_DYNAMIC_ENGINE
851f13597dSJung-uk Kim #    define DYNAMIC_ENGINE
861f13597dSJung-uk Kim #   endif
871f13597dSJung-uk Kim #  elif (OPENSSL_VERSION_NUMBER >= 0x00907000L)
881f13597dSJung-uk Kim #   ifdef ENGINE_DYNAMIC_SUPPORT
891f13597dSJung-uk Kim #    define DYNAMIC_ENGINE
901f13597dSJung-uk Kim #   endif
911f13597dSJung-uk Kim #  else
921f13597dSJung-uk Kim #   error "Only OpenSSL >= 0.9.7 is supported"
931f13597dSJung-uk Kim #  endif
941f13597dSJung-uk Kim 
956f9291ceSJung-uk Kim /*
966f9291ceSJung-uk Kim  * VIA PadLock AES is available *ONLY* on some x86 CPUs. Not only that it
976f9291ceSJung-uk Kim  * doesn't exist elsewhere, but it even can't be compiled on other platforms!
986f9291ceSJung-uk Kim  *
996f9291ceSJung-uk Kim  * In addition, because of the heavy use of inline assembler, compiler choice
1006f9291ceSJung-uk Kim  * is limited to GCC and Microsoft C.
1016f9291ceSJung-uk Kim  */
1021f13597dSJung-uk Kim #  undef COMPILE_HW_PADLOCK
1031f13597dSJung-uk Kim #  if !defined(I386_ONLY) && !defined(OPENSSL_NO_INLINE_ASM)
1041f13597dSJung-uk Kim #   if (defined(__GNUC__) && (defined(__i386__) || defined(__i386))) || \
1051f13597dSJung-uk Kim      (defined(_MSC_VER) && defined(_M_IX86))
1061f13597dSJung-uk Kim #    define COMPILE_HW_PADLOCK
1071f13597dSJung-uk Kim #   endif
1081f13597dSJung-uk Kim #  endif
1091f13597dSJung-uk Kim 
1101f13597dSJung-uk Kim #  ifdef OPENSSL_NO_DYNAMIC_ENGINE
1111f13597dSJung-uk Kim #   ifdef COMPILE_HW_PADLOCK
1121f13597dSJung-uk Kim static ENGINE *ENGINE_padlock(void);
1131f13597dSJung-uk Kim #   endif
1141f13597dSJung-uk Kim 
1151f13597dSJung-uk Kim void ENGINE_load_padlock(void)
1161f13597dSJung-uk Kim {
1171f13597dSJung-uk Kim /* On non-x86 CPUs it just returns. */
1181f13597dSJung-uk Kim #   ifdef COMPILE_HW_PADLOCK
1191f13597dSJung-uk Kim     ENGINE *toadd = ENGINE_padlock();
1206f9291ceSJung-uk Kim     if (!toadd)
1216f9291ceSJung-uk Kim         return;
1221f13597dSJung-uk Kim     ENGINE_add(toadd);
1231f13597dSJung-uk Kim     ENGINE_free(toadd);
1241f13597dSJung-uk Kim     ERR_clear_error();
1251f13597dSJung-uk Kim #   endif
1261f13597dSJung-uk Kim }
1271f13597dSJung-uk Kim 
1281f13597dSJung-uk Kim #  endif
1291f13597dSJung-uk Kim 
1301f13597dSJung-uk Kim #  ifdef COMPILE_HW_PADLOCK
1316f9291ceSJung-uk Kim /*
1326f9291ceSJung-uk Kim  * We do these includes here to avoid header problems on platforms that do
1336f9291ceSJung-uk Kim  * not have the VIA padlock anyway...
1346f9291ceSJung-uk Kim  */
1351f13597dSJung-uk Kim #   include <stdlib.h>
1361f13597dSJung-uk Kim #   ifdef _WIN32
1371f13597dSJung-uk Kim #    include <malloc.h>
1381f13597dSJung-uk Kim #    ifndef alloca
1391f13597dSJung-uk Kim #     define alloca _alloca
1401f13597dSJung-uk Kim #    endif
1411f13597dSJung-uk Kim #   elif defined(__GNUC__)
1421f13597dSJung-uk Kim #    ifndef alloca
1431f13597dSJung-uk Kim #     define alloca(s) __builtin_alloca(s)
1441f13597dSJung-uk Kim #    endif
1451f13597dSJung-uk Kim #   endif
1461f13597dSJung-uk Kim 
1471f13597dSJung-uk Kim /* Function for ENGINE detection and control */
1481f13597dSJung-uk Kim static int padlock_available(void);
1491f13597dSJung-uk Kim static int padlock_init(ENGINE *e);
1501f13597dSJung-uk Kim 
1511f13597dSJung-uk Kim /* RNG Stuff */
1521f13597dSJung-uk Kim static RAND_METHOD padlock_rand;
1531f13597dSJung-uk Kim 
1541f13597dSJung-uk Kim /* Cipher Stuff */
1551f13597dSJung-uk Kim #   ifndef OPENSSL_NO_AES
1566f9291ceSJung-uk Kim static int padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
1576f9291ceSJung-uk Kim                            const int **nids, int nid);
1581f13597dSJung-uk Kim #   endif
1591f13597dSJung-uk Kim 
1601f13597dSJung-uk Kim /* Engine names */
1611f13597dSJung-uk Kim static const char *padlock_id = "padlock";
1621f13597dSJung-uk Kim static char padlock_name[100];
1631f13597dSJung-uk Kim 
1641f13597dSJung-uk Kim /* Available features */
1651f13597dSJung-uk Kim static int padlock_use_ace = 0; /* Advanced Cryptography Engine */
1661f13597dSJung-uk Kim static int padlock_use_rng = 0; /* Random Number Generator */
1671f13597dSJung-uk Kim #   ifndef OPENSSL_NO_AES
1681f13597dSJung-uk Kim static int padlock_aes_align_required = 1;
1691f13597dSJung-uk Kim #   endif
1701f13597dSJung-uk Kim 
1711f13597dSJung-uk Kim /* ===== Engine "management" functions ===== */
1721f13597dSJung-uk Kim 
1731f13597dSJung-uk Kim /* Prepare the ENGINE structure for registration */
1746f9291ceSJung-uk Kim static int padlock_bind_helper(ENGINE *e)
1751f13597dSJung-uk Kim {
1761f13597dSJung-uk Kim     /* Check available features */
1771f13597dSJung-uk Kim     padlock_available();
1781f13597dSJung-uk Kim 
1796f9291ceSJung-uk Kim #   if 1                        /* disable RNG for now, see commentary in
1806f9291ceSJung-uk Kim                                  * vicinity of RNG code */
1811f13597dSJung-uk Kim     padlock_use_rng = 0;
1821f13597dSJung-uk Kim #   endif
1831f13597dSJung-uk Kim 
1841f13597dSJung-uk Kim     /* Generate a nice engine name with available features */
1851f13597dSJung-uk Kim     BIO_snprintf(padlock_name, sizeof(padlock_name),
1861f13597dSJung-uk Kim                  "VIA PadLock (%s, %s)",
1871f13597dSJung-uk Kim                  padlock_use_rng ? "RNG" : "no-RNG",
1881f13597dSJung-uk Kim                  padlock_use_ace ? "ACE" : "no-ACE");
1891f13597dSJung-uk Kim 
1901f13597dSJung-uk Kim     /* Register everything or return with an error */
1911f13597dSJung-uk Kim     if (!ENGINE_set_id(e, padlock_id) ||
1921f13597dSJung-uk Kim         !ENGINE_set_name(e, padlock_name) ||
1931f13597dSJung-uk Kim         !ENGINE_set_init_function(e, padlock_init) ||
1941f13597dSJung-uk Kim #   ifndef OPENSSL_NO_AES
1951f13597dSJung-uk Kim         (padlock_use_ace && !ENGINE_set_ciphers(e, padlock_ciphers)) ||
1961f13597dSJung-uk Kim #   endif
1971f13597dSJung-uk Kim         (padlock_use_rng && !ENGINE_set_RAND(e, &padlock_rand))) {
1981f13597dSJung-uk Kim         return 0;
1991f13597dSJung-uk Kim     }
2001f13597dSJung-uk Kim 
2011f13597dSJung-uk Kim     /* Everything looks good */
2021f13597dSJung-uk Kim     return 1;
2031f13597dSJung-uk Kim }
2041f13597dSJung-uk Kim 
2051f13597dSJung-uk Kim #   ifdef OPENSSL_NO_DYNAMIC_ENGINE
2061f13597dSJung-uk Kim 
2071f13597dSJung-uk Kim /* Constructor */
2086f9291ceSJung-uk Kim static ENGINE *ENGINE_padlock(void)
2091f13597dSJung-uk Kim {
2101f13597dSJung-uk Kim     ENGINE *eng = ENGINE_new();
2111f13597dSJung-uk Kim 
2121f13597dSJung-uk Kim     if (!eng) {
2131f13597dSJung-uk Kim         return NULL;
2141f13597dSJung-uk Kim     }
2151f13597dSJung-uk Kim 
2161f13597dSJung-uk Kim     if (!padlock_bind_helper(eng)) {
2171f13597dSJung-uk Kim         ENGINE_free(eng);
2181f13597dSJung-uk Kim         return NULL;
2191f13597dSJung-uk Kim     }
2201f13597dSJung-uk Kim 
2211f13597dSJung-uk Kim     return eng;
2221f13597dSJung-uk Kim }
2231f13597dSJung-uk Kim 
2241f13597dSJung-uk Kim #   endif
2251f13597dSJung-uk Kim 
2261f13597dSJung-uk Kim /* Check availability of the engine */
2276f9291ceSJung-uk Kim static int padlock_init(ENGINE *e)
2281f13597dSJung-uk Kim {
2291f13597dSJung-uk Kim     return (padlock_use_rng || padlock_use_ace);
2301f13597dSJung-uk Kim }
2311f13597dSJung-uk Kim 
2326f9291ceSJung-uk Kim /*
2336f9291ceSJung-uk Kim  * This stuff is needed if this ENGINE is being compiled into a
2346f9291ceSJung-uk Kim  * self-contained shared-library.
2351f13597dSJung-uk Kim  */
2361f13597dSJung-uk Kim #   ifdef DYNAMIC_ENGINE
2376f9291ceSJung-uk Kim static int padlock_bind_fn(ENGINE *e, const char *id)
2381f13597dSJung-uk Kim {
2391f13597dSJung-uk Kim     if (id && (strcmp(id, padlock_id) != 0)) {
2401f13597dSJung-uk Kim         return 0;
2411f13597dSJung-uk Kim     }
2421f13597dSJung-uk Kim 
2431f13597dSJung-uk Kim     if (!padlock_bind_helper(e)) {
2441f13597dSJung-uk Kim         return 0;
2451f13597dSJung-uk Kim     }
2461f13597dSJung-uk Kim 
2471f13597dSJung-uk Kim     return 1;
2481f13597dSJung-uk Kim }
2491f13597dSJung-uk Kim 
2501f13597dSJung-uk Kim IMPLEMENT_DYNAMIC_CHECK_FN()
2511f13597dSJung-uk Kim     IMPLEMENT_DYNAMIC_BIND_FN(padlock_bind_fn)
2521f13597dSJung-uk Kim #   endif                       /* DYNAMIC_ENGINE */
2531f13597dSJung-uk Kim /* ===== Here comes the "real" engine ===== */
2541f13597dSJung-uk Kim #   ifndef OPENSSL_NO_AES
2551f13597dSJung-uk Kim /* Some AES-related constants */
2561f13597dSJung-uk Kim #    define AES_BLOCK_SIZE          16
2571f13597dSJung-uk Kim #    define AES_KEY_SIZE_128        16
2581f13597dSJung-uk Kim #    define AES_KEY_SIZE_192        24
2591f13597dSJung-uk Kim #    define AES_KEY_SIZE_256        32
2606f9291ceSJung-uk Kim     /*
2616f9291ceSJung-uk Kim      * Here we store the status information relevant to the current context.
2621f13597dSJung-uk Kim      */
2636f9291ceSJung-uk Kim     /*
2646f9291ceSJung-uk Kim      * BIG FAT WARNING: Inline assembler in PADLOCK_XCRYPT_ASM() depends on
2656f9291ceSJung-uk Kim      * the order of items in this structure.  Don't blindly modify, reorder,
2666f9291ceSJung-uk Kim      * etc!
2676f9291ceSJung-uk Kim      */
2686f9291ceSJung-uk Kim struct padlock_cipher_data {
2691f13597dSJung-uk Kim     unsigned char iv[AES_BLOCK_SIZE]; /* Initialization vector */
2706f9291ceSJung-uk Kim     union {
2716f9291ceSJung-uk Kim         unsigned int pad[4];
2721f13597dSJung-uk Kim         struct {
2731f13597dSJung-uk Kim             int rounds:4;
2741f13597dSJung-uk Kim             int dgst:1;         /* n/a in C3 */
2751f13597dSJung-uk Kim             int align:1;        /* n/a in C3 */
2761f13597dSJung-uk Kim             int ciphr:1;        /* n/a in C3 */
2771f13597dSJung-uk Kim             unsigned int keygen:1;
2781f13597dSJung-uk Kim             int interm:1;
2791f13597dSJung-uk Kim             unsigned int encdec:1;
2801f13597dSJung-uk Kim             int ksize:2;
2811f13597dSJung-uk Kim         } b;
2821f13597dSJung-uk Kim     } cword;                    /* Control word */
2831f13597dSJung-uk Kim     AES_KEY ks;                 /* Encryption key */
2841f13597dSJung-uk Kim };
2851f13597dSJung-uk Kim 
2861f13597dSJung-uk Kim /*
2871f13597dSJung-uk Kim  * Essentially this variable belongs in thread local storage.
2881f13597dSJung-uk Kim  * Having this variable global on the other hand can only cause
2891f13597dSJung-uk Kim  * few bogus key reloads [if any at all on single-CPU system],
2901f13597dSJung-uk Kim  * so we accept the penatly...
2911f13597dSJung-uk Kim  */
2921f13597dSJung-uk Kim static volatile struct padlock_cipher_data *padlock_saved_context;
2931f13597dSJung-uk Kim #   endif
2941f13597dSJung-uk Kim 
2956f9291ceSJung-uk Kim /*-
2961f13597dSJung-uk Kim  * =======================================================
2971f13597dSJung-uk Kim  * Inline assembler section(s).
2981f13597dSJung-uk Kim  * =======================================================
2991f13597dSJung-uk Kim  * Order of arguments is chosen to facilitate Windows port
3001f13597dSJung-uk Kim  * using __fastcall calling convention. If you wish to add
3011f13597dSJung-uk Kim  * more routines, keep in mind that first __fastcall
3021f13597dSJung-uk Kim  * argument is passed in %ecx and second - in %edx.
3031f13597dSJung-uk Kim  * =======================================================
3041f13597dSJung-uk Kim  */
3051f13597dSJung-uk Kim #   if defined(__GNUC__) && __GNUC__>=2
3061f13597dSJung-uk Kim /*
3071f13597dSJung-uk Kim  * As for excessive "push %ebx"/"pop %ebx" found all over.
3081f13597dSJung-uk Kim  * When generating position-independent code GCC won't let
3091f13597dSJung-uk Kim  * us use "b" in assembler templates nor even respect "ebx"
3101f13597dSJung-uk Kim  * in "clobber description." Therefore the trouble...
3111f13597dSJung-uk Kim  */
3121f13597dSJung-uk Kim 
3136f9291ceSJung-uk Kim /*
3146f9291ceSJung-uk Kim  * Helper function - check if a CPUID instruction is available on this CPU
3156f9291ceSJung-uk Kim  */
3166f9291ceSJung-uk Kim static int padlock_insn_cpuid_available(void)
3171f13597dSJung-uk Kim {
3181f13597dSJung-uk Kim     int result = -1;
3191f13597dSJung-uk Kim 
3206f9291ceSJung-uk Kim     /*
3216f9291ceSJung-uk Kim      * We're checking if the bit #21 of EFLAGS can be toggled. If yes =
3226f9291ceSJung-uk Kim      * CPUID is available.
3236f9291ceSJung-uk Kim      */
3246f9291ceSJung-uk Kim     asm volatile ("pushf\n"
3251f13597dSJung-uk Kim                   "popl %%eax\n"
3261f13597dSJung-uk Kim                   "xorl $0x200000, %%eax\n"
3271f13597dSJung-uk Kim                   "movl %%eax, %%ecx\n"
3281f13597dSJung-uk Kim                   "andl $0x200000, %%ecx\n"
3291f13597dSJung-uk Kim                   "pushl %%eax\n"
3301f13597dSJung-uk Kim                   "popf\n"
3311f13597dSJung-uk Kim                   "pushf\n"
3321f13597dSJung-uk Kim                   "popl %%eax\n"
3331f13597dSJung-uk Kim                   "andl $0x200000, %%eax\n"
3341f13597dSJung-uk Kim                   "xorl %%eax, %%ecx\n"
3356f9291ceSJung-uk Kim                   "movl %%ecx, %0\n":"=r" (result)::"eax", "ecx");
3361f13597dSJung-uk Kim 
3371f13597dSJung-uk Kim     return (result == 0);
3381f13597dSJung-uk Kim }
3391f13597dSJung-uk Kim 
3406f9291ceSJung-uk Kim /*
3416f9291ceSJung-uk Kim  * Load supported features of the CPU to see if the PadLock is available.
3426f9291ceSJung-uk Kim  */
3436f9291ceSJung-uk Kim static int padlock_available(void)
3441f13597dSJung-uk Kim {
3451f13597dSJung-uk Kim     char vendor_string[16];
3461f13597dSJung-uk Kim     unsigned int eax, edx;
3471f13597dSJung-uk Kim 
3481f13597dSJung-uk Kim     /* First check if the CPUID instruction is available at all... */
3491f13597dSJung-uk Kim     if (!padlock_insn_cpuid_available())
3501f13597dSJung-uk Kim         return 0;
3511f13597dSJung-uk Kim 
3521f13597dSJung-uk Kim     /* Are we running on the Centaur (VIA) CPU? */
3531f13597dSJung-uk Kim     eax = 0x00000000;
3541f13597dSJung-uk Kim     vendor_string[12] = 0;
3556f9291ceSJung-uk Kim     asm volatile ("pushl  %%ebx\n"
3561f13597dSJung-uk Kim                   "cpuid\n"
3571f13597dSJung-uk Kim                   "movl   %%ebx,(%%edi)\n"
3581f13597dSJung-uk Kim                   "movl   %%edx,4(%%edi)\n"
3591f13597dSJung-uk Kim                   "movl   %%ecx,8(%%edi)\n"
3606f9291ceSJung-uk Kim                   "popl   %%ebx":"+a" (eax):"D"(vendor_string):"ecx", "edx");
3611f13597dSJung-uk Kim     if (strcmp(vendor_string, "CentaurHauls") != 0)
3621f13597dSJung-uk Kim         return 0;
3631f13597dSJung-uk Kim 
3641f13597dSJung-uk Kim     /* Check for Centaur Extended Feature Flags presence */
3651f13597dSJung-uk Kim     eax = 0xC0000000;
3666f9291ceSJung-uk Kim     asm volatile ("pushl %%ebx; cpuid; popl %%ebx":"+a" (eax)::"ecx", "edx");
3671f13597dSJung-uk Kim     if (eax < 0xC0000001)
3681f13597dSJung-uk Kim         return 0;
3691f13597dSJung-uk Kim 
3701f13597dSJung-uk Kim     /* Read the Centaur Extended Feature Flags */
3711f13597dSJung-uk Kim     eax = 0xC0000001;
3726f9291ceSJung-uk Kim     asm volatile ("pushl %%ebx; cpuid; popl %%ebx":"+a" (eax),
3736f9291ceSJung-uk Kim                   "=d"(edx)::"ecx");
3741f13597dSJung-uk Kim 
3751f13597dSJung-uk Kim     /* Fill up some flags */
3761f13597dSJung-uk Kim     padlock_use_ace = ((edx & (0x3 << 6)) == (0x3 << 6));
3771f13597dSJung-uk Kim     padlock_use_rng = ((edx & (0x3 << 2)) == (0x3 << 2));
3781f13597dSJung-uk Kim 
3791f13597dSJung-uk Kim     return padlock_use_ace + padlock_use_rng;
3801f13597dSJung-uk Kim }
3811f13597dSJung-uk Kim 
3821f13597dSJung-uk Kim #    ifndef OPENSSL_NO_AES
383751d2991SJung-uk Kim #     ifndef AES_ASM
3841f13597dSJung-uk Kim /* Our own htonl()/ntohl() */
3856f9291ceSJung-uk Kim static inline void padlock_bswapl(AES_KEY *ks)
3861f13597dSJung-uk Kim {
3871f13597dSJung-uk Kim     size_t i = sizeof(ks->rd_key) / sizeof(ks->rd_key[0]);
3881f13597dSJung-uk Kim     unsigned int *key = ks->rd_key;
3891f13597dSJung-uk Kim 
3901f13597dSJung-uk Kim     while (i--) {
3911f13597dSJung-uk Kim         asm volatile ("bswapl %0":"+r" (*key));
3921f13597dSJung-uk Kim         key++;
3931f13597dSJung-uk Kim     }
3941f13597dSJung-uk Kim }
3951f13597dSJung-uk Kim #     endif
396751d2991SJung-uk Kim #    endif
3971f13597dSJung-uk Kim 
3986f9291ceSJung-uk Kim /*
3996f9291ceSJung-uk Kim  * Force key reload from memory to the CPU microcode. Loading EFLAGS from the
4006f9291ceSJung-uk Kim  * stack clears EFLAGS[30] which does the trick.
4016f9291ceSJung-uk Kim  */
4026f9291ceSJung-uk Kim static inline void padlock_reload_key(void)
4031f13597dSJung-uk Kim {
4041f13597dSJung-uk Kim     asm volatile ("pushfl; popfl");
4051f13597dSJung-uk Kim }
4061f13597dSJung-uk Kim 
4071f13597dSJung-uk Kim #    ifndef OPENSSL_NO_AES
4081f13597dSJung-uk Kim /*
4091f13597dSJung-uk Kim  * This is heuristic key context tracing. At first one
4101f13597dSJung-uk Kim  * believes that one should use atomic swap instructions,
4111f13597dSJung-uk Kim  * but it's not actually necessary. Point is that if
4121f13597dSJung-uk Kim  * padlock_saved_context was changed by another thread
4131f13597dSJung-uk Kim  * after we've read it and before we compare it with cdata,
4141f13597dSJung-uk Kim  * our key *shall* be reloaded upon thread context switch
4151f13597dSJung-uk Kim  * and we are therefore set in either case...
4161f13597dSJung-uk Kim  */
4176f9291ceSJung-uk Kim static inline void padlock_verify_context(struct padlock_cipher_data *cdata)
4181f13597dSJung-uk Kim {
4196f9291ceSJung-uk Kim     asm volatile ("pushfl\n"
4201f13597dSJung-uk Kim                   "       btl     $30,(%%esp)\n"
4211f13597dSJung-uk Kim                   "       jnc     1f\n"
4221f13597dSJung-uk Kim                   "       cmpl    %2,%1\n"
4231f13597dSJung-uk Kim                   "       je      1f\n"
4241f13597dSJung-uk Kim                   "       popfl\n"
4251f13597dSJung-uk Kim                   "       subl    $4,%%esp\n"
4261f13597dSJung-uk Kim                   "1:     addl    $4,%%esp\n"
4276f9291ceSJung-uk Kim                   "       movl    %2,%0":"+m" (padlock_saved_context)
4281f13597dSJung-uk Kim                   :"r"(padlock_saved_context), "r"(cdata):"cc");
4291f13597dSJung-uk Kim }
4301f13597dSJung-uk Kim 
4311f13597dSJung-uk Kim /* Template for padlock_xcrypt_* modes */
4326f9291ceSJung-uk Kim /*
4336f9291ceSJung-uk Kim  * BIG FAT WARNING: The offsets used with 'leal' instructions describe items
4346f9291ceSJung-uk Kim  * of the 'padlock_cipher_data' structure.
4351f13597dSJung-uk Kim  */
4361f13597dSJung-uk Kim #     define PADLOCK_XCRYPT_ASM(name,rep_xcrypt)     \
4371f13597dSJung-uk Kim static inline void *name(size_t cnt,            \
4381f13597dSJung-uk Kim         struct padlock_cipher_data *cdata,      \
4391f13597dSJung-uk Kim         void *out, const void *inp)             \
4401f13597dSJung-uk Kim {       void *iv;                               \
4411f13597dSJung-uk Kim         asm volatile ( "pushl   %%ebx\n"        \
4421f13597dSJung-uk Kim                 "       leal    16(%0),%%edx\n" \
4431f13597dSJung-uk Kim                 "       leal    32(%0),%%ebx\n" \
4441f13597dSJung-uk Kim                         rep_xcrypt "\n"         \
4451f13597dSJung-uk Kim                 "       popl    %%ebx"          \
4461f13597dSJung-uk Kim                 : "=a"(iv), "=c"(cnt), "=D"(out), "=S"(inp) \
4471f13597dSJung-uk Kim                 : "0"(cdata), "1"(cnt), "2"(out), "3"(inp)  \
4481f13597dSJung-uk Kim                 : "edx", "cc", "memory");       \
4491f13597dSJung-uk Kim         return iv;                              \
4501f13597dSJung-uk Kim }
4511f13597dSJung-uk Kim 
4521f13597dSJung-uk Kim /* Generate all functions with appropriate opcodes */
4536f9291ceSJung-uk Kim /* rep xcryptecb */
4546f9291ceSJung-uk Kim PADLOCK_XCRYPT_ASM(padlock_xcrypt_ecb, ".byte 0xf3,0x0f,0xa7,0xc8")
4556f9291ceSJung-uk Kim /* rep xcryptcbc */
4566f9291ceSJung-uk Kim     PADLOCK_XCRYPT_ASM(padlock_xcrypt_cbc, ".byte 0xf3,0x0f,0xa7,0xd0")
4576f9291ceSJung-uk Kim /* rep xcryptcfb */
4586f9291ceSJung-uk Kim     PADLOCK_XCRYPT_ASM(padlock_xcrypt_cfb, ".byte 0xf3,0x0f,0xa7,0xe0")
4596f9291ceSJung-uk Kim /* rep xcryptofb */
4606f9291ceSJung-uk Kim     PADLOCK_XCRYPT_ASM(padlock_xcrypt_ofb, ".byte 0xf3,0x0f,0xa7,0xe8")
4611f13597dSJung-uk Kim #    endif
4621f13597dSJung-uk Kim /* The RNG call itself */
4636f9291ceSJung-uk Kim static inline unsigned int padlock_xstore(void *addr, unsigned int edx_in)
4641f13597dSJung-uk Kim {
4651f13597dSJung-uk Kim     unsigned int eax_out;
4661f13597dSJung-uk Kim 
4671f13597dSJung-uk Kim     asm volatile (".byte 0x0f,0xa7,0xc0" /* xstore */
4681f13597dSJung-uk Kim                   :"=a" (eax_out), "=m"(*(unsigned *)addr)
4691f13597dSJung-uk Kim                   :"D"(addr), "d"(edx_in)
4701f13597dSJung-uk Kim         );
4711f13597dSJung-uk Kim 
4721f13597dSJung-uk Kim     return eax_out;
4731f13597dSJung-uk Kim }
4741f13597dSJung-uk Kim 
4756f9291ceSJung-uk Kim /*
4766f9291ceSJung-uk Kim  * Why not inline 'rep movsd'? I failed to find information on what value in
4776f9291ceSJung-uk Kim  * Direction Flag one can expect and consequently have to apply
4786f9291ceSJung-uk Kim  * "better-safe-than-sorry" approach and assume "undefined." I could
4796f9291ceSJung-uk Kim  * explicitly clear it and restore the original value upon return from
4806f9291ceSJung-uk Kim  * padlock_aes_cipher, but it's presumably too much trouble for too little
4816f9291ceSJung-uk Kim  * gain... In case you wonder 'rep xcrypt*' instructions above are *not*
4826f9291ceSJung-uk Kim  * affected by the Direction Flag and pointers advance toward larger
4836f9291ceSJung-uk Kim  * addresses unconditionally.
4841f13597dSJung-uk Kim  */
4856f9291ceSJung-uk Kim static inline unsigned char *padlock_memcpy(void *dst, const void *src,
4866f9291ceSJung-uk Kim                                             size_t n)
4871f13597dSJung-uk Kim {
4881f13597dSJung-uk Kim     long *d = dst;
4891f13597dSJung-uk Kim     const long *s = src;
4901f13597dSJung-uk Kim 
4911f13597dSJung-uk Kim     n /= sizeof(*d);
4926f9291ceSJung-uk Kim     do {
4936f9291ceSJung-uk Kim         *d++ = *s++;
4946f9291ceSJung-uk Kim     } while (--n);
4951f13597dSJung-uk Kim 
4961f13597dSJung-uk Kim     return dst;
4971f13597dSJung-uk Kim }
4981f13597dSJung-uk Kim 
4991f13597dSJung-uk Kim #   elif defined(_MSC_VER)
5001f13597dSJung-uk Kim /*
5011f13597dSJung-uk Kim  * Unlike GCC these are real functions. In order to minimize impact
5021f13597dSJung-uk Kim  * on performance we adhere to __fastcall calling convention in
5031f13597dSJung-uk Kim  * order to get two first arguments passed through %ecx and %edx.
5041f13597dSJung-uk Kim  * Which kind of suits very well, as instructions in question use
5051f13597dSJung-uk Kim  * both %ecx and %edx as input:-)
5061f13597dSJung-uk Kim  */
5071f13597dSJung-uk Kim #    define REP_XCRYPT(code)                \
5081f13597dSJung-uk Kim         _asm _emit 0xf3                 \
5091f13597dSJung-uk Kim         _asm _emit 0x0f _asm _emit 0xa7 \
5101f13597dSJung-uk Kim         _asm _emit code
5111f13597dSJung-uk Kim 
5126f9291ceSJung-uk Kim /*
5136f9291ceSJung-uk Kim  * BIG FAT WARNING: The offsets used with 'lea' instructions describe items
5146f9291ceSJung-uk Kim  * of the 'padlock_cipher_data' structure.
5151f13597dSJung-uk Kim  */
5161f13597dSJung-uk Kim #    define PADLOCK_XCRYPT_ASM(name,code)   \
5171f13597dSJung-uk Kim static void * __fastcall                \
5181f13597dSJung-uk Kim         name (size_t cnt, void *cdata,  \
5191f13597dSJung-uk Kim         void *outp, const void *inp)    \
5201f13597dSJung-uk Kim {       _asm    mov     eax,edx         \
5211f13597dSJung-uk Kim         _asm    lea     edx,[eax+16]    \
5221f13597dSJung-uk Kim         _asm    lea     ebx,[eax+32]    \
5231f13597dSJung-uk Kim         _asm    mov     edi,outp        \
5241f13597dSJung-uk Kim         _asm    mov     esi,inp         \
5251f13597dSJung-uk Kim         REP_XCRYPT(code)                \
5261f13597dSJung-uk Kim }
5271f13597dSJung-uk Kim 
5281f13597dSJung-uk Kim PADLOCK_XCRYPT_ASM(padlock_xcrypt_ecb,0xc8)
5291f13597dSJung-uk Kim PADLOCK_XCRYPT_ASM(padlock_xcrypt_cbc,0xd0)
5301f13597dSJung-uk Kim PADLOCK_XCRYPT_ASM(padlock_xcrypt_cfb,0xe0)
5311f13597dSJung-uk Kim PADLOCK_XCRYPT_ASM(padlock_xcrypt_ofb,0xe8)
5321f13597dSJung-uk Kim 
5336f9291ceSJung-uk Kim static int __fastcall padlock_xstore(void *outp, unsigned int code)
5346f9291ceSJung-uk Kim {
5356f9291ceSJung-uk Kim     _asm    mov edi,ecx
5361f13597dSJung-uk Kim     _asm _emit 0x0f _asm _emit 0xa7 _asm _emit 0xc0
5371f13597dSJung-uk Kim }
5381f13597dSJung-uk Kim 
5396f9291ceSJung-uk Kim static void __fastcall padlock_reload_key(void)
5406f9291ceSJung-uk Kim {
5416f9291ceSJung-uk Kim     _asm pushfd
5426f9291ceSJung-uk Kim     _asm popfd
5436f9291ceSJung-uk Kim }
5441f13597dSJung-uk Kim 
5456f9291ceSJung-uk Kim static void __fastcall padlock_verify_context(void *cdata)
5466f9291ceSJung-uk Kim {
5476f9291ceSJung-uk Kim     _asm    {
5481f13597dSJung-uk Kim         pushfd
5491f13597dSJung-uk Kim         bt  DWORD PTR[esp],30
5501f13597dSJung-uk Kim         jnc skip
5511f13597dSJung-uk Kim         cmp ecx,padlock_saved_context
5521f13597dSJung-uk Kim         je  skip
5531f13597dSJung-uk Kim         popfd
5541f13597dSJung-uk Kim         sub esp,4
5551f13597dSJung-uk Kim     skip:   add esp,4
5561f13597dSJung-uk Kim         mov padlock_saved_context,ecx
5571f13597dSJung-uk Kim     }
5581f13597dSJung-uk Kim }
5591f13597dSJung-uk Kim 
5601f13597dSJung-uk Kim static int
5611f13597dSJung-uk Kim padlock_available(void)
5626f9291ceSJung-uk Kim {
5636f9291ceSJung-uk Kim     _asm    {
5641f13597dSJung-uk Kim         pushfd
5651f13597dSJung-uk Kim         pop eax
5661f13597dSJung-uk Kim         mov ecx,eax
5671f13597dSJung-uk Kim         xor eax,1<<21
5681f13597dSJung-uk Kim         push    eax
5691f13597dSJung-uk Kim         popfd
5701f13597dSJung-uk Kim         pushfd
5711f13597dSJung-uk Kim         pop eax
5721f13597dSJung-uk Kim         xor eax,ecx
5731f13597dSJung-uk Kim         bt  eax,21
5741f13597dSJung-uk Kim         jnc noluck
5751f13597dSJung-uk Kim         mov eax,0
5761f13597dSJung-uk Kim         cpuid
5771f13597dSJung-uk Kim         xor eax,eax
5781f13597dSJung-uk Kim         cmp ebx,'tneC'
5791f13597dSJung-uk Kim         jne noluck
5801f13597dSJung-uk Kim         cmp edx,'Hrua'
5811f13597dSJung-uk Kim         jne noluck
5821f13597dSJung-uk Kim         cmp ecx,'slua'
5831f13597dSJung-uk Kim         jne noluck
5841f13597dSJung-uk Kim         mov eax,0xC0000000
5851f13597dSJung-uk Kim         cpuid
5861f13597dSJung-uk Kim         mov edx,eax
5871f13597dSJung-uk Kim         xor eax,eax
5881f13597dSJung-uk Kim         cmp edx,0xC0000001
5891f13597dSJung-uk Kim         jb  noluck
5901f13597dSJung-uk Kim         mov eax,0xC0000001
5911f13597dSJung-uk Kim         cpuid
5921f13597dSJung-uk Kim         xor eax,eax
5931f13597dSJung-uk Kim         bt  edx,6
5941f13597dSJung-uk Kim         jnc skip_a
5951f13597dSJung-uk Kim         bt  edx,7
5961f13597dSJung-uk Kim         jnc skip_a
5971f13597dSJung-uk Kim         mov padlock_use_ace,1
5981f13597dSJung-uk Kim         inc eax
5991f13597dSJung-uk Kim     skip_a: bt  edx,2
6001f13597dSJung-uk Kim         jnc skip_r
6011f13597dSJung-uk Kim         bt  edx,3
6021f13597dSJung-uk Kim         jnc skip_r
6031f13597dSJung-uk Kim         mov padlock_use_rng,1
6041f13597dSJung-uk Kim         inc eax
6051f13597dSJung-uk Kim     skip_r:
6061f13597dSJung-uk Kim     noluck:
6071f13597dSJung-uk Kim     }
6081f13597dSJung-uk Kim }
6091f13597dSJung-uk Kim 
6106f9291ceSJung-uk Kim static void __fastcall padlock_bswapl(void *key)
6116f9291ceSJung-uk Kim {
6126f9291ceSJung-uk Kim     _asm    {
6131f13597dSJung-uk Kim         pushfd
6141f13597dSJung-uk Kim         cld
6151f13597dSJung-uk Kim         mov esi,ecx
6161f13597dSJung-uk Kim         mov edi,ecx
6171f13597dSJung-uk Kim         mov ecx,60
6181f13597dSJung-uk Kim     up: lodsd
6191f13597dSJung-uk Kim         bswap   eax
6201f13597dSJung-uk Kim         stosd
6211f13597dSJung-uk Kim         loop    up
6221f13597dSJung-uk Kim         popfd
6231f13597dSJung-uk Kim     }
6241f13597dSJung-uk Kim }
6251f13597dSJung-uk Kim 
6266f9291ceSJung-uk Kim /*
6276f9291ceSJung-uk Kim  * MS actually specifies status of Direction Flag and compiler even manages
6286f9291ceSJung-uk Kim  * to compile following as 'rep movsd' all by itself...
6291f13597dSJung-uk Kim  */
6301f13597dSJung-uk Kim #    define padlock_memcpy(o,i,n) ((unsigned char *)memcpy((o),(i),(n)&~3U))
6311f13597dSJung-uk Kim #   endif
6321f13597dSJung-uk Kim /* ===== AES encryption/decryption ===== */
6331f13597dSJung-uk Kim #   ifndef OPENSSL_NO_AES
6341f13597dSJung-uk Kim #    if defined(NID_aes_128_cfb128) && ! defined (NID_aes_128_cfb)
6351f13597dSJung-uk Kim #     define NID_aes_128_cfb NID_aes_128_cfb128
6361f13597dSJung-uk Kim #    endif
6371f13597dSJung-uk Kim #    if defined(NID_aes_128_ofb128) && ! defined (NID_aes_128_ofb)
6381f13597dSJung-uk Kim #     define NID_aes_128_ofb NID_aes_128_ofb128
6391f13597dSJung-uk Kim #    endif
6401f13597dSJung-uk Kim #    if defined(NID_aes_192_cfb128) && ! defined (NID_aes_192_cfb)
6411f13597dSJung-uk Kim #     define NID_aes_192_cfb NID_aes_192_cfb128
6421f13597dSJung-uk Kim #    endif
6431f13597dSJung-uk Kim #    if defined(NID_aes_192_ofb128) && ! defined (NID_aes_192_ofb)
6441f13597dSJung-uk Kim #     define NID_aes_192_ofb NID_aes_192_ofb128
6451f13597dSJung-uk Kim #    endif
6461f13597dSJung-uk Kim #    if defined(NID_aes_256_cfb128) && ! defined (NID_aes_256_cfb)
6471f13597dSJung-uk Kim #     define NID_aes_256_cfb NID_aes_256_cfb128
6481f13597dSJung-uk Kim #    endif
6491f13597dSJung-uk Kim #    if defined(NID_aes_256_ofb128) && ! defined (NID_aes_256_ofb)
6501f13597dSJung-uk Kim #     define NID_aes_256_ofb NID_aes_256_ofb128
6511f13597dSJung-uk Kim #    endif
6526f9291ceSJung-uk Kim /*
6536f9291ceSJung-uk Kim  * List of supported ciphers.
6546f9291ceSJung-uk Kim  */ static int padlock_cipher_nids[] = {
6551f13597dSJung-uk Kim     NID_aes_128_ecb,
6561f13597dSJung-uk Kim     NID_aes_128_cbc,
6571f13597dSJung-uk Kim     NID_aes_128_cfb,
6581f13597dSJung-uk Kim     NID_aes_128_ofb,
6591f13597dSJung-uk Kim 
6601f13597dSJung-uk Kim     NID_aes_192_ecb,
6611f13597dSJung-uk Kim     NID_aes_192_cbc,
6621f13597dSJung-uk Kim     NID_aes_192_cfb,
6631f13597dSJung-uk Kim     NID_aes_192_ofb,
6641f13597dSJung-uk Kim 
6651f13597dSJung-uk Kim     NID_aes_256_ecb,
6661f13597dSJung-uk Kim     NID_aes_256_cbc,
6671f13597dSJung-uk Kim     NID_aes_256_cfb,
6681f13597dSJung-uk Kim     NID_aes_256_ofb,
6691f13597dSJung-uk Kim };
6706f9291ceSJung-uk Kim 
6711f13597dSJung-uk Kim static int padlock_cipher_nids_num = (sizeof(padlock_cipher_nids) /
6721f13597dSJung-uk Kim                                       sizeof(padlock_cipher_nids[0]));
6731f13597dSJung-uk Kim 
6741f13597dSJung-uk Kim /* Function prototypes ... */
6751f13597dSJung-uk Kim static int padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
6761f13597dSJung-uk Kim                                 const unsigned char *iv, int enc);
6771f13597dSJung-uk Kim static int padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
6781f13597dSJung-uk Kim                               const unsigned char *in, size_t nbytes);
6791f13597dSJung-uk Kim 
6801f13597dSJung-uk Kim #    define NEAREST_ALIGNED(ptr) ( (unsigned char *)(ptr) +         \
6811f13597dSJung-uk Kim         ( (0x10 - ((size_t)(ptr) & 0x0F)) & 0x0F )      )
6821f13597dSJung-uk Kim #    define ALIGNED_CIPHER_DATA(ctx) ((struct padlock_cipher_data *)\
6831f13597dSJung-uk Kim         NEAREST_ALIGNED(ctx->cipher_data))
6841f13597dSJung-uk Kim 
6851f13597dSJung-uk Kim #    define EVP_CIPHER_block_size_ECB       AES_BLOCK_SIZE
6861f13597dSJung-uk Kim #    define EVP_CIPHER_block_size_CBC       AES_BLOCK_SIZE
6871f13597dSJung-uk Kim #    define EVP_CIPHER_block_size_OFB       1
6881f13597dSJung-uk Kim #    define EVP_CIPHER_block_size_CFB       1
6891f13597dSJung-uk Kim 
6906f9291ceSJung-uk Kim /*
6916f9291ceSJung-uk Kim  * Declaring so many ciphers by hand would be a pain. Instead introduce a bit
6926f9291ceSJung-uk Kim  * of preprocessor magic :-)
6936f9291ceSJung-uk Kim  */
6941f13597dSJung-uk Kim #    define DECLARE_AES_EVP(ksize,lmode,umode)      \
6951f13597dSJung-uk Kim static const EVP_CIPHER padlock_aes_##ksize##_##lmode = {       \
6961f13597dSJung-uk Kim         NID_aes_##ksize##_##lmode,              \
6971f13597dSJung-uk Kim         EVP_CIPHER_block_size_##umode,  \
6981f13597dSJung-uk Kim         AES_KEY_SIZE_##ksize,           \
6991f13597dSJung-uk Kim         AES_BLOCK_SIZE,                 \
7001f13597dSJung-uk Kim         0 | EVP_CIPH_##umode##_MODE,    \
7011f13597dSJung-uk Kim         padlock_aes_init_key,           \
7021f13597dSJung-uk Kim         padlock_aes_cipher,             \
7031f13597dSJung-uk Kim         NULL,                           \
7041f13597dSJung-uk Kim         sizeof(struct padlock_cipher_data) + 16,        \
7051f13597dSJung-uk Kim         EVP_CIPHER_set_asn1_iv,         \
7061f13597dSJung-uk Kim         EVP_CIPHER_get_asn1_iv,         \
7071f13597dSJung-uk Kim         NULL,                           \
7081f13597dSJung-uk Kim         NULL                            \
7091f13597dSJung-uk Kim }
7101f13597dSJung-uk Kim 
7111f13597dSJung-uk Kim DECLARE_AES_EVP(128, ecb, ECB);
7121f13597dSJung-uk Kim DECLARE_AES_EVP(128, cbc, CBC);
7131f13597dSJung-uk Kim DECLARE_AES_EVP(128, cfb, CFB);
7141f13597dSJung-uk Kim DECLARE_AES_EVP(128, ofb, OFB);
7151f13597dSJung-uk Kim 
7161f13597dSJung-uk Kim DECLARE_AES_EVP(192, ecb, ECB);
7171f13597dSJung-uk Kim DECLARE_AES_EVP(192, cbc, CBC);
7181f13597dSJung-uk Kim DECLARE_AES_EVP(192, cfb, CFB);
7191f13597dSJung-uk Kim DECLARE_AES_EVP(192, ofb, OFB);
7201f13597dSJung-uk Kim 
7211f13597dSJung-uk Kim DECLARE_AES_EVP(256, ecb, ECB);
7221f13597dSJung-uk Kim DECLARE_AES_EVP(256, cbc, CBC);
7231f13597dSJung-uk Kim DECLARE_AES_EVP(256, cfb, CFB);
7241f13597dSJung-uk Kim DECLARE_AES_EVP(256, ofb, OFB);
7251f13597dSJung-uk Kim 
7261f13597dSJung-uk Kim static int
7276f9291ceSJung-uk Kim padlock_ciphers(ENGINE *e, const EVP_CIPHER **cipher, const int **nids,
7286f9291ceSJung-uk Kim                 int nid)
7291f13597dSJung-uk Kim {
7301f13597dSJung-uk Kim     /* No specific cipher => return a list of supported nids ... */
7311f13597dSJung-uk Kim     if (!cipher) {
7321f13597dSJung-uk Kim         *nids = padlock_cipher_nids;
7331f13597dSJung-uk Kim         return padlock_cipher_nids_num;
7341f13597dSJung-uk Kim     }
7351f13597dSJung-uk Kim 
7361f13597dSJung-uk Kim     /* ... or the requested "cipher" otherwise */
7371f13597dSJung-uk Kim     switch (nid) {
7381f13597dSJung-uk Kim     case NID_aes_128_ecb:
7391f13597dSJung-uk Kim         *cipher = &padlock_aes_128_ecb;
7401f13597dSJung-uk Kim         break;
7411f13597dSJung-uk Kim     case NID_aes_128_cbc:
7421f13597dSJung-uk Kim         *cipher = &padlock_aes_128_cbc;
7431f13597dSJung-uk Kim         break;
7441f13597dSJung-uk Kim     case NID_aes_128_cfb:
7451f13597dSJung-uk Kim         *cipher = &padlock_aes_128_cfb;
7461f13597dSJung-uk Kim         break;
7471f13597dSJung-uk Kim     case NID_aes_128_ofb:
7481f13597dSJung-uk Kim         *cipher = &padlock_aes_128_ofb;
7491f13597dSJung-uk Kim         break;
7501f13597dSJung-uk Kim 
7511f13597dSJung-uk Kim     case NID_aes_192_ecb:
7521f13597dSJung-uk Kim         *cipher = &padlock_aes_192_ecb;
7531f13597dSJung-uk Kim         break;
7541f13597dSJung-uk Kim     case NID_aes_192_cbc:
7551f13597dSJung-uk Kim         *cipher = &padlock_aes_192_cbc;
7561f13597dSJung-uk Kim         break;
7571f13597dSJung-uk Kim     case NID_aes_192_cfb:
7581f13597dSJung-uk Kim         *cipher = &padlock_aes_192_cfb;
7591f13597dSJung-uk Kim         break;
7601f13597dSJung-uk Kim     case NID_aes_192_ofb:
7611f13597dSJung-uk Kim         *cipher = &padlock_aes_192_ofb;
7621f13597dSJung-uk Kim         break;
7631f13597dSJung-uk Kim 
7641f13597dSJung-uk Kim     case NID_aes_256_ecb:
7651f13597dSJung-uk Kim         *cipher = &padlock_aes_256_ecb;
7661f13597dSJung-uk Kim         break;
7671f13597dSJung-uk Kim     case NID_aes_256_cbc:
7681f13597dSJung-uk Kim         *cipher = &padlock_aes_256_cbc;
7691f13597dSJung-uk Kim         break;
7701f13597dSJung-uk Kim     case NID_aes_256_cfb:
7711f13597dSJung-uk Kim         *cipher = &padlock_aes_256_cfb;
7721f13597dSJung-uk Kim         break;
7731f13597dSJung-uk Kim     case NID_aes_256_ofb:
7741f13597dSJung-uk Kim         *cipher = &padlock_aes_256_ofb;
7751f13597dSJung-uk Kim         break;
7761f13597dSJung-uk Kim 
7771f13597dSJung-uk Kim     default:
7781f13597dSJung-uk Kim         /* Sorry, we don't support this NID */
7791f13597dSJung-uk Kim         *cipher = NULL;
7801f13597dSJung-uk Kim         return 0;
7811f13597dSJung-uk Kim     }
7821f13597dSJung-uk Kim 
7831f13597dSJung-uk Kim     return 1;
7841f13597dSJung-uk Kim }
7851f13597dSJung-uk Kim 
7861f13597dSJung-uk Kim /* Prepare the encryption key for PadLock usage */
7871f13597dSJung-uk Kim static int
7881f13597dSJung-uk Kim padlock_aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
7891f13597dSJung-uk Kim                      const unsigned char *iv, int enc)
7901f13597dSJung-uk Kim {
7911f13597dSJung-uk Kim     struct padlock_cipher_data *cdata;
7921f13597dSJung-uk Kim     int key_len = EVP_CIPHER_CTX_key_length(ctx) * 8;
7931f13597dSJung-uk Kim 
7946f9291ceSJung-uk Kim     if (key == NULL)
7956f9291ceSJung-uk Kim         return 0;               /* ERROR */
7961f13597dSJung-uk Kim 
7971f13597dSJung-uk Kim     cdata = ALIGNED_CIPHER_DATA(ctx);
7981f13597dSJung-uk Kim     memset(cdata, 0, sizeof(struct padlock_cipher_data));
7991f13597dSJung-uk Kim 
8001f13597dSJung-uk Kim     /* Prepare Control word. */
8011f13597dSJung-uk Kim     if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE)
8021f13597dSJung-uk Kim         cdata->cword.b.encdec = 0;
8031f13597dSJung-uk Kim     else
8041f13597dSJung-uk Kim         cdata->cword.b.encdec = (ctx->encrypt == 0);
8051f13597dSJung-uk Kim     cdata->cword.b.rounds = 10 + (key_len - 128) / 32;
8061f13597dSJung-uk Kim     cdata->cword.b.ksize = (key_len - 128) / 64;
8071f13597dSJung-uk Kim 
8081f13597dSJung-uk Kim     switch (key_len) {
8091f13597dSJung-uk Kim     case 128:
8106f9291ceSJung-uk Kim         /*
8116f9291ceSJung-uk Kim          * PadLock can generate an extended key for AES128 in hardware
8126f9291ceSJung-uk Kim          */
8131f13597dSJung-uk Kim         memcpy(cdata->ks.rd_key, key, AES_KEY_SIZE_128);
8141f13597dSJung-uk Kim         cdata->cword.b.keygen = 0;
8151f13597dSJung-uk Kim         break;
8161f13597dSJung-uk Kim 
8171f13597dSJung-uk Kim     case 192:
8181f13597dSJung-uk Kim     case 256:
8196f9291ceSJung-uk Kim         /*
8206f9291ceSJung-uk Kim          * Generate an extended AES key in software. Needed for AES192/AES256
8216f9291ceSJung-uk Kim          */
8226f9291ceSJung-uk Kim         /*
8236f9291ceSJung-uk Kim          * Well, the above applies to Stepping 8 CPUs and is listed as
8246f9291ceSJung-uk Kim          * hardware errata. They most likely will fix it at some point and
8256f9291ceSJung-uk Kim          * then a check for stepping would be due here.
8266f9291ceSJung-uk Kim          */
8271f13597dSJung-uk Kim         if (EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_CFB_MODE ||
8286f9291ceSJung-uk Kim             EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_OFB_MODE || enc)
8291f13597dSJung-uk Kim             AES_set_encrypt_key(key, key_len, &cdata->ks);
8301f13597dSJung-uk Kim         else
8311f13597dSJung-uk Kim             AES_set_decrypt_key(key, key_len, &cdata->ks);
8321f13597dSJung-uk Kim #    ifndef AES_ASM
8336f9291ceSJung-uk Kim         /*
8346f9291ceSJung-uk Kim          * OpenSSL C functions use byte-swapped extended key.
8356f9291ceSJung-uk Kim          */
8361f13597dSJung-uk Kim         padlock_bswapl(&cdata->ks);
8371f13597dSJung-uk Kim #    endif
8381f13597dSJung-uk Kim         cdata->cword.b.keygen = 1;
8391f13597dSJung-uk Kim         break;
8401f13597dSJung-uk Kim 
8411f13597dSJung-uk Kim     default:
8421f13597dSJung-uk Kim         /* ERROR */
8431f13597dSJung-uk Kim         return 0;
8441f13597dSJung-uk Kim     }
8451f13597dSJung-uk Kim 
8461f13597dSJung-uk Kim     /*
8471f13597dSJung-uk Kim      * This is done to cover for cases when user reuses the
8481f13597dSJung-uk Kim      * context for new key. The catch is that if we don't do
8491f13597dSJung-uk Kim      * this, padlock_eas_cipher might proceed with old key...
8501f13597dSJung-uk Kim      */
8511f13597dSJung-uk Kim     padlock_reload_key();
8521f13597dSJung-uk Kim 
8531f13597dSJung-uk Kim     return 1;
8541f13597dSJung-uk Kim }
8551f13597dSJung-uk Kim 
8566f9291ceSJung-uk Kim /*-
8571f13597dSJung-uk Kim  * Simplified version of padlock_aes_cipher() used when
8581f13597dSJung-uk Kim  * 1) both input and output buffers are at aligned addresses.
8591f13597dSJung-uk Kim  * or when
8601f13597dSJung-uk Kim  * 2) running on a newer CPU that doesn't require aligned buffers.
8611f13597dSJung-uk Kim  */
8621f13597dSJung-uk Kim static int
8631f13597dSJung-uk Kim padlock_aes_cipher_omnivorous(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
8641f13597dSJung-uk Kim                               const unsigned char *in_arg, size_t nbytes)
8651f13597dSJung-uk Kim {
8661f13597dSJung-uk Kim     struct padlock_cipher_data *cdata;
8671f13597dSJung-uk Kim     void *iv;
8681f13597dSJung-uk Kim 
8691f13597dSJung-uk Kim     cdata = ALIGNED_CIPHER_DATA(ctx);
8701f13597dSJung-uk Kim     padlock_verify_context(cdata);
8711f13597dSJung-uk Kim 
8721f13597dSJung-uk Kim     switch (EVP_CIPHER_CTX_mode(ctx)) {
8731f13597dSJung-uk Kim     case EVP_CIPH_ECB_MODE:
8741f13597dSJung-uk Kim         padlock_xcrypt_ecb(nbytes / AES_BLOCK_SIZE, cdata, out_arg, in_arg);
8751f13597dSJung-uk Kim         break;
8761f13597dSJung-uk Kim 
8771f13597dSJung-uk Kim     case EVP_CIPH_CBC_MODE:
8781f13597dSJung-uk Kim         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
8796f9291ceSJung-uk Kim         iv = padlock_xcrypt_cbc(nbytes / AES_BLOCK_SIZE, cdata, out_arg,
8806f9291ceSJung-uk Kim                                 in_arg);
8811f13597dSJung-uk Kim         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
8821f13597dSJung-uk Kim         break;
8831f13597dSJung-uk Kim 
8841f13597dSJung-uk Kim     case EVP_CIPH_CFB_MODE:
8851f13597dSJung-uk Kim         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
8866f9291ceSJung-uk Kim         iv = padlock_xcrypt_cfb(nbytes / AES_BLOCK_SIZE, cdata, out_arg,
8876f9291ceSJung-uk Kim                                 in_arg);
8881f13597dSJung-uk Kim         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
8891f13597dSJung-uk Kim         break;
8901f13597dSJung-uk Kim 
8911f13597dSJung-uk Kim     case EVP_CIPH_OFB_MODE:
8921f13597dSJung-uk Kim         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
8931f13597dSJung-uk Kim         padlock_xcrypt_ofb(nbytes / AES_BLOCK_SIZE, cdata, out_arg, in_arg);
8941f13597dSJung-uk Kim         memcpy(ctx->iv, cdata->iv, AES_BLOCK_SIZE);
8951f13597dSJung-uk Kim         break;
8961f13597dSJung-uk Kim 
8971f13597dSJung-uk Kim     default:
8981f13597dSJung-uk Kim         return 0;
8991f13597dSJung-uk Kim     }
9001f13597dSJung-uk Kim 
9011f13597dSJung-uk Kim     memset(cdata->iv, 0, AES_BLOCK_SIZE);
9021f13597dSJung-uk Kim 
9031f13597dSJung-uk Kim     return 1;
9041f13597dSJung-uk Kim }
9051f13597dSJung-uk Kim 
9061f13597dSJung-uk Kim #    ifndef  PADLOCK_CHUNK
9071f13597dSJung-uk Kim #     define PADLOCK_CHUNK  512 /* Must be a power of 2 larger than 16 */
9081f13597dSJung-uk Kim #    endif
9091f13597dSJung-uk Kim #    if PADLOCK_CHUNK<16 || PADLOCK_CHUNK&(PADLOCK_CHUNK-1)
9101f13597dSJung-uk Kim #     error "insane PADLOCK_CHUNK..."
9111f13597dSJung-uk Kim #    endif
9121f13597dSJung-uk Kim 
9136f9291ceSJung-uk Kim /*
9146f9291ceSJung-uk Kim  * Re-align the arguments to 16-Bytes boundaries and run the encryption
9156f9291ceSJung-uk Kim  * function itself. This function is not AES-specific.
9166f9291ceSJung-uk Kim  */
9171f13597dSJung-uk Kim static int
9181f13597dSJung-uk Kim padlock_aes_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out_arg,
9191f13597dSJung-uk Kim                    const unsigned char *in_arg, size_t nbytes)
9201f13597dSJung-uk Kim {
9211f13597dSJung-uk Kim     struct padlock_cipher_data *cdata;
9221f13597dSJung-uk Kim     const void *inp;
9231f13597dSJung-uk Kim     unsigned char *out;
9241f13597dSJung-uk Kim     void *iv;
9251f13597dSJung-uk Kim     int inp_misaligned, out_misaligned, realign_in_loop;
9261f13597dSJung-uk Kim     size_t chunk, allocated = 0;
9271f13597dSJung-uk Kim 
9286f9291ceSJung-uk Kim     /*
9296f9291ceSJung-uk Kim      * ctx->num is maintained in byte-oriented modes, such as CFB and OFB...
9306f9291ceSJung-uk Kim      */
9311f13597dSJung-uk Kim     if ((chunk = ctx->num)) {   /* borrow chunk variable */
9321f13597dSJung-uk Kim         unsigned char *ivp = ctx->iv;
9331f13597dSJung-uk Kim 
9341f13597dSJung-uk Kim         switch (EVP_CIPHER_CTX_mode(ctx)) {
9351f13597dSJung-uk Kim         case EVP_CIPH_CFB_MODE:
9361f13597dSJung-uk Kim             if (chunk >= AES_BLOCK_SIZE)
9371f13597dSJung-uk Kim                 return 0;       /* bogus value */
9381f13597dSJung-uk Kim 
9391f13597dSJung-uk Kim             if (ctx->encrypt)
9401f13597dSJung-uk Kim                 while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
9411f13597dSJung-uk Kim                     ivp[chunk] = *(out_arg++) = *(in_arg++) ^ ivp[chunk];
9421f13597dSJung-uk Kim                     chunk++, nbytes--;
9436f9291ceSJung-uk Kim             } else
9446f9291ceSJung-uk Kim                 while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
9451f13597dSJung-uk Kim                     unsigned char c = *(in_arg++);
9461f13597dSJung-uk Kim                     *(out_arg++) = c ^ ivp[chunk];
9471f13597dSJung-uk Kim                     ivp[chunk++] = c, nbytes--;
9481f13597dSJung-uk Kim                 }
9491f13597dSJung-uk Kim 
9501f13597dSJung-uk Kim             ctx->num = chunk % AES_BLOCK_SIZE;
9511f13597dSJung-uk Kim             break;
9521f13597dSJung-uk Kim         case EVP_CIPH_OFB_MODE:
9531f13597dSJung-uk Kim             if (chunk >= AES_BLOCK_SIZE)
9541f13597dSJung-uk Kim                 return 0;       /* bogus value */
9551f13597dSJung-uk Kim 
9561f13597dSJung-uk Kim             while (chunk < AES_BLOCK_SIZE && nbytes != 0) {
9571f13597dSJung-uk Kim                 *(out_arg++) = *(in_arg++) ^ ivp[chunk];
9581f13597dSJung-uk Kim                 chunk++, nbytes--;
9591f13597dSJung-uk Kim             }
9601f13597dSJung-uk Kim 
9611f13597dSJung-uk Kim             ctx->num = chunk % AES_BLOCK_SIZE;
9621f13597dSJung-uk Kim             break;
9631f13597dSJung-uk Kim         }
9641f13597dSJung-uk Kim     }
9651f13597dSJung-uk Kim 
9661f13597dSJung-uk Kim     if (nbytes == 0)
9671f13597dSJung-uk Kim         return 1;
9681f13597dSJung-uk Kim #    if 0
9691f13597dSJung-uk Kim     if (nbytes % AES_BLOCK_SIZE)
9701f13597dSJung-uk Kim         return 0;               /* are we expected to do tail processing? */
9711f13597dSJung-uk Kim #    else
9726f9291ceSJung-uk Kim     /*
9736f9291ceSJung-uk Kim      * nbytes is always multiple of AES_BLOCK_SIZE in ECB and CBC modes and
9746f9291ceSJung-uk Kim      * arbitrary value in byte-oriented modes, such as CFB and OFB...
9756f9291ceSJung-uk Kim      */
9761f13597dSJung-uk Kim #    endif
9771f13597dSJung-uk Kim 
9786f9291ceSJung-uk Kim     /*
9796f9291ceSJung-uk Kim      * VIA promises CPUs that won't require alignment in the future. For now
9806f9291ceSJung-uk Kim      * padlock_aes_align_required is initialized to 1 and the condition is
9816f9291ceSJung-uk Kim      * never met...
9826f9291ceSJung-uk Kim      */
9836f9291ceSJung-uk Kim     /*
9846f9291ceSJung-uk Kim      * C7 core is capable to manage unaligned input in non-ECB[!] mode, but
9856f9291ceSJung-uk Kim      * performance penalties appear to be approximately same as for software
9866f9291ceSJung-uk Kim      * alignment below or ~3x. They promise to improve it in the future, but
9876f9291ceSJung-uk Kim      * for now we can just as well pretend that it can only handle aligned
9886f9291ceSJung-uk Kim      * input...
9896f9291ceSJung-uk Kim      */
9901f13597dSJung-uk Kim     if (!padlock_aes_align_required && (nbytes % AES_BLOCK_SIZE) == 0)
9911f13597dSJung-uk Kim         return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
9921f13597dSJung-uk Kim 
9931f13597dSJung-uk Kim     inp_misaligned = (((size_t)in_arg) & 0x0F);
9941f13597dSJung-uk Kim     out_misaligned = (((size_t)out_arg) & 0x0F);
9951f13597dSJung-uk Kim 
9966f9291ceSJung-uk Kim     /*
9976f9291ceSJung-uk Kim      * Note that even if output is aligned and input not, I still prefer to
9986f9291ceSJung-uk Kim      * loop instead of copy the whole input and then encrypt in one stroke.
9996f9291ceSJung-uk Kim      * This is done in order to improve L1 cache utilization...
10006f9291ceSJung-uk Kim      */
10011f13597dSJung-uk Kim     realign_in_loop = out_misaligned | inp_misaligned;
10021f13597dSJung-uk Kim 
10031f13597dSJung-uk Kim     if (!realign_in_loop && (nbytes % AES_BLOCK_SIZE) == 0)
10041f13597dSJung-uk Kim         return padlock_aes_cipher_omnivorous(ctx, out_arg, in_arg, nbytes);
10051f13597dSJung-uk Kim 
10061f13597dSJung-uk Kim     /* this takes one "if" out of the loops */
10071f13597dSJung-uk Kim     chunk = nbytes;
10081f13597dSJung-uk Kim     chunk %= PADLOCK_CHUNK;
10096f9291ceSJung-uk Kim     if (chunk == 0)
10106f9291ceSJung-uk Kim         chunk = PADLOCK_CHUNK;
10111f13597dSJung-uk Kim 
10121f13597dSJung-uk Kim     if (out_misaligned) {
10131f13597dSJung-uk Kim         /* optmize for small input */
10141f13597dSJung-uk Kim         allocated = (chunk < nbytes ? PADLOCK_CHUNK : nbytes);
10151f13597dSJung-uk Kim         out = alloca(0x10 + allocated);
10161f13597dSJung-uk Kim         out = NEAREST_ALIGNED(out);
10176f9291ceSJung-uk Kim     } else
10181f13597dSJung-uk Kim         out = out_arg;
10191f13597dSJung-uk Kim 
10201f13597dSJung-uk Kim     cdata = ALIGNED_CIPHER_DATA(ctx);
10211f13597dSJung-uk Kim     padlock_verify_context(cdata);
10221f13597dSJung-uk Kim 
10231f13597dSJung-uk Kim     switch (EVP_CIPHER_CTX_mode(ctx)) {
10241f13597dSJung-uk Kim     case EVP_CIPH_ECB_MODE:
10251f13597dSJung-uk Kim         do {
10261f13597dSJung-uk Kim             if (inp_misaligned)
10271f13597dSJung-uk Kim                 inp = padlock_memcpy(out, in_arg, chunk);
10281f13597dSJung-uk Kim             else
10291f13597dSJung-uk Kim                 inp = in_arg;
10301f13597dSJung-uk Kim             in_arg += chunk;
10311f13597dSJung-uk Kim 
10321f13597dSJung-uk Kim             padlock_xcrypt_ecb(chunk / AES_BLOCK_SIZE, cdata, out, inp);
10331f13597dSJung-uk Kim 
10341f13597dSJung-uk Kim             if (out_misaligned)
10351f13597dSJung-uk Kim                 out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
10361f13597dSJung-uk Kim             else
10371f13597dSJung-uk Kim                 out = out_arg += chunk;
10381f13597dSJung-uk Kim 
10391f13597dSJung-uk Kim             nbytes -= chunk;
10401f13597dSJung-uk Kim             chunk = PADLOCK_CHUNK;
10411f13597dSJung-uk Kim         } while (nbytes);
10421f13597dSJung-uk Kim         break;
10431f13597dSJung-uk Kim 
10441f13597dSJung-uk Kim     case EVP_CIPH_CBC_MODE:
10451f13597dSJung-uk Kim         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
10461f13597dSJung-uk Kim         goto cbc_shortcut;
10471f13597dSJung-uk Kim         do {
10481f13597dSJung-uk Kim             if (iv != cdata->iv)
10491f13597dSJung-uk Kim                 memcpy(cdata->iv, iv, AES_BLOCK_SIZE);
10501f13597dSJung-uk Kim             chunk = PADLOCK_CHUNK;
10511f13597dSJung-uk Kim  cbc_shortcut:                 /* optimize for small input */
10521f13597dSJung-uk Kim             if (inp_misaligned)
10531f13597dSJung-uk Kim                 inp = padlock_memcpy(out, in_arg, chunk);
10541f13597dSJung-uk Kim             else
10551f13597dSJung-uk Kim                 inp = in_arg;
10561f13597dSJung-uk Kim             in_arg += chunk;
10571f13597dSJung-uk Kim 
10581f13597dSJung-uk Kim             iv = padlock_xcrypt_cbc(chunk / AES_BLOCK_SIZE, cdata, out, inp);
10591f13597dSJung-uk Kim 
10601f13597dSJung-uk Kim             if (out_misaligned)
10611f13597dSJung-uk Kim                 out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
10621f13597dSJung-uk Kim             else
10631f13597dSJung-uk Kim                 out = out_arg += chunk;
10641f13597dSJung-uk Kim 
10651f13597dSJung-uk Kim         } while (nbytes -= chunk);
10661f13597dSJung-uk Kim         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
10671f13597dSJung-uk Kim         break;
10681f13597dSJung-uk Kim 
10691f13597dSJung-uk Kim     case EVP_CIPH_CFB_MODE:
10701f13597dSJung-uk Kim         memcpy(iv = cdata->iv, ctx->iv, AES_BLOCK_SIZE);
10711f13597dSJung-uk Kim         chunk &= ~(AES_BLOCK_SIZE - 1);
10726f9291ceSJung-uk Kim         if (chunk)
10736f9291ceSJung-uk Kim             goto cfb_shortcut;
10746f9291ceSJung-uk Kim         else
10756f9291ceSJung-uk Kim             goto cfb_skiploop;
10761f13597dSJung-uk Kim         do {
10771f13597dSJung-uk Kim             if (iv != cdata->iv)
10781f13597dSJung-uk Kim                 memcpy(cdata->iv, iv, AES_BLOCK_SIZE);
10791f13597dSJung-uk Kim             chunk = PADLOCK_CHUNK;
10801f13597dSJung-uk Kim  cfb_shortcut:                 /* optimize for small input */
10811f13597dSJung-uk Kim             if (inp_misaligned)
10821f13597dSJung-uk Kim                 inp = padlock_memcpy(out, in_arg, chunk);
10831f13597dSJung-uk Kim             else
10841f13597dSJung-uk Kim                 inp = in_arg;
10851f13597dSJung-uk Kim             in_arg += chunk;
10861f13597dSJung-uk Kim 
10871f13597dSJung-uk Kim             iv = padlock_xcrypt_cfb(chunk / AES_BLOCK_SIZE, cdata, out, inp);
10881f13597dSJung-uk Kim 
10891f13597dSJung-uk Kim             if (out_misaligned)
10901f13597dSJung-uk Kim                 out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
10911f13597dSJung-uk Kim             else
10921f13597dSJung-uk Kim                 out = out_arg += chunk;
10931f13597dSJung-uk Kim 
10941f13597dSJung-uk Kim             nbytes -= chunk;
10951f13597dSJung-uk Kim         } while (nbytes >= AES_BLOCK_SIZE);
10961f13597dSJung-uk Kim 
10971f13597dSJung-uk Kim  cfb_skiploop:
10981f13597dSJung-uk Kim         if (nbytes) {
10991f13597dSJung-uk Kim             unsigned char *ivp = cdata->iv;
11001f13597dSJung-uk Kim 
11011f13597dSJung-uk Kim             if (iv != ivp) {
11021f13597dSJung-uk Kim                 memcpy(ivp, iv, AES_BLOCK_SIZE);
11031f13597dSJung-uk Kim                 iv = ivp;
11041f13597dSJung-uk Kim             }
11051f13597dSJung-uk Kim             ctx->num = nbytes;
11061f13597dSJung-uk Kim             if (cdata->cword.b.encdec) {
11071f13597dSJung-uk Kim                 cdata->cword.b.encdec = 0;
11081f13597dSJung-uk Kim                 padlock_reload_key();
11091f13597dSJung-uk Kim                 padlock_xcrypt_ecb(1, cdata, ivp, ivp);
11101f13597dSJung-uk Kim                 cdata->cword.b.encdec = 1;
11111f13597dSJung-uk Kim                 padlock_reload_key();
11121f13597dSJung-uk Kim                 while (nbytes) {
11131f13597dSJung-uk Kim                     unsigned char c = *(in_arg++);
11141f13597dSJung-uk Kim                     *(out_arg++) = c ^ *ivp;
11151f13597dSJung-uk Kim                     *(ivp++) = c, nbytes--;
11161f13597dSJung-uk Kim                 }
11176f9291ceSJung-uk Kim             } else {
11186f9291ceSJung-uk Kim                 padlock_reload_key();
11191f13597dSJung-uk Kim                 padlock_xcrypt_ecb(1, cdata, ivp, ivp);
11201f13597dSJung-uk Kim                 padlock_reload_key();
11211f13597dSJung-uk Kim                 while (nbytes) {
11221f13597dSJung-uk Kim                     *ivp = *(out_arg++) = *(in_arg++) ^ *ivp;
11231f13597dSJung-uk Kim                     ivp++, nbytes--;
11241f13597dSJung-uk Kim                 }
11251f13597dSJung-uk Kim             }
11261f13597dSJung-uk Kim         }
11271f13597dSJung-uk Kim 
11281f13597dSJung-uk Kim         memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
11291f13597dSJung-uk Kim         break;
11301f13597dSJung-uk Kim 
11311f13597dSJung-uk Kim     case EVP_CIPH_OFB_MODE:
11321f13597dSJung-uk Kim         memcpy(cdata->iv, ctx->iv, AES_BLOCK_SIZE);
11331f13597dSJung-uk Kim         chunk &= ~(AES_BLOCK_SIZE - 1);
11346f9291ceSJung-uk Kim         if (chunk)
11356f9291ceSJung-uk Kim             do {
11361f13597dSJung-uk Kim                 if (inp_misaligned)
11371f13597dSJung-uk Kim                     inp = padlock_memcpy(out, in_arg, chunk);
11381f13597dSJung-uk Kim                 else
11391f13597dSJung-uk Kim                     inp = in_arg;
11401f13597dSJung-uk Kim                 in_arg += chunk;
11411f13597dSJung-uk Kim 
11421f13597dSJung-uk Kim                 padlock_xcrypt_ofb(chunk / AES_BLOCK_SIZE, cdata, out, inp);
11431f13597dSJung-uk Kim 
11441f13597dSJung-uk Kim                 if (out_misaligned)
11451f13597dSJung-uk Kim                     out_arg = padlock_memcpy(out_arg, out, chunk) + chunk;
11461f13597dSJung-uk Kim                 else
11471f13597dSJung-uk Kim                     out = out_arg += chunk;
11481f13597dSJung-uk Kim 
11491f13597dSJung-uk Kim                 nbytes -= chunk;
11501f13597dSJung-uk Kim                 chunk = PADLOCK_CHUNK;
11511f13597dSJung-uk Kim             } while (nbytes >= AES_BLOCK_SIZE);
11521f13597dSJung-uk Kim 
11531f13597dSJung-uk Kim         if (nbytes) {
11541f13597dSJung-uk Kim             unsigned char *ivp = cdata->iv;
11551f13597dSJung-uk Kim 
11561f13597dSJung-uk Kim             ctx->num = nbytes;
11571f13597dSJung-uk Kim             padlock_reload_key(); /* empirically found */
11581f13597dSJung-uk Kim             padlock_xcrypt_ecb(1, cdata, ivp, ivp);
11591f13597dSJung-uk Kim             padlock_reload_key(); /* empirically found */
11601f13597dSJung-uk Kim             while (nbytes) {
11611f13597dSJung-uk Kim                 *(out_arg++) = *(in_arg++) ^ *ivp;
11621f13597dSJung-uk Kim                 ivp++, nbytes--;
11631f13597dSJung-uk Kim             }
11641f13597dSJung-uk Kim         }
11651f13597dSJung-uk Kim 
11661f13597dSJung-uk Kim         memcpy(ctx->iv, cdata->iv, AES_BLOCK_SIZE);
11671f13597dSJung-uk Kim         break;
11681f13597dSJung-uk Kim 
11691f13597dSJung-uk Kim     default:
11701f13597dSJung-uk Kim         return 0;
11711f13597dSJung-uk Kim     }
11721f13597dSJung-uk Kim 
11731f13597dSJung-uk Kim     /* Clean the realign buffer if it was used */
11741f13597dSJung-uk Kim     if (out_misaligned) {
11751f13597dSJung-uk Kim         volatile unsigned long *p = (void *)out;
11761f13597dSJung-uk Kim         size_t n = allocated / sizeof(*p);
11776f9291ceSJung-uk Kim         while (n--)
11786f9291ceSJung-uk Kim             *p++ = 0;
11791f13597dSJung-uk Kim     }
11801f13597dSJung-uk Kim 
11811f13597dSJung-uk Kim     memset(cdata->iv, 0, AES_BLOCK_SIZE);
11821f13597dSJung-uk Kim 
11831f13597dSJung-uk Kim     return 1;
11841f13597dSJung-uk Kim }
11851f13597dSJung-uk Kim 
11861f13597dSJung-uk Kim #   endif                       /* OPENSSL_NO_AES */
11871f13597dSJung-uk Kim 
11881f13597dSJung-uk Kim /* ===== Random Number Generator ===== */
11891f13597dSJung-uk Kim /*
11901f13597dSJung-uk Kim  * This code is not engaged. The reason is that it does not comply
11911f13597dSJung-uk Kim  * with recommendations for VIA RNG usage for secure applications
11921f13597dSJung-uk Kim  * (posted at http://www.via.com.tw/en/viac3/c3.jsp) nor does it
11931f13597dSJung-uk Kim  * provide meaningful error control...
11941f13597dSJung-uk Kim  */
11956f9291ceSJung-uk Kim /*
11966f9291ceSJung-uk Kim  * Wrapper that provides an interface between the API and the raw PadLock
11976f9291ceSJung-uk Kim  * RNG
11986f9291ceSJung-uk Kim  */
11996f9291ceSJung-uk Kim static int padlock_rand_bytes(unsigned char *output, int count)
12001f13597dSJung-uk Kim {
12011f13597dSJung-uk Kim     unsigned int eax, buf;
12021f13597dSJung-uk Kim 
12031f13597dSJung-uk Kim     while (count >= 8) {
12041f13597dSJung-uk Kim         eax = padlock_xstore(output, 0);
12056f9291ceSJung-uk Kim         if (!(eax & (1 << 6)))
12066f9291ceSJung-uk Kim             return 0;           /* RNG disabled */
12071f13597dSJung-uk Kim         /* this ---vv--- covers DC bias, Raw Bits and String Filter */
12086f9291ceSJung-uk Kim         if (eax & (0x1F << 10))
12096f9291ceSJung-uk Kim             return 0;
12106f9291ceSJung-uk Kim         if ((eax & 0x1F) == 0)
12116f9291ceSJung-uk Kim             continue;           /* no data, retry... */
12126f9291ceSJung-uk Kim         if ((eax & 0x1F) != 8)
12136f9291ceSJung-uk Kim             return 0;           /* fatal failure...  */
12141f13597dSJung-uk Kim         output += 8;
12151f13597dSJung-uk Kim         count -= 8;
12161f13597dSJung-uk Kim     }
12171f13597dSJung-uk Kim     while (count > 0) {
12181f13597dSJung-uk Kim         eax = padlock_xstore(&buf, 3);
12196f9291ceSJung-uk Kim         if (!(eax & (1 << 6)))
12206f9291ceSJung-uk Kim             return 0;           /* RNG disabled */
12211f13597dSJung-uk Kim         /* this ---vv--- covers DC bias, Raw Bits and String Filter */
12226f9291ceSJung-uk Kim         if (eax & (0x1F << 10))
12236f9291ceSJung-uk Kim             return 0;
12246f9291ceSJung-uk Kim         if ((eax & 0x1F) == 0)
12256f9291ceSJung-uk Kim             continue;           /* no data, retry... */
12266f9291ceSJung-uk Kim         if ((eax & 0x1F) != 1)
12276f9291ceSJung-uk Kim             return 0;           /* fatal failure...  */
12281f13597dSJung-uk Kim         *output++ = (unsigned char)buf;
12291f13597dSJung-uk Kim         count--;
12301f13597dSJung-uk Kim     }
12311f13597dSJung-uk Kim     *(volatile unsigned int *)&buf = 0;
12321f13597dSJung-uk Kim 
12331f13597dSJung-uk Kim     return 1;
12341f13597dSJung-uk Kim }
12351f13597dSJung-uk Kim 
12361f13597dSJung-uk Kim /* Dummy but necessary function */
12376f9291ceSJung-uk Kim static int padlock_rand_status(void)
12381f13597dSJung-uk Kim {
12391f13597dSJung-uk Kim     return 1;
12401f13597dSJung-uk Kim }
12411f13597dSJung-uk Kim 
12421f13597dSJung-uk Kim /* Prepare structure for registration */
12431f13597dSJung-uk Kim static RAND_METHOD padlock_rand = {
12441f13597dSJung-uk Kim     NULL,                       /* seed */
12451f13597dSJung-uk Kim     padlock_rand_bytes,         /* bytes */
12461f13597dSJung-uk Kim     NULL,                       /* cleanup */
12471f13597dSJung-uk Kim     NULL,                       /* add */
12481f13597dSJung-uk Kim     padlock_rand_bytes,         /* pseudorand */
12491f13597dSJung-uk Kim     padlock_rand_status,        /* rand status */
12501f13597dSJung-uk Kim };
12511f13597dSJung-uk Kim 
12521f13597dSJung-uk Kim #  else                         /* !COMPILE_HW_PADLOCK */
12531f13597dSJung-uk Kim #   ifndef OPENSSL_NO_DYNAMIC_ENGINE
12541f13597dSJung-uk Kim OPENSSL_EXPORT
12551f13597dSJung-uk Kim     int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns);
12561f13597dSJung-uk Kim OPENSSL_EXPORT
12576f9291ceSJung-uk Kim     int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns)
12586f9291ceSJung-uk Kim {
12596f9291ceSJung-uk Kim     return 0;
12606f9291ceSJung-uk Kim }
12616f9291ceSJung-uk Kim 
12621f13597dSJung-uk Kim IMPLEMENT_DYNAMIC_CHECK_FN()
12631f13597dSJung-uk Kim #   endif
12641f13597dSJung-uk Kim #  endif                        /* COMPILE_HW_PADLOCK */
12651f13597dSJung-uk Kim # endif                         /* !OPENSSL_NO_HW_PADLOCK */
12661f13597dSJung-uk Kim #endif                          /* !OPENSSL_NO_HW */
1267