[ovs-dev] [PATCH v3] Replace DIY AES with openssl if openssl is available

anton.ivanov at cambridgegreys.com anton.ivanov at cambridgegreys.com
Thu Aug 19 15:57:25 UTC 2021


From: Anton Ivanov <anton.ivanov at cambridgegreys.com>

This allows to leverage the openssl implementation which can use
hardware crypto on supported platforms.

UUID generation speed is improved by ~ 12% on an AMD Ryzen with
support for AES instructions.

Signed-off-by: Anton Ivanov <anton.ivanov at cambridgegreys.com>
---
 lib/aes128.c        | 79 +++++++++++++++++++++++++++++++++++++++++++--
 lib/aes128.h        | 13 +++++---
 lib/uuid.c          |  6 ++--
 tests/test-aes128.c |  6 ++--
 4 files changed, 90 insertions(+), 14 deletions(-)

diff --git a/lib/aes128.c b/lib/aes128.c
index 98447d14b..8236e8ba0 100644
--- a/lib/aes128.c
+++ b/lib/aes128.c
@@ -28,6 +28,75 @@
 
 #include "util.h"
 
+#ifdef HAVE_OPENSSL
+
+#include <openssl/conf.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <string.h>
+#include "entropy.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(aes);
+
+struct aes128 {
+    EVP_CIPHER_CTX *ctx;
+};
+
+void *aes128_schedule(const uint8_t key[16])
+{
+    uint8_t iv[16];
+
+    struct aes128 *aes = xmalloc(sizeof *aes);
+
+    aes->ctx = EVP_CIPHER_CTX_new();
+    memset(iv, 0, sizeof iv);
+    if (EVP_EncryptInit_ex(aes->ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
+        unsigned long ssl_error = ERR_get_error();
+
+        ERR_load_crypto_strings();
+        VLOG_FATAL("Encryption init failed. Error %s",
+                   ERR_error_string(ssl_error, NULL));
+    }
+    return aes;
+}
+
+void aes128_encrypt(void *aes, const void *plain, void *cipher)
+{
+    int len;
+    struct aes128 *aes_ctx = aes;
+
+    if (1 != EVP_EncryptUpdate(aes_ctx->ctx, cipher, &len, plain, 16)) {
+        unsigned long ssl_error = ERR_get_error();
+
+        ERR_load_crypto_strings();
+        VLOG_FATAL("Encryption failed. Error %s",
+                   ERR_error_string(ssl_error, NULL));
+    }
+}
+
+#else
+
+struct aes128 {
+    uint32_t rk[128/8 + 28];
+};
+
+void *aes128_schedule(const uint8_t key[16])
+{
+    return ovs_aes128_schedule(key);
+}
+
+void aes128_encrypt(void *aes, const void *input_, void *output_)
+{
+    ovs_aes128_encrypt(aes, input_, output_);
+}
+
+#endif
+
+struct ovs_aes128 {
+    uint32_t rk[128/8 + 28];
+};
+
 static const uint32_t Te0[256] = {
     0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
     0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
@@ -390,8 +459,9 @@ put_u32(uint8_t *p, uint32_t x)
 
 /* Expands 128-bit 'key' into the encryption key 'schedule'. */
 void
-aes128_schedule(struct aes128 *aes, const uint8_t key[16])
+*ovs_aes128_schedule(const uint8_t key[16])
 {
+    struct ovs_aes128 *aes = xmalloc(sizeof *aes);
     uint32_t *rk = aes->rk;
     int i;
 
@@ -412,14 +482,16 @@ aes128_schedule(struct aes128 *aes, const uint8_t key[16])
         rk[7] = rk[3] ^ rk[6];
     }
     ovs_assert(rk == &aes->rk[40]);
+    return aes;
 }
 
 void
-aes128_encrypt(const struct aes128 *aes, const void *input_, void *output_)
+ovs_aes128_encrypt(void *aes, const void *input_, void *output_)
 {
     const uint8_t *input = input_;
     uint8_t *output = output_;
-    const uint32_t *rk = aes->rk;
+    struct ovs_aes128 *ovs_aes = aes;
+    const uint32_t *rk = ovs_aes->rk;
     uint32_t s0, s1, s2, s3;
     uint32_t t0, t1, t2, t3;
     int r;
@@ -507,3 +579,4 @@ aes128_encrypt(const struct aes128 *aes, const void *input_, void *output_)
           ^ rk[3]);
     put_u32(output + 12, s3);
 }
+
diff --git a/lib/aes128.h b/lib/aes128.h
index f0f55d7cf..3e04e00c4 100644
--- a/lib/aes128.h
+++ b/lib/aes128.h
@@ -27,11 +27,14 @@
 
 #include <stdint.h>
 
-struct aes128 {
-    uint32_t rk[128/8 + 28];
-};
 
-void aes128_schedule(struct aes128 *, const uint8_t key[16]);
-void aes128_encrypt(const struct aes128 *, const void *, void *);
+void *aes128_schedule(const uint8_t key[16]);
+void aes128_encrypt(void *, const void *, void *);
+
+/* These are exposed for unit test purposes. */
+
+
+void *ovs_aes128_schedule(const uint8_t key[16]);
+void ovs_aes128_encrypt(void *, const void *, void *);
 
 #endif  /* aes128.h */
diff --git a/lib/uuid.c b/lib/uuid.c
index 8a16606da..3e14dcb5f 100644
--- a/lib/uuid.c
+++ b/lib/uuid.c
@@ -36,7 +36,7 @@
 
 VLOG_DEFINE_THIS_MODULE(uuid);
 
-static struct aes128 key;
+static void *key;
 static uint64_t counter[2];
 BUILD_ASSERT_DECL(sizeof counter == 16);
 
@@ -164,7 +164,7 @@ uuid_generate(struct uuid *uuid)
     ovs_mutex_unlock(&mutex);
 
     /* AES output is exactly 16 bytes, so we encrypt directly into 'uuid'. */
-    aes128_encrypt(&key, copy, uuid);
+    aes128_encrypt(key, copy, uuid);
 
     uuid_set_bits_v4(uuid);
 
@@ -370,7 +370,7 @@ do_init(void)
 
     /* Generate key. */
     BUILD_ASSERT(sizeof sha1 >= 16);
-    aes128_schedule(&key, sha1);
+    key = aes128_schedule(sha1);
 
     /* Generate initial counter. */
     get_entropy_or_die(counter, sizeof counter);
diff --git a/tests/test-aes128.c b/tests/test-aes128.c
index 7960551be..8706a7c7c 100644
--- a/tests/test-aes128.c
+++ b/tests/test-aes128.c
@@ -46,7 +46,7 @@ error:
 static void
 test_aes128_main(int argc, char *argv[])
 {
-    struct aes128 aes;
+    void *aes;
     uint8_t plaintext[16];
     uint8_t ciphertext[16];
     uint8_t key[16];
@@ -60,8 +60,8 @@ test_aes128_main(int argc, char *argv[])
     hex_to_uint8(argv[1], key, 16);
     hex_to_uint8(argv[2], plaintext, 16);
 
-    aes128_schedule(&aes, key);
-    aes128_encrypt(&aes, plaintext, ciphertext);
+    aes = ovs_aes128_schedule(key);
+    ovs_aes128_encrypt(aes, plaintext, ciphertext);
     for (i = 0; i < 16; i++) {
         printf("%02x", ciphertext[i]);
     }
-- 
2.20.1



More information about the dev mailing list