summaryrefslogtreecommitdiffstats
path: root/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c
diff options
context:
space:
mode:
Diffstat (limited to 'providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c')
-rw-r--r--providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c b/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c
new file mode 100644
index 0000000000..66f6ed457e
--- /dev/null
+++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * AES low level APIs are deprecated for public use, but still ok for internal
+ * use where we're using them to implement the higher level EVP interface, as is
+ * the case here.
+ */
+#include "internal/deprecated.h"
+
+#include <openssl/evp.h>
+#include <internal/endian.h>
+#include <prov/implementations.h>
+#include "cipher_aes_gcm_siv.h"
+
+static ossl_inline void mulx_ghash(uint64_t *a)
+{
+ uint64_t t[2], mask;
+
+ t[0] = BSWAP8(a[0]);
+ t[1] = BSWAP8(a[1]);
+ mask = -(int64_t)(t[1] & 1) & 0xe1;
+ mask <<= 56;
+
+ a[1] = BSWAP8((t[1] >> 1) ^ (t[0] << 63));
+ a[0] = BSWAP8((t[0] >> 1) ^ mask);
+}
+
+#define aligned64(p) (((uintptr_t)p & 0x07) == 0)
+static ossl_inline void byte_reverse16(uint8_t *out, const uint8_t *in)
+{
+ if (aligned64(out) && aligned64(in)) {
+ ((uint64_t *)out)[0] = BSWAP8(((uint64_t *)in)[1]);
+ ((uint64_t *)out)[1] = BSWAP8(((uint64_t *)in)[0]);
+ } else {
+ int i;
+
+ for (i = 0; i < 16; i++)
+ out[i] = in[15 - i];
+ }
+}
+
+/* Initialization of POLYVAL via existing GHASH implementation */
+void ossl_polyval_ghash_init(u128 Htable[16], const uint64_t H[2])
+{
+ uint64_t tmp[2];
+ DECLARE_IS_ENDIAN;
+
+ byte_reverse16((uint8_t *)tmp, (const uint8_t *)H);
+ mulx_ghash(tmp);
+ if (IS_LITTLE_ENDIAN) {
+ /* "H is stored in host byte order" */
+ tmp[0] = BSWAP8(tmp[0]);
+ tmp[1] = BSWAP8(tmp[1]);
+ }
+
+ ossl_gcm_init_4bit(Htable, (u64*)tmp);
+}
+
+/* Implmentation of POLYVAL via existing GHASH implementation */
+void ossl_polyval_ghash_hash(const u128 Htable[16], uint8_t *tag, const uint8_t *inp, size_t len)
+{
+ uint64_t out[2];
+ uint64_t tmp[2];
+ size_t i;
+
+ byte_reverse16((uint8_t *)out, (uint8_t *)tag);
+
+ /*
+ * This implementation doesn't deal with partials, callers do,
+ * so, len is a multiple of 16
+ */
+ for (i = 0; i < len; i += 16) {
+ byte_reverse16((uint8_t *)tmp, &inp[i]);
+ ossl_gcm_ghash_4bit((u64*)out, Htable, (uint8_t *)tmp, 16);
+ }
+ byte_reverse16(tag, (uint8_t *)out);
+}