diff --git a/crypto/digest_extra/digest_extra.c b/crypto/digest_extra/digest_extra.c index f6f3e9ca7d..7f2a1b36da 100644 --- a/crypto/digest_extra/digest_extra.c +++ b/crypto/digest_extra/digest_extra.c @@ -86,6 +86,12 @@ static const struct nid_to_digest nid_to_digest_mapping[] = { {NID_sha512, EVP_sha512, SN_sha512, LN_sha512}, {NID_sha512_224, EVP_sha512_224, SN_sha512_224, LN_sha512_224}, {NID_sha512_256, EVP_sha512_256, SN_sha512_256, LN_sha512_256}, + {NID_sha3_224, EVP_sha3_224, SN_sha3_224, LN_sha3_224}, + {NID_sha3_256, EVP_sha3_256, SN_sha3_256, LN_sha3_256}, + {NID_sha3_384, EVP_sha3_384, SN_sha3_384, LN_sha3_384}, + {NID_sha3_512, EVP_sha3_512, SN_sha3_512, LN_sha3_512}, + {NID_shake128, EVP_shake128, SN_shake128, LN_shake128}, + {NID_shake256, EVP_shake256, SN_shake256, LN_shake256}, {NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1}, // As a remnant of signing |EVP_MD|s, OpenSSL returned the corresponding // hash function when given a signature OID. To avoid unintended lax parsing @@ -264,6 +270,7 @@ static const EVP_MD evp_md_blake2b256 = { blake2b256_final, BLAKE2B_CBLOCK, sizeof(BLAKE2B_CTX), + /*finalXOf*/ NULL, }; const EVP_MD *EVP_blake2b256(void) { return &evp_md_blake2b256; } diff --git a/crypto/digest_extra/digest_test.cc b/crypto/digest_extra/digest_test.cc index b13599a9ca..56d980cf5f 100644 --- a/crypto/digest_extra/digest_test.cc +++ b/crypto/digest_extra/digest_test.cc @@ -46,31 +46,37 @@ struct MD { // one_shot_func is the convenience one-shot version of the // digest. uint8_t *(*one_shot_func)(const uint8_t *, size_t, uint8_t *); + // one_shot_xof_func is the convenience one-shot version of the + // digest. + uint8_t *(*one_shot_xof_func)(const uint8_t *, const size_t in_len, uint8_t *, size_t); }; -static const MD md4 = { "MD4", &EVP_md4, nullptr }; -static const MD md5 = { "MD5", &EVP_md5, &MD5 }; -static const MD ripemd160 = { "RIPEMD160", &EVP_ripemd160, &RIPEMD160 }; -static const MD sha1 = { "SHA1", &EVP_sha1, &SHA1 }; -static const MD sha224 = { "SHA224", &EVP_sha224, &SHA224 }; -static const MD sha256 = { "SHA256", &EVP_sha256, &SHA256 }; -static const MD sha384 = { "SHA384", &EVP_sha384, &SHA384 }; -static const MD sha512 = { "SHA512", &EVP_sha512, &SHA512 }; -static const MD sha512_224 = { "SHA512-224", &EVP_sha512_224, &SHA512_224 }; -static const MD sha512_256 = { "SHA512-256", &EVP_sha512_256, &SHA512_256 }; -static const MD sha3_224 = { "SHA3-224", &EVP_sha3_224, &SHA3_224 }; -static const MD sha3_256 = { "SHA3-256", &EVP_sha3_256, &SHA3_256 }; -static const MD sha3_384 = { "SHA3-384", &EVP_sha3_384, &SHA3_384 }; -static const MD sha3_512 = { "SHA3-512", &EVP_sha3_512, &SHA3_512 }; -static const MD md5_sha1 = { "MD5-SHA1", &EVP_md5_sha1, nullptr }; -static const MD blake2b256 = { "BLAKE2b-256", &EVP_blake2b256, nullptr }; +static const MD md4 = { "MD4", &EVP_md4, nullptr, nullptr }; +static const MD md5 = { "MD5", &EVP_md5, &MD5, nullptr }; +static const MD ripemd160 = { "RIPEMD160", &EVP_ripemd160, &RIPEMD160, nullptr }; +static const MD sha1 = { "SHA1", &EVP_sha1, &SHA1, nullptr }; +static const MD sha224 = { "SHA224", &EVP_sha224, &SHA224, nullptr }; +static const MD sha256 = { "SHA256", &EVP_sha256, &SHA256, nullptr }; +static const MD sha384 = { "SHA384", &EVP_sha384, &SHA384, nullptr }; +static const MD sha512 = { "SHA512", &EVP_sha512, &SHA512, nullptr }; +static const MD sha512_224 = { "SHA512-224", &EVP_sha512_224, &SHA512_224, nullptr }; +static const MD sha512_256 = { "SHA512-256", &EVP_sha512_256, &SHA512_256, nullptr }; +static const MD sha3_224 = { "SHA3-224", &EVP_sha3_224, &SHA3_224, nullptr }; +static const MD sha3_256 = { "SHA3-256", &EVP_sha3_256, &SHA3_256, nullptr }; +static const MD sha3_384 = { "SHA3-384", &EVP_sha3_384, &SHA3_384, nullptr }; +static const MD sha3_512 = { "SHA3-512", &EVP_sha3_512, &SHA3_512, nullptr }; +static const MD shake128 = { "shake128", &EVP_shake128, nullptr, &SHAKE128}; +static const MD shake256 = { "shake256", &EVP_shake256, nullptr, &SHAKE256}; +static const MD md5_sha1 = { "MD5-SHA1", &EVP_md5_sha1, nullptr, nullptr }; +static const MD blake2b256 = { "BLAKE2b-256", &EVP_blake2b256, nullptr, nullptr }; struct DigestTestVector { // md is the digest to test. const MD &md; // input is a NUL-terminated string to hash. const char *input; - // repeat is the number of times to repeat input. + // for regular digest, repeat is the number of times to repeat input. for + // XOF, it is the requested output size. size_t repeat; // expected_hex is the expected digest in hexadecimal. const char *expected_hex; @@ -224,7 +230,26 @@ static const DigestTestVector kTestVectors[] = { {sha3_512, "\xec\x83\xd7\x07\xa1\x41\x4a", 1, "84fd3775bac5b87e550d03ec6fe4905cc60e851a4c33a61858d4e7d8a34d471f05008b9a1d63044445df5a9fce958cb012a6ac778ecf45104b0fcb979aa4692d"}, {sha3_512, "\x0c\xe9\xf8\xc3\xa9\x90\xc2\x68\xf3\x4e\xfd\x9b\xef\xdb\x0f\x7c\x4e\xf8\x46\x6c\xfd\xb0\x11\x71\xf8\xde\x70\xdc\x5f\xef\xa9\x2a\xcb\xe9\x3d\x29\xe2\xac\x1a\x5c\x29\x79\x12\x9f\x1a\xb0\x8c\x0e\x77\xde\x79\x24\xdd\xf6\x8a\x20\x9c\xdf\xa0\xad\xc6\x2f\x85\xc1\x86\x37\xd9\xc6\xb3\x3f\x4f\xf8", 1, "b018a20fcf831dde290e4fb18c56342efe138472cbe142da6b77eea4fce52588c04c808eb32912faa345245a850346faec46c3a16d39bd2e1ddb1816bc57d2da"}, - + + // SHAKE128 XOF tests, from NIST. + // http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html + // NOTE: the |repeat| field in this struct denotes output length for XOF digests. + {shake128, "\x84\xe9\x50\x05\x18\x76\x05\x0d\xc8\x51\xfb\xd9\x9e\x62\x47\xb8", 16, "8599bd89f63a848c49ca593ec37a12c6"}, + {shake128, "\xf1\x67\x51\x1e\xc8\x86\x49\x79\x30\x22\x37\xab\xea\x4c\xf7\xef", 17, "20f8938daa54b260860a104f8556278bac"}, + {shake128, "\x96\xdb\xe1\x83\xec\x72\x90\x57\x0b\x82\x54\x6a\xf7\x92\xeb\x90", 18, "762b421dc6374055a061caeddcf50f5dfbb6"}, + {shake128, "\x9b\xd2\xbd\x3a\x38\x4b\x9e\xf1\x41\xea\xd2\x63\x04\x96\x35\x49", 36, "3cdecb09f1673d8c823da2e02a2eeb28f32095e7c0ce8ab391811c626c472511a433845b"}, + {shake128, "\x5b\x2f\x2f\x2a\xf8\x3e\x86\xd4\x2c\x4e\x98\x15\x3f\xce\x27\x79", 37, "b6e0361dbce6d4a809a2e982f1dcffa4a49781c989402bf9c603cdacbc15484261a47b050d"}, + + + // SHAKE256 XOF tests, from NIST. + // http://csrc.nist.gov/groups/STM/cavp/secure-hashing.html + // NOTE: the |repeat| field in this struct denotes output length for XOF digests. + {shake256, "\xdc\x88\x6d\xf3\xf6\x9c\x49\x51\x3d\xe3\x62\x7e\x94\x81\xdb\x58\x71\xe8\xee\x88\xeb\x9f\x99\x61\x15\x41\x93\x0a\x8b\xc8\x85\xe0", 16, "00648afbc5e651649db1fd82936b00db"}, + {shake256, "\x8d\x80\x01\xe2\xc0\x96\xf1\xb8\x8e\x7c\x92\x24\xa0\x86\xef\xd4\x79\x7f\xbf\x74\xa8\x03\x3a\x2d\x42\x2a\x2b\x6b\x8f\x67\x47\xe4", 17, "2e975f6a8a14f0704d51b13667d8195c21"}, + {shake256, "\xe3\xef\x12\x7e\xad\xfa\xfa\xf4\x04\x08\xce\xbb\x28\x70\x5d\xf3\x0b\x68\xd9\x9d\xfa\x18\x93\x50\x7e\xf3\x06\x2d\x85\x46\x17\x15", 18, "7314002948c057006d4fc21e3e19c258fb5b"}, + {shake256, "\xdc\x88\x6d\xf3\xf6\x9c\x49\x51\x3d\xe3\x62\x7e\x94\x81\xdb\x58\x71\xe8\xee\x88\xeb\x9f\x99\x61\x15\x41\x93\x0a\x8b\xc8\x85\xe0", 36, "00648afbc5e651649db1fd82936b00dbbc122fb4c877860d385c4950d56de7e096d613d7"}, + {shake256, "\x79\x35\xb6\x8b\xb3\x34\xf3\x5d\xdc\x15\x7a\x8c\x47\x33\x49\xeb\x03\xad\x0e\x41\x53\x0d\x3c\x04\x5e\x2c\x5f\x64\x28\x50\xad\x8c", 37, "b44d25998e5cf77a83a4c0b2aae3061785adc7507d76fe07f4dcf299e04c991c922b51570f"}, + // MD5-SHA1 tests. {md5_sha1, "abc", 1, "900150983cd24fb0d6963f7d28e17f72a9993e364706816aba3e25717850c26c9cd0d89d"}, @@ -241,29 +266,44 @@ static void CompareDigest(const DigestTestVector *test, EncodeHex(bssl::MakeConstSpan(digest, digest_len))); } +static bool DoFinal(const DigestTestVector *test, EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *out_size) { + if (ctx->digest && (EVP_MD_flags(ctx->digest) & EVP_MD_FLAG_XOF)) { + // For XOF digests, DigestTestVector.repeat is the desired output length + *out_size = test->repeat; + return EVP_DigestFinalXOF(ctx, md_out, *out_size); + } + return EVP_DigestFinal(ctx, md_out, out_size); +} + static void TestDigest(const DigestTestVector *test) { SCOPED_TRACE(test->md.name); + const bool is_xof = EVP_MD_flags(test->md.func()) & EVP_MD_FLAG_XOF; + const size_t repeat = is_xof ? 1 : test->repeat; + const size_t expected_output_size = is_xof + ? test->repeat + : EVP_MD_size(test->md.func()); + bssl::ScopedEVP_MD_CTX ctx; // Test the input provided. ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr)); - for (size_t i = 0; i < test->repeat; i++) { + for (size_t i = 0; i < repeat; i++) { ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), test->input, strlen(test->input))); } - std::unique_ptr digest(new uint8_t[EVP_MD_size(test->md.func())]); + std::unique_ptr digest(new uint8_t[expected_output_size]); unsigned digest_len; - ASSERT_TRUE(EVP_DigestFinal_ex(ctx.get(), digest.get(), &digest_len)); + ASSERT_TRUE(DoFinal(test, ctx.get(), digest.get(), &digest_len)); CompareDigest(test, digest.get(), digest_len); // Test the input one character at a time. ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), nullptr, 0)); - for (size_t i = 0; i < test->repeat; i++) { + for (size_t i = 0; i < repeat; i++) { for (const char *p = test->input; *p; p++) { ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), p, 1)); } } - ASSERT_TRUE(EVP_DigestFinal_ex(ctx.get(), digest.get(), &digest_len)); - EXPECT_EQ(EVP_MD_size(test->md.func()), digest_len); + ASSERT_TRUE(DoFinal(test, ctx.get(), digest.get(), &digest_len)); + EXPECT_EQ(expected_output_size, digest_len); CompareDigest(test, digest.get(), digest_len); // Test with unaligned input. @@ -274,20 +314,20 @@ static void TestDigest(const DigestTestVector *test) { ptr++; } OPENSSL_memcpy(ptr, test->input, strlen(test->input)); - for (size_t i = 0; i < test->repeat; i++) { + for (size_t i = 0; i < repeat; i++) { ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), ptr, strlen(test->input))); } - ASSERT_TRUE(EVP_DigestFinal_ex(ctx.get(), digest.get(), &digest_len)); + ASSERT_TRUE(DoFinal(test, ctx.get(), digest.get(), &digest_len)); CompareDigest(test, digest.get(), digest_len); // Make a copy of the digest in the initial state. ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr)); bssl::ScopedEVP_MD_CTX copy; ASSERT_TRUE(EVP_MD_CTX_copy_ex(copy.get(), ctx.get())); - for (size_t i = 0; i < test->repeat; i++) { + for (size_t i = 0; i < repeat; i++) { ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input))); } - ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len)); + ASSERT_TRUE(DoFinal(test, copy.get(), digest.get(), &digest_len)); CompareDigest(test, digest.get(), digest_len); // Make a copy of the digest with half the input provided. @@ -296,19 +336,19 @@ static void TestDigest(const DigestTestVector *test) { ASSERT_TRUE(EVP_MD_CTX_copy_ex(copy.get(), ctx.get())); ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input + half, strlen(test->input) - half)); - for (size_t i = 1; i < test->repeat; i++) { + for (size_t i = 1; i < repeat; i++) { ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input))); } - ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len)); + ASSERT_TRUE(DoFinal(test, copy.get(), digest.get(), &digest_len)); CompareDigest(test, digest.get(), digest_len); // Move the digest from the initial state. ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test->md.func(), nullptr)); copy = std::move(ctx); - for (size_t i = 0; i < test->repeat; i++) { + for (size_t i = 0; i < repeat; i++) { ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input))); } - ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len)); + ASSERT_TRUE(DoFinal(test, copy.get(), digest.get(), &digest_len)); CompareDigest(test, digest.get(), digest_len); // Move the digest with half the input provided. @@ -317,20 +357,25 @@ static void TestDigest(const DigestTestVector *test) { copy = std::move(ctx); ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input + half, strlen(test->input) - half)); - for (size_t i = 1; i < test->repeat; i++) { + for (size_t i = 1; i < repeat; i++) { ASSERT_TRUE(EVP_DigestUpdate(copy.get(), test->input, strlen(test->input))); } - ASSERT_TRUE(EVP_DigestFinal_ex(copy.get(), digest.get(), &digest_len)); + ASSERT_TRUE(DoFinal(test, copy.get(), digest.get(), &digest_len)); CompareDigest(test, digest.get(), digest_len); + // Digest context should be cleared by finalization + EXPECT_FALSE(DoFinal(test, copy.get(), digest.get(), &digest_len)); + // Test the one-shot function. - if (test->md.one_shot_func && test->repeat == 1) { - uint8_t *out = test->md.one_shot_func((const uint8_t *)test->input, - strlen(test->input), digest.get()); - // One-shot functions return their supplied buffers. - EXPECT_EQ(digest.get(), out); - CompareDigest(test, digest.get(), EVP_MD_size(test->md.func())); - } + if (is_xof || (test->md.one_shot_func && test->repeat == 1)) { + uint8_t *out = is_xof + ? test->md.one_shot_xof_func((const uint8_t *)test->input, strlen(test->input), + digest.get(), expected_output_size) + : test->md.one_shot_func((const uint8_t *)test->input, strlen(test->input), digest.get()); + // One-shot functions return their supplied buffers. + EXPECT_EQ(digest.get(), out); + CompareDigest(test, digest.get(), expected_output_size); + } } TEST(DigestTest, TestVectors) { @@ -358,6 +403,17 @@ TEST(DigestTest, Getters) { EXPECT_EQ(EVP_sha1(), EVP_get_digestbyobj(OBJ_nid2obj(NID_sha1))); } +TEST(DigestTest, TestXOF) { + // Assert that passing null outsize pointer for EVP XOF results in error. + // Use same buffer for input/output; contents don't matter. + const size_t out_size = 16; + std::unique_ptr digest(new uint8_t[out_size]); + EXPECT_FALSE(EVP_Digest(digest.get(), out_size, digest.get(), + /*out_len*/nullptr, EVP_shake128(), /*engine*/nullptr)); + EXPECT_EQ(ERR_R_PASSED_NULL_PARAMETER, ERR_GET_REASON(ERR_peek_last_error())); + ERR_clear_error(); +} + TEST(DigestTest, ASN1) { bssl::ScopedCBB cbb; ASSERT_TRUE(CBB_init(cbb.get(), 0)); diff --git a/crypto/evp_extra/evp_test.cc b/crypto/evp_extra/evp_test.cc index 880278f836..c1dc70501f 100644 --- a/crypto/evp_extra/evp_test.cc +++ b/crypto/evp_extra/evp_test.cc @@ -115,6 +115,10 @@ static const EVP_MD *GetDigest(FileTest *t, const std::string &name) { return EVP_sha3_384(); } else if (name == "SHA3-512") { return EVP_sha3_512(); + } else if (name == "SHAKE128") { + return EVP_shake128(); + } else if (name == "SHAKE256") { + return EVP_shake256(); } ADD_FAILURE() << "Unknown digest: " << name; return nullptr; diff --git a/crypto/fipsmodule/digest/digest.c b/crypto/fipsmodule/digest/digest.c index 4799f2f304..433ec00f25 100644 --- a/crypto/fipsmodule/digest/digest.c +++ b/crypto/fipsmodule/digest/digest.c @@ -131,8 +131,16 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx) { void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { EVP_MD_CTX_free(ctx); } 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; + if (ctx->digest == NULL) { + return 0; + } + if ((EVP_MD_flags(ctx->digest) & EVP_MD_FLAG_XOF) == 0) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + ctx->digest->finalXOF(ctx, out, len); + EVP_MD_CTX_cleanse(ctx); + return 1; } uint32_t EVP_MD_meth_get_flags(const EVP_MD *md) { return EVP_MD_flags(md); } @@ -245,6 +253,10 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *size) { if (ctx->digest == NULL) { return 0; } + if (EVP_MD_flags(ctx->digest) & EVP_MD_FLAG_XOF) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE); ctx->digest->final(ctx, md_out); @@ -256,7 +268,6 @@ int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *size) { } int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md, unsigned int *size) { - int ok = EVP_DigestFinal_ex(ctx, md, size); EVP_MD_CTX_cleanup(ctx); return ok; @@ -267,11 +278,23 @@ int EVP_Digest(const void *data, size_t count, uint8_t *out_md, EVP_MD_CTX ctx; int ret; + if ((EVP_MD_flags(type) & EVP_MD_FLAG_XOF) && out_size == NULL) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + EVP_MD_CTX_init(&ctx); ret = EVP_DigestInit_ex(&ctx, type, impl) && - EVP_DigestUpdate(&ctx, data, count) && - EVP_DigestFinal_ex(&ctx, out_md, out_size); - EVP_MD_CTX_cleanup(&ctx); + EVP_DigestUpdate(&ctx, data, count); + if (ret == 0) { + return 0; + } + + if (EVP_MD_flags(type) & EVP_MD_FLAG_XOF) { + ret &= EVP_DigestFinalXOF(&ctx, out_md, *out_size); + } else { + ret &= EVP_DigestFinal(&ctx, out_md, out_size); + } return ret; } diff --git a/crypto/fipsmodule/digest/digests.c b/crypto/fipsmodule/digest/digests.c index 95e71a22e6..648278c6d0 100644 --- a/crypto/fipsmodule/digest/digests.c +++ b/crypto/fipsmodule/digest/digests.c @@ -95,6 +95,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_md4) { out->init = md4_init; out->update = md4_update; out->final = md4_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(MD4_CTX); } @@ -119,6 +120,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_md5) { out->init = md5_init; out->update = md5_update; out->final = md5_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(MD5_CTX); } @@ -143,6 +145,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_ripemd160) { out->init = ripemd160_init; out->update = ripemd160_update; out->final = ripemd160_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(RIPEMD160_CTX); } @@ -167,6 +170,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha1) { out->init = sha1_init; out->update = sha1_update; out->final = sha1_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(SHA_CTX); } @@ -191,6 +195,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha224) { out->init = sha224_init; out->update = sha224_update; out->final = sha224_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(SHA256_CTX); } @@ -215,6 +220,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha256) { out->init = sha256_init; out->update = sha256_update; out->final = sha256_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(SHA256_CTX); } @@ -239,6 +245,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha384) { out->init = sha384_init; out->update = sha384_update; out->final = sha384_final; + out->finalXOF = NULL; out->block_size = 128; out->ctx_size = sizeof(SHA512_CTX); } @@ -263,6 +270,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha512) { out->init = sha512_init; out->update = sha512_update; out->final = sha512_final; + out->finalXOF = NULL; out->block_size = 128; out->ctx_size = sizeof(SHA512_CTX); } @@ -311,6 +319,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha512_256) { out->init = sha512_256_init; out->update = sha512_256_update; out->final = sha512_256_final; + out->finalXOF = NULL; out->block_size = 128; out->ctx_size = sizeof(SHA512_CTX); } @@ -335,6 +344,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha3_224) { out->init = sha3_224_init; out->update = sha3_224_update; out->final = sha3_224_final; + out->finalXOF = NULL; out->block_size = SHA3_BLOCKSIZE(SHA3_224_DIGEST_BITLENGTH); out->ctx_size = sizeof(KECCAK1600_CTX); } @@ -359,6 +369,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha3_256) { out->init = sha3_256_init; out->update = sha3_256_update; out->final = sha3_256_final; + out->finalXOF = NULL; out->block_size = SHA3_BLOCKSIZE(SHA3_256_DIGEST_BITLENGTH); out->ctx_size = sizeof(KECCAK1600_CTX); } @@ -383,6 +394,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha3_384) { out->init = sha3_384_init; out->update = sha3_384_update; out->final = sha3_384_final; + out->finalXOF = NULL; out->block_size = SHA3_BLOCKSIZE(SHA3_384_DIGEST_BITLENGTH); out->ctx_size = sizeof(KECCAK1600_CTX); } @@ -407,10 +419,62 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_sha3_512) { out->init = sha3_512_init; out->update = sha3_512_update; out->final = sha3_512_final; + out->finalXOF = NULL; out->block_size = SHA3_BLOCKSIZE(SHA3_512_DIGEST_BITLENGTH); out->ctx_size = sizeof(KECCAK1600_CTX); } + +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(SHA3_Update(ctx->md_data, data, count)); +} + +static void shake128_final(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { + CHECK(SHAKE_Final(md, ctx->md_data, len)); +} + +DEFINE_METHOD_FUNCTION(EVP_MD, EVP_shake128) { + out->type = NID_shake128; + out->md_size = 0; + out->flags = EVP_MD_FLAG_XOF; + out->init = shake128_init; + out->update = shake128_update; + out->final = NULL; + out->finalXOF = shake128_final; + out->block_size = SHAKE128_BLOCKSIZE; + 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(SHA3_Update(ctx->md_data, data, count)); +} + +static void shake256_finalXOF(EVP_MD_CTX *ctx, uint8_t *md, size_t len) { + CHECK(SHAKE_Final(md, ctx->md_data, len)); +} + +DEFINE_METHOD_FUNCTION(EVP_MD, EVP_shake256) { + out->type = NID_shake256; + out->md_size = 0; + out->flags = EVP_MD_FLAG_XOF; + out->init = shake256_init; + out->update = shake256_update; + out->final = NULL; + out->finalXOF = shake256_finalXOF; + out->block_size = SHAKE256_BLOCKSIZE; + out->ctx_size = sizeof(KECCAK1600_CTX); +} + + typedef struct { MD5_CTX md5; SHA_CTX sha1; @@ -441,6 +505,7 @@ DEFINE_METHOD_FUNCTION(EVP_MD, EVP_md5_sha1) { out->init = md5_sha1_init; out->update = md5_sha1_update; out->final = md5_sha1_final; + out->finalXOF = NULL; out->block_size = 64; out->ctx_size = sizeof(MD5_SHA1_CTX); } diff --git a/crypto/fipsmodule/digest/internal.h b/crypto/fipsmodule/digest/internal.h index ac3c77d1d4..7b93754f5a 100644 --- a/crypto/fipsmodule/digest/internal.h +++ b/crypto/fipsmodule/digest/internal.h @@ -90,6 +90,10 @@ struct env_md_st { // ctx_size contains the size, in bytes, of the state of the hash function. 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); }; // evp_md_pctx_ops contains function pointers to allow the |pctx| member of diff --git a/crypto/fipsmodule/service_indicator/service_indicator_test.cc b/crypto/fipsmodule/service_indicator/service_indicator_test.cc index be9e11eaa0..3642d5c69d 100644 --- a/crypto/fipsmodule/service_indicator/service_indicator_test.cc +++ b/crypto/fipsmodule/service_indicator/service_indicator_test.cc @@ -31,6 +31,7 @@ #include "../../test/test_util.h" #include "../bn/internal.h" #include "../rand/internal.h" +#include "../sha/internal.h" static const uint8_t kAESKey[16] = { 'A','W','S','-','L','C','C','r','y','p','t','o',' ','K', 'e','y'}; @@ -371,6 +372,50 @@ static const uint8_t kOutput_sha512_256[SHA512_256_DIGEST_LENGTH] = { 0x2d, 0xfb, 0x72, 0x35, 0xfa, 0xc1, 0xc4, 0x5f, 0x5c, 0x49, 0x91, 0x08, 0x95, 0x0b, 0x0f, 0xc9, 0x88, 0x44, 0x12, 0x01, 0x6a}; +static const uint8_t kOutput_sha3_224[SHA3_224_DIGEST_LENGTH] = { + 0xd4, 0x7e, 0x2d, 0xca, 0xf9, 0x36, 0x7a, 0x73, 0x2f, 0x9b, 0x42, 0x46, + 0x25, 0x49, 0x29, 0x68, 0xfa, 0x2c, 0xc7, 0xd0, 0xb0, 0x11, 0x1c, 0x86, + 0xa6, 0xc0, 0xa1, 0x29}; + +static const uint8_t kOutput_sha3_256[SHA3_256_DIGEST_LENGTH] = { + 0x4a, 0x95, 0x1c, 0x1e, 0xd1, 0x58, 0x5f, 0xa3, 0xcf, 0x77, 0x24, 0x73, + 0x7b, 0xd2, 0x28, 0x55, 0x9f, 0xa5, 0xe8, 0xc6, 0x58, 0x99, 0xe3, 0xb1, + 0x88, 0x17, 0xd6, 0xc4, 0x1d, 0x3e, 0xa8, 0x4c}; + +static const uint8_t kOutput_sha3_384[SHA3_384_DIGEST_LENGTH] = { + 0x19, 0x97, 0xad, 0xa6, 0x45, 0x40, 0x3d, 0x10, 0xda, 0xe6, 0xd4, 0xfd, + 0xe1, 0xd3, 0x2b, 0x1b, 0xd6, 0xdb, 0x0c, 0xdb, 0xca, 0x6f, 0xae, 0x58, + 0xbf, 0x75, 0x9a, 0xf6, 0x97, 0xc6, 0xb4, 0xb4, 0xbf, 0xef, 0x3c, 0x2d, + 0xb1, 0xb3, 0x4a, 0x1d, 0xd9, 0x69, 0x58, 0x25, 0x5b, 0xd0, 0xb6, 0xad}; + +static const uint8_t kOutput_sha3_512[SHA3_512_DIGEST_LENGTH] = { + 0x36, 0xe5, 0xa2, 0x70, 0xa4, 0xd1, 0xc3, 0x76, 0xc6, 0x44, 0xe6, 0x00, + 0x49, 0xae, 0x7d, 0x83, 0x21, 0xdc, 0xab, 0x2e, 0xa2, 0xe3, 0x96, 0xc2, + 0xeb, 0xe6, 0x61, 0x14, 0x95, 0xd6, 0x6a, 0xf2, 0xf0, 0xa0, 0x4e, 0x93, + 0x14, 0x2f, 0x02, 0x6a, 0xdb, 0xae, 0xbd, 0x76, 0x4e, 0xb9, 0x52, 0x88, + 0x85, 0x3c, 0x64, 0xa1, 0x56, 0x6f, 0xeb, 0x76, 0x25, 0x9a, 0x4a, 0x44, + 0x23, 0xf7, 0xcf, 0x46}; + +// NOTE: SHAKE is a variable-length XOF; this number is chosen somewhat +// arbitrarily for testing. +static const size_t SHAKE_OUTPUT_LENGTH = 64; + +static const uint8_t kOutput_shake128[SHAKE_OUTPUT_LENGTH] = { + 0x22, 0xfe, 0x51, 0xb7, 0x9c, 0x28, 0x1c, 0x0e, 0xfc, 0x66, 0x58, 0x6a, + 0xa1, 0x60, 0x85, 0x0b, 0xe6, 0xeb, 0x20, 0x0b, 0xdb, 0x0c, 0xe7, 0xfe, + 0x49, 0x51, 0xcd, 0xc2, 0x92, 0x3f, 0xfc, 0xf8, 0xcb, 0x4b, 0x19, 0xce, + 0x80, 0x9f, 0x1f, 0xbf, 0x10, 0xf1, 0x74, 0x38, 0x7a, 0x19, 0xd0, 0xca, + 0x52, 0xf2, 0xf3, 0xd0, 0x77, 0x08, 0xe2, 0x1e, 0x20, 0x2d, 0x57, 0x25, + 0x8b, 0xd5, 0xca, 0x66}; + +static const uint8_t kOutput_shake256[SHAKE_OUTPUT_LENGTH] = { + 0xfc, 0xd1, 0x32, 0xd0, 0x02, 0x43, 0x7c, 0x31, 0xb2, 0x78, 0xdf, 0x34, + 0x74, 0xc8, 0x9b, 0x77, 0x08, 0x14, 0x9d, 0xde, 0x69, 0x79, 0xb5, 0x58, + 0x98, 0x01, 0x69, 0xaa, 0x64, 0x11, 0x04, 0xbe, 0xa2, 0x5f, 0xf1, 0x29, + 0x9b, 0x94, 0x03, 0x4a, 0x1e, 0x82, 0xf0, 0x9e, 0xee, 0x9b, 0xa0, 0xe3, + 0xe1, 0x5f, 0x9c, 0x13, 0xb7, 0x52, 0xef, 0x3c, 0x96, 0xf3, 0xf8, 0xf3, + 0x1f, 0x59, 0x7e, 0x41}; + static const uint8_t kHMACOutput_sha1[SHA_DIGEST_LENGTH] = { 0x34, 0xac, 0x50, 0x9b, 0xa9, 0x4c, 0x39, 0xef, 0x45, 0xa0, 0x6b, 0xdc, 0xfc, 0xbd, 0x3d, 0x42, 0xe8, 0x0a, 0x97, 0x86}; @@ -1082,6 +1127,38 @@ static const struct DigestTestVector { kOutput_sha512_256, AWSLC_APPROVED, }, + { + "SHA3-224", + SHA3_224_DIGEST_LENGTH, + &EVP_sha3_224, + &SHA3_224, + kOutput_sha3_224, + AWSLC_APPROVED, + }, + { + "SHA3-256", + SHA3_256_DIGEST_LENGTH, + &EVP_sha3_256, + &SHA3_256, + kOutput_sha3_256, + AWSLC_APPROVED, + }, + { + "SHA3-384", + SHA3_384_DIGEST_LENGTH, + &EVP_sha3_384, + &SHA3_384, + kOutput_sha3_384, + AWSLC_APPROVED, + }, + { + "SHA3-512", + SHA3_512_DIGEST_LENGTH, + &EVP_sha3_512, + &SHA3_512, + kOutput_sha3_512, + AWSLC_APPROVED, + }, }; class EVPMDServiceIndicatorTest : public TestWithNoErrors {}; @@ -1128,6 +1205,75 @@ TEST_P(EVPMDServiceIndicatorTest, EVP_Digests) { EXPECT_EQ(Bytes(test.expected_digest, test.length), Bytes(digest)); } +static const struct XofTestVector { + // name is the name of the digest test. + const char *name; + // output length to specify in XOF finalization + const int length; + // func is the digest to test. + const EVP_MD *(*func)(); + // one_shot_func is the convenience one-shot version of the digest. + uint8_t *(*one_shot_func)(const uint8_t *, size_t, uint8_t *, size_t); + // expected_digest is the expected digest. + const uint8_t *expected_digest; + // expected to be approved or not. + const FIPSStatus expect_approved; +} kXofTestVectors[] = { + { + "SHAKE128", + SHAKE_OUTPUT_LENGTH, + &EVP_shake128, + &SHAKE128, + kOutput_shake128, + AWSLC_APPROVED, + }, + { + "SHAKE256", + SHAKE_OUTPUT_LENGTH, + &EVP_shake256, + &SHAKE256, + kOutput_shake256, + AWSLC_APPROVED, + }, +}; + +class EVPXOFServiceIndicatorTest : public TestWithNoErrors {}; + +INSTANTIATE_TEST_SUITE_P(All, EVPXOFServiceIndicatorTest, + testing::ValuesIn(kXofTestVectors)); + +TEST_P(EVPXOFServiceIndicatorTest, EVP_Xofs) { + const XofTestVector &test = GetParam(); + SCOPED_TRACE(test.name); + + FIPSStatus approved = AWSLC_NOT_APPROVED; + bssl::ScopedEVP_MD_CTX ctx; + std::vector digest(test.length); + + // Test running the EVP_Digest interfaces one by one directly, and check + // |EVP_DigestFinalXOF| for approval at the end. |EVP_DigestInit_ex| and + // |EVP_DigestUpdate| should not be approved, because the functions do not + // indicate that a service has been fully completed yet. + CALL_SERVICE_AND_CHECK_APPROVED(approved, + ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), test.func(), nullptr))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + CALL_SERVICE_AND_CHECK_APPROVED(approved, + ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), kPlaintext, sizeof(kPlaintext)))); + EXPECT_EQ(approved, AWSLC_NOT_APPROVED); + EXPECT_TRUE(EVP_MD_flags(ctx->digest) & EVP_MD_FLAG_XOF); + CALL_SERVICE_AND_CHECK_APPROVED(approved, + ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest.data(), test.length))); + EXPECT_EQ(approved, test.expect_approved); + EXPECT_EQ(Bytes(test.expected_digest, test.length), Bytes(digest)); + + // Test using the one-shot API for approval. + CALL_SERVICE_AND_CHECK_APPROVED( + approved, + test.one_shot_func(kPlaintext, sizeof(kPlaintext), digest.data(), test.length)); + EXPECT_EQ(approved, test.expect_approved); + EXPECT_EQ(Bytes(test.expected_digest, test.length), Bytes(digest)); +} + static const struct HMACTestVector { // func is the hash function for HMAC to test. const EVP_MD *(*func)(void); diff --git a/crypto/fipsmodule/sha/internal.h b/crypto/fipsmodule/sha/internal.h index 014143d14b..caeac4a976 100644 --- a/crypto/fipsmodule/sha/internal.h +++ b/crypto/fipsmodule/sha/internal.h @@ -126,6 +126,14 @@ OPENSSL_EXPORT uint8_t *SHAKE128(const uint8_t *data, const size_t in_len, OPENSSL_EXPORT uint8_t *SHAKE256(const uint8_t *data, const size_t in_len, uint8_t *out, size_t out_len); +// SHAKE_Init initializes |ctx| with specified |block_size|, returns 1 on +// success and 0 on failure. Calls SHA3_Init under the hood. +OPENSSL_EXPORT int SHAKE_Init(KECCAK1600_CTX *ctx, size_t block_size); + +// SHAKE_Final writes |len| bytes of finalized digest to |md|, returns 1 on +// success and 0 on failure. Calls SHA3_Final under the hood. +OPENSSL_EXPORT int SHAKE_Final(uint8_t *md, KECCAK1600_CTX *ctx, size_t len); + // SHA3_Reset zeros the bitstate and the amount of processed input. OPENSSL_EXPORT void SHA3_Reset(KECCAK1600_CTX *ctx); diff --git a/crypto/fipsmodule/sha/sha3.c b/crypto/fipsmodule/sha/sha3.c index 7bab5ebd3b..bd2076a415 100644 --- a/crypto/fipsmodule/sha/sha3.c +++ b/crypto/fipsmodule/sha/sha3.c @@ -13,96 +13,116 @@ uint8_t *SHA3_224(const uint8_t *data, size_t len, uint8_t out[SHA3_224_DIGEST_LENGTH]) { + FIPS_service_indicator_lock_state(); KECCAK1600_CTX ctx; int ok = (SHA3_Init(&ctx, SHA3_PAD_CHAR, SHA3_224_DIGEST_BITLENGTH) && SHA3_Update(&ctx, data, len) && SHA3_Final(out, &ctx)); OPENSSL_cleanse(&ctx, sizeof(ctx)); + FIPS_service_indicator_unlock_state(); if (ok == 0) { return NULL; } + FIPS_service_indicator_update_state(); return out; } uint8_t *SHA3_256(const uint8_t *data, size_t len, uint8_t out[SHA3_256_DIGEST_LENGTH]) { + FIPS_service_indicator_lock_state(); KECCAK1600_CTX ctx; int ok = (SHA3_Init(&ctx, SHA3_PAD_CHAR, SHA3_256_DIGEST_BITLENGTH) && SHA3_Update(&ctx, data, len) && SHA3_Final(out, &ctx)); OPENSSL_cleanse(&ctx, sizeof(ctx)); + FIPS_service_indicator_unlock_state(); if (ok == 0) { return NULL; } + FIPS_service_indicator_update_state(); return out; } uint8_t *SHA3_384(const uint8_t *data, size_t len, uint8_t out[SHA3_384_DIGEST_LENGTH]) { + FIPS_service_indicator_lock_state(); KECCAK1600_CTX ctx; int ok = (SHA3_Init(&ctx, SHA3_PAD_CHAR, SHA3_384_DIGEST_BITLENGTH) && SHA3_Update(&ctx, data, len) && SHA3_Final(out, &ctx)); OPENSSL_cleanse(&ctx, sizeof(ctx)); + FIPS_service_indicator_unlock_state(); if (ok == 0) { return NULL; } + FIPS_service_indicator_update_state(); return out; } uint8_t *SHA3_512(const uint8_t *data, size_t len, uint8_t out[SHA3_512_DIGEST_LENGTH]) { + FIPS_service_indicator_lock_state(); KECCAK1600_CTX ctx; int ok = (SHA3_Init(&ctx, SHA3_PAD_CHAR, SHA3_512_DIGEST_BITLENGTH) && SHA3_Update(&ctx, data, len) && SHA3_Final(out, &ctx)); OPENSSL_cleanse(&ctx, sizeof(ctx)); + FIPS_service_indicator_unlock_state(); if (ok == 0) { return NULL; } + FIPS_service_indicator_update_state(); return out; } uint8_t *SHAKE128(const uint8_t *data, const size_t in_len, uint8_t *out, size_t out_len) { + FIPS_service_indicator_lock_state(); KECCAK1600_CTX ctx; - - // The SHAKE block size depends on the security level of the algorithm only - // It is independent of the output size - ctx.block_size = SHAKE128_BLOCKSIZE; - - int ok = (SHA3_Init(&ctx, SHAKE_PAD_CHAR, out_len) && + int ok = (SHAKE_Init(&ctx, SHAKE128_BLOCKSIZE) && SHA3_Update(&ctx, data, in_len) && - SHA3_Final(out, &ctx)); + SHAKE_Final(out, &ctx, out_len)); OPENSSL_cleanse(&ctx, sizeof(ctx)); + FIPS_service_indicator_unlock_state(); if (ok == 0) { return NULL; } + FIPS_service_indicator_update_state(); return out; } uint8_t *SHAKE256(const uint8_t *data, const size_t in_len, uint8_t *out, size_t out_len) { + FIPS_service_indicator_lock_state(); KECCAK1600_CTX ctx; - - // The SHAKE block size depends on the security level of the algorithm only - // It is independent of the output size - ctx.block_size = SHAKE256_BLOCKSIZE; - - int ok = (SHA3_Init(&ctx, SHAKE_PAD_CHAR, out_len) && + int ok = (SHAKE_Init(&ctx, SHAKE256_BLOCKSIZE) && SHA3_Update(&ctx, data, in_len) && - SHA3_Final(out, &ctx)); - + SHAKE_Final(out, &ctx, out_len)); OPENSSL_cleanse(&ctx, sizeof(ctx)); + FIPS_service_indicator_unlock_state(); if (ok == 0) { return NULL; } + FIPS_service_indicator_update_state(); return out; } +int SHAKE_Init(KECCAK1600_CTX *ctx, size_t block_size) { + // The SHAKE block size depends on the security level of the algorithm only + // It is independent of the output size + ctx->block_size = block_size; + return SHA3_Init(ctx, SHAKE_PAD_CHAR, 0); +} + + +int SHAKE_Final(uint8_t *md, KECCAK1600_CTX *ctx, size_t len) { + ctx->md_size = len; + return SHA3_Final(md, ctx); +} + void SHA3_Reset(KECCAK1600_CTX *ctx) { memset(ctx->A, 0, sizeof(ctx->A)); ctx->buf_load = 0; @@ -202,5 +222,7 @@ int SHA3_Final(uint8_t *md, KECCAK1600_CTX *ctx) { SHA3_Squeeze(ctx->A, md, ctx->md_size, block_size); + FIPS_service_indicator_update_state(); + return 1; } diff --git a/crypto/fipsmodule/sha/sha3_test.cc b/crypto/fipsmodule/sha/sha3_test.cc index 0d1be686a3..cb39fc2f66 100644 --- a/crypto/fipsmodule/sha/sha3_test.cc +++ b/crypto/fipsmodule/sha/sha3_test.cc @@ -52,24 +52,24 @@ class SHA3TestVector { OPENSSL_free(ctx); } - void NISTTestVectors_SHAKE128() const { + void NISTTestVectors_SHAKE(const EVP_MD *algorithm) const { uint32_t digest_length = out_len_ / 8; std::unique_ptr digest(new uint8_t[digest_length]); + EVP_MD_CTX* ctx = EVP_MD_CTX_new(); - ASSERT_TRUE(SHAKE128(msg_.data(), msg_.size() , digest.get(), out_len_)); - - ASSERT_EQ(Bytes(digest.get(), out_len_ / 8), - Bytes(digest_.data(), out_len_ / 8)); - } - - void NISTTestVectors_SHAKE256() const { - uint32_t digest_length = out_len_ / 8; - std::unique_ptr digest(new uint8_t[digest_length]); + // Test the incremental EVP API + ASSERT_TRUE(EVP_DigestInit(ctx, algorithm)); + ASSERT_TRUE(EVP_DigestUpdate(ctx, msg_.data(), msg_.size())); + ASSERT_TRUE(EVP_DigestFinalXOF(ctx, digest.get(), digest_length)); + EXPECT_EQ(Bytes(digest.get(), digest_length), + Bytes(digest_.data(), digest_length)); - ASSERT_TRUE(SHAKE256(msg_.data(), msg_.size() , digest.get(), out_len_)); + // Test the one-shot + ASSERT_TRUE(EVP_Digest(msg_.data(), msg_.size(), digest.get(), &digest_length, algorithm, NULL)); + EXPECT_EQ(Bytes(digest.get(), digest_length), + Bytes(digest_.data(), digest_length)); - ASSERT_EQ(Bytes(digest.get(), out_len_ / 8), - Bytes(digest_.data(), out_len_ / 8)); + OPENSSL_free(ctx); } private: @@ -183,18 +183,15 @@ TEST(KeccakInternalTest, SqueezeOutputBufferOverflow) { EVP_MD_unstable_sha3_enable(false); } -TEST(SHAKE128Test, NISTTestVectors) { +TEST(SHAKETest, NISTTestVectors) { FileTestGTest("crypto/fipsmodule/sha/testvectors/SHAKE128VariableOut.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); - test_vec.NISTTestVectors_SHAKE128(); + test_vec.NISTTestVectors_SHAKE(EVP_shake128()); }); -} - -TEST(SHAKE256Test, NISTTestVectors) { FileTestGTest("crypto/fipsmodule/sha/testvectors/SHAKE256VariableOut.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); - test_vec.NISTTestVectors_SHAKE256(); + test_vec.NISTTestVectors_SHAKE(EVP_shake256()); }); } diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h index 9765fd9462..982564af50 100644 --- a/crypto/obj/obj_dat.h +++ b/crypto/obj/obj_dat.h @@ -56,7 +56,7 @@ /* This file is generated by crypto/obj/objects.go. */ -#define NUM_NID 980 +#define NUM_NID 981 static const uint8_t kObjectData[] = { /* NID_rsadsi */ @@ -7198,6 +7198,26 @@ static const uint8_t kObjectData[] = { 0x04, 0x02, 0x05, + /* NID_shake128 */ + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x02, + 0x0b, + /* NID_shake256 */ + 0x60, + 0x86, + 0x48, + 0x01, + 0x65, + 0x03, + 0x04, + 0x02, + 0x0c, }; static const ASN1_OBJECT kObjects[NUM_NID] = { @@ -8860,8 +8880,9 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { &kObjectData[6232], 0}, {"ffdhe2048", "ffdhe2048", NID_ffdhe2048, 0, NULL, 0}, {"ffdhe4096", "ffdhe4096", NID_ffdhe4096, 0, NULL, 0}, - {NULL, NULL, NID_undef, 0, NULL, 0}, {"SHA512-224", "sha512-224", NID_sha512_224, 9, &kObjectData[6243], 0}, + {"SHAKE128", "shake128", NID_shake128, 9, &kObjectData[6252], 0}, + {"SHAKE256", "shake256", NID_shake256, 9, &kObjectData[6261], 0}, }; static const uint16_t kNIDsInShortNameOrder[] = { @@ -9063,8 +9084,10 @@ static const uint16_t kNIDsInShortNameOrder[] = { 968 /* SHA3-512 */, 673 /* SHA384 */, 674 /* SHA512 */, - 979 /* SHA512-224 */, + 978 /* SHA512-224 */, 962 /* SHA512-256 */, + 979 /* SHAKE128 */, + 980 /* SHAKE256 */, 188 /* SMIME */, 167 /* SMIME-CAPS */, 100 /* SN */, @@ -10754,10 +10777,12 @@ static const uint16_t kNIDsInLongNameOrder[] = { 673 /* sha384 */, 669 /* sha384WithRSAEncryption */, 674 /* sha512 */, - 979 /* sha512-224 */, + 978 /* sha512-224 */, 962 /* sha512-256 */, 670 /* sha512WithRSAEncryption */, 42 /* shaWithRSAEncryption */, + 979 /* shake128 */, + 980 /* shake256 */, 52 /* signingTime */, 454 /* simpleSecurityObject */, 496 /* singleLevelQuality */, @@ -10809,8 +10834,8 @@ static const uint16_t kNIDsInLongNameOrder[] = { static const uint16_t kNIDsInOIDOrder[] = { 434 /* 0.9 (OBJ_data) */, 182 /* 1.2 (OBJ_member_body) */, - 379 /* 1.3 (OBJ_org) */, 676 /* 1.3 (OBJ_identified_organization) */, + 379 /* 1.3 (OBJ_org) */, 11 /* 2.5 (OBJ_X500) */, 647 /* 2.23 (OBJ_international_organizations) */, 380 /* 1.3.6 (OBJ_dod) */, @@ -11515,12 +11540,14 @@ static const uint16_t kNIDsInOIDOrder[] = { 673 /* 2.16.840.1.101.3.4.2.2 (OBJ_sha384) */, 674 /* 2.16.840.1.101.3.4.2.3 (OBJ_sha512) */, 675 /* 2.16.840.1.101.3.4.2.4 (OBJ_sha224) */, - 979 /* 2.16.840.1.101.3.4.2.5 (OBJ_sha512_224) */, + 978 /* 2.16.840.1.101.3.4.2.5 (OBJ_sha512_224) */, 962 /* 2.16.840.1.101.3.4.2.6 (OBJ_sha512_256) */, 965 /* 2.16.840.1.101.3.4.2.7 (OBJ_sha3_224) */, 966 /* 2.16.840.1.101.3.4.2.8 (OBJ_sha3_256) */, 967 /* 2.16.840.1.101.3.4.2.9 (OBJ_sha3_384) */, 968 /* 2.16.840.1.101.3.4.2.10 (OBJ_sha3_512) */, + 979 /* 2.16.840.1.101.3.4.2.11 (OBJ_shake128) */, + 980 /* 2.16.840.1.101.3.4.2.12 (OBJ_shake256) */, 802 /* 2.16.840.1.101.3.4.3.1 (OBJ_dsa_with_SHA224) */, 803 /* 2.16.840.1.101.3.4.3.2 (OBJ_dsa_with_SHA256) */, 71 /* 2.16.840.1.113730.1.1 (OBJ_netscape_cert_type) */, diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num index 1de1519e0b..25d96d4084 100644 --- a/crypto/obj/obj_mac.num +++ b/crypto/obj/obj_mac.num @@ -965,4 +965,6 @@ KYBER1024_R3 974 DILITHIUM3_R3 975 ffdhe2048 976 ffdhe4096 977 -sha512_224 979 +sha512_224 978 +shake128 979 +shake256 980 diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt index 812c9969b7..a0d2bf794d 100644 --- a/crypto/obj/objects.txt +++ b/crypto/obj/objects.txt @@ -1369,6 +1369,8 @@ nist_sha3hashalgs 7 : SHA3-224 : sha3-224 nist_sha3hashalgs 8 : SHA3-256 : sha3-256 nist_sha3hashalgs 9 : SHA3-384 : sha3-384 nist_sha3hashalgs 10 : SHA3-512 : sha3-512 +nist_sha3hashalgs 11 : SHAKE128 : shake128 +nist_sha3hashalgs 12 : SHAKE256 : shake256 : HKDF : hkdf diff --git a/include/openssl/digest.h b/include/openssl/digest.h index e940ffe635..3d3d359e42 100644 --- a/include/openssl/digest.h +++ b/include/openssl/digest.h @@ -91,6 +91,8 @@ OPENSSL_EXPORT const EVP_MD *EVP_sha3_224(void); OPENSSL_EXPORT const EVP_MD *EVP_sha3_256(void); OPENSSL_EXPORT const EVP_MD *EVP_sha3_384(void); OPENSSL_EXPORT const EVP_MD *EVP_sha3_512(void); +OPENSSL_EXPORT const EVP_MD *EVP_shake128(void); +OPENSSL_EXPORT const EVP_MD *EVP_shake256(void); OPENSSL_EXPORT const EVP_MD *EVP_blake2b256(void); // EVP_md5_sha1 is a TLS-specific |EVP_MD| which computes the concatenation of @@ -191,9 +193,10 @@ OPENSSL_EXPORT int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, // bytes from |data| and writes the digest to |md_out|. |EVP_MD_CTX_size| bytes // are written, which is at most |EVP_MAX_MD_SIZE|. If |out_size| is not NULL // then |*out_size| is set to the number of bytes written. It returns one on -// success and zero otherwise. +// success and zero otherwise. If |type| is an XOF, |out_size| must be set to +// the desired output length. OPENSSL_EXPORT int EVP_Digest(const void *data, size_t len, uint8_t *md_out, - unsigned int *md_out_size, const EVP_MD *type, + unsigned int *out_size, const EVP_MD *type, ENGINE *impl); @@ -221,8 +224,7 @@ OPENSSL_EXPORT size_t EVP_MD_block_size(const EVP_MD *md); #define EVP_MD_FLAG_DIGALGID_ABSENT 2 // EVP_MD_FLAG_XOF indicates that the digest is an extensible-output function -// (XOF). This flag is defined for compatibility and will never be set in any -// |EVP_MD| in BoringSSL. +// (XOF). #define EVP_MD_FLAG_XOF 4 @@ -290,8 +292,8 @@ OPENSSL_EXPORT EVP_MD_CTX *EVP_MD_CTX_create(void); // EVP_MD_CTX_destroy calls |EVP_MD_CTX_free|. OPENSSL_EXPORT void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); -// EVP_DigestFinalXOF returns zero and adds an error to the error queue. -// BoringSSL does not support any XOF digests. +// EVP_DigestFinalXOF behaves like |EVP_DigestFinal| for XOF digests, writing +// |len| bytes of extended output to |out|. OPENSSL_EXPORT int EVP_DigestFinalXOF(EVP_MD_CTX *ctx, uint8_t *out, size_t len); diff --git a/include/openssl/nid.h b/include/openssl/nid.h index 3382ef679a..0eb236bf03 100644 --- a/include/openssl/nid.h +++ b/include/openssl/nid.h @@ -4306,9 +4306,19 @@ extern "C" { #define SN_sha512_224 "SHA512-224" #define LN_sha512_224 "sha512-224" -#define NID_sha512_224 979 +#define NID_sha512_224 978 #define OBJ_sha512_224 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 5L +#define SN_shake128 "SHAKE128" +#define LN_shake128 "shake128" +#define NID_shake128 979 +#define OBJ_shake128 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 11L + +#define SN_shake256 "SHAKE256" +#define LN_shake256 "shake256" +#define NID_shake256 980 +#define OBJ_shake256 2L, 16L, 840L, 1L, 101L, 3L, 4L, 2L, 12L + #if defined(__cplusplus) } /* extern C */ #endif diff --git a/util/fipstools/acvp/ACVP.md b/util/fipstools/acvp/ACVP.md index 9a6ba86c75..60673bd6de 100644 --- a/util/fipstools/acvp/ACVP.md +++ b/util/fipstools/acvp/ACVP.md @@ -100,6 +100,8 @@ The other commands are as follows. (Note that you only need to implement the com | SHA2-512 | Value to hash | Digest | | SHA2-512/224 | Value to hash | Digest | | SHA2-512/256 | Value to hash | Digest | +| SHAKE-128 | Value to hash, output len | Digest | +| SHAKE-256 | Value to hash, output len | Digest | | SHA-1/MCT | Initial seed¹ | Digest | | SHA2-224/MCT | Initial seed¹ | Digest | | SHA2-256/MCT | Initial seed¹ | Digest | @@ -107,6 +109,8 @@ The other commands are as follows. (Note that you only need to implement the com | SHA2-512/MCT | Initial seed¹ | Digest | | SHA2-512/224/MCT | Initial seed¹ | Digest | | SHA2-512/256/MCT | Initial seed¹ | Digest | +| SHAKE-128/MCT | Initial seed_, output len | Digest | +| SHAKE-256/MCT | Initial seed_, output len | Digest | | TLSKDF/<1.0\|1.2>/<HASH> | Number output bytes, secret, label, seed1, seed2 | Output | ¹ The iterated tests would result in excessive numbers of round trips if the module wrapper handled only basic operations. Thus some ACVP logic is pushed down for these tests so that the inner loop can be handled locally. Either read the NIST documentation ([block-ciphers](https://pages.nist.gov/ACVP/draft-celi-acvp-symmetric.html#name-monte-carlo-tests-for-block) [hashes](https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-monte-carlo-tests-for-sha-1)) to understand the iteration count and return values or, probably more fruitfully, see how these functions are handled in the `modulewrapper` directory. diff --git a/util/fipstools/acvp/acvptool/subprocess/hash.go b/util/fipstools/acvp/acvptool/subprocess/hash.go index b5a6e8952e..f9caf85e17 100644 --- a/util/fipstools/acvp/acvptool/subprocess/hash.go +++ b/util/fipstools/acvp/acvptool/subprocess/hash.go @@ -19,6 +19,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "strings" ) // The following structures reflect the JSON of ACVP hash tests. See @@ -29,13 +30,16 @@ type hashTestVectorSet struct { } type hashTestGroup struct { - ID uint64 `json:"tgId"` - Type string `json:"testType"` - Tests []struct { - ID uint64 `json:"tcId"` - BitLength uint64 `json:"len"` - MsgHex string `json:"msg"` - LargeMsg hashLargeMsg `json:"largeMsg"` + ID uint64 `json:"tgId"` + Type string `json:"testType"` + MaxOutLen *uint64 `json:"maxOutLen,omitempty"` + MinOutLen *uint64 `json:"minxOutLen,omitempty"` + Tests []struct { + ID uint64 `json:"tcId"` + BitLength uint64 `json:"len"` + MsgHex string `json:"msg"` + OutputLength *uint64 `json:"outLen,omitempty"` + LargeMsg hashLargeMsg `json:"largeMsg"` } `json:"tests"` } @@ -97,8 +101,16 @@ func (h *hashPrimitive) Process(vectorSet []byte, m Transactable) (any, error) { // http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-sha-00.html#rfc.section.3 switch group.Type { + case "VOT": + fallthrough case "AFT": - result, err := m.Transact(h.algo, 1, msg) + args := [][]byte{} + args = append(args, msg) + if test.OutputLength != nil { + outLenBytes := *test.OutputLength / 8 + args = append(args, uint32le(uint32(outLenBytes))) + } + result, err := m.Transact(h.algo, 1, args...) if err != nil { panic(h.algo + " hash operation failed: " + err.Error()) } @@ -109,7 +121,10 @@ func (h *hashPrimitive) Process(vectorSet []byte, m Transactable) (any, error) { }) case "MCT": - if len(msg) != h.size { + // MCT tests for conventional digest functions expect message + // and digest output lengths to be equivalent, however SHAKE + // does not have a predefined output length. + if len(msg) != h.size && !strings.HasPrefix(h.algo, "SHAKE") { return nil, fmt.Errorf("MCT test case %d/%d contains message of length %d but the digest length is %d", group.ID, test.ID, len(msg), h.size) } diff --git a/util/fipstools/acvp/acvptool/subprocess/subprocess.go b/util/fipstools/acvp/acvptool/subprocess/subprocess.go index f6726c5447..26e1d2fab0 100644 --- a/util/fipstools/acvp/acvptool/subprocess/subprocess.go +++ b/util/fipstools/acvp/acvptool/subprocess/subprocess.go @@ -97,17 +97,20 @@ func NewWithIO(cmd *exec.Cmd, in io.WriteCloser, out io.ReadCloser) *Subprocess } m.primitives = map[string]primitive{ - "SHA-1": &hashPrimitive{"SHA-1", 20}, - "SHA2-224": &hashPrimitive{"SHA2-224", 28}, - "SHA2-256": &hashPrimitive{"SHA2-256", 32}, - "SHA2-384": &hashPrimitive{"SHA2-384", 48}, - "SHA2-512": &hashPrimitive{"SHA2-512", 64}, - "SHA2-512/224": &hashPrimitive{"SHA2-512/224", 28}, - "SHA2-512/256": &hashPrimitive{"SHA2-512/256", 32}, - "SHA3-224": &hashPrimitive{"SHA3-224", 28}, - "SHA3-256": &hashPrimitive{"SHA3-256", 32}, - "SHA3-384": &hashPrimitive{"SHA3-384", 48}, - "SHA3-512": &hashPrimitive{"SHA3-512", 64}, + "SHA-1": &hashPrimitive{"SHA-1", 20}, + "SHA2-224": &hashPrimitive{"SHA2-224", 28}, + "SHA2-256": &hashPrimitive{"SHA2-256", 32}, + "SHA2-384": &hashPrimitive{"SHA2-384", 48}, + "SHA2-512": &hashPrimitive{"SHA2-512", 64}, + "SHA2-512/224": &hashPrimitive{"SHA2-512/224", 28}, + "SHA2-512/256": &hashPrimitive{"SHA2-512/256", 32}, + "SHA3-224": &hashPrimitive{"SHA3-224", 28}, + "SHA3-256": &hashPrimitive{"SHA3-256", 32}, + "SHA3-384": &hashPrimitive{"SHA3-384", 48}, + "SHA3-512": &hashPrimitive{"SHA3-512", 64}, + // NOTE: SHAKE does not have a predifined digest output size + "SHAKE-128": &hashPrimitive{"SHAKE-128", -1}, + "SHAKE-256": &hashPrimitive{"SHAKE-256", -1}, "ACVP-AES-ECB": &blockCipher{"AES", 16, 2, true, false, iterateAES}, "ACVP-AES-CBC": &blockCipher{"AES-CBC", 16, 2, true, true, iterateAESCBC}, "ACVP-AES-CBC-CS3": &blockCipher{"AES-CBC-CS3", 16, 1, false, true, iterateAESCBC}, diff --git a/util/fipstools/acvp/acvptool/test/expected/SHAKE-128.bz2 b/util/fipstools/acvp/acvptool/test/expected/SHAKE-128.bz2 new file mode 100644 index 0000000000..c7895f91e9 Binary files /dev/null and b/util/fipstools/acvp/acvptool/test/expected/SHAKE-128.bz2 differ diff --git a/util/fipstools/acvp/acvptool/test/expected/SHAKE-256.bz2 b/util/fipstools/acvp/acvptool/test/expected/SHAKE-256.bz2 new file mode 100644 index 0000000000..8cc895f0de Binary files /dev/null and b/util/fipstools/acvp/acvptool/test/expected/SHAKE-256.bz2 differ diff --git a/util/fipstools/acvp/acvptool/test/sha-tests/shake-128-tests.json b/util/fipstools/acvp/acvptool/test/sha-tests/shake-128-tests.json new file mode 100644 index 0000000000..b5b0720ace --- /dev/null +++ b/util/fipstools/acvp/acvptool/test/sha-tests/shake-128-tests.json @@ -0,0 +1 @@ +[{"Wrapper": "modulewrapper", "In": "vectors/SHAKE-128.bz2", "Out": "expected/SHAKE-128.bz2"}] diff --git a/util/fipstools/acvp/acvptool/test/sha-tests/shake-256-tests.json b/util/fipstools/acvp/acvptool/test/sha-tests/shake-256-tests.json new file mode 100644 index 0000000000..dd10960bfd --- /dev/null +++ b/util/fipstools/acvp/acvptool/test/sha-tests/shake-256-tests.json @@ -0,0 +1 @@ +[{"Wrapper": "modulewrapper", "In": "vectors/SHAKE-256.bz2", "Out": "expected/SHAKE-256.bz2"}] diff --git a/util/fipstools/acvp/acvptool/test/vectors/SHAKE-128.bz2 b/util/fipstools/acvp/acvptool/test/vectors/SHAKE-128.bz2 new file mode 100644 index 0000000000..235f4dbac2 Binary files /dev/null and b/util/fipstools/acvp/acvptool/test/vectors/SHAKE-128.bz2 differ diff --git a/util/fipstools/acvp/acvptool/test/vectors/SHAKE-256.bz2 b/util/fipstools/acvp/acvptool/test/vectors/SHAKE-256.bz2 new file mode 100644 index 0000000000..10ba367bbb Binary files /dev/null and b/util/fipstools/acvp/acvptool/test/vectors/SHAKE-256.bz2 differ diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 4c36c5ec11..48bc917b70 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -266,6 +266,22 @@ static bool GetConfig(const Span args[], ReplyCallback write_repl }], "performLargeDataTest": [1, 2, 4, 8] }, + { + "algorithm": "SHAKE-128", + "revision": "2.0", + "messageLength": [{ + "min": 0, "max": 65536, "increment": 8 + }], + "performLargeDataTest": [1, 2, 4, 8] + }, + { + "algorithm": "SHAKE-256", + "revision": "2.0", + "messageLength": [{ + "min": 0, "max": 65536, "increment": 8 + }], + "performLargeDataTest": [1, 2, 4, 8] + }, { "algorithm": "SHA-1", "revision": "1.0", @@ -1118,6 +1134,26 @@ static bool HashSha3(const Span args[], ReplyCallback write_reply return write_reply({Span(digest)}); } +template +static bool HashXof(const Span args[], ReplyCallback write_reply) { + // NOTE: Max outLen in the test vectors is 1024 bits (128 bytes). If that + // changes, we'll need to use a bigger stack-allocated array size here. + uint8_t digest[128]; + const EVP_MD *md = MDFunc(); + const uint8_t *outlen_bytes = args[1].data(); + // MD outLen is passed to modulewrapper as a length-4 byte array representing + // a little-endian unsigned 32-bit integer. + uint32_t md_out_size = 0; + md_out_size |= outlen_bytes[3] << 24; + md_out_size |= outlen_bytes[2] << 16; + md_out_size |= outlen_bytes[1] << 8; + md_out_size |= outlen_bytes[0] << 0; + + EVP_Digest(args[0].data(), args[0].size(), digest, &md_out_size, md, NULL); + + return write_reply({Span(digest, md_out_size)}); +} + template static bool HashMCT(const Span args[], @@ -1151,7 +1187,6 @@ static bool HashMCTSha3(const Span args[], const EVP_MD *evp_md = MDFunc(); unsigned int md_out_size = DigestLength; - // The following logic conforms to the Monte Carlo tests described in // https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-monte-carlo-tests-for-sha3- unsigned char md[1001][DigestLength]; @@ -1168,6 +1203,39 @@ static bool HashMCTSha3(const Span args[], {Span(md[1000])}); } +template +static bool HashMCTXof(const Span args[], ReplyCallback write_reply) { + // The spec for SHAKE monte carlo tests is written to be generic between a + // minimum and maximum output length, but the vectors obtained from ACVP + // allow only 1024 bits. Supporting dynamically sized MCTs would require + // passing the min/max output lengths to the modulewrapper, parsing ibid., + // and dynamically allocating and freeing appropriately sized bufffers. To + // keep things simple, we defer that complexity until/if needed. + // + // https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-shake-monte-carlo-test + const unsigned output_len = 1024/8; + const unsigned msg_size = 128/8; + const size_t array_len = 1001; + unsigned char md[array_len][output_len]; + unsigned char msg[array_len][msg_size]; + + // Zero out |md| and |msg| to clear any residual stack garbage before XOF computation + for (size_t i = 0; i < array_len; i++) { + OPENSSL_cleanse(md[i], sizeof(md[0]) * sizeof(unsigned char)); + OPENSSL_cleanse(msg[i], sizeof(msg[0]) * sizeof(unsigned char)); + } + + memcpy(md[0], args[0].data(), msg_size); + + unsigned output_len_mut = output_len; + for (size_t i = 1; i < array_len; i++) { + memcpy(msg[i], md[i-1], msg_size); + EVP_Digest(msg[i], sizeof(msg[i]), md[i], &output_len_mut, MDFunc(), NULL); + } + + return write_reply({Span(md[1000])}); +} + // The following logic conforms to the Large Data Tests described in // https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-large-data-tests-for-sha-1- // Which are the same for SHA-1, SHA2, and SHA3 @@ -1953,6 +2021,10 @@ static const EVP_MD *HashFromName(Span name) { return EVP_sha512_224(); } else if (StringEq(name, "SHA2-512/256")) { return EVP_sha512_256(); + } else if (StringEq(name, "SHAKE-128")) { + return EVP_shake128(); + } else if (StringEq(name, "SHAKE-256")) { + return EVP_shake256(); } else { return nullptr; } @@ -2454,6 +2526,8 @@ static struct { {"SHA3-256", 1, HashSha3}, {"SHA3-384", 1, HashSha3}, {"SHA3-512", 1, HashSha3}, + {"SHAKE-128", 2, HashXof}, + {"SHAKE-256", 2, HashXof}, {"SHA-1/MCT", 1, HashMCT}, {"SHA2-224/MCT", 1, HashMCT}, {"SHA2-256/MCT", 1, HashMCT}, @@ -2465,6 +2539,8 @@ static struct { {"SHA3-256/MCT", 1, HashMCTSha3}, {"SHA3-384/MCT", 1, HashMCTSha3}, {"SHA3-512/MCT", 1, HashMCTSha3}, + {"SHAKE-128/MCT", 1, HashMCTXof}, + {"SHAKE-256/MCT", 1, HashMCTXof}, {"SHA-1/LDT", 2, HashLDT}, {"SHA2-224/LDT", 2, HashLDT}, {"SHA2-256/LDT", 2, HashLDT},