From eb173822b2c02122844f4ffe89e38fe8e6d04697 Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Fri, 8 Nov 2019 12:14:44 +1000 Subject: [PATCH] Add AES SIV ciphers to default provider Reviewed-by: Richard Levitte Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/10120) --- crypto/evp/evp_enc.c | 9 + doc/man7/provider-cipher.pod | 7 + include/openssl/core_names.h | 2 + providers/defltprov.c | 5 + providers/implementations/ciphers/build.info | 6 + .../implementations/ciphers/cipher_aes_siv.c | 236 ++++++++++++++++++ .../implementations/ciphers/cipher_aes_siv.h | 34 +++ .../ciphers/cipher_aes_siv_hw.c | 99 ++++++++ .../include/prov/implementations.h | 6 + test/recipes/30-test_evp.t | 6 +- 10 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 providers/implementations/ciphers/cipher_aes_siv.c create mode 100644 providers/implementations/ciphers/cipher_aes_siv.h create mode 100644 providers/implementations/ciphers/cipher_aes_siv_hw.c diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index efcb7e509a..53bd02d3c4 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -171,6 +171,9 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, case NID_aes_256_gcm: case NID_aes_192_gcm: case NID_aes_128_gcm: + case NID_aes_256_siv: + case NID_aes_192_siv: + case NID_aes_128_siv: case NID_id_aes256_wrap: case NID_id_aes256_wrap_pad: case NID_id_aes192_wrap: @@ -1124,6 +1127,12 @@ int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) i = (unsigned int)arg; params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_ROUNDS, &i); break; + case EVP_CTRL_SET_SPEED: + if (arg < 0) + return 0; + i = (unsigned int)arg; + params[0] = OSSL_PARAM_construct_uint(OSSL_CIPHER_PARAM_SPEED, &i); + break; case EVP_CTRL_AEAD_GET_TAG: set_params = 0; /* Fall thru */ case EVP_CTRL_AEAD_SET_TAG: diff --git a/doc/man7/provider-cipher.pod b/doc/man7/provider-cipher.pod index cd9e0fd8a9..c5415a5441 100644 --- a/doc/man7/provider-cipher.pod +++ b/doc/man7/provider-cipher.pod @@ -342,6 +342,13 @@ This is used by the RC5 cipher. Gets or sets the effective keybits used for a RC2 cipher. The length of the "keybits" parameter should not exceed that of a B. +=item "speed" (B) + +Sets the speed option for the associated cipher ctx. This is only supported +by AES SIV ciphers which disallow multiple operations by default. +Setting "speed" to 1 allows another encrypt or decrypt operation to be +performed. This is used for performance testing. + =back =head1 RETURN VALUES diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 4cbcf0cc71..42350e80d1 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -69,9 +69,11 @@ extern "C" { #define OSSL_CIPHER_PARAM_AEAD_MAC_KEY "mackey" /* octet_string */ #define OSSL_CIPHER_PARAM_RANDOM_KEY "randkey" /* octet_string */ #define OSSL_CIPHER_PARAM_RC2_KEYBITS "keybits" /* size_t */ +#define OSSL_CIPHER_PARAM_SPEED "speed" /* uint */ /* For passing the AlgorithmIdentifier parameter in DER form */ #define OSSL_CIPHER_PARAM_ALG_ID "alg_id_param" /* octet_string */ + /* digest parameters */ #define OSSL_DIGEST_PARAM_XOFLEN "xoflen" /* size_t */ #define OSSL_DIGEST_PARAM_SSL3_MS "ssl3-ms" /* octet string */ diff --git a/providers/defltprov.c b/providers/defltprov.c index a0f3b8bb9f..186f1f5368 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -156,6 +156,11 @@ static const OSSL_ALGORITHM deflt_ciphers[] = { { "AES-192-OCB", "default=yes", aes192ocb_functions }, { "AES-128-OCB", "default=yes", aes128ocb_functions }, #endif /* OPENSSL_NO_OCB */ +#ifndef OPENSSL_NO_SIV + { "AES-128-SIV", "default=yes", aes128siv_functions }, + { "AES-192-SIV", "default=yes", aes192siv_functions }, + { "AES-256-SIV", "default=yes", aes256siv_functions }, +#endif /* OPENSSL_NO_SIV */ { "AES-256-GCM:id-aes256-GCM", "default=yes", aes256gcm_functions }, { "AES-192-GCM:id-aes192-GCM", "default=yes", aes192gcm_functions }, { "AES-128-GCM:id-aes128-GCM", "default=yes", aes128gcm_functions }, diff --git a/providers/implementations/ciphers/build.info b/providers/implementations/ciphers/build.info index 7f0b76c01b..1ac2a70ca6 100644 --- a/providers/implementations/ciphers/build.info +++ b/providers/implementations/ciphers/build.info @@ -21,6 +21,7 @@ $RC5_GOAL=../../libimplementations.a $RC2_GOAL=../../libimplementations.a $CHACHA_GOAL=../../libimplementations.a $CHACHAPOLY_GOAL=../../libimplementations.a +$SIV_GOAL=../../libimplementations.a IF[{- !$disabled{des} -}] SOURCE[$TDES_1_GOAL]=cipher_tdes.c cipher_tdes_hw.c @@ -37,6 +38,11 @@ SOURCE[$AES_GOAL]=\ SOURCE[../../libfips.a]=cipher_aes_xts_fips.c SOURCE[../../libnonfips.a]=cipher_aes_xts_fips.c +IF[{- !$disabled{siv} -}] + SOURCE[$SIV_GOAL]=\ + cipher_aes_siv.c cipher_aes_siv_hw.c +ENDIF + IF[{- !$disabled{des} -}] SOURCE[$TDES_2_GOAL]=\ cipher_tdes_default.c cipher_tdes_default_hw.c \ diff --git a/providers/implementations/ciphers/cipher_aes_siv.c b/providers/implementations/ciphers/cipher_aes_siv.c new file mode 100644 index 0000000000..6a5d211a7d --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_siv.c @@ -0,0 +1,236 @@ +/* + * Copyright 2019 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 */ + +#include "cipher_aes_siv.h" +#include "prov/implementations.h" +#include "prov/providercommonerr.h" +#include "prov/cipher_aead.h" + +#define siv_stream_update siv_cipher +#define SIV_FLAGS AEAD_FLAGS + +static void *aes_siv_newctx(void *provctx, size_t keybits, unsigned int mode, + uint64_t flags) +{ + PROV_AES_SIV_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx != NULL) { + ctx->taglen = SIV_LEN; + ctx->mode = mode; + ctx->flags = flags; + ctx->keylen = keybits / 8; + ctx->hw = PROV_CIPHER_HW_aes_siv(keybits); + } + return ctx; +} + +static void aes_siv_freectx(void *vctx) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (ctx != NULL) { + ctx->hw->cleanup(ctx); + OPENSSL_clear_free(ctx, sizeof(*ctx)); + } +} + +static int siv_init(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, int enc) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + ctx->enc = enc; + + if (iv != NULL) + return 0; + + if (key != NULL) { + if (keylen != ctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return 0; + } + return ctx->hw->initkey(ctx, key, ctx->keylen); + } + return 1; +} + +static int siv_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen) +{ + return siv_init(vctx, key, keylen, iv, ivlen, 1); +} + +static int siv_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen) +{ + return siv_init(vctx, key, keylen, iv, ivlen, 0); +} + +static int siv_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, size_t inl) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (ctx->hw->cipher(ctx, out, in, inl) <= 0) + return 0; + + if (outl != NULL) + *outl = inl; + return 1; +} + +static int siv_stream_final(void *vctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + + if (!ctx->hw->cipher(vctx, out, NULL, 0)) + return 0; + + if (outl != NULL) + *outl = 0; + return 1; +} + +static int aes_siv_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + 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 + || p->data_size != ctx->taglen + || !OSSL_PARAM_set_octet_string(p, &sctx->tag.byte, ctx->taglen)) { + 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, ctx->taglen)) { + 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->keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + return 1; +} + +static const OSSL_PARAM aes_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_uint(OSSL_CIPHER_PARAM_SPEED, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; +static const OSSL_PARAM *aes_siv_gettable_ctx_params(void) +{ + return aes_siv_known_gettable_ctx_params; +} + +static int aes_siv_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + const OSSL_PARAM *p; + unsigned int speed = 0; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p != NULL) { + if (ctx->enc) + return 1; + if (p->data_type != OSSL_PARAM_OCTET_STRING + || !ctx->hw->settag(ctx, p->data, p->data_size)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + } + 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->hw->setspeed(ctx, (int)speed); + } + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return 0; + } + /* The key length can not be modified */ + if (keylen != ctx->keylen) + return 0; + } + return 1; +} + +static const OSSL_PARAM aes_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 *aes_siv_settable_ctx_params(void) +{ + return aes_siv_known_settable_ctx_params; +} + +#define IMPLEMENT_cipher(alg, lc, UCMODE, flags, kbits, blkbits, ivbits) \ +static OSSL_OP_cipher_get_params_fn alg##_##kbits##_##lc##_get_params; \ +static int alg##_##kbits##_##lc##_get_params(OSSL_PARAM params[]) \ +{ \ + return cipher_generic_get_params(params, EVP_CIPH_##UCMODE##_MODE, \ + flags, 2*kbits, blkbits, ivbits); \ +} \ +static OSSL_OP_cipher_newctx_fn alg##kbits##lc##_newctx; \ +static void * alg##kbits##lc##_newctx(void *provctx) \ +{ \ + return alg##_##lc##_newctx(provctx, 2*kbits, EVP_CIPH_##UCMODE##_MODE, \ + flags); \ +} \ +const OSSL_DISPATCH alg##kbits##lc##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))alg##kbits##lc##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))alg##_##lc##_freectx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, (void (*)(void)) lc##_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, (void (*)(void)) lc##_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, (void (*)(void)) lc##_stream_update }, \ + { OSSL_FUNC_CIPHER_FINAL, (void (*)(void)) lc##_stream_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void)) lc##_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void)) alg##_##kbits##_##lc##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))cipher_generic_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void)) alg##_##lc##_settable_ctx_params }, \ + { 0, NULL } \ +}; + +IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 128, 8, 0) +IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 192, 8, 0) +IMPLEMENT_cipher(aes, siv, SIV, SIV_FLAGS, 256, 8, 0) diff --git a/providers/implementations/ciphers/cipher_aes_siv.h b/providers/implementations/ciphers/cipher_aes_siv.h new file mode 100644 index 0000000000..8f35d757dc --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_siv.h @@ -0,0 +1,34 @@ +/* + * Copyright 2019 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 "prov/ciphercommon.h" +#include "include/crypto/siv.h" + +typedef struct prov_cipher_hw_aes_siv_st { + int (*initkey)(void *ctx, const uint8_t *key, size_t keylen); + int (*cipher)(void *ctx, unsigned char *out, const unsigned char *in, + size_t len); + void (*setspeed)(void *ctx, int speed); + int (*settag)(void *ctx, const unsigned char *tag, size_t tagl); + void (*cleanup)(void *ctx); +} PROV_CIPHER_HW_AES_SIV; + +typedef struct prov_siv_ctx_st { + unsigned int mode; /* The mode that we are using */ + unsigned int enc : 1; /* Set to 1 if we are encrypting or 0 otherwise */ + uint64_t flags; + size_t keylen; /* The input keylength (twice the alg key length) */ + size_t taglen; /* the taglen is the same as the sivlen */ + SIV128_CONTEXT siv; + EVP_CIPHER *ctr; /* These are fetched - so we need to free them */ + EVP_CIPHER *cbc; + const PROV_CIPHER_HW_AES_SIV *hw; +} PROV_AES_SIV_CTX; + +const PROV_CIPHER_HW_AES_SIV *PROV_CIPHER_HW_aes_siv(size_t keybits); diff --git a/providers/implementations/ciphers/cipher_aes_siv_hw.c b/providers/implementations/ciphers/cipher_aes_siv_hw.c new file mode 100644 index 0000000000..b8fbc61a63 --- /dev/null +++ b/providers/implementations/ciphers/cipher_aes_siv_hw.c @@ -0,0 +1,99 @@ +/* + * Copyright 2019 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 "cipher_aes_siv.h" + +static int aes_siv_initkey(void *vctx, const unsigned char *key, size_t keylen) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + size_t klen = keylen / 2; + + switch (klen) { + case 16: + ctx->cbc = EVP_CIPHER_fetch(NULL, "AES-128-CBC", ""); + ctx->ctr = EVP_CIPHER_fetch(NULL, "AES-128-CTR", ""); + break; + case 24: + ctx->cbc = EVP_CIPHER_fetch(NULL, "AES-192-CBC", ""); + ctx->ctr = EVP_CIPHER_fetch(NULL, "AES-192-CTR", ""); + break; + case 32: + ctx->cbc = EVP_CIPHER_fetch(NULL, "AES-256-CBC", ""); + ctx->ctr = EVP_CIPHER_fetch(NULL, "AES-256-CTR", ""); + break; + default: + return 0; + } + /* + * klen is the length of the underlying cipher, not the input key, + * which should be twice as long + */ + return CRYPTO_siv128_init(sctx, key, klen, ctx->cbc, ctx->ctr); +} + +static int aes_siv_settag(void *vctx, const unsigned char *tag, size_t tagl) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + return CRYPTO_siv128_set_tag(sctx, tag, tagl); +} + +static void aes_siv_setspeed(void *vctx, int speed) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + CRYPTO_siv128_speed(sctx, (int)speed); +} + +static void aes_siv_cleanup(void *vctx) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + CRYPTO_siv128_cleanup(sctx); + EVP_CIPHER_free(ctx->cbc); + EVP_CIPHER_free(ctx->ctr); +} + +static int aes_siv_cipher(void *vctx, unsigned char *out, + const unsigned char *in, size_t len) +{ + PROV_AES_SIV_CTX *ctx = (PROV_AES_SIV_CTX *)vctx; + SIV128_CONTEXT *sctx = &ctx->siv; + + /* EncryptFinal or DecryptFinal */ + if (in == NULL) + return CRYPTO_siv128_finish(sctx) == 0; + + /* Deal with associated data */ + if (out == NULL) + return (CRYPTO_siv128_aad(sctx, in, len) == 1); + + if (ctx->enc) + return CRYPTO_siv128_encrypt(sctx, in, out, len) > 0; + + return CRYPTO_siv128_decrypt(sctx, in, out, len) > 0; +} + +static const PROV_CIPHER_HW_AES_SIV aes_siv_hw = +{ + aes_siv_initkey, + aes_siv_cipher, + aes_siv_setspeed, + aes_siv_settag, + aes_siv_cleanup +}; + +const PROV_CIPHER_HW_AES_SIV *PROV_CIPHER_HW_aes_siv(size_t keybits) +{ + return &aes_siv_hw; +} diff --git a/providers/implementations/include/prov/implementations.h b/providers/implementations/include/prov/implementations.h index ded3ef97f7..9aef2c3768 100644 --- a/providers/implementations/include/prov/implementations.h +++ b/providers/implementations/include/prov/implementations.h @@ -211,6 +211,12 @@ extern const OSSL_DISPATCH chacha20_poly1305_functions[]; #endif /* OPENSSL_NO_CHACHA */ +#ifndef OPENSSL_NO_SIV +extern const OSSL_DISPATCH aes128siv_functions[]; +extern const OSSL_DISPATCH aes192siv_functions[]; +extern const OSSL_DISPATCH aes256siv_functions[]; +#endif /* OPENSSL_NO_SIV */ + /* MACs */ extern const OSSL_DISPATCH blake2bmac_functions[]; extern const OSSL_DISPATCH blake2smac_functions[]; diff --git a/test/recipes/30-test_evp.t b/test/recipes/30-test_evp.t index 28029e765c..a5060971fc 100644 --- a/test/recipes/30-test_evp.t +++ b/test/recipes/30-test_evp.t @@ -33,11 +33,13 @@ push @configs, 'fips.cnf' unless $no_fips; my @files = qw( evpciph.txt evpdigest.txt ); my @defltfiles = qw( evpencod.txt evpkdf.txt evppkey_kdf.txt evpmac.txt - evppbe.txt evppkey.txt evppkey_ecc.txt evpcase.txt evpaessiv.txt - evpccmcavs.txt ); + evppbe.txt evppkey.txt evppkey_ecc.txt evpcase.txt evpccmcavs.txt ); my @ideafiles = qw( evpciph_idea.txt ); push @defltfiles, @ideafiles unless disabled("idea"); +my @sivfiles = qw( evpaessiv.txt ); +push @defltfiles, @sivfiles unless disabled("siv"); + my @castfiles = qw( evpciph_cast5.txt ); push @defltfiles, @castfiles unless disabled("cast"); -- 2.25.1