VERY EXPERIMENTAL HMAC redirection example in OpenSSL ENGINE. Untested at this
[openssl.git] / crypto / engine / eng_aesni.c
index 5491063811b60a6439ed66edeb807104d797257e..e9f277390aee0f0e66fe5394ed0ca9b599aadd13 100644 (file)
 #if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_AES_NI) && !defined(OPENSSL_NO_AES)
 
 #include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <openssl/crypto.h>
+#include "cryptlib.h"
 #include <openssl/dso.h>
 #include <openssl/engine.h>
 #include <openssl/evp.h>
 #include <openssl/aes.h>
 #include <openssl/err.h>
-#include <cryptlib.h>
 #include <openssl/modes.h>
 
 /* AES-NI is available *ONLY* on some x86 CPUs.  Not only that it
@@ -114,9 +111,38 @@ void ENGINE_load_aesni (void)
 }
 
 #ifdef COMPILE_HW_AESNI
-int aesni_set_encrypt_key(const unsigned char *userKey, const int bits,
+
+typedef unsigned int u32;
+typedef unsigned char u8;
+
+#if defined(__GNUC__) && __GNUC__>=2 && !defined(PEDANTIC)
+#  define BSWAP4(x) ({ u32 ret=(x);                    \
+                       asm volatile ("bswapl %0"       \
+                       : "+r"(ret));   ret;            })
+#elif defined(_MSC_VER)
+# if _MSC_VER>=1300
+#  pragma intrinsic(_byteswap_ulong)
+#  define BSWAP4(x)    _byteswap_ulong((u32)(x))
+# elif defined(_M_IX86)
+   __inline u32 _bswap4(u32 val) {
+       _asm mov eax,val
+       _asm bswap eax
+   }
+#  define BSWAP4(x)    _bswap4(x)
+# endif
+#endif
+
+#ifdef BSWAP4
+#define GETU32(p)      BSWAP4(*(const u32 *)(p))
+#define PUTU32(p,v)    *(u32 *)(p) = BSWAP4(v)
+#else
+#define GETU32(p)      ((u32)(p)[0]<<24|(u32)(p)[1]<<16|(u32)(p)[2]<<8|(u32)(p)[3])
+#define PUTU32(p,v)    ((p)[0]=(u8)((v)>>24),(p)[1]=(u8)((v)>>16),(p)[2]=(u8)((v)>>8),(p)[3]=(u8)(v))
+#endif
+
+int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
                              AES_KEY *key);
-int aesni_set_decrypt_key(const unsigned char *userKey, const int bits,
+int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
                              AES_KEY *key);
 
 void aesni_encrypt(const unsigned char *in, unsigned char *out,
@@ -126,14 +152,20 @@ void aesni_decrypt(const unsigned char *in, unsigned char *out,
 
 void aesni_ecb_encrypt(const unsigned char *in,
                           unsigned char *out,
-                          const unsigned long length,
+                          size_t length,
                           const AES_KEY *key,
-                          const int enc);
+                          int enc);
 void aesni_cbc_encrypt(const unsigned char *in,
                           unsigned char *out,
-                          const unsigned long length,
+                          size_t length,
                           const AES_KEY *key,
-                          unsigned char *ivec, const int enc);
+                          unsigned char *ivec, int enc);
+
+void aesni_ctr32_encrypt_blocks(const unsigned char *in,
+                          unsigned char *out,
+                          size_t blocks,
+                          const void *key,
+                          const unsigned char *ivec);
 
 /* Function for ENGINE detection and control */
 static int aesni_init(ENGINE *e);
@@ -227,16 +259,19 @@ static int aesni_cipher_nids[] = {
        NID_aes_128_cbc,
        NID_aes_128_cfb,
        NID_aes_128_ofb,
+       NID_aes_128_ctr,
 
        NID_aes_192_ecb,
        NID_aes_192_cbc,
        NID_aes_192_cfb,
        NID_aes_192_ofb,
+       NID_aes_192_ctr,
 
        NID_aes_256_ecb,
        NID_aes_256_cbc,
        NID_aes_256_cfb,
        NID_aes_256_ofb,
+       NID_aes_256_ctr,
 };
 static int aesni_cipher_nids_num =
        (sizeof(aesni_cipher_nids)/sizeof(aesni_cipher_nids[0]));
@@ -248,24 +283,34 @@ typedef struct
 } AESNI_KEY;
 
 static int
-aesni_init_key (EVP_CIPHER_CTX *ctx, const unsigned char *user_key,
+aesni_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *user_key,
                    const unsigned char *iv, int enc)
 {
        int ret;
        AES_KEY *key = AESNI_ALIGN(ctx->cipher_data);
 
-       if ((ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_CFB_MODE
-           || (ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_OFB_MODE
-           || enc)
-               ret=aesni_set_encrypt_key(user_key, ctx->key_len * 8, key);
-       else
+       if (((ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_ECB_MODE
+           || (ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_CBC_MODE)
+           && !enc)
                ret=aesni_set_decrypt_key(user_key, ctx->key_len * 8, key);
+       else
+               ret=aesni_set_encrypt_key(user_key, ctx->key_len * 8, key);
 
        if(ret < 0) {
-               EVPerr(EVP_F_AES_INIT_KEY,EVP_R_AES_KEY_SETUP_FAILED);
+               EVPerr(EVP_F_AESNI_INIT_KEY,EVP_R_AES_KEY_SETUP_FAILED);
                return 0;
        }
 
+       if (ctx->cipher->flags&EVP_CIPH_CUSTOM_IV)
+               {
+               if (iv!=NULL)
+                       memcpy (ctx->iv,iv,ctx->cipher->iv_len);
+               else    {
+                       EVPerr(EVP_F_AESNI_INIT_KEY,EVP_R_AES_IV_SETUP_FAILED);
+                       return 0;
+                       }
+               }
+
        return 1;
 }
 
@@ -339,6 +384,74 @@ DECLARE_AES_EVP(256,cbc,CBC);
 DECLARE_AES_EVP(256,cfb,CFB);
 DECLARE_AES_EVP(256,ofb,OFB);
 
+#if notused
+static void ctr96_inc(unsigned char *counter) {
+       u32 n=12;
+       u8  c;
+
+       do {
+               --n;
+               c = counter[n];
+               ++c;
+               counter[n] = c;
+               if (c) return;
+       } while (n);
+}
+#endif
+
+static int aesni_counter(EVP_CIPHER_CTX *ctx, unsigned char *out,
+               const unsigned char *in, size_t len)
+{
+       AES_KEY *key = AESNI_ALIGN(ctx->cipher_data);
+
+       CRYPTO_ctr128_encrypt_ctr32(in,out,len,key,
+                               ctx->iv,ctx->buf,(unsigned int *)&ctx->num,
+                               aesni_ctr32_encrypt_blocks);
+       return 1;
+}
+
+static const EVP_CIPHER aesni_128_ctr=
+       {
+       NID_aes_128_ctr,1,16,16,
+       EVP_CIPH_CUSTOM_IV,
+       aesni_init_key,
+       aesni_counter,
+       NULL,
+       sizeof(AESNI_KEY),
+       NULL,
+       NULL,
+       NULL,
+       NULL
+       };
+
+static const EVP_CIPHER aesni_192_ctr=
+       {
+       NID_aes_192_ctr,1,24,16,
+       EVP_CIPH_CUSTOM_IV,
+       aesni_init_key,
+       aesni_counter,
+       NULL,
+       sizeof(AESNI_KEY),
+       NULL,
+       NULL,
+       NULL,
+       NULL
+       };
+
+static const EVP_CIPHER aesni_256_ctr=
+       {
+       NID_aes_256_ctr,1,32,16,
+       EVP_CIPH_CUSTOM_IV,
+       aesni_init_key,
+       aesni_counter,
+       NULL,
+       sizeof(AESNI_KEY),
+       NULL,
+       NULL,
+       NULL,
+       NULL
+       };
+
 static int
 aesni_ciphers (ENGINE *e, const EVP_CIPHER **cipher,
                      const int **nids, int nid)
@@ -363,6 +476,9 @@ aesni_ciphers (ENGINE *e, const EVP_CIPHER **cipher,
        case NID_aes_128_ofb:
                *cipher = &aesni_128_ofb;
                break;
+       case NID_aes_128_ctr:
+               *cipher = &aesni_128_ctr;
+               break;
 
        case NID_aes_192_ecb:
                *cipher = &aesni_192_ecb;
@@ -376,6 +492,9 @@ aesni_ciphers (ENGINE *e, const EVP_CIPHER **cipher,
        case NID_aes_192_ofb:
                *cipher = &aesni_192_ofb;
                break;
+       case NID_aes_192_ctr:
+               *cipher = &aesni_192_ctr;
+               break;
 
        case NID_aes_256_ecb:
                *cipher = &aesni_256_ecb;
@@ -389,6 +508,9 @@ aesni_ciphers (ENGINE *e, const EVP_CIPHER **cipher,
        case NID_aes_256_ofb:
                *cipher = &aesni_256_ofb;
                break;
+       case NID_aes_256_ctr:
+               *cipher = &aesni_256_ctr;
+               break;
 
        default:
                /* Sorry, we don't support this NID */