aarch64 support.
This is an initial cut at aarch64 support. I have only qemu to test it
however—hopefully hardware will be coming soon.
This also affects 32-bit ARM in that aarch64 chips can run 32-bit code
and we would like to be able to take advantage of the crypto operations
even in 32-bit mode. AES and GHASH should Just Work in this case: the
-armx.pl files can be built for either 32- or 64-bit mode based on the
flavour argument given to the Perl script.
SHA-1 and SHA-256 don't work like this however because they've never
support for multiple implementations, thus BoringSSL built for 32-bit
won't use the SHA instructions on an aarch64 chip.
No dedicated ChaCha20 or Poly1305 support yet.
Change-Id: Ib275bc4894a365c8ec7c42f4e91af6dba3bd686c
Reviewed-on: https://boringssl-review.googlesource.com/2801
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/cipher/e_aes.c b/crypto/cipher/e_aes.c
index 03cef73..0b8b4b9 100644
--- a/crypto/cipher/e_aes.c
+++ b/crypto/cipher/e_aes.c
@@ -103,14 +103,33 @@
}
#endif
-#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM)
+#elif !defined(OPENSSL_NO_ASM) && \
+ (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
#include "../arm_arch.h"
-#if __ARM_ARCH__ >= 7
+
+#if defined(OPENSSL_ARM)
#define BSAES
static char bsaes_capable(void) {
return CRYPTO_is_NEON_capable();
}
-#endif /* __ARM_ARCH__ >= 7 */
+#endif
+
+#define HWAES
+static char 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);
+void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, const int enc);
+void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, const uint8_t ivec[16]);
+
#endif /* OPENSSL_ARM */
#if defined(BSAES)
@@ -174,6 +193,41 @@
}
#endif
+#if !defined(HWAES)
+/* If HWAES isn't defined then we provide dummy functions for each of the hwaes
+ * functions. */
+int hwaes_capable() {
+ return 0;
+}
+
+int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits,
+ AES_KEY *key) {
+ abort();
+}
+
+int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) {
+ abort();
+}
+
+void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+
+void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) {
+ abort();
+}
+
+void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length,
+ const AES_KEY *key, uint8_t *ivec, int enc) {
+ abort();
+}
+
+void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len,
+ const AES_KEY *key, const uint8_t ivec[16]) {
+ abort();
+}
+#endif
+
#if !defined(OPENSSL_NO_ASM) && \
(defined(OPENSSL_X86_64) || defined(OPENSSL_X86))
int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key);
@@ -227,7 +281,14 @@
mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK;
if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) {
- if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) {
+ if (hwaes_capable()) {
+ ret = aes_v8_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)aes_v8_decrypt;
+ dat->stream.cbc = NULL;
+ if (mode == EVP_CIPH_CBC_MODE) {
+ dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt;
+ }
+ } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) {
ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
dat->block = (block128_f)AES_decrypt;
dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt;
@@ -242,6 +303,15 @@
dat->stream.cbc =
mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL;
}
+ } else if (hwaes_capable()) {
+ ret = aes_v8_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
+ dat->block = (block128_f)aes_v8_encrypt;
+ dat->stream.cbc = NULL;
+ if (mode == EVP_CIPH_CBC_MODE) {
+ dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt;
+ } else if (mode == EVP_CIPH_CTR_MODE) {
+ dat->stream.ctr = (ctr128_f)aes_v8_ctr32_encrypt_blocks;
+ }
} else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) {
ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks);
dat->block = (block128_f)AES_encrypt;
@@ -316,6 +386,12 @@
static ctr128_f aes_gcm_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx,
const uint8_t *key, size_t key_len) {
+ if (hwaes_capable()) {
+ aes_v8_set_encrypt_key(key, key_len * 8, aes_key);
+ CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_v8_encrypt);
+ return (ctr128_f)aes_v8_ctr32_encrypt_blocks;
+ }
+
if (bsaes_capable()) {
AES_set_encrypt_key(key, key_len * 8, aes_key);
CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)AES_encrypt);
@@ -1274,6 +1350,8 @@
int EVP_has_aes_hardware(void) {
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
return aesni_capable() && crypto_gcm_clmul_enabled();
+#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
+ return hwaes_capable() && (OPENSSL_armcap_P & ARMV8_PMULL);
#else
return 0;
#endif