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