From 128035323f48001ed184f7d4f54f9dbffe728481 Mon Sep 17 00:00:00 2001 From: manastasova Date: Wed, 5 Feb 2025 00:09:17 +0000 Subject: [PATCH] Add new SHAKE EVP_ tests Add new checks Test Update after Squeeze and Test Final XOF after Squeeze Digest functions restrict the calls to |update| and |final| after |final| is called via |ctx->digest == NULL| check. Digest |final| functions cleanse the |ctx->md_data|, thus, the check on |ctx->digest| would prevent calling |update| or |final| once |final| has been processed; XOF Squeeze, however, does not finalize the squeeze step, thus, does not cleanse the |ctx->md_digest| (as the final digest functions do) since the XOF Squeeze could be called arbitrary number of times. Therefore, the |update| (SHAKE_Squeeze) and |finalXOF| (SHAKE_Final) return 1 on success and 0 on failure, based on the return value of the underlying SHAKE_ function. Internally, the check is performed via the |ctx->state| flag. The change in the |update| XOF function return value (int, instead of void), all digest |update| functions require a return value. They would always return 1 since a failure would be cought by the higer level EVP_Digest function (i.e., cleansed |ctx| variable --- crypto/digest_extra/digest_extra.c | 5 +- crypto/fipsmodule/digest/digest.c | 11 ++- crypto/fipsmodule/digest/digests.c | 80 +++++++++++----- crypto/fipsmodule/digest/internal.h | 11 ++- crypto/fipsmodule/evp/digestsign.c | 3 +- crypto/fipsmodule/sha/sha3_test.cc | 144 +++++++++++++++------------- include/openssl/digest.h | 2 +- 7 files changed, 155 insertions(+), 101 deletions(-) diff --git a/crypto/digest_extra/digest_extra.c b/crypto/digest_extra/digest_extra.c index e74a00e9f4..40a984c4a2 100644 --- a/crypto/digest_extra/digest_extra.c +++ b/crypto/digest_extra/digest_extra.c @@ -254,8 +254,9 @@ const EVP_MD *EVP_get_digestbyname(const char *name) { static void blake2b256_init(EVP_MD_CTX *ctx) { BLAKE2B256_Init(ctx->md_data); } -static void blake2b256_update(EVP_MD_CTX *ctx, const void *data, size_t len) { +static int blake2b256_update(EVP_MD_CTX *ctx, const void *data, size_t len) { BLAKE2B256_Update(ctx->md_data, data, len); + return 1; } static void blake2b256_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -279,7 +280,7 @@ const EVP_MD *EVP_blake2b256(void) { return &evp_md_blake2b256; } static void null_init(EVP_MD_CTX *ctx) {} -static void null_update(EVP_MD_CTX *ctx, const void *data, size_t count) {} +static int null_update(EVP_MD_CTX *ctx, const void *data, size_t count) { return 1;} static void null_final(EVP_MD_CTX *ctx, unsigned char *md) {} diff --git a/crypto/fipsmodule/digest/digest.c b/crypto/fipsmodule/digest/digest.c index 52dc8ce29d..5f1075c225 100644 --- a/crypto/fipsmodule/digest/digest.c +++ b/crypto/fipsmodule/digest/digest.c @@ -137,6 +137,10 @@ void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { EVP_MD_CTX_free(ctx); } // EVP_DigestFinalXOF is a single-shot XOF output generation function // It can be called once. On sequential calls, it returns 0. +// The |ctx->digest| check prevents calling EVP_DigestFinalXOF consecutively. +// To catch single-shot XOF EVP_DigestFinalXOF calls after |EVP_DigestSqueeze|, +// the return |SHAKE_Final| value is used (the check is internally performed via +// the |KECCAK1600_CTX *ctx| state flag). int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, uint8_t *out, size_t len) { if (ctx->digest == NULL) { return 0; @@ -145,9 +149,9 @@ int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, uint8_t *out, size_t len) { OPENSSL_PUT_ERROR(DIGEST, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } - ctx->digest->finalXOF(ctx, out, len); + int ok = ctx->digest->finalXOF(ctx, out, len); EVP_MD_CTX_cleanse(ctx); - return 1; + return ok; } // EVP_DigestSqueeze is a streaming XOF output generation function @@ -290,8 +294,7 @@ int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { if (ctx->update == NULL) { return 0; } - ctx->update(ctx, data, len); - return 1; + return ctx->update(ctx, data, len);; } int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *size) { diff --git a/crypto/fipsmodule/digest/digests.c b/crypto/fipsmodule/digest/digests.c index e1a9744bf0..69e9f59986 100644 --- a/crypto/fipsmodule/digest/digests.c +++ b/crypto/fipsmodule/digest/digests.c @@ -80,8 +80,9 @@ static void md4_init(EVP_MD_CTX *ctx) { CHECK(MD4_Init(ctx->md_data)); } -static void md4_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int md4_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(MD4_Update(ctx->md_data, data, count)); + return 1; } static void md4_final(EVP_MD_CTX *ctx, uint8_t *out) { @@ -106,8 +107,9 @@ static void md5_init(EVP_MD_CTX *ctx) { CHECK(MD5_Init(ctx->md_data)); } -static void md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(MD5_Update(ctx->md_data, data, count)); + return 1; } static void md5_final(EVP_MD_CTX *ctx, uint8_t *out) { @@ -132,8 +134,9 @@ static void ripemd160_init(EVP_MD_CTX *ctx) { CHECK(RIPEMD160_Init(ctx->md_data)); } -static void ripemd160_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int ripemd160_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(RIPEMD160_Update(ctx->md_data, data, count)); + return 1; } static void ripemd160_final(EVP_MD_CTX *ctx, uint8_t *out) { @@ -158,8 +161,9 @@ static void sha1_init(EVP_MD_CTX *ctx) { CHECK(SHA1_Init(ctx->md_data)); } -static void sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA1_Update(ctx->md_data, data, count)); + return 1; } static void sha1_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -184,8 +188,9 @@ static void sha224_init(EVP_MD_CTX *ctx) { CHECK(SHA224_Init(ctx->md_data)); } -static void sha224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA224_Update(ctx->md_data, data, count)); + return 1; } static void sha224_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -210,8 +215,9 @@ static void sha256_init(EVP_MD_CTX *ctx) { CHECK(SHA256_Init(ctx->md_data)); } -static void sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA256_Update(ctx->md_data, data, count)); + return 1; } static void sha256_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -236,8 +242,9 @@ static void sha384_init(EVP_MD_CTX *ctx) { CHECK(SHA384_Init(ctx->md_data)); } -static void sha384_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha384_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA384_Update(ctx->md_data, data, count)); + return 1; } static void sha384_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -262,8 +269,9 @@ static void sha512_init(EVP_MD_CTX *ctx) { CHECK(SHA512_Init(ctx->md_data)); } -static void sha512_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha512_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA512_Update(ctx->md_data, data, count)); + return 1; } static void sha512_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -288,8 +296,9 @@ static void sha512_224_init(EVP_MD_CTX *ctx) { CHECK(SHA512_224_Init(ctx->md_data)); } -static void sha512_224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha512_224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA512_224_Update(ctx->md_data, data, count)); + return 1; } static void sha512_224_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -312,8 +321,9 @@ static void sha512_256_init(EVP_MD_CTX *ctx) { CHECK(SHA512_256_Init(ctx->md_data)); } -static void sha512_256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha512_256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA512_256_Update(ctx->md_data, data, count)); + return 1; } static void sha512_256_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -338,8 +348,9 @@ static void sha3_224_init(EVP_MD_CTX *ctx) { CHECK(SHA3_Init(ctx->md_data, SHA3_224_DIGEST_BITLENGTH)); } -static void sha3_224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha3_224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA3_Update(ctx->md_data, data, count)); + return 1; } static void sha3_224_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -364,8 +375,9 @@ static void sha3_256_init(EVP_MD_CTX *ctx) { CHECK(SHA3_Init(ctx->md_data, SHA3_256_DIGEST_BITLENGTH)); } -static void sha3_256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha3_256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA3_Update(ctx->md_data, data, count)); + return 1; } static void sha3_256_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -390,8 +402,9 @@ static void sha3_384_init(EVP_MD_CTX *ctx) { CHECK(SHA3_Init(ctx->md_data, SHA3_384_DIGEST_BITLENGTH)); } -static void sha3_384_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha3_384_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA3_Update(ctx->md_data, data, count)); + return 1; } static void sha3_384_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -416,8 +429,9 @@ static void sha3_512_init(EVP_MD_CTX *ctx) { CHECK(SHA3_Init(ctx->md_data, SHA3_512_DIGEST_BITLENGTH)); } -static void sha3_512_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int sha3_512_update(EVP_MD_CTX *ctx, const void *data, size_t count) { CHECK(SHA3_Update(ctx->md_data, data, count)); + return 1; } static void sha3_512_final(EVP_MD_CTX *ctx, uint8_t *md) { @@ -442,12 +456,21 @@ static void shake128_init(EVP_MD_CTX *ctx) { CHECK(SHAKE_Init(ctx->md_data, SHAKE128_BLOCKSIZE)); } -static void shake128_update(EVP_MD_CTX *ctx, const void *data, size_t count) { - CHECK(SHAKE_Absorb(ctx->md_data, data, count)); +// Digest XOF functions return 1 on seccess and 0 on failure, returned +// from |SHAKE_Absorb|, to restrict update calls after |squeezeXOF|. +static int shake128_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + int ok; + CHECK((ok = SHAKE_Absorb(ctx->md_data, data, count))); + return ok; } -static void shake128_final(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { - CHECK(SHAKE_Final(md, ctx->md_data, len)); +// Digest XOF functions return 1 on seccess and 0 on failure, +// returned from |SHAKE_Final|, to restrict Signle-Shot SHAKE_Final +// calls after |squeezeXOF|. +static int shake128_final(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { + int ok; + CHECK((ok = SHAKE_Final(md, ctx->md_data, len))); + return ok; } static void shake128_squeeze(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { @@ -467,17 +490,25 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_shake128) { out->ctx_size = sizeof(KECCAK1600_CTX); } - static void shake256_init(EVP_MD_CTX *ctx) { CHECK(SHAKE_Init(ctx->md_data, SHAKE256_BLOCKSIZE)); } -static void shake256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { - CHECK(SHAKE_Absorb(ctx->md_data, data, count)); +// Digest XOF functions return 1 on seccess and 0 on failure, returned +// from |SHAKE_Absorb|, to restrict update calls after |squeezeXOF|. +static int shake256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + int ok; + CHECK((ok = SHAKE_Absorb(ctx->md_data, data, count))); + return ok; } -static void shake256_final(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { - CHECK(SHAKE_Final(md, ctx->md_data, len)); +// Digest XOF functions return 1 on seccess and 0 on failure, +// returned from |SHAKE_Final|, to restrict Signle-Shot SHAKE_Final +// calls after |squeezeXOF|. +static int shake256_final(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { + int ok; + CHECK((ok = SHAKE_Final(md, ctx->md_data, len))); + return ok; } static void shake256_squeeze(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { @@ -507,11 +538,12 @@ static void md5_sha1_init(EVP_MD_CTX *md_ctx) { CHECK(MD5_Init(&ctx->md5) && SHA1_Init(&ctx->sha1)); } -static void md5_sha1_update(EVP_MD_CTX *md_ctx, const void *data, +static int md5_sha1_update(EVP_MD_CTX *md_ctx, const void *data, size_t count) { MD5_SHA1_CTX *ctx = md_ctx->md_data; CHECK(MD5_Update(&ctx->md5, data, count) && SHA1_Update(&ctx->sha1, data, count)); + return 1; } static void md5_sha1_final(EVP_MD_CTX *md_ctx, uint8_t *out) { diff --git a/crypto/fipsmodule/digest/internal.h b/crypto/fipsmodule/digest/internal.h index 02234a7f0d..a15ff67141 100644 --- a/crypto/fipsmodule/digest/internal.h +++ b/crypto/fipsmodule/digest/internal.h @@ -79,7 +79,11 @@ struct env_md_st { void (*init)(EVP_MD_CTX *ctx); // update hashes |len| bytes of |data| into the state in |ctx->md_data|. - void (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); + // Digest functions always return 1. update calls after |final| are + // via checking the |ctx| (|final| cleanses the |ctx|). + // Digest XOF functions return 1 on seccess and 0 on failure, + // returned from |SHAKE_Absorb|, to restrict update calls after |squeezeXOF|. + int (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); // final completes the hash and writes |md_size| bytes of digest to |out|. void (*final)(EVP_MD_CTX *ctx, uint8_t *out); @@ -91,8 +95,9 @@ struct env_md_st { unsigned ctx_size; // finalXOF completes the hash and writes |len| bytes of digest extended output - // to |out|. - void (*finalXOF)(EVP_MD_CTX *ctx, uint8_t *out, size_t len); + // to |out|. Returns 1 on seccess and 0 on failure, returned from |SHAKE_Final|, + // to restrict Signle-Shot finalXOF calls after |squeezeXOF|. + int (*finalXOF)(EVP_MD_CTX *ctx, uint8_t *out, size_t len); // squeezeXOF incrementally generates |len| bytes of digest extended output // to |out|. diff --git a/crypto/fipsmodule/evp/digestsign.c b/crypto/fipsmodule/evp/digestsign.c index 794e452301..1f6a9782f7 100644 --- a/crypto/fipsmodule/evp/digestsign.c +++ b/crypto/fipsmodule/evp/digestsign.c @@ -94,9 +94,10 @@ static int uses_prehash(EVP_MD_CTX *ctx, enum evp_sign_verify_t op) { : (ctx->pctx->pmeth->verify != NULL); } -static void hmac_update(EVP_MD_CTX *ctx, const void *data, size_t count) { +static int hmac_update(EVP_MD_CTX *ctx, const void *data, size_t count) { HMAC_PKEY_CTX *hctx = ctx->pctx->data; CHECK(HMAC_Update(&hctx->ctx, data, count)); + return 1; } static int HMAC_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *out_sig, diff --git a/crypto/fipsmodule/sha/sha3_test.cc b/crypto/fipsmodule/sha/sha3_test.cc index 3bd4c9beaa..d4f4d8da02 100644 --- a/crypto/fipsmodule/sha/sha3_test.cc +++ b/crypto/fipsmodule/sha/sha3_test.cc @@ -152,10 +152,23 @@ class SHA3TestVector { ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); + // Test Final XOF after Squeeze + // Assert fail when |EVP_DigestFinalXOF| is called after |EVP_DigestSqueeze| + ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); + ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get(), digest_length/2)); + ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get() + digest_length/2, + digest_length/2)); + + // Test Update after Squeeze + // Assert fail when |EVP_DigestUpdate| is called after |EVP_DigestSqueeze| + ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); + ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get(), digest_length)); + ASSERT_FALSE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); + // Test Absorb // Assert success when |EVP_DigestUpdate| is called byte-by-byte OPENSSL_memset(digest.get(), 0, digest_length); - ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); + ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), nullptr, 0)); for (const char p : msg_) { ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), &p, 1)); @@ -196,92 +209,91 @@ class SHA3TestVector { } EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); - } - - // Test Squeeze with random Input - // Assert success when |EVP_DigestSqueeze| is called on a random message - const size_t num_bytes = 256; - const size_t expected_output_size = 256; - - std::unique_ptr digest_stream(new uint8_t[expected_output_size]); - std::unique_ptr digest_signle_shot(new uint8_t[expected_output_size]); - - std::ifstream urandom("/dev/urandom", std::ios::binary); - if (!urandom) { - return; - } - - std::vector random_bytes(num_bytes); - urandom.read(reinterpret_cast(random_bytes.data()), num_bytes); - if (!urandom) { - return; - } + } - ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); - ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); + // Test Squeeze with random Input + // Assert success when |EVP_DigestSqueeze| is called on a random message + const size_t num_bytes = 256; + const size_t expected_output_size = 256; - for (size_t i = 0; i < expected_output_size; i++) { - ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + i, 1)); - } + std::unique_ptr digest_stream(new uint8_t[expected_output_size]); + std::unique_ptr digest_signle_shot(new uint8_t[expected_output_size]); - ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); - ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); - ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), expected_output_size)); - - EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), expected_output_size)), - EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), expected_output_size))); - - // Test Squeeze with random Input - // Assert success when |EVP_DigestSqueeze| is called on a random message - // in set byte increments - for (cur_test = 0, sqd_bytes = 0; cur_test < (int) (sizeof(stride_tests)/sizeof(stride_tests[0])); cur_test++, sqd_bytes = 0) { - to_sq_bytes = stride_tests[cur_test].startsz; - OPENSSL_memset(digest_stream.get(), 0, expected_output_size); - OPENSSL_memset(digest_signle_shot.get(), 0, expected_output_size); + std::ifstream urandom("/dev/urandom", std::ios::binary); + if (!urandom) { + return; + } + std::vector random_bytes(num_bytes); urandom.read(reinterpret_cast(random_bytes.data()), num_bytes); if (!urandom) { return; } - // Incremental Squeezes - ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); - ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); - - while (sqd_bytes < expected_output_size) { - if ((sqd_bytes + to_sq_bytes) > expected_output_size) { - to_sq_bytes = expected_output_size - sqd_bytes; - } - ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + sqd_bytes, to_sq_bytes)); - sqd_bytes += to_sq_bytes; - to_sq_bytes = stride_tests[cur_test].incsz; + ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); + ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); + + for (size_t i = 0; i < expected_output_size; i++) { + ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + i, 1)); } - // Single-Shot Squeeze ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), expected_output_size)); EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), expected_output_size)), - EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), expected_output_size))); - } + EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), expected_output_size))); + + // Test Squeeze with random Input + // Assert success when |EVP_DigestSqueeze| is called on a random message + // in set byte increments + for (cur_test = 0, sqd_bytes = 0; cur_test < (int) (sizeof(stride_tests)/sizeof(stride_tests[0])); cur_test++, sqd_bytes = 0) { + to_sq_bytes = stride_tests[cur_test].startsz; + OPENSSL_memset(digest_stream.get(), 0, expected_output_size); + OPENSSL_memset(digest_signle_shot.get(), 0, expected_output_size); - // Test Final XOF without Update - // Assert fail when |EVP_DigestFinalXOF| is called as a streaming API - OPENSSL_memset(digest_signle_shot.get(), 0, expected_output_size); - OPENSSL_memset(digest_stream.get(), 0, expected_output_size); + urandom.read(reinterpret_cast(random_bytes.data()), num_bytes); + if (!urandom) { + return; + } - ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); - ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), expected_output_size)); + // Incremental Squeezes + ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); + ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); - ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); - ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get(), expected_output_size/2)); - ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + expected_output_size/2, - expected_output_size/2)); + while (sqd_bytes < expected_output_size) { + if ((sqd_bytes + to_sq_bytes) > expected_output_size) { + to_sq_bytes = expected_output_size - sqd_bytes; + } + ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + sqd_bytes, to_sq_bytes)); + sqd_bytes += to_sq_bytes; + to_sq_bytes = stride_tests[cur_test].incsz; + } - EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), expected_output_size)), - EncodeHex(bssl::MakeConstSpan(digest_stream.get(), expected_output_size)); + // Single-Shot Squeeze + ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); + ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes.data(), num_bytes)); + ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), expected_output_size)); + EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), expected_output_size)), + EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), expected_output_size))); + } + + // Test Final XOF without Update + // Assert fail when |EVP_DigestFinalXOF| is called as a streaming API + OPENSSL_memset(digest_signle_shot.get(), 0, expected_output_size); + OPENSSL_memset(digest_stream.get(), 0, expected_output_size); + + ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); + ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), expected_output_size)); + + ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); + ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get(), expected_output_size/2)); + ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + expected_output_size/2, + expected_output_size/2)); + + EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), expected_output_size)), + EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), expected_output_size))); } private: diff --git a/include/openssl/digest.h b/include/openssl/digest.h index aae668f166..5ee9263dd5 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -345,7 +345,7 @@ struct env_md_ctx_st { // |digest->update|. |digest->update| operates against |md_data| above, but // |HMAC_CTX| maintains its own data state in |HMAC_CTX->md_ctx|. // |HMAC_Update| also has an additional state transition to handle. - void (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); + int (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); // pctx is an opaque (at this layer) pointer to additional context that // EVP_PKEY functions may store in this object.