From: Todd Short Date: Thu, 28 Apr 2022 18:56:11 +0000 (-0400) Subject: Implement AES-GCM-SIV (RFC8452) X-Git-Tag: openssl-3.2.0-alpha1~2315 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0113ec8460a918f8bc782130db8f75540b3b1ab2;p=thirdparty%2Fopenssl.git Implement AES-GCM-SIV (RFC8452) 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 Reviewed-by: Tomas Mraz Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/18693) --- diff --git a/.github/workflows/run-checker-ci.yml b/.github/workflows/run-checker-ci.yml index cfc458ac583..222cffa5b99 100644 --- a/.github/workflows/run-checker-ci.yml +++ b/.github/workflows/run-checker-ci.yml @@ -23,6 +23,7 @@ jobs: no-dtls, no-ec, no-ec2m, + no-siv, no-legacy, no-rfc3779, no-sock, diff --git a/apps/speed.c b/apps/speed.c index 3d9e7479003..2eab740fc5b 100644 --- a/apps/speed.c +++ b/apps/speed.c @@ -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); } diff --git a/crypto/modes/gcm128.c b/crypto/modes/gcm128.c index 84cc6fb08a2..9a9adc9df86 100644 --- a/crypto/modes/gcm128.c +++ b/crypto/modes/gcm128.c @@ -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; diff --git a/doc/man3/EVP_EncryptInit.pod b/doc/man3/EVP_EncryptInit.pod index 4069866a9ff..f81fdb2e00c 100644 --- a/doc/man3/EVP_EncryptInit.pod +++ b/doc/man3/EVP_EncryptInit.pod @@ -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. diff --git a/include/crypto/modes.h b/include/crypto/modes.h index 573e1197d09..d567a0ba843 100644 --- a/include/crypto/modes.h +++ b/include/crypto/modes.h @@ -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. diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 9cd8f220cce..a8f875a59ab 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -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 */ diff --git a/include/openssl/evp.h b/include/openssl/evp.h index cec3fa98e9b..d9b3db6ae6a 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -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 diff --git a/providers/defltprov.c b/providers/defltprov.c index 3add4cdaf69..edfcc97bae7 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -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), diff --git a/providers/implementations/ciphers/build.info b/providers/implementations/ciphers/build.info index b5d9d4f6c1e..c8f35bb1d88 100644 --- a/providers/implementations/ciphers/build.info +++ b/providers/implementations/ciphers/build.info @@ -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 index 00000000000..93e65d530e0 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv.c @@ -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 +#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 index 00000000000..1224512e3a7 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv.h @@ -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 +#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 index 00000000000..9ee5c32f4fd --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c @@ -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 +#include +#include +#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 index 00000000000..66f6ed457ec --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c @@ -0,0 +1,84 @@ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * AES low level APIs are deprecated for public use, but still ok for internal + * use where we're using them to implement the higher level EVP interface, as is + * the case here. + */ +#include "internal/deprecated.h" + +#include +#include +#include +#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); +} diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index 57400282875..03ce43719e4 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -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 */ diff --git a/providers/implementations/include/prov/names.h b/providers/implementations/include/prov/names.h index 97cbae70f12..3acea6eaa0e 100644 --- a/providers/implementations/include/prov/names.h +++ b/providers/implementations/include/prov/names.h @@ -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" diff --git a/test/evp_test.c b/test/evp_test.c index f0ca8c48ffb..4a532bee762 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -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; diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t index 9f321850dde..572f5b1d8ef 100644 --- a/test/recipes/30-test_evp.t +++ b/test/recipes/30-test_evp.t @@ -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 index 00000000000..39c880cda9a --- /dev/null +++ b/test/recipes/30-test_evp_data/evpciph_aes_gcm_siv.txt @@ -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 + +