From cd8d1456c97ad17fb147f4fdcbb5ba8c983b8bb8 Mon Sep 17 00:00:00 2001 From: Andy Polyakov Date: Thu, 10 Aug 2017 22:39:40 +0200 Subject: [PATCH] Add EVP_DigestFinalXOF, interface to extendable-output functions, XOFs. Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/4137) --- crypto/err/openssl.txt | 2 ++ crypto/evp/digest.c | 21 +++++++++++++++++++++ crypto/evp/evp_err.c | 3 +++ doc/man3/EVP_DigestInit.pod | 14 +++++++++++--- include/openssl/evp.h | 6 ++++++ include/openssl/evperr.h | 2 ++ test/evp_test.c | 22 ++++++++++++++++++---- util/libcrypto.num | 1 + 8 files changed, 64 insertions(+), 7 deletions(-) diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index cbbbdaee5f..13b1348a93 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -646,6 +646,7 @@ EVP_F_EVP_CIPHER_CTX_CTRL:124:EVP_CIPHER_CTX_ctrl EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH:122:EVP_CIPHER_CTX_set_key_length EVP_F_EVP_DECRYPTFINAL_EX:101:EVP_DecryptFinal_ex EVP_F_EVP_DECRYPTUPDATE:166:EVP_DecryptUpdate +EVP_F_EVP_DIGESTFINALXOF:174:EVP_DigestFinalXOF EVP_F_EVP_DIGESTINIT_EX:128:EVP_DigestInit_ex EVP_F_EVP_ENCRYPTFINAL_EX:127:EVP_EncryptFinal_ex EVP_F_EVP_ENCRYPTUPDATE:167:EVP_EncryptUpdate @@ -1939,6 +1940,7 @@ EVP_R_MEMORY_LIMIT_EXCEEDED:172:memory limit exceeded EVP_R_MESSAGE_DIGEST_IS_NULL:159:message digest is null EVP_R_METHOD_NOT_SUPPORTED:144:method not supported EVP_R_MISSING_PARAMETERS:103:missing parameters +EVP_R_NOT_XOF_OR_INVALID_LENGTH:178:not XOF or invalid length EVP_R_NO_CIPHER_SET:131:no cipher set EVP_R_NO_DEFAULT_DIGEST:158:no default digest EVP_R_NO_DIGEST_SET:139:no digest set diff --git a/crypto/evp/digest.c b/crypto/evp/digest.c index 65eff7c8c1..c380dca0b5 100644 --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -174,6 +174,27 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) return ret; } +int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t size) +{ + int ret = 0; + + if (ctx->digest->flags & EVP_MD_FLAG_XOF + && size <= INT_MAX + && ctx->digest->md_ctrl(ctx, EVP_MD_CTRL_XOF_LEN, (int)size, NULL)) { + ret = ctx->digest->final(ctx, md); + + if (ctx->digest->cleanup != NULL) { + ctx->digest->cleanup(ctx); + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + } + OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size); + } else { + EVPerr(EVP_F_EVP_DIGESTFINALXOF, EVP_R_NOT_XOF_OR_INVALID_LENGTH); + } + + return ret; +} + int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) { EVP_MD_CTX_reset(out); diff --git a/crypto/evp/evp_err.c b/crypto/evp/evp_err.c index 9c6b514aa9..97fdf68b47 100644 --- a/crypto/evp/evp_err.c +++ b/crypto/evp/evp_err.c @@ -38,6 +38,7 @@ static const ERR_STRING_DATA EVP_str_functs[] = { {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTFINAL_EX, 0), "EVP_DecryptFinal_ex"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DECRYPTUPDATE, 0), "EVP_DecryptUpdate"}, + {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DIGESTFINALXOF, 0), "EVP_DigestFinalXOF"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DIGESTINIT_EX, 0), "EVP_DigestInit_ex"}, {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_ENCRYPTFINAL_EX, 0), "EVP_EncryptFinal_ex"}, @@ -179,6 +180,8 @@ static const ERR_STRING_DATA EVP_str_reasons[] = { {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_METHOD_NOT_SUPPORTED), "method not supported"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_MISSING_PARAMETERS), "missing parameters"}, + {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NOT_XOF_OR_INVALID_LENGTH), + "not XOF or invalid length"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_CIPHER_SET), "no cipher set"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DEFAULT_DIGEST), "no default digest"}, {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_NO_DIGEST_SET), "no digest set"}, diff --git a/doc/man3/EVP_DigestInit.pod b/doc/man3/EVP_DigestInit.pod index c051dfa220..b703762ff0 100644 --- a/doc/man3/EVP_DigestInit.pod +++ b/doc/man3/EVP_DigestInit.pod @@ -3,9 +3,10 @@ =head1 NAME EVP_MD_CTX_new, EVP_MD_CTX_reset, EVP_MD_CTX_free, EVP_MD_CTX_copy_ex, -EVP_MD_CTX_ctrl, EVP_DigestInit_ex, EVP_DigestUpdate, EVP_DigestFinal_ex, -EVP_DigestInit, EVP_DigestFinal, EVP_MD_CTX_copy, EVP_MD_type, -EVP_MD_pkey_type, EVP_MD_size, EVP_MD_block_size, EVP_MD_CTX_md, EVP_MD_CTX_size, +EVP_MD_CTX_ctrl, EVP_DigestInit_ex, EVP_DigestInit, EVP_DigestUpdate, +EVP_DigestFinal_ex, EVP_DigestFinalXOF, EVP_DigestFinal, +EVP_MD_CTX_copy, EVP_MD_type, EVP_MD_pkey_type, EVP_MD_size, +EVP_MD_block_size, EVP_MD_CTX_md, EVP_MD_CTX_size, EVP_MD_CTX_block_size, EVP_MD_CTX_type, EVP_md_null, EVP_md2, EVP_md5, EVP_sha1, EVP_sha224, EVP_sha256, EVP_sha384, EVP_sha512, EVP_sha3_224, EVP_sha3_256, EVP_sha3_384, EVP_sha3_512, EVP_mdc2, EVP_ripemd160, EVP_blake2b512, @@ -24,6 +25,7 @@ EVP_get_digestbyobj - EVP digest routines int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl); int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *d, size_t cnt); int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s); + int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, size_t len); int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in); @@ -97,6 +99,12 @@ After calling EVP_DigestFinal_ex() no additional calls to EVP_DigestUpdate() can be made, but EVP_DigestInit_ex() can be called to initialize a new digest operation. +EVP_DigestFinalXOF() interfaces to extendable-output functions, XOFs, +such as SHAKE128 and SHAKE256. It retrieves the digest value from +B and places it in B-sized md. After calling this function +no additional calls to EVP_DigestUpdate() can be made, but +EVP_DigestInit_ex() can be called to initialize a new operation. + EVP_MD_CTX_copy_ex() can be used to copy the message digest state from B to B. This is useful if large amounts of data are to be hashed which only differ in the last few bytes. B must be initialized diff --git a/include/openssl/evp.h b/include/openssl/evp.h index dd02077e05..e472ea2cba 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -109,6 +109,9 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd, /* digest can only handle a single block */ # define EVP_MD_FLAG_ONESHOT 0x0001 +/* digest is extensible-output function, XOF */ +# define EVP_MD_FLAG_XOF 0x0002 + /* DigestAlgorithmIdentifier flags... */ # define EVP_MD_FLAG_DIGALGID_MASK 0x0018 @@ -132,6 +135,7 @@ int (*EVP_MD_meth_get_ctrl(const EVP_MD *md))(EVP_MD_CTX *ctx, int cmd, # define EVP_MD_CTRL_DIGALGID 0x1 # define EVP_MD_CTRL_MICALG 0x2 +# define EVP_MD_CTRL_XOF_LEN 0x3 /* Minimum Algorithm specific ctrl value */ @@ -546,6 +550,8 @@ __owur int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in); __owur int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); __owur int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *s); +__owur int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, unsigned char *md, + size_t len); int EVP_read_pw_string(char *buf, int length, const char *prompt, int verify); int EVP_read_pw_string_min(char *buf, int minlen, int maxlen, diff --git a/include/openssl/evperr.h b/include/openssl/evperr.h index 334d84e625..750d68f9b0 100644 --- a/include/openssl/evperr.h +++ b/include/openssl/evperr.h @@ -40,6 +40,7 @@ int ERR_load_EVP_strings(void); # define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH 122 # define EVP_F_EVP_DECRYPTFINAL_EX 101 # define EVP_F_EVP_DECRYPTUPDATE 166 +# define EVP_F_EVP_DIGESTFINALXOF 174 # define EVP_F_EVP_DIGESTINIT_EX 128 # define EVP_F_EVP_ENCRYPTFINAL_EX 127 # define EVP_F_EVP_ENCRYPTUPDATE 167 @@ -136,6 +137,7 @@ int ERR_load_EVP_strings(void); # define EVP_R_MESSAGE_DIGEST_IS_NULL 159 # define EVP_R_METHOD_NOT_SUPPORTED 144 # define EVP_R_MISSING_PARAMETERS 103 +# define EVP_R_NOT_XOF_OR_INVALID_LENGTH 178 # define EVP_R_NO_CIPHER_SET 131 # define EVP_R_NO_DEFAULT_DIGEST 158 # define EVP_R_NO_DIGEST_SET 139 diff --git a/test/evp_test.c b/test/evp_test.c index 8fd082f30c..3875081c39 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -360,13 +360,18 @@ static int digest_test_run(EVP_TEST *t) { DIGEST_DATA *expected = t->data; EVP_MD_CTX *mctx; - unsigned char got[EVP_MAX_MD_SIZE]; + unsigned char *got = NULL; unsigned int got_len; t->err = "TEST_FAILURE"; if (!TEST_ptr(mctx = EVP_MD_CTX_new())) goto err; + got = OPENSSL_malloc(expected->output_len > EVP_MAX_MD_SIZE ? + expected->output_len : EVP_MAX_MD_SIZE); + if (!TEST_ptr(got)) + goto err; + if (!EVP_DigestInit_ex(mctx, expected->digest, NULL)) { t->err = "DIGESTINIT_ERROR"; goto err; @@ -376,9 +381,17 @@ static int digest_test_run(EVP_TEST *t) goto err; } - if (!EVP_DigestFinal(mctx, got, &got_len)) { - t->err = "DIGESTFINAL_ERROR"; - goto err; + if (EVP_MD_flags(expected->digest) & EVP_MD_FLAG_XOF) { + got_len = expected->output_len; + if (!EVP_DigestFinalXOF(mctx, got, got_len)) { + t->err = "DIGESTFINALXOF_ERROR"; + goto err; + } + } else { + if (!EVP_DigestFinal(mctx, got, &got_len)) { + t->err = "DIGESTFINAL_ERROR"; + goto err; + } } if (!TEST_int_eq(expected->output_len, got_len)) { t->err = "DIGEST_LENGTH_MISMATCH"; @@ -391,6 +404,7 @@ static int digest_test_run(EVP_TEST *t) t->err = NULL; err: + OPENSSL_free(got); EVP_MD_CTX_free(mctx); return 1; } diff --git a/util/libcrypto.num b/util/libcrypto.num index 42284ec9ca..995cbc6672 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4380,3 +4380,4 @@ ASN1_TIME_normalize 4323 1_1_1 EXIST::FUNCTION: ASN1_TIME_cmp_time_t 4324 1_1_1 EXIST::FUNCTION: ASN1_TIME_compare 4325 1_1_1 EXIST::FUNCTION: EVP_PKEY_CTX_ctrl_uint64 4326 1_1_1 EXIST::FUNCTION: +EVP_DigestFinalXOF 4327 1_1_1 EXIST::FUNCTION: -- 2.25.1