e_aes.c: integrate AESNI directly into EVP.
authorAndy Polyakov <appro@openssl.org>
Mon, 30 May 2011 09:16:01 +0000 (09:16 +0000)
committerAndy Polyakov <appro@openssl.org>
Mon, 30 May 2011 09:16:01 +0000 (09:16 +0000)
crypto/evp/e_aes.c

index 361abf2..93d6d97 100644 (file)
 #include "modes_lcl.h"
 #include <openssl/rand.h>
 
-static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
-                                       const unsigned char *iv, int enc);
-
 typedef struct
        {
        AES_KEY ks;
        } EVP_AES_KEY;
 
+#if    defined(AES_ASM) && !defined(I386_ONLY) &&      (  \
+       ((defined(__i386)       || defined(__i386__)    || \
+         defined(_M_IX86)) && defined(OPENSSL_IA32_SSE2))|| \
+       defined(__x86_64)       || defined(__x86_64__)  || \
+       defined(_M_AMD64)       || defined(_M_X64)      || \
+       defined(__INTEL__)                              )
+
+int aesni_set_encrypt_key(const unsigned char *userKey, int bits,
+                             AES_KEY *key);
+int aesni_set_decrypt_key(const unsigned char *userKey, int bits,
+                             AES_KEY *key);
+
+void aesni_encrypt(const unsigned char *in, unsigned char *out,
+                      const AES_KEY *key);
+void aesni_decrypt(const unsigned char *in, unsigned char *out,
+                      const AES_KEY *key);
+
+void aesni_ecb_encrypt(const unsigned char *in,
+                          unsigned char *out,
+                          size_t length,
+                          const AES_KEY *key,
+                          int enc);
+void aesni_cbc_encrypt(const unsigned char *in,
+                          unsigned char *out,
+                          size_t length,
+                          const AES_KEY *key,
+                          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);
+
+extern unsigned int OPENSSL_ia32cap_P[2];
+#define        AESNI_CAPABLE   (1<<(57-32))
+
+static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                  const unsigned char *iv, int enc)
+       {
+       int ret;
+
+       if (((ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_ECB_MODE
+           || (ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_CBC_MODE)
+           && !enc) 
+               ret = OPENSSL_ia32cap_P[1]&AESNI_CAPABLE ?
+                       aesni_set_decrypt_key(key, ctx->key_len*8, ctx->cipher_data):
+                       AES_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+       else
+               ret = OPENSSL_ia32cap_P[1]&AESNI_CAPABLE ?
+                       aesni_set_encrypt_key(key, ctx->key_len*8, ctx->cipher_data):
+                       AES_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+
+       if(ret < 0)
+               {
+               EVPerr(EVP_F_AES_INIT_KEY,EVP_R_AES_KEY_SETUP_FAILED);
+               return 0;
+               }
+
+       return 1;
+       }
+
+static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in, size_t len)
+{
+       if (OPENSSL_ia32cap_P[1]&AESNI_CAPABLE)
+               aesni_cbc_encrypt(in,out,len,ctx->cipher_data,ctx->iv,ctx->encrypt);
+       else
+               AES_cbc_encrypt(in,out,len,ctx->cipher_data,ctx->iv,ctx->encrypt);
+
+       return 1;
+}
+
+static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in, size_t len)
+{
+       size_t  bl = ctx->cipher->block_size;
+
+       if (len<bl)     return 1;
+
+       if (OPENSSL_ia32cap_P[1]&AESNI_CAPABLE)
+               aesni_ecb_encrypt(in,out,len,ctx->cipher_data,ctx->encrypt);
+       else {
+               size_t i;
+
+               if (ctx->encrypt) {
+                       for (i=0,len-=bl;i<=len;i+=bl)
+                               AES_encrypt(in+i,out+i,ctx->cipher_data);
+               } else {
+                       for (i=0,len-=bl;i<=len;i+=bl)
+                               AES_decrypt(in+i,out+i,ctx->cipher_data);
+               }
+       }
+
+       return 1;
+}
+
+static int aes_ofb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       CRYPTO_ofb128_encrypt(in,out,len,ctx->cipher_data,
+                       ctx->iv,&ctx->num,
+                       OPENSSL_ia32cap_P[1]&AESNI_CAPABLE ?
+                               (block128_f)aesni_encrypt  :
+                               (block128_f)AES_encrypt);
+       return 1;
+}
+
+static int aes_cfb_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       CRYPTO_cfb128_encrypt(in,out,len,ctx->cipher_data,
+                       ctx->iv,&ctx->num,ctx->encrypt,
+                       OPENSSL_ia32cap_P[1]&AESNI_CAPABLE ?
+                               (block128_f)aesni_encrypt  :
+                               (block128_f)AES_encrypt);
+       return 1;
+}
+
+static int aes_cfb8_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       CRYPTO_cfb128_8_encrypt(in,out,len,ctx->cipher_data,
+                       ctx->iv,&ctx->num,ctx->encrypt,
+                       OPENSSL_ia32cap_P[1]&AESNI_CAPABLE ?
+                               (block128_f)aesni_encrypt  :
+                               (block128_f)AES_encrypt);
+       return 1;
+}
+
+static int aes_cfb1_cipher(EVP_CIPHER_CTX *ctx,unsigned char *out,
+       const unsigned char *in,size_t len)
+{
+       CRYPTO_cfb128_1_encrypt(in,out,len,ctx->cipher_data,
+                       ctx->iv,&ctx->num,ctx->encrypt,
+                       OPENSSL_ia32cap_P[1]&AESNI_CAPABLE ?
+                               (block128_f)aesni_encrypt  :
+                               (block128_f)AES_encrypt);
+       return 1;
+}
+
+static int aes_counter(EVP_CIPHER_CTX *ctx, unsigned char *out,
+               const unsigned char *in, size_t len)
+{
+       unsigned int num;
+       num = ctx->num;
+
+       if (OPENSSL_ia32cap_P[1]&AESNI_CAPABLE)
+               CRYPTO_ctr128_encrypt_ctr32(in,out,len,
+                       ctx->cipher_data,ctx->iv,ctx->buf,&num,
+                       (ctr128_f)aesni_ctr32_encrypt_blocks);
+       else
+               CRYPTO_ctr128_encrypt(in,out,len,
+                       ctx->cipher_data,ctx->iv,ctx->buf,&num,
+                       (block128_f)AES_encrypt);
+       ctx->num = (size_t)num;
+       return 1;
+}
+
+#define BLOCK_CIPHER_mydef(nid,keylen,blocksize,ivlen,nmode,mode,MODE,flags) \
+static const EVP_CIPHER aes_##keylen##_##mode = { \
+       nid##_##keylen##_##nmode,blocksize,keylen/8,ivlen, \
+       flags|EVP_CIPH_##MODE##_MODE, \
+       aes_init_key,aes_##mode##_cipher,NULL,sizeof(EVP_AES_KEY), \
+       NULL,NULL,NULL,NULL }; \
+const EVP_CIPHER *EVP_aes_##keylen##_##mode(void) { return &aes_##keylen##_##mode; }
+
+#define BLOCK_CIPHER_mydefs(nid,keylen,flags)          \
+       BLOCK_CIPHER_mydef(nid,keylen,16,16,cbc,cbc,CBC,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)       \
+       BLOCK_CIPHER_mydef(nid,keylen,16,0,ecb,ecb,ECB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)        \
+       BLOCK_CIPHER_mydef(nid,keylen,1,16,ofb128,ofb,OFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)     \
+       BLOCK_CIPHER_mydef(nid,keylen,1,16,cfb128,cfb,CFB,flags|EVP_CIPH_FLAG_DEFAULT_ASN1)     \
+       BLOCK_CIPHER_mydef(nid,keylen,1,16,cfb1,cfb1,CFB,flags) \
+       BLOCK_CIPHER_mydef(nid,keylen,1,16,cfb8,cfb8,CFB,flags)
+
+BLOCK_CIPHER_mydefs(NID_aes,128,EVP_CIPH_FLAG_FIPS)
+BLOCK_CIPHER_mydefs(NID_aes,192,EVP_CIPH_FLAG_FIPS)
+BLOCK_CIPHER_mydefs(NID_aes,256,EVP_CIPH_FLAG_FIPS)
+
+#else
+
+static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+                  const unsigned char *iv, int enc)
+       {
+       int ret;
+
+       if (((ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_ECB_MODE
+           || (ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_CBC_MODE)
+           && !enc) 
+               ret=AES_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+       else
+               ret=AES_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
+
+       if(ret < 0)
+               {
+               EVPerr(EVP_F_AES_INIT_KEY,EVP_R_AES_KEY_SETUP_FAILED);
+               return 0;
+               }
+
+       return 1;
+       }
+
 #define data(ctx)      EVP_C_DATA(EVP_AES_KEY,ctx)
 
 IMPLEMENT_BLOCK_CIPHER(aes_128, ks, AES, EVP_AES_KEY,
@@ -116,6 +315,8 @@ static int aes_counter (EVP_CIPHER_CTX *ctx, unsigned char *out,
        return 1;
 }
 
+#endif
+
 static const EVP_CIPHER aes_128_ctr_cipher=
        {
        NID_aes_128_ctr,1,16,16,
@@ -167,27 +368,6 @@ static const EVP_CIPHER aes_256_ctr_cipher=
 const EVP_CIPHER *EVP_aes_256_ctr (void)
 {      return &aes_256_ctr_cipher;     }
 
-static int aes_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
-                  const unsigned char *iv, int enc)
-       {
-       int ret;
-
-       if (((ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_ECB_MODE
-           || (ctx->cipher->flags & EVP_CIPH_MODE) == EVP_CIPH_CBC_MODE)
-           && !enc) 
-               ret=AES_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
-       else
-               ret=AES_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data);
-
-       if(ret < 0)
-               {
-               EVPerr(EVP_F_AES_INIT_KEY,EVP_R_AES_KEY_SETUP_FAILED);
-               return 0;
-               }
-
-       return 1;
-       }
-
 typedef struct
        {
        /* AES key schedule to use */
@@ -482,7 +662,7 @@ static int aes_xts_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key,
        if (key)
                {
                /* key_len is two AES keys */
-               if (ctx->encrypt)
+               if (enc)
                        {
                        AES_set_encrypt_key(key, ctx->key_len * 4, &xctx->ks1);
                        xctx->xts.block1 = (block128_f)AES_encrypt;