]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Implement AES-GCM-SIV (RFC8452)
authorTodd Short <tshort@akamai.com>
Thu, 28 Apr 2022 18:56:11 +0000 (14:56 -0400)
committerTodd Short <todd.short@me.com>
Fri, 29 Jul 2022 12:32:16 +0000 (08:32 -0400)
Fixes #16721

This uses AES-ECB to create a counter mode AES-CTR32 (32bit counter, I could
not get AES-CTR to work as-is), and GHASH to implement POLYVAL. Optimally,
there would be separate polyval assembly implementation(s), but the only one
I could find (and it was SSE2 x86_64 code) was not Apache 2.0 licensed.

This implementation lives only in the default provider; there is no legacy
implementation.

The code offered in #16721 is not used; that implementation sits on top of
OpenSSL, this one is embedded inside OpenSSL.

Full test vectors from RFC8452 are included, except the 0 length plaintext;
that is not supported; and I'm not sure it's worthwhile to do so.

Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/18693)

18 files changed:
.github/workflows/run-checker-ci.yml
apps/speed.c
crypto/modes/gcm128.c
doc/man3/EVP_EncryptInit.pod
include/crypto/modes.h
include/openssl/core_names.h
include/openssl/evp.h
providers/defltprov.c
providers/implementations/ciphers/build.info
providers/implementations/ciphers/cipher_aes_gcm_siv.c [new file with mode: 0644]
providers/implementations/ciphers/cipher_aes_gcm_siv.h [new file with mode: 0644]
providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c [new file with mode: 0644]
providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c [new file with mode: 0644]
providers/implementations/include/prov/implementations.h
providers/implementations/include/prov/names.h
test/evp_test.c
test/recipes/30-test_evp.t
test/recipes/30-test_evp_data/evpciph_aes_gcm_siv.txt [new file with mode: 0644]

index cfc458ac583cc6fc89e3584c542918cbb1d56d58..222cffa5b9994aed910e3308e2d75c9ed9a4545b 100644 (file)
@@ -23,6 +23,7 @@ jobs:
           no-dtls,
           no-ec,
           no-ec2m,
+          no-siv,
           no-legacy,
           no-rfc3779,
           no-sock,
index 3d9e7479003e0ef2504baaf4eaefd003f004ea71..2eab740fc5b0537a4bf83f4f0e6e0bebd6910459 100644 (file)
@@ -2259,8 +2259,9 @@ int speed_main(int argc, char **argv)
                     }
                     OPENSSL_clear_free(loopargs[k].key, keylen);
 
-                    /* SIV mode only allows for a single Update operation */
-                    if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_SIV_MODE)
+                    /* GCM-SIV/SIV mode only allows for a single Update operation */
+                    if (EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_SIV_MODE
+                            || EVP_CIPHER_get_mode(evp_cipher) == EVP_CIPH_GCM_SIV_MODE)
                         (void)EVP_CIPHER_CTX_ctrl(loopargs[k].ctx,
                                                   EVP_CTRL_SET_SPEED, 1, NULL);
                 }
index 84cc6fb08a205e0917b7cb213e879b4a8c6c0e4d..9a9adc9df86b9bcecd748e6b7b65dcacc14cf748 100644 (file)
@@ -510,6 +510,43 @@ static void gcm_get_funcs(struct gcm_funcs_st *ctx)
 #endif
 }
 
+void ossl_gcm_init_4bit(u128 Htable[16], const u64 H[2])
+{
+    struct gcm_funcs_st funcs;
+
+    gcm_get_funcs(&funcs);
+    funcs.ginit(Htable, H);
+}
+
+void ossl_gcm_gmult_4bit(u64 Xi[2], const u128 Htable[16])
+{
+    struct gcm_funcs_st funcs;
+
+    gcm_get_funcs(&funcs);
+    funcs.gmult(Xi, Htable);
+}
+
+void ossl_gcm_ghash_4bit(u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len)
+{
+    struct gcm_funcs_st funcs;
+    u64 tmp[2];
+    size_t i;
+
+    gcm_get_funcs(&funcs);
+    if (funcs.ghash != NULL) {
+        funcs.ghash(Xi, Htable, inp, len);
+    } else {
+        /* Emulate ghash if needed */
+        for (i = 0; i < len; i += 16) {
+            memcpy(tmp, &inp[i], sizeof(tmp));
+            Xi[0] ^= tmp[0];
+            Xi[1] ^= tmp[1];
+            funcs.gmult(Xi, Htable);
+        }
+    }
+}
+
 void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block)
 {
     DECLARE_IS_ENDIAN;
index 4069866a9ff88efb5f757dd2a2a24430dbf7e633..f81fdb2e00c119a5f0985a2b3cd5b39408b00565 100644 (file)
@@ -1375,6 +1375,8 @@ AES.
 
 =head2 SIV Mode
 
+Both the AES-SIV and AES-GCM-SIV ciphers fall under this mode.
+
 For SIV mode ciphers the behaviour of the EVP interface is subtly
 altered and several additional ctrl operations are supported.
 
index 573e1197d09b70fd294eeb20364a6385a188ada1..d567a0ba84344617b47c012d3ca6e1b71edf6afb 100644 (file)
@@ -138,6 +138,12 @@ struct gcm128_context {
 #endif
 };
 
+/* GHASH functions */
+void ossl_gcm_init_4bit(u128 Htable[16], const u64 H[2]);
+void ossl_gcm_ghash_4bit(u64 Xi[2], const u128 Htable[16],
+                         const u8 *inp, size_t len);
+void ossl_gcm_gmult_4bit(u64 Xi[2], const u128 Htable[16]);
+
 /*
  * The maximum permitted number of cipher blocks per data unit in XTS mode.
  * Reference IEEE Std 1619-2018.
index 9cd8f220cce4b2c16d55e890d1b78d7ed4e0f32d..a8f875a59abd84bbfb7a279320d1028bfba789c6 100644 (file)
@@ -120,6 +120,11 @@ extern "C" {
 #define OSSL_CIPHER_CTS_MODE_CS2 "CS2"
 #define OSSL_CIPHER_CTS_MODE_CS3 "CS3"
 
+/* Known CIPHER names (not a complete list) */
+#define OSSL_CIPHER_NAME_AES_128_GCM_SIV      "AES-128-GCM-SIV"
+#define OSSL_CIPHER_NAME_AES_192_GCM_SIV      "AES-192-GCM-SIV"
+#define OSSL_CIPHER_NAME_AES_256_GCM_SIV      "AES-256-GCM-SIV"
+
 /* digest parameters */
 #define OSSL_DIGEST_PARAM_XOFLEN       "xoflen"        /* size_t */
 #define OSSL_DIGEST_PARAM_SSL3_MS      "ssl3-ms"       /* octet string */
index cec3fa98e9b55dd73a7fbe5a3e6ab8534361418c..d9b3db6ae6afeb0bf9f7278d8fba9aa1ef5dbeb2 100644 (file)
@@ -306,6 +306,7 @@ OSSL_DEPRECATEDIN_3_0 int
 # define         EVP_CIPH_WRAP_MODE              0x10002
 # define         EVP_CIPH_OCB_MODE               0x10003
 # define         EVP_CIPH_SIV_MODE               0x10004
+# define         EVP_CIPH_GCM_SIV_MODE           0x10005
 # define         EVP_CIPH_MODE                   0xF0007
 /* Set if variable length cipher */
 # define         EVP_CIPH_VARIABLE_LENGTH        0x8
index 3add4cdaf69e0af668b112ebd111500ce4205392..edfcc97bae7be5d2599a3c28f067c8bef30fc670 100644 (file)
@@ -194,6 +194,9 @@ static const OSSL_ALGORITHM_CAPABLE deflt_ciphers[] = {
     ALG(PROV_NAMES_AES_128_SIV, ossl_aes128siv_functions),
     ALG(PROV_NAMES_AES_192_SIV, ossl_aes192siv_functions),
     ALG(PROV_NAMES_AES_256_SIV, ossl_aes256siv_functions),
+    ALG(PROV_NAMES_AES_128_GCM_SIV, ossl_aes128gcm_siv_functions),
+    ALG(PROV_NAMES_AES_192_GCM_SIV, ossl_aes192gcm_siv_functions),
+    ALG(PROV_NAMES_AES_256_GCM_SIV, ossl_aes256gcm_siv_functions),
 #endif /* OPENSSL_NO_SIV */
     ALG(PROV_NAMES_AES_256_GCM, ossl_aes256gcm_functions),
     ALG(PROV_NAMES_AES_192_GCM, ossl_aes192gcm_functions),
index b5d9d4f6c1e5f1e0eba9a0a4220827245b8baca6..c8f35bb1d8829f550f4047757b5ada3ef31ee3a0 100644 (file)
@@ -26,6 +26,50 @@ $CHACHA_GOAL=../../libdefault.a
 $CHACHAPOLY_GOAL=../../libdefault.a
 $SIV_GOAL=../../libdefault.a
 
+IF[{- !$disabled{asm} -}]
+  $GHASHDEF_x86=GHASH_ASM
+  $GHASHDEF_x86_sse2=OPENSSL_IA32_SSE2
+
+  $GHASHDEF_x86_64=GHASH_ASM
+  $GHASHDEF_x86_64_sse2=OPENSSL_IA32_SSE2
+
+  # ghash-ia64.s doesn't work on VMS
+  IF[{- $config{target} !~ /^vms-/ -}]
+    $GHASHDEF_ia64=GHASH_ASM
+  ENDIF
+
+  $GHASHDEF_sparcv9=GHASH_ASM
+
+  $GHASHDEF_alpha=GHASH_ASM
+
+  $GHASHDEF_s390x=GHASH_ASM
+
+  $GHASHDEF_armv4=GHASH_ASM
+  $GHASHDEF_aarch64=
+
+  $GHASHDEF_parisc11=GHASH_ASM
+  $GHASHDEF_parisc20_64=$GHASHDEF_parisc11
+
+  $GHASHDEF_ppc32=
+  $GHASHDEF_ppc64=$GHASHDEF_ppc32
+
+  $GHASHDEF_c64xplus=GHASH_ASM
+
+  $GHASHDEF_riscv64=GHASH_ASM
+
+  # Now that we have defined all the arch specific variables, use the
+  # appropriate one, and define the appropriate macros
+
+  IF[$GHASHDEF_{- $target{asm_arch} -}]
+    $GHASHDEF=$GHASHDEF_{- $target{asm_arch} -}
+    IF[{- !$disabled{sse2} -}]
+      IF[$GHASHDEF_{- $target{asm_arch} -}_sse2]
+        $GHASHDEF=$GHASHDEF_{- $target{asm_arch} -}_sse2
+      ENDIF
+    ENDIF
+  ENDIF
+ENDIF
+
 # This source is common building blocks for all ciphers in all our providers.
 SOURCE[$COMMON_GOAL]=\
         ciphercommon.c ciphercommon_hw.c ciphercommon_block.c \
@@ -54,8 +98,10 @@ SOURCE[$AES_GOAL]=\
 SOURCE[$AES_GOAL]=cipher_aes_xts_fips.c
 
 IF[{- !$disabled{siv} -}]
+  DEFINE[$SIV_GOAL]=$GHASHDEF
   SOURCE[$SIV_GOAL]=\
-      cipher_aes_siv.c cipher_aes_siv_hw.c
+      cipher_aes_siv.c cipher_aes_siv_hw.c \
+      cipher_aes_gcm_siv.c cipher_aes_gcm_siv_hw.c cipher_aes_gcm_siv_polyval.c
 ENDIF
 
 IF[{- !$disabled{des} -}]
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv.c b/providers/implementations/ciphers/cipher_aes_gcm_siv.c
new file mode 100644 (file)
index 0000000..93e65d5
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * 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
+ */
+
+/* Dispatch functions for AES SIV mode */
+
+/*
+ * This file uses the low level AES functions (which are deprecated for
+ * non-internal use) in order to implement provider AES ciphers.
+ */
+#include "internal/deprecated.h"
+
+#include <openssl/proverr.h>
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/ciphercommon_aead.h"
+#include "prov/provider_ctx.h"
+#include "cipher_aes_gcm_siv.h"
+
+static int ossl_aes_gcm_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[]);
+
+static void *ossl_aes_gcm_siv_newctx(void *provctx, size_t keybits)
+{
+    PROV_AES_GCM_SIV_CTX *ctx;
+
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    ctx = OPENSSL_zalloc(sizeof(*ctx));
+    if (ctx != NULL) {
+        ctx->key_len = keybits / 8;
+        ctx->hw = ossl_prov_cipher_hw_aes_gcm_siv(keybits);
+        ctx->libctx = PROV_LIBCTX_OF(provctx);
+        ctx->provctx = provctx;
+    }
+    return ctx;
+}
+
+static void ossl_aes_gcm_siv_freectx(void *vctx)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+
+    if (ctx == NULL)
+        return;
+
+    OPENSSL_clear_free(ctx->aad, ctx->aad_len);
+    ctx->hw->clean_ctx(ctx);
+    OPENSSL_clear_free(ctx, sizeof(*ctx));
+}
+
+static void *ossl_aes_gcm_siv_dupctx(void *vctx)
+{
+    PROV_AES_GCM_SIV_CTX *in = (PROV_AES_GCM_SIV_CTX *)vctx;
+    PROV_AES_GCM_SIV_CTX *ret;
+
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    if (in->hw == NULL)
+        return NULL;
+
+    ret = OPENSSL_memdup(in, sizeof(*in));
+    if (ret == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
+    /* NULL-out these things we create later */
+    ret->aad = NULL;
+    ret->ecb_ctx = NULL;
+
+    if (in->aad == NULL) {
+        if ((ret->aad = OPENSSL_memdup(in->aad, UP16(ret->aad_len))) == NULL) {
+            ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+            goto err;
+        }
+    }
+
+    if (!in->hw->dup_ctx(ret, in))
+        goto err;
+
+    return ret;
+ err:
+    if (ret != NULL) {
+        OPENSSL_clear_free(ret->aad, ret->aad_len);
+        OPENSSL_free(ret);
+    }
+    return NULL;
+}
+
+static int ossl_aes_gcm_siv_init(void *vctx, const unsigned char *key, size_t keylen,
+                                 const unsigned char *iv, size_t ivlen,
+                                 const OSSL_PARAM params[], int enc)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    ctx->enc = enc;
+
+    if (key != NULL) {
+        if (keylen != ctx->key_len) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+            return 0;
+        }
+        memcpy(ctx->key_gen_key, key, ctx->key_len);
+    }
+    if (iv != NULL) {
+        if (ivlen != sizeof(ctx->nonce)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH);
+            return 0;
+        }
+        memcpy(ctx->nonce, iv, sizeof(ctx->nonce));
+    }
+
+    if (!ctx->hw->initkey(ctx))
+        return 0;
+
+    return ossl_aes_gcm_siv_set_ctx_params(ctx, params);
+}
+
+static int ossl_aes_gcm_siv_einit(void *vctx, const unsigned char *key, size_t keylen,
+                                  const unsigned char *iv, size_t ivlen,
+                                  const OSSL_PARAM params[])
+{
+    return ossl_aes_gcm_siv_init(vctx, key, keylen, iv, ivlen, params, 1);
+}
+
+static int ossl_aes_gcm_siv_dinit(void *vctx, const unsigned char *key, size_t keylen,
+                                  const unsigned char *iv, size_t ivlen,
+                                  const OSSL_PARAM params[])
+{
+    return ossl_aes_gcm_siv_init(vctx, key, keylen, iv, ivlen, params, 0);
+}
+
+#define ossl_aes_gcm_siv_stream_update ossl_aes_gcm_siv_cipher
+static int ossl_aes_gcm_siv_cipher(void *vctx, unsigned char *out, size_t *outl,
+                                   size_t outsize, const unsigned char *in, size_t inl)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+    int error = 0;
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    /* The RFC has a test case for this, but we don't try to do anything */
+    if (inl == 0) {
+        if (outl != NULL)
+            *outl = 0;
+        return 1;
+    }
+
+    if (outsize < inl) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+        return 0;
+    }
+
+    error |= !ctx->hw->cipher(ctx, out, in, inl);
+
+    if (outl != NULL && !error)
+        *outl = inl;
+    return !error;
+}
+
+static int ossl_aes_gcm_siv_stream_final(void *vctx, unsigned char *out, size_t *outl,
+                                         size_t outsize)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+    int error = 0;
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    error |= !ctx->hw->cipher(vctx, out, NULL, 0);
+
+    if (outl != NULL && !error)
+        *outl = 0;
+    return !error;
+}
+
+static int ossl_aes_gcm_siv_get_ctx_params(void *vctx, OSSL_PARAM params[])
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+    OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG);
+    if (p != NULL && p->data_type == OSSL_PARAM_OCTET_STRING) {
+        if (!ctx->enc || !ctx->generated_tag
+                || p->data_size != sizeof(ctx->tag)
+                || !OSSL_PARAM_set_octet_string(p, ctx->tag, sizeof(ctx->tag))) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+            return 0;
+        }
+    }
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, sizeof(ctx->tag))) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+    p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN);
+    if (p != NULL && !OSSL_PARAM_set_size_t(p, ctx->key_len)) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER);
+        return 0;
+    }
+    return 1;
+}
+
+static const OSSL_PARAM aes_gcm_siv_known_gettable_ctx_params[] = {
+    OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+    OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL),
+    OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *ossl_aes_gcm_siv_gettable_ctx_params(ossl_unused void *cctx,
+                                                              ossl_unused void *provctx)
+{
+    return aes_gcm_siv_known_gettable_ctx_params;
+}
+
+static int ossl_aes_gcm_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+    const OSSL_PARAM *p;
+    unsigned int speed = 0;
+
+    if (params == NULL)
+        return 1;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG);
+    if (p != NULL) {
+        if (p->data_type != OSSL_PARAM_OCTET_STRING
+                || p->data_size != sizeof(ctx->user_tag)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
+        if (!ctx->enc) {
+            memcpy(ctx->user_tag, p->data, sizeof(ctx->tag));
+            ctx->have_user_tag = 1;
+        }
+    }
+    p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_SPEED);
+    if (p != NULL) {
+        if (!OSSL_PARAM_get_uint(p, &speed)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
+        ctx->speed = !!speed;
+    }
+    p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN);
+    if (p != NULL) {
+        size_t key_len;
+
+        if (!OSSL_PARAM_get_size_t(p, &key_len)) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
+            return 0;
+        }
+        /* The key length can not be modified */
+        if (key_len != ctx->key_len) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static const OSSL_PARAM aes_gcm_siv_known_settable_ctx_params[] = {
+    OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL),
+    OSSL_PARAM_uint(OSSL_CIPHER_PARAM_SPEED, NULL),
+    OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0),
+    OSSL_PARAM_END
+};
+static const OSSL_PARAM *ossl_aes_gcm_siv_settable_ctx_params(ossl_unused void *cctx,
+                                                              ossl_unused void *provctx)
+{
+    return aes_gcm_siv_known_settable_ctx_params;
+}
+
+#define IMPLEMENT_cipher(alg, lc, UCMODE, flags, kbits, blkbits, ivbits)                                \
+static OSSL_FUNC_cipher_newctx_fn              ossl_##alg##kbits##_##lc##_newctx;                       \
+static OSSL_FUNC_cipher_freectx_fn             ossl_##alg##_##lc##_freectx;                             \
+static OSSL_FUNC_cipher_dupctx_fn              ossl_##alg##_##lc##_dupctx;                              \
+static OSSL_FUNC_cipher_encrypt_init_fn        ossl_##alg##_##lc##_einit;                               \
+static OSSL_FUNC_cipher_decrypt_init_fn        ossl_##alg##_##lc##_dinit;                               \
+static OSSL_FUNC_cipher_update_fn              ossl_##alg##_##lc##_stream_update;                       \
+static OSSL_FUNC_cipher_final_fn               ossl_##alg##_##lc##_stream_final;                        \
+static OSSL_FUNC_cipher_cipher_fn              ossl_##alg##_##lc##_cipher;                              \
+static OSSL_FUNC_cipher_get_params_fn          ossl_##alg##_##kbits##_##lc##_get_params;                \
+static OSSL_FUNC_cipher_get_ctx_params_fn      ossl_##alg##_##lc##_get_ctx_params;                      \
+static OSSL_FUNC_cipher_gettable_ctx_params_fn ossl_##alg##_##lc##_gettable_ctx_params;                 \
+static OSSL_FUNC_cipher_set_ctx_params_fn      ossl_##alg##_##lc##_set_ctx_params;                      \
+static OSSL_FUNC_cipher_settable_ctx_params_fn ossl_##alg##_##lc##_settable_ctx_params;                 \
+static int ossl_##alg##_##kbits##_##lc##_get_params(OSSL_PARAM params[])                                \
+{                                                                                                       \
+    return ossl_cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE,                             \
+                                          flags, kbits, blkbits, ivbits);                               \
+}                                                                                                       \
+static void * ossl_##alg##kbits##_##lc##_newctx(void *provctx)                                          \
+{                                                                                                       \
+    return ossl_##alg##_##lc##_newctx(provctx, kbits);                                                  \
+}                                                                                                       \
+const OSSL_DISPATCH ossl_##alg##kbits##lc##_functions[] = {                                             \
+    { OSSL_FUNC_CIPHER_NEWCTX,              (void (*)(void))ossl_##alg##kbits##_##lc##_newctx },        \
+    { OSSL_FUNC_CIPHER_FREECTX,             (void (*)(void))ossl_##alg##_##lc##_freectx },              \
+    { OSSL_FUNC_CIPHER_DUPCTX,              (void (*)(void))ossl_##alg##_##lc##_dupctx },               \
+    { OSSL_FUNC_CIPHER_ENCRYPT_INIT,        (void (*)(void))ossl_##alg##_##lc##_einit },                \
+    { OSSL_FUNC_CIPHER_DECRYPT_INIT,        (void (*)(void))ossl_##alg##_##lc##_dinit },                \
+    { OSSL_FUNC_CIPHER_UPDATE,              (void (*)(void))ossl_##alg##_##lc##_stream_update },        \
+    { OSSL_FUNC_CIPHER_FINAL,               (void (*)(void))ossl_##alg##_##lc##_stream_final },         \
+    { OSSL_FUNC_CIPHER_CIPHER,              (void (*)(void))ossl_##alg##_##lc##_cipher },               \
+    { OSSL_FUNC_CIPHER_GET_PARAMS,          (void (*)(void))ossl_##alg##_##kbits##_##lc##_get_params }, \
+    { OSSL_FUNC_CIPHER_GETTABLE_PARAMS,     (void (*)(void))ossl_cipher_generic_gettable_params },      \
+    { OSSL_FUNC_CIPHER_GET_CTX_PARAMS,      (void (*)(void))ossl_##alg##_##lc##_get_ctx_params },       \
+    { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, (void (*)(void))ossl_##alg##_##lc##_gettable_ctx_params },  \
+    { OSSL_FUNC_CIPHER_SET_CTX_PARAMS,      (void (*)(void))ossl_##alg##_##lc##_set_ctx_params },       \
+    { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, (void (*)(void))ossl_##alg##_##lc##_settable_ctx_params },  \
+    { 0, NULL }                                                                                         \
+}
+
+IMPLEMENT_cipher(aes, gcm_siv, GCM_SIV, AEAD_FLAGS, 128, 8, 96);
+IMPLEMENT_cipher(aes, gcm_siv, GCM_SIV, AEAD_FLAGS, 192, 8, 96);
+IMPLEMENT_cipher(aes, gcm_siv, GCM_SIV, AEAD_FLAGS, 256, 8, 96);
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv.h b/providers/implementations/ciphers/cipher_aes_gcm_siv.h
new file mode 100644 (file)
index 0000000..1224512
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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
+ */
+
+#include <openssl/aes.h>
+#include "prov/ciphercommon.h"
+#include "crypto/aes_platform.h"
+
+#define BLOCK_SIZE 16
+#define NONCE_SIZE 12
+#define TAG_SIZE   16
+
+/* AAD manipulation macros */
+#define UP16(x) (((x) + 15) & ~0x0F)
+#define DOWN16(x) ((x) & ~0x0F)
+#define REMAINDER16(x) ((x) & 0x0F)
+#define IS16(x) (((x) & 0x0F) == 0)
+
+typedef struct prov_cipher_hw_aes_gcm_siv_st {
+    int (*initkey)(void *vctx);
+    int (*cipher)(void *vctx, unsigned char *out, const unsigned char *in,
+                  size_t len);
+    int (*dup_ctx)(void *vdst, void *vsrc);
+    void (*clean_ctx)(void *vctx);
+} PROV_CIPHER_HW_AES_GCM_SIV;
+
+/* Arranged for alignment purposes */
+typedef struct prov_aes_gcm_siv_ctx_st {
+    EVP_CIPHER_CTX *ecb_ctx;
+    const PROV_CIPHER_HW_AES_GCM_SIV *hw; /* maybe not used, yet? */
+    uint8_t *aad;            /* Allocated, rounded up to 16 bytes, from user */
+    OSSL_LIB_CTX *libctx;
+    OSSL_PROVIDER *provctx;
+    size_t aad_len;          /* actual AAD length */
+    size_t key_len;
+    uint8_t key_gen_key[32]; /* from user */
+    uint8_t msg_enc_key[32]; /* depends on key size */
+    uint8_t msg_auth_key[BLOCK_SIZE];
+    uint8_t tag[TAG_SIZE];          /* generated tag, given to user or compared to user */
+    uint8_t user_tag[TAG_SIZE];     /* from user */
+    uint8_t nonce[NONCE_SIZE];       /* from user */
+    u128 Htable[16];         /* Polyval calculations via ghash */
+    unsigned int enc : 1;    /* Set to 1 if we are encrypting or 0 otherwise */
+    unsigned int have_user_tag : 1;
+    unsigned int generated_tag : 1;
+    unsigned int used_enc : 1;
+    unsigned int used_dec : 1;
+    unsigned int speed : 1;
+} PROV_AES_GCM_SIV_CTX;
+
+const PROV_CIPHER_HW_AES_GCM_SIV *ossl_prov_cipher_hw_aes_gcm_siv(size_t keybits);
+
+void ossl_polyval_ghash_init(u128 Htable[16], const uint64_t H[2]);
+void ossl_polyval_ghash_hash(const u128 Htable[16], uint8_t *tag,  const uint8_t *inp, size_t len);
+
+/* Define our own BSWAP8/BSWAP4, if not already defined */
+#ifndef BSWAP8
+static ossl_inline uint64_t BSWAP8(uint64_t n)
+{
+    uint8_t *p = (uint8_t *)&n;
+
+    return (uint64_t)GETU32(p) << 32 | GETU32(p + 4);
+}
+#endif
+
+#ifndef BSWAP4
+static ossl_inline uint32_t BSWAP4(uint32_t n)
+{
+    uint8_t *p = (uint8_t *)&n;
+
+    return GETU32(p);
+}
+#endif
diff --git a/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c
new file mode 100644 (file)
index 0000000..9ee5c32
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * 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 int aes_gcm_siv_ctr32(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *init_counter,
+                             unsigned char *out, const unsigned char *in, size_t len);
+
+static int aes_gcm_siv_initkey(void *vctx)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+    uint8_t output[BLOCK_SIZE];
+    uint32_t counter = 0x0;
+    size_t i;
+    union {
+        uint32_t counter;
+        uint8_t block[BLOCK_SIZE];
+    } data;
+    int out_len;
+    EVP_CIPHER *ecb = NULL;
+    DECLARE_IS_ENDIAN;
+
+    switch (ctx->key_len) {
+    case 16:
+        ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-128-ECB", NULL);
+        break;
+    case 24:
+        ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-192-ECB", NULL);
+        break;
+    case 32:
+        ecb = EVP_CIPHER_fetch(ctx->libctx, "AES-256-ECB", NULL);
+        break;
+    default:
+        goto err;
+    }
+
+    if (ctx->ecb_ctx == NULL && (ctx->ecb_ctx = EVP_CIPHER_CTX_new()) == NULL)
+        goto err;
+    if (!EVP_EncryptInit_ex2(ctx->ecb_ctx, ecb, ctx->key_gen_key, NULL, NULL))
+        goto err;
+
+    memset(&data, 0, sizeof(data));
+    memcpy(&data.block[sizeof(data.counter)], ctx->nonce, NONCE_SIZE);
+
+    /* msg_auth_key is always 16 bytes in size, regardless of AES128/AES256 */
+    /* counter is stored little-endian */
+    for (i = 0; i < BLOCK_SIZE; i += 8) {
+        if (IS_LITTLE_ENDIAN) {
+            data.counter = counter;
+        } else {
+            data.counter = BSWAP4(counter);
+        }
+        /* Block size is 16 (128 bits), but only 8 bytes are used */
+        out_len = BLOCK_SIZE;
+        if (!EVP_EncryptUpdate(ctx->ecb_ctx, output, &out_len, data.block, BLOCK_SIZE))
+            goto err;
+        memcpy(&ctx->msg_auth_key[i], output, 8);
+        counter++;
+    }
+
+    /* msg_enc_key length is directly tied to key length AES128/AES256 */
+    for (i = 0; i < ctx->key_len; i += 8) {
+        if (IS_LITTLE_ENDIAN) {
+            data.counter = counter;
+        } else {
+            data.counter = BSWAP4(counter);
+        }
+        /* Block size is 16 bytes (128 bits), but only 8 bytes are used */
+        out_len = BLOCK_SIZE;
+        if (!EVP_EncryptUpdate(ctx->ecb_ctx, output, &out_len, data.block, BLOCK_SIZE))
+            goto err;
+        memcpy(&ctx->msg_enc_key[i], output, 8);
+        counter++;
+    }
+
+    if (!EVP_EncryptInit_ex2(ctx->ecb_ctx, ecb, ctx->msg_enc_key, NULL, NULL))
+        goto err;
+
+    /* Freshen up the state */
+    ctx->used_enc = 0;
+    ctx->used_dec = 0;
+    EVP_CIPHER_free(ecb);
+    return 1;
+ err:
+    EVP_CIPHER_CTX_free(ctx->ecb_ctx);
+    EVP_CIPHER_free(ecb);
+    ctx->ecb_ctx = NULL;
+    return 0;
+}
+
+static int aes_gcm_siv_aad(PROV_AES_GCM_SIV_CTX *ctx,
+                           const unsigned char *aad, size_t len)
+{
+    size_t to_alloc;
+    uint8_t *ptr;
+    uint64_t len64;
+
+    /* length of 0 resets the AAD */
+    if (len == 0) {
+        OPENSSL_free(ctx->aad);
+        ctx->aad = NULL;
+        ctx->aad_len = 0;
+        return 1;
+    }
+    to_alloc = UP16(ctx->aad_len + len);
+    /* need to check the size of the AAD per RFC8452 */
+    len64 = to_alloc;
+    if (len64 > ((uint64_t)1 << 36))
+        return 0;
+    ptr = OPENSSL_realloc(ctx->aad, to_alloc);
+    if (ptr == NULL)
+        return 0;
+    ctx->aad = ptr;
+    memcpy(&ctx->aad[ctx->aad_len], aad, len);
+    ctx->aad_len += len;
+    if (to_alloc > ctx->aad_len)
+        memset(&ctx->aad[ctx->aad_len], 0, to_alloc - ctx->aad_len);
+    return 1;
+}
+
+static int aes_gcm_siv_finish(PROV_AES_GCM_SIV_CTX *ctx)
+{
+    int ret = 0;
+
+    if (ctx->enc)
+        return ctx->generated_tag;
+    ret = !CRYPTO_memcmp(ctx->tag, ctx->user_tag, sizeof(ctx->tag));
+    ret &= ctx->have_user_tag;
+    return ret;
+}
+
+static int aes_gcm_siv_encrypt(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *in,
+                               unsigned char *out, size_t len)
+{
+    uint64_t len_blk[2];
+    uint8_t S_s[TAG_SIZE];
+    uint8_t counter_block[TAG_SIZE];
+    uint8_t padding[BLOCK_SIZE];
+    size_t i;
+    int64_t len64 = len;
+    int out_len;
+    int error = 0;
+    DECLARE_IS_ENDIAN;
+
+    ctx->generated_tag = 0;
+    if (!ctx->speed && ctx->used_enc)
+        return 0;
+    /* need to check the size of the input! */
+    if (len64 > ((int64_t)1 << 36) || len == 0)
+        return 0;
+
+    if (IS_LITTLE_ENDIAN) {
+        len_blk[0] = (uint64_t)ctx->aad_len * 8;
+        len_blk[1] = (uint64_t)len * 8;
+    } else {
+        len_blk[0] = BSWAP8((uint64_t)ctx->aad_len * 8);
+        len_blk[1] = BSWAP8((uint64_t)len * 8);
+    }
+    memset(S_s, 0, TAG_SIZE);
+    ossl_polyval_ghash_init(ctx->Htable, (const uint64_t*)ctx->msg_auth_key);
+
+    if (ctx->aad != NULL) {
+        /* AAD is allocated with padding, but need to adjust length */
+        ossl_polyval_ghash_hash(ctx->Htable, S_s, ctx->aad, UP16(ctx->aad_len));
+    }
+    if (DOWN16(len) > 0)
+        ossl_polyval_ghash_hash(ctx->Htable, S_s, (uint8_t *) in, DOWN16(len));
+    if (!IS16(len)) {
+        /* deal with padding - probably easier to memset the padding first rather than calculate */
+        memset(padding, 0, sizeof(padding));
+        memcpy(padding, &in[DOWN16(len)], REMAINDER16(len));
+        ossl_polyval_ghash_hash(ctx->Htable, S_s, padding, sizeof(padding));
+    }
+    ossl_polyval_ghash_hash(ctx->Htable, S_s, (uint8_t *) len_blk, sizeof(len_blk));
+
+    for (i = 0; i < NONCE_SIZE; i++)
+        S_s[i] ^= ctx->nonce[i];
+
+    S_s[TAG_SIZE - 1] &= 0x7f;
+    out_len = sizeof(ctx->tag);
+    error |= !EVP_EncryptUpdate(ctx->ecb_ctx, ctx->tag, &out_len, S_s, sizeof(S_s));
+    memcpy(counter_block, ctx->tag, TAG_SIZE);
+    counter_block[TAG_SIZE - 1] |= 0x80;
+
+    error |= !aes_gcm_siv_ctr32(ctx, counter_block, out, in, len);
+
+    ctx->generated_tag = !error;
+    /* Regardless of error */
+    ctx->used_enc = 1;
+    return !error;
+}
+
+static int aes_gcm_siv_decrypt(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *in,
+                               unsigned char *out, size_t len)
+{
+    uint8_t counter_block[TAG_SIZE];
+    uint64_t len_blk[2];
+    uint8_t S_s[TAG_SIZE];
+    size_t i;
+    uint64_t padding[2];
+    int64_t len64 = len;
+    int out_len;
+    int error = 0;
+    DECLARE_IS_ENDIAN;
+
+    ctx->generated_tag = 0;
+    if (!ctx->speed && ctx->used_dec)
+        return 0;
+    /* need to check the size of the input! */
+    if (len64 > ((int64_t)1 << 36) || len == 0)
+        return 0;
+
+    memcpy(counter_block, ctx->user_tag, sizeof(counter_block));
+    counter_block[TAG_SIZE - 1] |= 0x80;
+
+    error |= !aes_gcm_siv_ctr32(ctx, counter_block, out, in, len);
+
+    if (IS_LITTLE_ENDIAN) {
+        len_blk[0] = (uint64_t)ctx->aad_len * 8;
+        len_blk[1] = (uint64_t)len * 8;
+    } else {
+        len_blk[0] = BSWAP8((uint64_t)ctx->aad_len * 8);
+        len_blk[1] = BSWAP8((uint64_t)len * 8);
+    }
+    memset(S_s, 0, TAG_SIZE);
+    ossl_polyval_ghash_init(ctx->Htable, (const uint64_t*)ctx->msg_auth_key);
+    if (ctx->aad != NULL) {
+        /* AAD allocated with padding, but need to adjust length */
+        ossl_polyval_ghash_hash(ctx->Htable, S_s, ctx->aad, UP16(ctx->aad_len));
+    }
+    if (DOWN16(len) > 0)
+        ossl_polyval_ghash_hash(ctx->Htable, S_s, out, DOWN16(len));
+    if (!IS16(len)) {
+        /* deal with padding - probably easier to "memset" the padding first rather than calculate */
+        padding[0] = padding[1] = 0;
+        memcpy(padding, &out[DOWN16(len)], REMAINDER16(len));
+        ossl_polyval_ghash_hash(ctx->Htable, S_s, (uint8_t *)padding, sizeof(padding));
+    }
+    ossl_polyval_ghash_hash(ctx->Htable, S_s, (uint8_t *)len_blk, TAG_SIZE);
+
+    for (i = 0; i < NONCE_SIZE; i++)
+        S_s[i] ^= ctx->nonce[i];
+
+    S_s[TAG_SIZE - 1] &= 0x7f;
+
+    /*
+     * In the ctx, user_tag is the one received/set by the user,
+     * and tag is generated from the input
+     */
+    out_len = sizeof(ctx->tag);
+    error |= !EVP_EncryptUpdate(ctx->ecb_ctx, ctx->tag, &out_len, S_s, sizeof(S_s));
+    ctx->generated_tag = !error;
+    /* Regardless of error */
+    ctx->used_dec = 1;
+    return !error;
+}
+
+static int aes_gcm_siv_cipher(void *vctx, unsigned char *out,
+                              const unsigned char *in, size_t len)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+
+    /* EncryptFinal or DecryptFinal */
+    if (in == NULL)
+        return aes_gcm_siv_finish(ctx);
+
+    /* Deal with associated data */
+    if (out == NULL)
+        return aes_gcm_siv_aad(ctx, in, len);
+
+    if (ctx->enc)
+        return aes_gcm_siv_encrypt(ctx, in, out, len);
+
+    return aes_gcm_siv_decrypt(ctx, in, out, len);
+}
+
+static void aes_gcm_siv_clean_ctx(void *vctx)
+{
+    PROV_AES_GCM_SIV_CTX *ctx = (PROV_AES_GCM_SIV_CTX *)vctx;
+
+    EVP_CIPHER_CTX_free(ctx->ecb_ctx);
+    ctx->ecb_ctx = NULL;
+}
+
+static int aes_gcm_siv_dup_ctx(void *vdst, void *vsrc)
+{
+    PROV_AES_GCM_SIV_CTX *dst = (PROV_AES_GCM_SIV_CTX *)vdst;
+    PROV_AES_GCM_SIV_CTX *src = (PROV_AES_GCM_SIV_CTX *)vsrc;
+
+    dst->ecb_ctx = NULL;
+    if (src->ecb_ctx != NULL) {
+        if ((dst->ecb_ctx = EVP_CIPHER_CTX_new()) == NULL)
+            goto err;
+        if (!EVP_CIPHER_CTX_copy(dst->ecb_ctx, src->ecb_ctx))
+            goto err;
+    }
+    return 1;
+
+ err:
+    EVP_CIPHER_CTX_free(dst->ecb_ctx);
+    dst->ecb_ctx = NULL;
+    return 0;
+}
+
+static const PROV_CIPHER_HW_AES_GCM_SIV aes_gcm_siv_hw =
+{
+    aes_gcm_siv_initkey,
+    aes_gcm_siv_cipher,
+    aes_gcm_siv_dup_ctx,
+    aes_gcm_siv_clean_ctx,
+};
+
+const PROV_CIPHER_HW_AES_GCM_SIV *ossl_prov_cipher_hw_aes_gcm_siv(size_t keybits)
+{
+    return &aes_gcm_siv_hw;
+}
+
+/* AES-GCM-SIV needs AES-CTR32, which is different than the AES-CTR implementation */
+static int aes_gcm_siv_ctr32(PROV_AES_GCM_SIV_CTX *ctx, const unsigned char *init_counter,
+                             unsigned char *out, const unsigned char *in, size_t len)
+{
+    uint8_t keystream[BLOCK_SIZE];
+    int out_len;
+    size_t i;
+    size_t j;
+    size_t todo;
+    uint32_t counter;
+    int error = 0;
+    union {
+        uint32_t x32[BLOCK_SIZE / sizeof(uint32_t)];
+        uint8_t x8[BLOCK_SIZE];
+    } block;
+    DECLARE_IS_ENDIAN;
+
+    memcpy(&block, init_counter, sizeof(block));
+    if (IS_BIG_ENDIAN) {
+        counter = BSWAP4(block.x32[0]);
+    }
+
+    for (i = 0; i < len; i += sizeof(block)) {
+        out_len = BLOCK_SIZE;
+        error |= !EVP_EncryptUpdate(ctx->ecb_ctx, keystream, &out_len, (uint8_t*)&block, sizeof(block));
+        if (IS_LITTLE_ENDIAN) {
+            block.x32[0]++;
+        } else {
+            counter++;
+            block.x32[0] = BSWAP4(counter);
+        }
+        todo = len - i;
+        if (todo > sizeof(keystream))
+            todo = sizeof(keystream);
+        /* Non optimal, but avoids alignment issues */
+        for (j = 0; j < todo; j++)
+            out[i + j] = in[i + j] ^ keystream[j];
+    }
+    return !error;
+}
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 (file)
index 0000000..66f6ed4
--- /dev/null
@@ -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);
+}
index 57400282875f6d9d9acf305285f80aeb38da295d..03ce43719e4debbd65c6370d938ea4b6297c907d 100644 (file)
@@ -245,6 +245,9 @@ extern const OSSL_DISPATCH ossl_chacha20_ossl_poly1305_functions[];
 extern const OSSL_DISPATCH ossl_aes128siv_functions[];
 extern const OSSL_DISPATCH ossl_aes192siv_functions[];
 extern const OSSL_DISPATCH ossl_aes256siv_functions[];
+extern const OSSL_DISPATCH ossl_aes128gcm_siv_functions[];
+extern const OSSL_DISPATCH ossl_aes192gcm_siv_functions[];
+extern const OSSL_DISPATCH ossl_aes256gcm_siv_functions[];
 #endif /* OPENSSL_NO_SIV */
 
 /* MACs */
index 97cbae70f122d6240dc92fd1c00d390c1178a276..3acea6eaa0e89441ef6df5a76903c75607b812de 100644 (file)
@@ -97,6 +97,9 @@
 #define PROV_NAMES_AES_128_SIV "AES-128-SIV"
 #define PROV_NAMES_AES_192_SIV "AES-192-SIV"
 #define PROV_NAMES_AES_256_SIV "AES-256-SIV"
+#define PROV_NAMES_AES_128_GCM_SIV "AES-128-GCM-SIV"
+#define PROV_NAMES_AES_192_GCM_SIV "AES-192-GCM-SIV"
+#define PROV_NAMES_AES_256_GCM_SIV "AES-256-GCM-SIV"
 #define PROV_NAMES_ARIA_256_GCM "ARIA-256-GCM:1.2.410.200046.1.1.36"
 #define PROV_NAMES_ARIA_192_GCM "ARIA-192-GCM:1.2.410.200046.1.1.35"
 #define PROV_NAMES_ARIA_128_GCM "ARIA-128-GCM:1.2.410.200046.1.1.34"
index f0ca8c48ffb7b658de91f662b8bc34fcbdacc484..4a532bee76269f723c496595160bb07ffd03a16a 100644 (file)
@@ -1099,6 +1099,7 @@ static int cipher_test_run(EVP_TEST *t)
                     && EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_STREAM_CIPHER)
                 || ((EVP_CIPHER_get_flags(cdat->cipher) & EVP_CIPH_FLAG_CTS) != 0)
                 || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_SIV_MODE
+                || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_GCM_SIV_MODE
                 || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_XTS_MODE
                 || EVP_CIPHER_get_mode(cdat->cipher) == EVP_CIPH_WRAP_MODE)
                 break;
index 9f321850dde1d5e8f456fdd1fefe4c13027b9ecf..572f5b1d8ef85a97d297cf958f15276832a2d871 100644 (file)
@@ -28,6 +28,7 @@ my $no_dsa = disabled("dsa");
 my $no_ec = disabled("ec");
 my $no_gost = disabled("gost");
 my $no_sm2 = disabled("sm2");
+my $no_siv = disabled("siv");
 
 # Default config depends on if the legacy module is built or not
 my $defaultcnf = $no_legacy ? 'default.cnf' : 'default-and-legacy.cnf';
@@ -83,7 +84,6 @@ push @files, qw(
 # (i.e. The algorithms are not present in the fips provider)
 my @defltfiles = qw(
                      evpciph_aes_ocb.txt
-                     evpciph_aes_siv.txt
                      evpciph_aria.txt 
                      evpciph_bf.txt
                      evpciph_camellia.txt
@@ -120,6 +120,8 @@ my @defltfiles = qw(
                     );
 push @defltfiles, qw(evppkey_brainpool.txt) unless $no_ec;
 push @defltfiles, qw(evppkey_sm2.txt) unless $no_sm2;
+push @defltfiles, qw(evpciph_aes_gcm_siv.txt) unless $no_siv;
+push @defltfiles, qw(evpciph_aes_siv.txt) unless $no_siv;
 
 plan tests =>
     + (scalar(@configs) * scalar(@files))
diff --git a/test/recipes/30-test_evp_data/evpciph_aes_gcm_siv.txt b/test/recipes/30-test_evp_data/evpciph_aes_gcm_siv.txt
new file mode 100644 (file)
index 0000000..39c880c
--- /dev/null
@@ -0,0 +1,418 @@
+#
+# Copyright 2018-2020 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
+
+# Tests start with one of these keywords
+#       Cipher Decrypt Derive Digest Encoding KDF MAC PBE
+#       PrivPubKeyPair Sign Verify VerifyRecover
+# and continue until a blank line. Lines starting with a pound sign are ignored.
+
+Title = RFC8452 AES-GCM-SIV
+
+Cipher = aes-128-gcm-siv
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 578782fff6013b815b287c22493a364c
+Plaintext = 0100000000000000
+Ciphertext = b5d839330ac7b786
+
+
+Cipher = aes-128-gcm-siv
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = a4978db357391a0bc4fdec8b0d106639
+Plaintext = 010000000000000000000000
+Ciphertext = 7323ea61d05932260047d942
+
+
+Cipher = aes-128-gcm-siv
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 303aaf90f6fe21199c6068577437a0c4
+Plaintext = 01000000000000000000000000000000
+Ciphertext = 743f7c8077ab25f8624e2e948579cf77
+
+
+Cipher = aes-128-gcm-siv
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 1a8e45dcd4578c667cd86847bf6155ff
+Plaintext = 0100000000000000000000000000000002000000000000000000000000000000
+Ciphertext = 84e07e62ba83a6585417245d7ec413a9fe427d6315c09b57ce45f2e3936a9445
+
+
+Cipher = aes-128-gcm-siv
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 5e6e311dbf395d35b0fe39c2714388f8
+Plaintext = 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+Ciphertext = 3fd24ce1f5a67b75bf2351f181a475c7b800a5b4d3dcf70106b1eea82fa1d64df42bf7226122fa92e17a40eeaac1201b
+
+
+Cipher = aes-128-gcm-siv
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 8a263dd317aa88d56bdf3936dba75bb8
+Plaintext = 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+Ciphertext = 2433668f1058190f6d43e360f4f35cd8e475127cfca7028ea8ab5c20f7ab2af02516a2bdcbc08d521be37ff28c152bba36697f25b4cd169c6590d1dd39566d3f
+
+
+Cipher = aes-128-gcm-siv
+AAD = 01
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 3b0a1a2560969cdf790d99759abd1508
+Plaintext = 0200000000000000
+Ciphertext = 1e6daba35669f427
+
+
+Cipher = aes-128-gcm-siv
+AAD = 01
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 08299c5102745aaa3a0c469fad9e075a
+Plaintext = 020000000000000000000000
+Ciphertext = 296c7889fd99f41917f44620
+
+
+Cipher = aes-128-gcm-siv
+AAD = 01
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 8f8936ec039e4e4bb97ebd8c4457441f
+Plaintext = 02000000000000000000000000000000
+Ciphertext = e2b0c5da79a901c1745f700525cb335b
+
+
+Cipher = aes-128-gcm-siv
+AAD = 01
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = e6af6a7f87287da059a71684ed3498e1
+Plaintext = 0200000000000000000000000000000003000000000000000000000000000000
+Ciphertext = 620048ef3c1e73e57e02bb8562c416a319e73e4caac8e96a1ecb2933145a1d71
+
+
+Cipher = aes-128-gcm-siv
+AAD = 01
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 6a8cc3865f76897c2e4b245cf31c51f2
+Plaintext = 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+Ciphertext = 50c8303ea93925d64090d07bd109dfd9515a5a33431019c17d93465999a8b0053201d723120a8562b838cdff25bf9d1e
+
+
+Cipher = aes-128-gcm-siv
+AAD = 01
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = cdc46ae475563de037001ef84ae21744
+Plaintext = 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+Ciphertext = 2f5c64059db55ee0fb847ed513003746aca4e61c711b5de2e7a77ffd02da42feec601910d3467bb8b36ebbaebce5fba30d36c95f48a3e7980f0e7ac299332a80
+
+
+Cipher = aes-128-gcm-siv
+AAD = 010000000000000000000000
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 07eb1f84fb28f8cb73de8e99e2f48a14
+Plaintext = 02000000
+Ciphertext = a8fe3e87
+
+
+Cipher = aes-128-gcm-siv
+AAD = 010000000000000000000000000000000200
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 24afc9805e976f451e6d87f6fe106514
+Plaintext = 0300000000000000000000000000000004000000
+Ciphertext = 6bb0fecf5ded9b77f902c7d5da236a4391dd0297
+
+
+Cipher = aes-128-gcm-siv
+AAD = 0100000000000000000000000000000002000000
+Key = 01000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = bff9b2ef00fb47920cc72a0c0f13b9fd
+Plaintext = 030000000000000000000000000000000400
+Ciphertext = 44d0aaf6fb2f1f34add5e8064e83e12a2ada
+
+Cipher = aes-128-gcm-siv
+AAD = 46bb91c3c5
+Key = 36864200e0eaf5284d884a0e77d31646
+IV = bae8e37fc83441b16034566b
+Tag = 711bd85bc1e4d3e0a462e074eea428a8
+Plaintext = 7a806c
+Ciphertext = af60eb
+
+
+Cipher = aes-128-gcm-siv
+AAD = fc880c94a95198874296
+Key = aedb64a6c590bc84d1a5e269e4b47801
+IV = afc0577e34699b9e671fdd4f
+Tag = d6a9c45545cfc11f03ad743dba20f966
+Plaintext = bdc66f146545
+Ciphertext = bb93a3e34d3c
+
+
+Cipher = aes-128-gcm-siv
+AAD = 046787f3ea22c127aaf195d1894728
+Key = d5cc1fd161320b6920ce07787f86743b
+IV = 275d1ab32f6d1f0434d8848c
+Tag = 1d02fd0cd174c84fc5dae2f60f52fd2b
+Plaintext = 1177441f195495860f
+Ciphertext = 4f37281f7ad12949d0
+
+
+Cipher = aes-128-gcm-siv
+AAD = c9882e5386fd9f92ec489c8fde2be2cf97e74e93
+Key = b3fed1473c528b8426a582995929a149
+IV = 9e9ad8780c8d63d0ab4149c0
+Tag = c1dc2f871fb7561da1286e655e24b7b0
+Plaintext = 9f572c614b4745914474e7c7
+Ciphertext = f54673c5ddf710c745641c8b
+
+
+Cipher = aes-128-gcm-siv
+AAD = 2950a70d5a1db2316fd568378da107b52b0da55210cc1c1b0a
+Key = 2d4ed87da44102952ef94b02b805249b
+IV = ac80e6f61455bfac8308a2d4
+Tag = 83b3449b9f39552de99dc214a1190b0b
+Plaintext = 0d8c8451178082355c9e940fea2f58
+Ciphertext = c9ff545e07b88a015f05b274540aa1
+
+
+Cipher = aes-128-gcm-siv
+AAD = 1860f762ebfbd08284e421702de0de18baa9c9596291b08466f37de21c7f
+Key = bde3b2f204d1e9f8b06bc47f9745b3d1
+IV = ae06556fb6aa7890bebc18fe
+Tag = 3e377094f04709f64d7b985310a4db84
+Plaintext = 6b3db4da3d57aa94842b9803a96e07fb6de7
+Ciphertext = 6298b296e24e8cc35dce0bed484b7f30d580
+
+
+Cipher = aes-128-gcm-siv
+AAD = 7576f7028ec6eb5ea7e298342a94d4b202b370ef9768ec6561c4fe6b7e7296fa859c21
+Key = f901cfe8a69615a93fdf7a98cad48179
+IV = 6245709fb18853f68d833640
+Tag = 2d15506c84a9edd65e13e9d24a2a6e70
+Plaintext = e42a3c02c25b64869e146d7b233987bddfc240871d
+Ciphertext = 391cc328d484a4f46406181bcd62efd9b3ee197d05
+
+
+# AES_256_GCM_SIV
+
+
+Cipher = aes-256-gcm-siv
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 843122130f7364b761e0b97427e3df28
+Plaintext = 0100000000000000
+Ciphertext = c2ef328e5c71c83b
+
+
+Cipher = aes-256-gcm-siv
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 8ca50da9ae6559e48fd10f6e5c9ca17e
+Plaintext = 010000000000000000000000
+Ciphertext = 9aab2aeb3faa0a34aea8e2b1
+
+
+Cipher = aes-256-gcm-siv
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = c9eac6fa700942702e90862383c6c366
+Plaintext = 01000000000000000000000000000000
+Ciphertext = 85a01b63025ba19b7fd3ddfc033b3e76
+
+
+Cipher = aes-256-gcm-siv
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = e819e63abcd020b006a976397632eb5d
+Plaintext = 0100000000000000000000000000000002000000000000000000000000000000
+Ciphertext = 4a6a9db4c8c6549201b9edb53006cba821ec9cf850948a7c86c68ac7539d027f
+
+
+Cipher = aes-256-gcm-siv
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 790bc96880a99ba804bd12c0e6a22cc4
+Plaintext = 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000
+Ciphertext = c00d121893a9fa603f48ccc1ca3c57ce7499245ea0046db16c53c7c66fe717e39cf6c748837b61f6ee3adcee17534ed5
+
+
+Cipher = aes-256-gcm-siv
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 112864c269fc0d9d88c61fa47e39aa08
+Plaintext = 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+Ciphertext = c2d5160a1f8683834910acdafc41fbb1632d4a353e8b905ec9a5499ac34f96c7e1049eb080883891a4db8caaa1f99dd004d80487540735234e3744512c6f90ce
+
+
+Cipher = aes-256-gcm-siv
+AAD = 01
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 91213f267e3b452f02d01ae33e4ec854
+Plaintext = 0200000000000000
+Ciphertext = 1de22967237a8132
+
+
+Cipher = aes-256-gcm-siv
+AAD = 01
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = c1a4a19ae800941ccdc57cc8413c277f
+Plaintext = 020000000000000000000000
+Ciphertext = 163d6f9cc1b346cd453a2e4c
+
+
+Cipher = aes-256-gcm-siv
+AAD = 01
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = b292d28ff61189e8e49f3875ef91aff7
+Plaintext = 02000000000000000000000000000000
+Ciphertext = c91545823cc24f17dbb0e9e807d5ec17
+
+
+Cipher = aes-256-gcm-siv
+AAD = 01
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = aea1bad12702e1965604374aab96dbbc
+Plaintext = 0200000000000000000000000000000003000000000000000000000000000000
+Ciphertext = 07dad364bfc2b9da89116d7bef6daaaf6f255510aa654f920ac81b94e8bad365
+
+
+Cipher = aes-256-gcm-siv
+AAD = 01
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 03332742b228c647173616cfd44c54eb
+Plaintext = 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000
+Ciphertext = c67a1f0f567a5198aa1fcc8e3f21314336f7f51ca8b1af61feac35a86416fa47fbca3b5f749cdf564527f2314f42fe25
+
+
+Cipher = aes-256-gcm-siv
+AAD = 01
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 5bde0285037c5de81e5b570a049b62a0
+Plaintext = 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000
+Ciphertext = 67fd45e126bfb9a79930c43aad2d36967d3f0e4d217c1e551f59727870beefc98cb933a8fce9de887b1e40799988db1fc3f91880ed405b2dd298318858467c89
+
+
+Cipher = aes-256-gcm-siv
+AAD = 010000000000000000000000
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = 1835e517741dfddccfa07fa4661b74cf
+Plaintext = 02000000
+Ciphertext = 22b3f4cd
+
+
+Cipher = aes-256-gcm-siv
+AAD = 010000000000000000000000000000000200
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = b879ad976d8242acc188ab59cabfe307
+Plaintext = 0300000000000000000000000000000004000000
+Ciphertext = 43dd0163cdb48f9fe3212bf61b201976067f342b
+
+
+Cipher = aes-256-gcm-siv
+AAD = 0100000000000000000000000000000002000000
+Key = 0100000000000000000000000000000000000000000000000000000000000000
+IV = 030000000000000000000000
+Tag = cfcdf5042112aa29685c912fc2056543
+Plaintext = 030000000000000000000000000000000400
+Ciphertext = 462401724b5ce6588d5a54aae5375513a075
+
+Cipher = aes-256-gcm-siv
+AAD = 4fbdc66f14
+Key = bae8e37fc83441b16034566b7a806c46bb91c3c5aedb64a6c590bc84d1a5e269
+IV = e4b47801afc0577e34699b9e
+Tag = 93da9bb81333aee0c785b240d319719d
+Plaintext = 671fdd
+Ciphertext = 0eaccb
+
+
+Cipher = aes-256-gcm-siv
+AAD = 6787f3ea22c127aaf195
+Key = 6545fc880c94a95198874296d5cc1fd161320b6920ce07787f86743b275d1ab3
+IV = 2f6d1f0434d8848c1177441f
+Tag = 6b62b84dc40c84636a5ec12020ec8c2c
+Plaintext = 195495860f04
+Ciphertext = a254dad4f3f9
+
+
+Cipher = aes-256-gcm-siv
+AAD = 489c8fde2be2cf97e74e932d4ed87d
+Key = d1894728b3fed1473c528b8426a582995929a1499e9ad8780c8d63d0ab4149c0
+IV = 9f572c614b4745914474e7c7
+Tag = c0fd3dc6628dfe55ebb0b9fb2295c8c2
+Plaintext = c9882e5386fd9f92ec
+Ciphertext = 0df9e308678244c44b
+
+
+Cipher = aes-256-gcm-siv
+AAD = 0da55210cc1c1b0abde3b2f204d1e9f8b06bc47f
+Key = a44102952ef94b02b805249bac80e6f61455bfac8308a2d40d8c845117808235
+IV = 5c9e940fea2f582950a70d5a
+Tag = 404099c2587f64979f21826706d497d5
+Plaintext = 1db2316fd568378da107b52b
+Ciphertext = 8dbeb9f7255bf5769dd56692
+
+
+Cipher = aes-256-gcm-siv
+AAD = f37de21c7ff901cfe8a69615a93fdf7a98cad481796245709f
+Key = 9745b3d1ae06556fb6aa7890bebc18fe6b3db4da3d57aa94842b9803a96e07fb
+IV = 6de71860f762ebfbd08284e4
+Tag = b3080d28f6ebb5d3648ce97bd5ba67fd
+Plaintext = 21702de0de18baa9c9596291b08466
+Ciphertext = 793576dfa5c0f88729a7ed3c2f1bff
+
+
+Cipher = aes-256-gcm-siv
+AAD = 9c2159058b1f0fe91433a5bdc20e214eab7fecef4454a10ef0657df21ac7
+Key = b18853f68d833640e42a3c02c25b64869e146d7b233987bddfc240871d7576f7
+IV = 028ec6eb5ea7e298342a94d4
+Tag = 454fc2a154fea91f8363a39fec7d0a49
+Plaintext = b202b370ef9768ec6561c4fe6b7e7296fa85
+Ciphertext = 857e16a64915a787637687db4a9519635cdd
+
+
+Cipher = aes-256-gcm-siv
+AAD = 734320ccc9d9bbbb19cb81b2af4ecbc3e72834321f7aa0f70b7282b4f33df23f167541
+Key = 3c535de192eaed3822a2fbbe2ca9dfc88255e14a661b8aa82cc54236093bbc23
+IV = 688089e55540db1872504e1c
+Tag = 9d6c7029675b89eaf4ba1ded1a286594
+Plaintext = ced532ce4159b035277d4dfbb7db62968b13cd4eec
+Ciphertext = 626660c26ea6612fb17ad91e8e767639edd6c9faee
+
+# The tests in this section use AEAD_AES_256_GCM_SIV and are crafted to
+# test correct wrapping of the block counter.
+
+Cipher = aes-256-gcm-siv
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+IV = 000000000000000000000000
+Tag = ffffffff000000000000000000000000
+Plaintext = 000000000000000000000000000000004db923dc793ee6497c76dcc03a98e108
+Ciphertext = f3f80f2cf0cb2dd9c5984fcda908456cc537703b5ba70324a6793a7bf218d3ea
+
+
+Cipher = aes-256-gcm-siv
+Key = 0000000000000000000000000000000000000000000000000000000000000000
+IV = 000000000000000000000000
+Tag = ffffffff000000000000000000000000
+Plaintext = eb3640277c7ffd1303c7a542d02d3e4c0000000000000000
+Ciphertext = 18ce4f0b8cb4d0cac65fea8f79257b20888e53e72299e56d
+
+