From bb640c26d3366983443865c7000f003bcfcfa8ff Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Tue, 16 Aug 2022 16:37:51 +0900 Subject: Implement AES-GCM-SIV This implements AES-GCM-SIV, described in RFC8452, on top of the existing AES-GCM primitives. In particular, its hash algorithm POLYVAL is implemented using the GHASH with additional byte order conversion according to RFC8452 Appendix A. Signed-off-by: Daiki Ueno --- Makefile.in | 7 +- block-internal.h | 12 + bswap-internal.h | 6 + ghash-internal.h | 13 + nettle-internal.h | 1 + nettle.texinfo | 86 ++++++ siv-gcm-aes128.c | 65 +++++ siv-gcm-aes256.c | 65 +++++ siv-gcm.c | 230 +++++++++++++++ siv-gcm.h | 107 +++++++ siv-ghash-set-key.c | 52 ++++ siv-ghash-update.c | 65 +++++ testsuite/.gitignore | 1 + testsuite/Makefile.in | 2 +- testsuite/siv-gcm-test.c | 731 +++++++++++++++++++++++++++++++++++++++++++++++ 15 files changed, 1440 insertions(+), 3 deletions(-) create mode 100644 siv-gcm-aes128.c create mode 100644 siv-gcm-aes256.c create mode 100644 siv-gcm.c create mode 100644 siv-gcm.h create mode 100644 siv-ghash-set-key.c create mode 100644 siv-ghash-update.c create mode 100644 testsuite/siv-gcm-test.c diff --git a/Makefile.in b/Makefile.in index ca1466b7..0f7bf4d6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -100,13 +100,16 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c aes-decrypt-table.c \ cbc.c cbc-aes128-encrypt.c cbc-aes192-encrypt.c cbc-aes256-encrypt.c \ ccm.c ccm-aes128.c ccm-aes192.c ccm-aes256.c cfb.c \ siv-cmac.c siv-cmac-aes128.c siv-cmac-aes256.c \ + siv-gcm.c siv-gcm-aes128.c siv-gcm-aes256.c \ cnd-memcpy.c \ chacha-crypt.c chacha-core-internal.c \ chacha-poly1305.c chacha-poly1305-meta.c \ chacha-set-key.c chacha-set-nonce.c \ ctr.c ctr16.c des.c des3.c \ eax.c eax-aes128.c eax-aes128-meta.c \ - ghash-set-key.c ghash-update.c gcm.c gcm-aes.c \ + ghash-set-key.c ghash-update.c \ + siv-ghash-set-key.c siv-ghash-update.c \ + gcm.c gcm-aes.c \ gcm-aes128.c gcm-aes128-meta.c \ gcm-aes192.c gcm-aes192-meta.c \ gcm-aes256.c gcm-aes256-meta.c \ @@ -228,7 +231,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \ gcm.h gostdsa.h gosthash94.h hmac.h \ knuth-lfib.h hkdf.h \ macros.h \ - cmac.h siv-cmac.h \ + cmac.h siv-cmac.h siv-gcm.h \ md2.h md4.h \ md5.h md5-compat.h \ memops.h memxor.h \ diff --git a/block-internal.h b/block-internal.h index d7b0c315..e9c26ff6 100644 --- a/block-internal.h +++ b/block-internal.h @@ -40,6 +40,7 @@ #include #include "nettle-types.h" +#include "bswap-internal.h" #include "memxor.h" static inline void @@ -197,4 +198,15 @@ block16_mulx_ghash (union nettle_block16 *r, } #endif /* ! WORDS_BIGENDIAN */ +/* Reverse bytes in X and store the result in R. This supports + in-place operation (R and X can overlap). */ +static inline void +block16_bswap (union nettle_block16 *r, + const union nettle_block16 *x) +{ + uint64_t t = nettle_bswap64 (x->u64[0]); + r->u64[0] = nettle_bswap64 (x->u64[1]); + r->u64[1] = t; +} + #endif /* NETTLE_BLOCK_INTERNAL_H_INCLUDED */ diff --git a/bswap-internal.h b/bswap-internal.h index f9606f1d..b9923f99 100644 --- a/bswap-internal.h +++ b/bswap-internal.h @@ -68,4 +68,10 @@ nettle_bswap32 (uint32_t x) #define bswap64_if_le nettle_bswap64 #endif +#if WORDS_BIGENDIAN +#define bswap64_if_be nettle_bswap64 +#else +#define bswap64_if_be(x) (x) +#endif + #endif /* NETTLE_BSWAP_INTERNAL_H_INCLUDED */ diff --git a/ghash-internal.h b/ghash-internal.h index 97dff024..2504dc09 100644 --- a/ghash-internal.h +++ b/ghash-internal.h @@ -38,6 +38,8 @@ /* Name mangling */ #define _ghash_set_key _nettle_ghash_set_key #define _ghash_update _nettle_ghash_update +#define _siv_ghash_set_key _nettle_siv_ghash_set_key +#define _siv_ghash_update _nettle_siv_ghash_update #ifdef __cplusplus extern "C" { @@ -58,6 +60,17 @@ const uint8_t * _ghash_update (const struct gcm_key *ctx, union nettle_block16 *state, size_t blocks, const uint8_t *data); +/* Expands KEY as needed, for corresponding _siv_ghash_update */ +void +_siv_ghash_set_key (struct gcm_key *ctx, const union nettle_block16 *key); + +/* Updates STATE by hashing DATA, which must be an integral number of + blocks. For convenience, returns a pointer to the end of the + data. */ +const uint8_t * +_siv_ghash_update (const struct gcm_key *ctx, union nettle_block16 *state, + size_t blocks, const uint8_t *data); + #ifdef __cplusplus } #endif diff --git a/nettle-internal.h b/nettle-internal.h index 92416400..b7726d68 100644 --- a/nettle-internal.h +++ b/nettle-internal.h @@ -80,6 +80,7 @@ #define NETTLE_MAX_HASH_CONTEXT_SIZE (sizeof(struct sha3_224_ctx)) #define NETTLE_MAX_SEXP_ASSOC 17 #define NETTLE_MAX_CIPHER_BLOCK_SIZE 32 +#define NETTLE_MAX_CIPHER_KEY_SIZE 32 /* Doesn't quite fit with the other algorithms, because of the weak * keys. Weak keys are not reported, the functions will simply crash diff --git a/nettle.texinfo b/nettle.texinfo index 677a4d3f..ca4f9253 100644 --- a/nettle.texinfo +++ b/nettle.texinfo @@ -123,6 +123,7 @@ Authenticated encryption with associated data * CCM:: * ChaCha-Poly1305:: * SIV-CMAC:: +* SIV-GCM:: * nettle_aead abstraction:: Keyed Hash Functions @@ -2880,6 +2881,7 @@ more adventurous alternative, in particular if performance is important. * CCM:: * ChaCha-Poly1305:: * SIV-CMAC:: +* SIV-GCM:: * nettle_aead abstraction:: @end menu @@ -3733,6 +3735,90 @@ are equal, this will return 1 indicating a valid and authenticated message. Otherwise, this function will return zero. @end deftypefun +@node SIV-GCM +@subsection SIV-GCM + +@acronym{SIV-GCM}, described in @cite{RFC 8452}, is an @acronym{AEAD} +construction similar to @acronym{AES-GCM}, but provides protection against +accidental nonce misuse like @acronym{SIV-CMAC} mode. + +It is constructed on top of a block cipher which must have a block size of 128 +bits and a nonce size of 12 bytes. Nettle's support for @acronym{SIV-GCM} +consists of a message encryption and authentication interface, for +@acronym{SIV-GCM} using AES as the underlying block cipher. These +interfaces are defined in @file{}. + +Unlike other @acronym{AEAD} mode in @acronym{SIV-GCM} the tag is calculated +over the encoded additional authentication data and plaintext instead of the +ciphertext. + +@subsubsection General interface + +@defvr Constant SIV_GCM_BLOCK_SIZE +@acronym{SIV-GCM}'s block size, 16. +@end defvr + +@defvr Constant SIV_GCM_DIGEST_SIZE +Size of the @acronym{SIV-GCM} digest for tags, 16. +@end defvr + +@defvr Constant SIV_GCM_NONCE_SIZE +Size of the @acronym{SIV-GCM} nonce, 12. +@end defvr + +@deftypefun void siv_gcm_encrypt_message (const struct nettle_cipher *@var{nc}, const void *@var{ctx}, void *@var{ctr_ctx}, size_t @var{nlength}, const uint8_t *@var{nonce}, size_t @var{alength}, const uint8_t *@var{adata}, size_t @var{clength}, uint8_t *@var{dst}, const uint8_t *@var{src}) +Computes the message digest from the @var{adata} and @var{src} +parameters, encrypts the plaintext from @var{src}, appends the +authentication tag to the ciphertext and outputs it to @var{dst}. The +@var{clength} variable must be equal to the length of @var{src} plus +@code{SIV_GCM_DIGEST_SIZE}. +@end deftypefun + +@deftypefun int siv_gcm_decrypt_message (const struct nettle_cipher *@var{nc}, const void *@var{ctx}, void *@var{ctr_ctx}, size_t @var{nlength}, const uint8_t *@var{nonce}, size_t @var{alength}, const uint8_t *@var{adata}, size_t @var{mlength}, uint8_t *@var{dst}, const uint8_t *@var{src}) +Decrypts the ciphertext from @var{src}, outputs the plaintext to +@var{dst}, recalculates the initialization vector from @var{adata} and the +plaintext. If the values of the received and calculated initialization vector +are equal, this will return 1 indicating a valid and authenticated +message. Otherwise, this function will return zero. +@end deftypefun + +In the above interface, @var{nc} must point to a cipher that works +with 16-byte block size and the key sizes that are multiple of +8-bytes. The @var{ctr} and @var{ctr_ctx} context structures must be +initialized for encryption mode using a set-key function, before using +any of the functions in this interface. These structures can point to +the same area. For convenience, Nettle provides wrapper functions +that works with @acronym{AES} described in the following section. + +@subsubsection @acronym{SIV-GCM}-@acronym{AES} interface + +The @acronym{SIV-GCM} functions provide an API for using @acronym{SIV-GCM} +mode with the @acronym{AES} block ciphers. The parameters all have the same +meaning as the general and message interfaces, except that the @var{cipher}, +@var{f}, and @var{ctx} parameters are replaced with an @acronym{AES} context +structure. The @acronym{AES} context structure must be initialized for +encryption mode using a set-key function, before using any of the functions in +this interface. + +@deftypefun void siv_gcm_aes128_encrypt_message (const struct aes128_ctx *@var{ctx}, size_t @var{nlength}, const uint8_t *@var{nonce}, size_t @var{alength}, const uint8_t *@var{adata}, size_t @var{clength}, uint8_t *@var{dst}, const uint8_t *@var{src}) +@deftypefunx void siv_gcm_aes256_encrypt_message (const struct aes256_ctx *@var{ctx}, size_t @var{nlength}, const uint8_t *@var{nonce}, size_t @var{alength}, const uint8_t *@var{adata}, size_t @var{clength}, uint8_t *@var{dst}, const uint8_t *@var{src}) +Computes the message digest from the @var{adata} and @var{src} +parameters, encrypts the plaintext from @var{src}, appends the +authentication tag to the ciphertext and outputs it to @var{dst}. +The @var{clength} variable must be equal to the length of @var{src} +plus @code{SIV_GCM_DIGEST_SIZE}. + +@end deftypefun + +@deftypefun int siv_gcm_aes128_decrypt_message (const struct aes128_ctx *@var{ctx}, size_t @var{nlength}, const uint8_t *@var{nonce}, size_t @var{alength}, const uint8_t *@var{adata}, size_t @var{mlength}, uint8_t *@var{dst}, const uint8_t *@var{src}) +@deftypefunx int siv_gcm_aes256_decrypt_message (const struct aes256_ctx *@var{ctx}, size_t @var{nlength}, const uint8_t *@var{nonce}, size_t @var{alength}, const uint8_t *@var{adata}, size_t @var{mlength}, uint8_t *@var{dst}, const uint8_t *@var{src}) +Decrypts the ciphertext from @var{src}, outputs the plaintext to +@var{dst}, recalculates the initialization vector from @var{adata} and the +plaintext. If the values of the received and calculated initialization vector +are equal, this will return 1 indicating a valid and authenticated +message. Otherwise, this function will return zero. +@end deftypefun + @node nettle_aead abstraction @subsection The @code{struct nettle_aead} abstraction @cindex nettle_aead diff --git a/siv-gcm-aes128.c b/siv-gcm-aes128.c new file mode 100644 index 00000000..4317d3d8 --- /dev/null +++ b/siv-gcm-aes128.c @@ -0,0 +1,65 @@ +/* siv-gcm-aes128.c + + AES-GCM-SIV, RFC8452 + + Copyright (C) 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "nettle-meta.h" +#include "siv-gcm.h" + +void +siv_gcm_aes128_encrypt_message (const struct aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src) +{ + struct aes128_ctx ctr_ctx; + siv_gcm_encrypt_message (&nettle_aes128, ctx, &ctr_ctx, + nlength, nonce, + alength, adata, + clength, dst, src); +} + +int +siv_gcm_aes128_decrypt_message (const struct aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + struct aes128_ctx ctr_ctx; + return siv_gcm_decrypt_message (&nettle_aes128, ctx, &ctr_ctx, + nlength, nonce, + alength, adata, + mlength, dst, src); +} diff --git a/siv-gcm-aes256.c b/siv-gcm-aes256.c new file mode 100644 index 00000000..70bf3f35 --- /dev/null +++ b/siv-gcm-aes256.c @@ -0,0 +1,65 @@ +/* siv-gcm-aes256.c + + AES-GCM-SIV, RFC8452 + + Copyright (C) 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "nettle-meta.h" +#include "siv-gcm.h" + +void +siv_gcm_aes256_encrypt_message (const struct aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src) +{ + struct aes256_ctx ctr_ctx; + siv_gcm_encrypt_message (&nettle_aes256, ctx, &ctr_ctx, + nlength, nonce, + alength, adata, + clength, dst, src); +} + +int +siv_gcm_aes256_decrypt_message (const struct aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + struct aes256_ctx ctr_ctx; + return siv_gcm_decrypt_message (&nettle_aes256, ctx, &ctr_ctx, + nlength, nonce, + alength, adata, + mlength, dst, src); +} diff --git a/siv-gcm.c b/siv-gcm.c new file mode 100644 index 00000000..3a6b1de9 --- /dev/null +++ b/siv-gcm.c @@ -0,0 +1,230 @@ +/* siv-gcm.c + + AES-GCM-SIV, RFC8452 + + Copyright (C) 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "siv-gcm.h" +#include "ghash-internal.h" +#include "block-internal.h" +#include "nettle-internal.h" +#include "macros.h" +#include "memops.h" +#include "ctr-internal.h" +#include + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +static void +siv_gcm_derive_keys (const void *ctx, + nettle_cipher_func *f, + size_t key_size, + size_t nlength, const uint8_t *nonce, + union nettle_block16 *auth_key, + uint8_t *encryption_key) +{ + union nettle_block16 block; + union nettle_block16 out; + size_t i; + + block16_zero (&block); + memcpy (block.b + 4, nonce, MIN(nlength, SIV_GCM_NONCE_SIZE)); + + f (ctx, SIV_GCM_BLOCK_SIZE, out.b, block.b); + auth_key->u64[0] = out.u64[0]; + + block.b[0] = 1; + f (ctx, SIV_GCM_BLOCK_SIZE, out.b, block.b); + auth_key->u64[1] = out.u64[0]; + + assert (key_size % 8 == 0 && key_size / 8 + 2 <= UINT8_MAX); + + for (i = 0; i < key_size; i += 8) + { + block.b[0]++; + f (ctx, SIV_GCM_BLOCK_SIZE, out.b, block.b); + memcpy (encryption_key + i, out.b, 8); + } +} + +static nettle_fill16_func siv_gcm_fill; + +static void +siv_gcm_fill(uint8_t *ctr, size_t blocks, union nettle_block16 *buffer) +{ + uint32_t c; + + c = LE_READ_UINT32(ctr); + + for (; blocks-- > 0; buffer++, c++) + { + memcpy(buffer->b + 4, ctr + 4, SIV_GCM_BLOCK_SIZE - 4); + LE_WRITE_UINT32(buffer->b, c); + } + + LE_WRITE_UINT32(ctr, c); +} + +static void +siv_ghash_pad_update (struct gcm_key *ctx, + union nettle_block16 *state, + size_t length, const uint8_t *data) +{ + size_t blocks; + + blocks = length / SIV_GCM_BLOCK_SIZE; + if (blocks > 0) + { + data = _siv_ghash_update (ctx, state, blocks, data); + length &= 0xf; + } + if (length > 0) + { + uint8_t block[SIV_GCM_BLOCK_SIZE]; + + memset (block + length, 0, SIV_GCM_BLOCK_SIZE - length); + memcpy (block, data, length); + _siv_ghash_update (ctx, state, 1, block); + } +} + +static void +siv_gcm_authenticate (const void *ctx, + const struct nettle_cipher *nc, + const union nettle_block16 *authentication_key, + const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, const uint8_t *mdata, + uint8_t *tag) +{ + union nettle_block16 state; + struct gcm_key siv_ghash_key; + union nettle_block16 block; + + _siv_ghash_set_key (&siv_ghash_key, authentication_key); + + block16_zero (&state); + siv_ghash_pad_update (&siv_ghash_key, &state, alength, adata); + siv_ghash_pad_update (&siv_ghash_key, &state, mlength, mdata); + + block.u64[0] = bswap64_if_be (alength * 8); + block.u64[1] = bswap64_if_be (mlength * 8); + + _siv_ghash_update (&siv_ghash_key, &state, 1, block.b); + block16_bswap (&state, &state); + + memxor (state.b, nonce, SIV_GCM_NONCE_SIZE); + state.b[15] &= 0x7f; + nc->encrypt (ctx, SIV_GCM_BLOCK_SIZE, tag, state.b); +} + +void +siv_gcm_encrypt_message (const struct nettle_cipher *nc, + const void *ctx, + void *ctr_ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src) +{ + union nettle_block16 authentication_key; + TMP_DECL(encryption_key, uint8_t, NETTLE_MAX_CIPHER_KEY_SIZE); + uint8_t ctr[SIV_GCM_DIGEST_SIZE]; + uint8_t *tag = dst + clength - SIV_GCM_BLOCK_SIZE; + + assert (clength >= SIV_GCM_DIGEST_SIZE); + assert (nlength == SIV_GCM_NONCE_SIZE); + + TMP_ALLOC(encryption_key, nc->key_size); + siv_gcm_derive_keys (ctx, nc->encrypt, nc->key_size, nlength, nonce, + &authentication_key, encryption_key); + + /* Calculate authentication tag. */ + nc->set_encrypt_key (ctr_ctx, encryption_key); + + siv_gcm_authenticate (ctr_ctx, nc, + &authentication_key, + nonce, alength, adata, + clength - SIV_GCM_BLOCK_SIZE, src, + tag); + + /* Encrypt the plaintext. */ + + /* The initial counter block is the tag with the most significant + bit of the last byte set to one. */ + memcpy (ctr, tag, SIV_GCM_DIGEST_SIZE); + ctr[15] |= 0x80; + _nettle_ctr_crypt16 (ctr_ctx, nc->encrypt, siv_gcm_fill, ctr, + clength - SIV_GCM_BLOCK_SIZE, dst, src); +} + +int +siv_gcm_decrypt_message (const struct nettle_cipher *nc, + const void *ctx, + void *ctr_ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src) +{ + union nettle_block16 authentication_key; + TMP_DECL(encryption_key, uint8_t, NETTLE_MAX_CIPHER_KEY_SIZE); + struct gcm_key siv_ghash_key; + union nettle_block16 state; + uint8_t tag[SIV_GCM_DIGEST_SIZE]; + + assert (nlength == SIV_GCM_NONCE_SIZE); + + TMP_ALLOC(encryption_key, nc->key_size); + siv_gcm_derive_keys (ctx, nc->encrypt, nc->key_size, nlength, nonce, + &authentication_key, encryption_key); + + memcpy (state.b, src + mlength, SIV_GCM_DIGEST_SIZE); + /* The initial counter block is the tag with the most significant + bit of the last byte set to one. */ + state.b[15] |= 0x80; + + /* Decrypt the ciphertext. */ + nc->set_encrypt_key (ctr_ctx, encryption_key); + + _nettle_ctr_crypt16 (ctr_ctx, nc->encrypt, siv_gcm_fill, state.b, + mlength, dst, src); + + /* Calculate authentication tag. */ + siv_gcm_authenticate (ctr_ctx, nc, + &authentication_key, + nonce, alength, adata, + mlength, dst, + tag); + + return memeql_sec (tag, src + mlength, SIV_GCM_DIGEST_SIZE); +} diff --git a/siv-gcm.h b/siv-gcm.h new file mode 100644 index 00000000..1a9e3084 --- /dev/null +++ b/siv-gcm.h @@ -0,0 +1,107 @@ +/* siv-gcm.h + + AES-GCM-SIV, RFC8452 + + Copyright (C) 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#ifndef NETTLE_SIV_GCM_H_INCLUDED +#define NETTLE_SIV_GCM_H_INCLUDED + +#include "nettle-types.h" +#include "nettle-meta.h" +#include "aes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define siv_gcm_encrypt_message nettle_siv_gcm_encrypt_message +#define siv_gcm_decrypt_message nettle_siv_gcm_decrypt_message +#define siv_gcm_aes128_encrypt_message nettle_siv_gcm_aes128_encrypt_message +#define siv_gcm_aes128_decrypt_message nettle_siv_gcm_aes128_decrypt_message +#define siv_gcm_aes256_encrypt_message nettle_siv_gcm_aes256_encrypt_message +#define siv_gcm_aes256_decrypt_message nettle_siv_gcm_aes256_decrypt_message + +/* For AES-GCM-SIV, the block size of the underlying cipher shall be 128 bits. */ +#define SIV_GCM_BLOCK_SIZE 16 +#define SIV_GCM_DIGEST_SIZE 16 +#define SIV_GCM_NONCE_SIZE 12 + +/* Generic interface. NC must be a block cipher with 128-bit block + size, and keysize that is a multiple of 64 bits, such as AES-128 or + AES-256. */ +void +siv_gcm_encrypt_message (const struct nettle_cipher *nc, + const void *ctx, + void *ctr_ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src); + +int +siv_gcm_decrypt_message (const struct nettle_cipher *nc, + const void *ctx, + void *ctr_ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src); + +/* AEAD_AES_128_GCM_SIV */ +void +siv_gcm_aes128_encrypt_message (const struct aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src); + +int +siv_gcm_aes128_decrypt_message (const struct aes128_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src); + +/* AEAD_AES_256_GCM_SIV */ +void +siv_gcm_aes256_encrypt_message (const struct aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src); + +int +siv_gcm_aes256_decrypt_message (const struct aes256_ctx *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src); + +#ifdef __cplusplus +} +#endif + +#endif /* NETTLE_SIV_H_INCLUDED */ diff --git a/siv-ghash-set-key.c b/siv-ghash-set-key.c new file mode 100644 index 00000000..b13d7495 --- /dev/null +++ b/siv-ghash-set-key.c @@ -0,0 +1,52 @@ +/* siv-ghash-set-key.c + + POLYVAL implementation for AES-GCM-SIV, based on GHASH + + Copyright (C) 2011 Katholieke Universiteit Leuven + Copyright (C) 2011, 2013, 2018, 2022 Niels Möller + Copyright (C) 2018, 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ghash-internal.h" +#include "block-internal.h" + +void +_siv_ghash_set_key (struct gcm_key *ctx, const union nettle_block16 *key) +{ + union nettle_block16 h; + + block16_bswap (&h, key); + block16_mulx_ghash (&h, &h); + + _ghash_set_key (ctx, &h); +} diff --git a/siv-ghash-update.c b/siv-ghash-update.c new file mode 100644 index 00000000..21ce5c6e --- /dev/null +++ b/siv-ghash-update.c @@ -0,0 +1,65 @@ +/* siv-ghash-update.c + + POLYVAL implementation for AES-GCM-SIV, based on GHASH + + Copyright (C) 2011 Katholieke Universiteit Leuven + Copyright (C) 2011, 2013, 2018, 2022 Niels Möller + Copyright (C) 2018, 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "ghash-internal.h" +#include "block-internal.h" +#include "macros.h" + +const uint8_t * +_siv_ghash_update (const struct gcm_key *ctx, union nettle_block16 *state, + size_t blocks, const uint8_t *data) +{ + for (; blocks-- > 0; data += GCM_BLOCK_SIZE) + { + union nettle_block16 b; + +#if WORDS_BIGENDIAN + b.u64[1] = LE_READ_UINT64(data); + b.u64[0] = LE_READ_UINT64(data + 8); +#else + b.u64[1] = READ_UINT64(data); + b.u64[0] = READ_UINT64(data + 8); +#endif + + _ghash_update (ctx, state, 1, b.b); + } + + return data; +} + diff --git a/testsuite/.gitignore b/testsuite/.gitignore index 07127d2b..309464d6 100644 --- a/testsuite/.gitignore +++ b/testsuite/.gitignore @@ -107,6 +107,7 @@ /xts-test /cmac-test /siv-test +/siv-gcm-test /bcrypt-test /ed448-test /shake256-test diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in index 604dc1ff..05442595 100644 --- a/testsuite/Makefile.in +++ b/testsuite/Makefile.in @@ -28,7 +28,7 @@ TS_NETTLE_SOURCES = aes-test.c aes-keywrap-test.c arcfour-test.c arctwo-test.c \ serpent-test.c twofish-test.c version-test.c \ knuth-lfib-test.c \ cbc-test.c cfb-test.c ctr-test.c gcm-test.c eax-test.c ccm-test.c \ - cmac-test.c siv-test.c \ + cmac-test.c siv-test.c siv-gcm-test.c \ poly1305-test.c chacha-poly1305-test.c \ hmac-test.c umac-test.c \ meta-hash-test.c meta-cipher-test.c\ diff --git a/testsuite/siv-gcm-test.c b/testsuite/siv-gcm-test.c new file mode 100644 index 00000000..eba03f23 --- /dev/null +++ b/testsuite/siv-gcm-test.c @@ -0,0 +1,731 @@ +/* siv-gcm-test.c + + Self-test and vectors for AES-GCM-SIV mode ciphers + + Copyright (C) 2022 Red Hat, Inc. + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +/* The test vectors have been collected from the following standards: + * RFC8452 + */ + +#include "testutils.h" +#include "ghash-internal.h" +#include "block-internal.h" +#include "aes.h" +#include "siv-gcm.h" + +/* AEAD ciphers */ +typedef void +nettle_encrypt_message_func(void *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t clength, uint8_t *dst, const uint8_t *src); + +typedef int +nettle_decrypt_message_func(void *ctx, + size_t nlength, const uint8_t *nonce, + size_t alength, const uint8_t *adata, + size_t mlength, uint8_t *dst, const uint8_t *src); + +static void +test_compare_results (const char *name, + const struct tstring *adata, + /* Expected results. */ + const struct tstring *e_clear, + const struct tstring *e_cipher, + /* Actual results. */ + const void *clear, + const void *cipher) +{ + if (!MEMEQ(e_cipher->length, e_cipher->data, cipher)) + { + fprintf (stderr, "%s: encryption failed\nAdata: ", name); + tstring_print_hex (adata); + fprintf (stderr, "\nInput: "); + tstring_print_hex (e_clear); + fprintf (stderr, "\nOutput: "); + print_hex (e_cipher->length, cipher); + fprintf (stderr, "\nExpected:"); + tstring_print_hex (e_cipher); + fprintf (stderr, "\n"); + FAIL(); + } + if (!MEMEQ(e_clear->length, e_clear->data, clear)) + { + fprintf (stderr, "%s decrypt failed:\nAdata:", name); + tstring_print_hex (adata); + fprintf (stderr, "\nInput: "); + tstring_print_hex (e_cipher); + fprintf (stderr, "\nOutput: "); + print_hex (e_clear->length, clear); + fprintf (stderr, "\nExpected:"); + tstring_print_hex (e_clear); + fprintf (stderr, "\n"); + FAIL(); + } +} /* test_compare_results */ + +static void +test_cipher_siv_gcm (const char *name, + nettle_set_key_func *siv_gcm_set_key, + nettle_encrypt_message_func *siv_gcm_encrypt, + nettle_decrypt_message_func *siv_gcm_decrypt, + size_t context_size, size_t key_size, + const struct tstring *key, + const struct tstring *nonce, + const struct tstring *authdata, + const struct tstring *cleartext, + const struct tstring *ciphertext) +{ + void *ctx = xalloc (context_size); + uint8_t *en_data; + uint8_t *de_data; + int ret; + + ASSERT (key->length == key_size); + ASSERT (cleartext->length + SIV_GCM_DIGEST_SIZE == ciphertext->length); + + de_data = xalloc (cleartext->length); + en_data = xalloc (ciphertext->length); + + /* Ensure we get the same answers using the all-in-one API. */ + memset (de_data, 0, cleartext->length); + memset (en_data, 0, ciphertext->length); + + siv_gcm_set_key (ctx, key->data); + siv_gcm_encrypt (ctx, nonce->length, nonce->data, + authdata->length, authdata->data, + ciphertext->length, en_data, cleartext->data); + ret = siv_gcm_decrypt (ctx, nonce->length, nonce->data, + authdata->length, authdata->data, + cleartext->length, de_data, ciphertext->data); + + if (ret != 1) + { + fprintf (stderr, "siv_gcm_decrypt_message failed to validate message\n"); + FAIL(); + } + test_compare_results (name, authdata, + cleartext, ciphertext, de_data, en_data); + + /* Ensure that we can detect corrupted message or tag data. */ + en_data[0] ^= 1; + ret = siv_gcm_decrypt (ctx, nonce->length, nonce->data, + authdata->length, authdata->data, + cleartext->length, de_data, en_data); + if (ret != 0) + { + fprintf (stderr, "siv_gcm_decrypt_message failed to detect corrupted message\n"); + FAIL(); + } + + /* Ensure we can detect corrupted adata. */ + if (authdata->length) + { + en_data[0] ^= 1; + ret = siv_gcm_decrypt (ctx, nonce->length, nonce->data, + authdata->length-1, authdata->data, + cleartext->length, de_data, en_data); + if (ret != 0) + { + fprintf (stderr, "siv_decrypt_message failed to detect corrupted message\n"); + FAIL(); + } + } + + free (ctx); + free (en_data); + free (de_data); +} + +#define test_siv_gcm_aes128(name, key, nonce, authdata, cleartext, ciphertext) \ + test_cipher_siv_gcm(name, (nettle_set_key_func*)aes128_set_encrypt_key, \ + (nettle_encrypt_message_func*)siv_gcm_aes128_encrypt_message, \ + (nettle_decrypt_message_func*)siv_gcm_aes128_decrypt_message, \ + sizeof(struct aes128_ctx), AES128_KEY_SIZE, \ + key, nonce, authdata, cleartext, ciphertext) + +#define test_siv_gcm_aes256(name, key, nonce, authdata, cleartext, ciphertext) \ + test_cipher_siv_gcm(name, (nettle_set_key_func*)aes256_set_encrypt_key, \ + (nettle_encrypt_message_func*)siv_gcm_aes256_encrypt_message, \ + (nettle_decrypt_message_func*)siv_gcm_aes256_decrypt_message, \ + sizeof(struct aes256_ctx), AES256_KEY_SIZE, \ + key, nonce, authdata, cleartext, ciphertext) + +static void +test_polyval_internal (const struct tstring *key, + const struct tstring *message, + const struct tstring *digest) +{ + ASSERT (key->length == GCM_BLOCK_SIZE); + ASSERT (message->length % GCM_BLOCK_SIZE == 0); + ASSERT (digest->length == GCM_BLOCK_SIZE); + struct gcm_key gcm_key; + union nettle_block16 state; + + memcpy (state.b, key->data, GCM_BLOCK_SIZE); + _siv_ghash_set_key (&gcm_key, &state); + + block16_zero (&state); + _siv_ghash_update (&gcm_key, &state, message->length / GCM_BLOCK_SIZE, message->data); + block16_bswap (&state, &state); + + if (!MEMEQ(GCM_BLOCK_SIZE, state.b, digest->data)) + { + fprintf (stderr, "POLYVAL failed\n"); + fprintf (stderr, "Key: "); + tstring_print_hex (key); + fprintf (stderr, "\nMessage: "); + tstring_print_hex (message); + fprintf (stderr, "\nOutput: "); + print_hex (GCM_BLOCK_SIZE, state.b); + fprintf (stderr, "\nExpected:"); + tstring_print_hex (digest); + fprintf (stderr, "\n"); + FAIL(); + } +} + +void +test_main(void) +{ + /* RFC8452, Appendix A. */ + test_polyval_internal (SHEX("25629347589242761d31f826ba4b757b"), + SHEX("4f4f95668c83dfb6401762bb2d01a262" + "d1a24ddd2721d006bbe45f20d3c9f362"), + SHEX("f7a3b47b846119fae5b7866cf5e5b77e")); + + /* RFC8452, Appendix C.1. */ + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX(""), + SHEX("dc20e2d83f25705bb49e439eca56de25")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV 1", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("0100000000000000"), + SHEX("b5d839330ac7b786578782fff6013b81" + "5b287c22493a364c")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("010000000000000000000000"), + SHEX("7323ea61d05932260047d942a4978db3" + "57391a0bc4fdec8b0d106639")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000"), + SHEX("743f7c8077ab25f8624e2e948579cf77" + "303aaf90f6fe21199c6068577437a0c4")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000" + "02000000000000000000000000000000"), + SHEX("84e07e62ba83a6585417245d7ec413a9" + "fe427d6315c09b57ce45f2e3936a9445" + "1a8e45dcd4578c667cd86847bf6155ff")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000" + "02000000000000000000000000000000" + "03000000000000000000000000000000"), + SHEX("3fd24ce1f5a67b75bf2351f181a475c7" + "b800a5b4d3dcf70106b1eea82fa1d64d" + "f42bf7226122fa92e17a40eeaac1201b" + "5e6e311dbf395d35b0fe39c2714388f8")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000" + "02000000000000000000000000000000" + "03000000000000000000000000000000" + "04000000000000000000000000000000"), + SHEX("2433668f1058190f6d43e360f4f35cd8" + "e475127cfca7028ea8ab5c20f7ab2af0" + "2516a2bdcbc08d521be37ff28c152bba" + "36697f25b4cd169c6590d1dd39566d3f" + "8a263dd317aa88d56bdf3936dba75bb8")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("0200000000000000"), + SHEX("1e6daba35669f4273b0a1a2560969cdf" + "790d99759abd1508")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("020000000000000000000000"), + SHEX("296c7889fd99f41917f4462008299c51" + "02745aaa3a0c469fad9e075a")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000"), + SHEX("e2b0c5da79a901c1745f700525cb335b" + "8f8936ec039e4e4bb97ebd8c4457441f")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000" + "03000000000000000000000000000000"), + SHEX("620048ef3c1e73e57e02bb8562c416a3" + "19e73e4caac8e96a1ecb2933145a1d71" + "e6af6a7f87287da059a71684ed3498e1")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000" + "03000000000000000000000000000000" + "04000000000000000000000000000000"), + SHEX("50c8303ea93925d64090d07bd109dfd9" + "515a5a33431019c17d93465999a8b005" + "3201d723120a8562b838cdff25bf9d1e" + "6a8cc3865f76897c2e4b245cf31c51f2")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000" + "03000000000000000000000000000000" + "04000000000000000000000000000000" + "05000000000000000000000000000000"), + SHEX("2f5c64059db55ee0fb847ed513003746" + "aca4e61c711b5de2e7a77ffd02da42fe" + "ec601910d3467bb8b36ebbaebce5fba3" + "0d36c95f48a3e7980f0e7ac299332a80" + "cdc46ae475563de037001ef84ae21744")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("010000000000000000000000"), + SHEX("02000000"), + SHEX("a8fe3e8707eb1f84fb28f8cb73de8e99" + "e2f48a14")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01000000000000000000000000000000" + "0200"), + SHEX("03000000000000000000000000000000" + "04000000"), + SHEX("6bb0fecf5ded9b77f902c7d5da236a43" + "91dd029724afc9805e976f451e6d87f6" + "fe106514")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("01000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01000000000000000000000000000000" + "02000000"), + SHEX("03000000000000000000000000000000" + "0400"), + SHEX("44d0aaf6fb2f1f34add5e8064e83e12a" + "2adabff9b2ef00fb47920cc72a0c0f13" + "b9fd")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("e66021d5eb8e4f4066d4adb9c33560e4"), + SHEX("f46e44bb3da0015c94f70887"), + SHEX(""), + SHEX(""), + SHEX("a4194b79071b01a87d65f706e3949578")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("36864200e0eaf5284d884a0e77d31646"), + SHEX("bae8e37fc83441b16034566b"), + SHEX("46bb91c3c5"), + SHEX("7a806c"), + SHEX("af60eb711bd85bc1e4d3e0a462e074ee" + "a428a8")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("aedb64a6c590bc84d1a5e269e4b47801"), + SHEX("afc0577e34699b9e671fdd4f"), + SHEX("fc880c94a95198874296"), + SHEX("bdc66f146545"), + SHEX("bb93a3e34d3cd6a9c45545cfc11f03ad" + "743dba20f966")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("d5cc1fd161320b6920ce07787f86743b"), + SHEX("275d1ab32f6d1f0434d8848c"), + SHEX("046787f3ea22c127aaf195d1894728"), + SHEX("1177441f195495860f"), + SHEX("4f37281f7ad12949d01d02fd0cd174c8" + "4fc5dae2f60f52fd2b")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("b3fed1473c528b8426a582995929a149"), + SHEX("9e9ad8780c8d63d0ab4149c0"), + SHEX("c9882e5386fd9f92ec489c8fde2be2cf" + "97e74e93"), + SHEX("9f572c614b4745914474e7c7"), + SHEX("f54673c5ddf710c745641c8bc1dc2f87" + "1fb7561da1286e655e24b7b0")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("2d4ed87da44102952ef94b02b805249b"), + SHEX("ac80e6f61455bfac8308a2d4"), + SHEX("2950a70d5a1db2316fd568378da107b5" + "2b0da55210cc1c1b0a"), + SHEX("0d8c8451178082355c9e940fea2f58"), + SHEX("c9ff545e07b88a015f05b274540aa183" + "b3449b9f39552de99dc214a1190b0b")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("bde3b2f204d1e9f8b06bc47f9745b3d1"), + SHEX("ae06556fb6aa7890bebc18fe"), + SHEX("1860f762ebfbd08284e421702de0de18" + "baa9c9596291b08466f37de21c7f"), + SHEX("6b3db4da3d57aa94842b9803a96e07fb" + "6de7"), + SHEX("6298b296e24e8cc35dce0bed484b7f30" + "d5803e377094f04709f64d7b985310a4" + "db84")); + + test_siv_gcm_aes128 ("AEAD_AES_128_GCM_SIV", + SHEX("f901cfe8a69615a93fdf7a98cad48179"), + SHEX("6245709fb18853f68d833640"), + SHEX("7576f7028ec6eb5ea7e298342a94d4b2" + "02b370ef9768ec6561c4fe6b7e7296fa" + "859c21"), + SHEX("e42a3c02c25b64869e146d7b233987bd" + "dfc240871d"), + SHEX("391cc328d484a4f46406181bcd62efd9" + "b3ee197d052d15506c84a9edd65e13e9" + "d24a2a6e70")); + + /* RFC8452, Appendix C.2. */ + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX(""), + SHEX("07f5f4169bbf55a8400cd47ea6fd400f")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("0100000000000000"), + SHEX("c2ef328e5c71c83b843122130f7364b7" + "61e0b97427e3df28")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("010000000000000000000000"), + SHEX("9aab2aeb3faa0a34aea8e2b18ca50da9" + "ae6559e48fd10f6e5c9ca17e")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000"), + SHEX("85a01b63025ba19b7fd3ddfc033b3e76" + "c9eac6fa700942702e90862383c6c366")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000" + "02000000000000000000000000000000"), + SHEX("4a6a9db4c8c6549201b9edb53006cba8" + "21ec9cf850948a7c86c68ac7539d027f" + "e819e63abcd020b006a976397632eb5d")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000" + "02000000000000000000000000000000" + "03000000000000000000000000000000"), + SHEX("c00d121893a9fa603f48ccc1ca3c57ce" + "7499245ea0046db16c53c7c66fe717e3" + "9cf6c748837b61f6ee3adcee17534ed5" + "790bc96880a99ba804bd12c0e6a22cc4")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX(""), + SHEX("01000000000000000000000000000000" + "02000000000000000000000000000000" + "03000000000000000000000000000000" + "04000000000000000000000000000000"), + SHEX("c2d5160a1f8683834910acdafc41fbb1" + "632d4a353e8b905ec9a5499ac34f96c7" + "e1049eb080883891a4db8caaa1f99dd0" + "04d80487540735234e3744512c6f90ce" + "112864c269fc0d9d88c61fa47e39aa08")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("0200000000000000"), + SHEX("1de22967237a813291213f267e3b452f" + "02d01ae33e4ec854")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("020000000000000000000000"), + SHEX("163d6f9cc1b346cd453a2e4cc1a4a19a" + "e800941ccdc57cc8413c277f")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000"), + SHEX("c91545823cc24f17dbb0e9e807d5ec17" + "b292d28ff61189e8e49f3875ef91aff7")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000" + "03000000000000000000000000000000"), + SHEX("07dad364bfc2b9da89116d7bef6daaaf" + "6f255510aa654f920ac81b94e8bad365" + "aea1bad12702e1965604374aab96dbbc")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000" + "03000000000000000000000000000000" + "04000000000000000000000000000000"), + SHEX("c67a1f0f567a5198aa1fcc8e3f213143" + "36f7f51ca8b1af61feac35a86416fa47" + "fbca3b5f749cdf564527f2314f42fe25" + "03332742b228c647173616cfd44c54eb")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01"), + SHEX("02000000000000000000000000000000" + "03000000000000000000000000000000" + "04000000000000000000000000000000" + "05000000000000000000000000000000"), + SHEX("67fd45e126bfb9a79930c43aad2d3696" + "7d3f0e4d217c1e551f59727870beefc9" + "8cb933a8fce9de887b1e40799988db1f" + "c3f91880ed405b2dd298318858467c89" + "5bde0285037c5de81e5b570a049b62a0")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("010000000000000000000000"), + SHEX("02000000"), + SHEX("22b3f4cd1835e517741dfddccfa07fa4" + "661b74cf")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01000000000000000000000000000000" + "0200"), + SHEX("03000000000000000000000000000000" + "04000000"), + SHEX("43dd0163cdb48f9fe3212bf61b201976" + "067f342bb879ad976d8242acc188ab59" + "cabfe307")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("01000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("030000000000000000000000"), + SHEX("01000000000000000000000000000000" + "02000000"), + SHEX("03000000000000000000000000000000" + "0400"), + SHEX("462401724b5ce6588d5a54aae5375513" + "a075cfcdf5042112aa29685c912fc205" + "6543")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("e66021d5eb8e4f4066d4adb9c33560e4" + "f46e44bb3da0015c94f7088736864200"), + SHEX("e0eaf5284d884a0e77d31646"), + SHEX(""), + SHEX(""), + SHEX("169fbb2fbf389a995f6390af22228a62")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("bae8e37fc83441b16034566b7a806c46" + "bb91c3c5aedb64a6c590bc84d1a5e269"), + SHEX("e4b47801afc0577e34699b9e"), + SHEX("4fbdc66f14"), + SHEX("671fdd"), + SHEX("0eaccb93da9bb81333aee0c785b240d3" + "19719d")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("6545fc880c94a95198874296d5cc1fd1" + "61320b6920ce07787f86743b275d1ab3"), + SHEX("2f6d1f0434d8848c1177441f"), + SHEX("6787f3ea22c127aaf195"), + SHEX("195495860f04"), + SHEX("a254dad4f3f96b62b84dc40c84636a5e" + "c12020ec8c2c")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("d1894728b3fed1473c528b8426a58299" + "5929a1499e9ad8780c8d63d0ab4149c0"), + SHEX("9f572c614b4745914474e7c7"), + SHEX("489c8fde2be2cf97e74e932d4ed87d"), + SHEX("c9882e5386fd9f92ec"), + SHEX("0df9e308678244c44bc0fd3dc6628dfe" + "55ebb0b9fb2295c8c2")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("a44102952ef94b02b805249bac80e6f6" + "1455bfac8308a2d40d8c845117808235"), + SHEX("5c9e940fea2f582950a70d5a"), + SHEX("0da55210cc1c1b0abde3b2f204d1e9f8" + "b06bc47f"), + SHEX("1db2316fd568378da107b52b"), + SHEX("8dbeb9f7255bf5769dd56692404099c2" + "587f64979f21826706d497d5")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("9745b3d1ae06556fb6aa7890bebc18fe" + "6b3db4da3d57aa94842b9803a96e07fb"), + SHEX("6de71860f762ebfbd08284e4"), + SHEX("f37de21c7ff901cfe8a69615a93fdf7a" + "98cad481796245709f"), + SHEX("21702de0de18baa9c9596291b08466"), + SHEX("793576dfa5c0f88729a7ed3c2f1bffb3" + "080d28f6ebb5d3648ce97bd5ba67fd")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("b18853f68d833640e42a3c02c25b6486" + "9e146d7b233987bddfc240871d7576f7"), + SHEX("028ec6eb5ea7e298342a94d4"), + SHEX("9c2159058b1f0fe91433a5bdc20e214e" + "ab7fecef4454a10ef0657df21ac7"), + SHEX("b202b370ef9768ec6561c4fe6b7e7296" + "fa85"), + SHEX("857e16a64915a787637687db4a951963" + "5cdd454fc2a154fea91f8363a39fec7d" + "0a49")); + + test_siv_gcm_aes256 ("AEAD_AES_256_GCM_SIV", + SHEX("3c535de192eaed3822a2fbbe2ca9dfc8" + "8255e14a661b8aa82cc54236093bbc23"), + SHEX("688089e55540db1872504e1c"), + SHEX("734320ccc9d9bbbb19cb81b2af4ecbc3" + "e72834321f7aa0f70b7282b4f33df23f" + "167541"), + SHEX("ced532ce4159b035277d4dfbb7db6296" + "8b13cd4eec"), + SHEX("626660c26ea6612fb17ad91e8e767639" + "edd6c9faee9d6c7029675b89eaf4ba1d" + "ed1a286594")); + + /* RFC8452, Appendix C.3. */ + test_siv_gcm_aes256 ("Counter wrap", + SHEX("00000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("000000000000000000000000"), + SHEX(""), + SHEX("00000000000000000000000000000000" + "4db923dc793ee6497c76dcc03a98e108"), + SHEX("f3f80f2cf0cb2dd9c5984fcda908456c" + "c537703b5ba70324a6793a7bf218d3ea" + "ffffffff000000000000000000000000")); + + test_siv_gcm_aes256 ("Counter wrap", + SHEX("00000000000000000000000000000000" + "00000000000000000000000000000000"), + SHEX("000000000000000000000000"), + SHEX(""), + SHEX("eb3640277c7ffd1303c7a542d02d3e4c" + "0000000000000000"), + SHEX("18ce4f0b8cb4d0cac65fea8f79257b20" + "888e53e72299e56dffffffff00000000" + "0000000000000000")); +} -- cgit v1.2.1