Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design for support of HMAC precomputed keys #1574

Merged
merged 31 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
fa25f37
Initial design for export of Merkle-Damgard hash state
May 6, 2024
7058ed3
Initial design for support of HMAC precomputed keys
May 6, 2024
3a3a9ad
Addressing comments from review of PR #1574
Jun 10, 2024
f4b67b1
Clarifying definition of EVP_MAX_MD_CHAINING_LENGTH following review
Jun 10, 2024
7148248
Merge branch 'main' into hmac-precompute
Jun 10, 2024
8b5dbea
Remove redundant function declaration in HMAC/SHA256 trampoline
Jun 10, 2024
6734e02
Function comments improvements from review of PR #1574
Jun 13, 2024
7c68e2f
Update function comment in crypto/fipsmodule/hmac/internal.h
fabrice102 Jun 13, 2024
1f6b510
Function comments improvements from review of PR #1574
Jun 14, 2024
a11cb33
Improve error management and check out_len - from review of PR #1574
Jun 14, 2024
41fd25d
Apply suggestions from code review
fabrice102 Jun 14, 2024
6f14823
Apply suggestions from code review
Jun 14, 2024
73debcf
Function comments improvements from review of PR #1574
fabrice102 Jun 14, 2024
580159c
Extend PR #1574 to the other hash functions
Jun 19, 2024
35b4f90
Fix warnings when assert disabled in release mode
Jun 19, 2024
31a27df
Improving comment
Jun 19, 2024
e867e8f
Fix bug in HMAC_with_precompute
Jun 20, 2024
57aec5b
Add service indicator tests for HMAC with precomputed keys
Jun 20, 2024
e16bd40
Fix SHA-512 Init_with_stae/get_state + comment improvements
Jul 5, 2024
866fd7f
Unit test for HMAC_with_precompute service indicator
Jul 5, 2024
7a99180
Unit test for hash Init_with_state/get_state after hashing > 2^32 bits
Jul 8, 2024
7227a2c
Fixing type of some constants
Jul 8, 2024
6df5d2e
Adding unit tests to increase coverage
Jul 8, 2024
43510e5
Style and comment improvements from review of PR aws/aws-lc#1574
Jul 11, 2024
220b8d3
Merge branch 'main' into hmac-precompute
Jul 11, 2024
4ec5b37
Add hmac.errordata
Jul 17, 2024
34e5089
python3 ./util/generate_build_files.py
skmcgrail Jul 17, 2024
f096cfb
Merge branch 'main' into hmac-precompute
nebeid Jul 18, 2024
cd102d6
Fix Windows ARM64 compilation + comment improvements
Jul 18, 2024
1fd75d9
Merge branch 'main' into hmac-precompute
nebeid Jul 19, 2024
d77ee73
Merge branch 'main' into hmac-precompute
nebeid Jul 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ if(GO_EXECUTABLE)
err/engine.errordata
err/evp.errordata
err/hkdf.errordata
err/hmac.errordata
err/obj.errordata
err/ocsp.errordata
err/pem.errordata
Expand Down
236 changes: 236 additions & 0 deletions crypto/digest_extra/digest_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <openssl/ripemd.h>
#include <openssl/sha.h>

#include "../fipsmodule/md5/internal.h"
#include "../fipsmodule/sha/internal.h"
#include "../internal.h"
#include "../test/test_util.h"
Expand Down Expand Up @@ -481,3 +482,238 @@ TEST(DigestTest, TransformBlocks) {

EXPECT_TRUE(0 == OPENSSL_memcmp(ctx1.h, ctx2.h, sizeof(ctx1.h)));
}

// DIGEST_TEST_InitAndGetStateBasic_Body expands to the body of the various
// InitAndGetStateBasic* tests below.
// Because EXPECT_* outputs the line where the macro is called/expanded,
// we need to add diagnostic information `<< ...` after each EXPECT_*
#define DIGEST_TEST_InitAndGetStateBasic_Body(HASH_NAME, HASH_CTX, \
HASH_CBLOCK) \
{ \
const size_t nb_blocks = 10; \
const size_t block_size = HASH_CBLOCK; \
uint8_t data[block_size * nb_blocks]; \
for (size_t i = 0; i < sizeof(data); i++) { \
data[i] = i * 3; \
} \
\
/* Compute the hash of the data for the baseline */ \
HASH_CTX ctx1; \
EXPECT_TRUE(HASH_NAME##_Init(&ctx1)) << "init 1"; \
EXPECT_TRUE(HASH_NAME##_Update(&ctx1, data, sizeof(data))) << "update 1"; \
uint8_t hash1[HASH_NAME##_DIGEST_LENGTH]; \
EXPECT_TRUE(HASH_NAME##_Final(hash1, &ctx1)) << "final 1"; \
\
/* Compute it by stopping in the middle, getting the state, and restoring \
* it */ \
HASH_CTX ctx2; \
EXPECT_TRUE(HASH_NAME##_Init(&ctx2)) << "init 2"; \
EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data, 1)) << "update 2a"; \
uint8_t state_h[HASH_NAME##_CHAINING_LENGTH]; \
uint64_t state_n; \
/* we should not be able to export the state before a full block */ \
EXPECT_FALSE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \
<< "get_state 2a"; \
/* finish 2 blocks */ \
EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data + 1, 2 * block_size - 1)) \
<< "update 2b"; \
/* now we should be able to export the state */ \
EXPECT_TRUE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \
<< "get_state 2b"; \
/* check that state_n corresponds to 2 blocks */ \
EXPECT_EQ(2 * block_size * 8, state_n) << "correct state_n"; \
\
/* and we continue on a fresh new context */ \
HASH_CTX ctx3; \
EXPECT_TRUE(HASH_NAME##_Init_from_state(&ctx3, state_h, state_n)) \
<< "init 3"; \
EXPECT_TRUE(HASH_NAME##_Update(&ctx3, data + 2 * block_size, \
(nb_blocks - 2) * block_size)) \
<< "update 3"; \
uint8_t hash2[HASH_NAME##_DIGEST_LENGTH]; \
EXPECT_TRUE(HASH_NAME##_Final(hash2, &ctx3)) << "final 3"; \
\
/* finally check the resulting hash matches the baseline hash */ \
EXPECT_EQ(Bytes(hash1), Bytes(hash2)) << "same hash"; \
\
/* Check that Init_from_state requires the number of bits to be a \
* multiple of the block size */ \
HASH_CTX ctx4; \
EXPECT_FALSE(HASH_NAME##_Init_from_state(&ctx4, state_h, 1)) \
<< "init 4 n not multiple of block size"; \
}


// DIGEST_TEST_InitAndGetStateLarge_Body expands to the body of the various
// InitAndGetStateLarge* tests below.
// Compared to DIGEST_TEST_InitAndGetStateBasic_Body, it allows testing
// hashing an arbitrary amount of data.
// Of particular interest is the choice of NB_1000_BLOCKS to be such that
// the number of hash bits n > 2^32: this allows to test an important corner
// case. Indeed, HASH_CTX->Nl can be uint64_t (for SHA-512, SHA-384,
// SHA-512/224, SHA-512/256) or uint32_t (for all other hash functions). In the
// latter case, when n > 2^32 bits, the 32 most significant bits of the 64-bit
// value n are stored in HASH_CTX->Nh.
// Concretely, the test evaluates the hash function over (NB_1000_BLOCKS+2)*1000
// blocks, exporting the state after NB_1000_BLOCKS * 1000 blocks.
// Because EXPECT_* outputs the line where the macro is called/expanded, we need
// to add diagnostic information `<< ...` after each EXPECT_*
#define DIGEST_TEST_InitAndGetStateLarge_Body(HASH_NAME, HASH_CTX, \
HASH_CBLOCK, NB_1000_BLOCKS) \
{ \
const size_t block_size = HASH_CBLOCK; \
uint8_t data_1000_blocks[block_size * 1000]; \
for (size_t i = 0; i < sizeof(data_1000_blocks); i++) { \
data_1000_blocks[i] = i * 3; \
} \
\
/* Compute the hash of the NB_1000_BLOCKS+2 times the data_1000_blocks for \
* the baseline */ \
HASH_CTX ctx1; \
EXPECT_TRUE(HASH_NAME##_Init(&ctx1)) << "init 1"; \
for (size_t i = 0; i < NB_1000_BLOCKS + 2; i++) { \
EXPECT_TRUE(HASH_NAME##_Update(&ctx1, data_1000_blocks, \
sizeof(data_1000_blocks))) \
<< "update 1 - i=" << i; \
fabrice102 marked this conversation as resolved.
Show resolved Hide resolved
} \
uint8_t hash1[HASH_NAME##_DIGEST_LENGTH]; \
EXPECT_TRUE(HASH_NAME##_Final(hash1, &ctx1)) << "final 1"; \
\
/* Compute it by stopping after NB_1000_BLOCKS, getting the state, and \
* restoring it */ \
HASH_CTX ctx2; \
EXPECT_TRUE(HASH_NAME##_Init(&ctx2)) << "init 2"; \
/* Hash NB_1000_BLOCKS blocks minus one single byte */ \
for (size_t i = 0; i < NB_1000_BLOCKS - 1; i++) { \
EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data_1000_blocks, \
sizeof(data_1000_blocks))) \
<< "update 2a - i=" << i; \
} \
EXPECT_TRUE(HASH_NAME##_Update(&ctx2, data_1000_blocks, \
sizeof(data_1000_blocks) - 1)) \
<< "update 2b"; \
uint8_t state_h[HASH_NAME##_CHAINING_LENGTH]; \
uint64_t state_n; \
/* we should not be able to export the state because did not hash a \
* multiple of blocks (since we skip the last byte) */ \
EXPECT_FALSE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \
<< "get_state 2b"; \
/* finish the current block, i.e., hash the last byte */ \
EXPECT_TRUE(HASH_NAME##_Update( \
&ctx2, data_1000_blocks + sizeof(data_1000_blocks) - 1, 1)) \
<< "update 2c"; \
/* now we should be able to export the state */ \
EXPECT_TRUE(HASH_NAME##_get_state(&ctx2, state_h, &state_n)) \
<< "get_state 2c"; \
/* check that state_n corresponds to NB_1000_BLOCKS blocks */ \
EXPECT_EQ((uint64_t)(NB_1000_BLOCKS) * sizeof(data_1000_blocks) * 8, \
state_n) \
<< "correct state_n"; \
\
/* and we continue on a fresh new context: \
* we just need to hash the remaining 2 * 1000 blocks */ \
HASH_CTX ctx3; \
EXPECT_TRUE(HASH_NAME##_Init_from_state(&ctx3, state_h, state_n)) \
<< "init 3"; \
for (size_t i = 0; i < 2; i++) { \
EXPECT_TRUE(HASH_NAME##_Update(&ctx3, data_1000_blocks, \
sizeof(data_1000_blocks))) \
<< "update 3 - i=" << i; \
} \
uint8_t hash2[HASH_NAME##_DIGEST_LENGTH]; \
EXPECT_TRUE(HASH_NAME##_Final(hash2, &ctx3)) << "final 3"; \
\
/* finally check the resulting hash matches the baseline hash */ \
EXPECT_EQ(Bytes(hash1), Bytes(hash2)) << "same hash"; \
}


TEST(DigestTest, InitAndGetStateMD5Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(MD5, MD5_CTX, MD5_CBLOCK);
}

TEST(DigestTest, InitAndGetStateMD5Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
MD5, MD5_CTX, MD5_CBLOCK,
(((uint64_t)1) << 32) / MD5_CBLOCK / 8 / 1000 + 10);
}

// Define SHA1_DIGEST_LENGTH to make the macro work...
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
TEST(DigestTest, InitAndGetStateSHA1Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA1, SHA_CTX, SHA_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA1Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA1, SHA_CTX, SHA_CBLOCK,
(((uint64_t)1) << 32) / SHA_CBLOCK / 8 / 1000 + 10);
}

TEST(DigestTest, InitAndGetStateSHA224Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA224, SHA256_CTX, SHA256_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA224Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA224, SHA256_CTX, SHA224_CBLOCK,
(((uint64_t)1) << 32) / SHA224_CBLOCK / 8 / 1000 + 10);
}

TEST(DigestTest, InitAndGetStateSHA256Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA256, SHA256_CTX, SHA256_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA256Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA256, SHA256_CTX, SHA256_CBLOCK,
(((uint64_t)1) << 32) / SHA256_CBLOCK / 8 / 1000 + 10);
}

TEST(DigestTest, InitAndGetStateSHA384Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA384, SHA512_CTX, SHA512_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA384Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA384, SHA512_CTX, SHA384_CBLOCK,
(((uint64_t)1) << 32) / SHA384_CBLOCK / 8 / 1000 + 10);
}

TEST(DigestTest, InitAndGetStateSHA512Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA512, SHA512_CTX, SHA512_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA512Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA512, SHA512_CTX, SHA512_CBLOCK,
(((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10);
}

TEST(DigestTest, InitAndGetStateSHA512_224Basic) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA512_224, SHA512_CTX, SHA512_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA512_224Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA512_224, SHA512_CTX, SHA512_CBLOCK,
(((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10);
}

TEST(DigestTest, InitAndGetStateSHA512_256) {
DIGEST_TEST_InitAndGetStateBasic_Body(SHA512_256, SHA512_CTX, SHA512_CBLOCK);
}

TEST(DigestTest, InitAndGetStateSHA512_256Large) {
// Hash more than 2^32 bits
DIGEST_TEST_InitAndGetStateLarge_Body(
SHA512_256, SHA512_CTX, SHA512_CBLOCK,
(((uint64_t)1) << 32) / SHA512_CBLOCK / 8 / 1000 + 10);
}
4 changes: 4 additions & 0 deletions crypto/err/hmac.errordata
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
HMAC,102,BUFFER_TOO_SMALL
HMAC,100,MISSING_PARAMETERS
HMAC,104,NOT_CALLED_JUST_AFTER_INIT
HMAC,103,SET_PRECOMPUTED_KEY_EXPORT_NOT_CALLED
Loading
Loading