Use armv8 functions for of AES_[en|de]crypt and AES_set_[en|de]crypt_key, if available.

This change causes ARM and Aarch64 to use the ARMv8 AES instructions, if
provided by the current CPU.

Change-Id: I50cb36270139fcf4ce42e5ebb8afe24ffcab22e3
Reviewed-on: https://boringssl-review.googlesource.com/6002
Reviewed-by: David Benjamin <davidben@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/aes/aes.c b/crypto/aes/aes.c
index 933aa07..12cd2f3 100644
--- a/crypto/aes/aes.c
+++ b/crypto/aes/aes.c
@@ -49,10 +49,49 @@
 #include <openssl/aes.h>
 
 #include <assert.h>
+#include <stdlib.h>
 
 #include "internal.h"
 
 
+#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
+#include <openssl/arm_arch.h>
+
+static int hwaes_capable(void) {
+  return (OPENSSL_armcap_P & ARMV8_AES) != 0;
+}
+
+int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits,
+                           AES_KEY *key);
+int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits,
+                           AES_KEY *key);
+void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
+
+#else
+
+static int hwaes_capable(void) {
+  return 0;
+}
+
+static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
+  abort();
+}
+
+static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
+  abort();
+}
+
+static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+  abort();
+}
+
+static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+  abort();
+}
+
+#endif
+
 #if defined(OPENSSL_NO_ASM) || \
     (!defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) && !defined(OPENSSL_ARM))
 
@@ -1064,22 +1103,38 @@
 
 void asm_AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
 void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
-  asm_AES_encrypt(in, out, key);
+  if (hwaes_capable()) {
+    aes_v8_encrypt(in, out, key);
+  } else {
+    asm_AES_encrypt(in, out, key);
+  }
 }
 
 void asm_AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key);
 void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
-  asm_AES_decrypt(in, out, key);
+  if (hwaes_capable()) {
+    aes_v8_decrypt(in, out, key);
+  } else {
+    asm_AES_decrypt(in, out, key);
+  }
 }
 
 int asm_AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey);
 int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
-  return asm_AES_set_encrypt_key(key, bits, aeskey);
+  if (hwaes_capable()) {
+    return aes_v8_set_encrypt_key(key, bits, aeskey);
+  } else {
+    return asm_AES_set_encrypt_key(key, bits, aeskey);
+  }
 }
 
 int asm_AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey);
 int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) {
-  return asm_AES_set_decrypt_key(key, bits, aeskey);
+  if (hwaes_capable()) {
+    return aes_v8_set_decrypt_key(key, bits, aeskey);
+  } else {
+    return asm_AES_set_decrypt_key(key, bits, aeskey);
+  }
 }
 
 #endif  /* OPENSSL_NO_ASM || (!OPENSSL_X86 && !OPENSSL_X86_64 && !OPENSSL_ARM) */