-
Notifications
You must be signed in to change notification settings - Fork 121
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
SHA3 and SHAKE - New API Design #2084
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2084 +/- ##
=======================================
Coverage 78.74% 78.75%
=======================================
Files 598 598
Lines 103656 103700 +44
Branches 14718 14732 +14
=======================================
+ Hits 81628 81664 +36
- Misses 21374 21384 +10
+ Partials 654 652 -2 ☔ View full report in Codecov by Sentry. |
Define Keccak1600, FIPS202, and SHA3/SHAKE API layers Keccak1600 implements absorb and squeeze functionalities. It defines the lowest lever APIs for SHA3/SHAKE; Keccak1600 functions only process complete blocks; internal input/output buffers are handles by higher layer (FIPS202) APIs. FIPS202 APIs handle the internal input/output buffers to allow incremental function calls. FIPS202 layer is used by both SHA3 and SHAKE high level APIs. FIPS202 defines Reset, Init, Update, Finalize APIs. SHA3/SHAKE layer implements the SHA3 and SHAKE algorithms. SHA3 supports Init, Update and Final APIs since it produces a given length digest and should be Finalized in a single Final function call. SHAKE supports Init, Update, Finalize and Squeeze APIs since it can generate arbitrary length output in incremental way. SHAKE_Finalize processes padding and absorb of last input block and generates the first output value; Incremental XOF output generation is defined by SHAKE_Squeeze function which implements the squeeze phase (it does not finalize the absorb, SHAKE_Squeeze can be only called after SHAKE_Finalize
Note: symmetric-shake.c will be inlined, therefore, additional checks for |ctx->padded| flag will be omitted (SHAKE_Finalize should be called once to finalize absorb and initialize squeeze phase; SHAKE_Squeeze should be called to generate additional incremental XOF output).
Update blocksize/rate macro names
50e9841
to
eb992ea
Compare
…on may not be completed (incremental XOF output request); however, the SHAKE_Finalize function completes the first requested output, thus, SHAKE has processed the first valid output value
Rename SHAKE_Update to SHAKE_Absorb; Define SHAKE_Final as a single-shot API; Defined SHAKE_Squeeze as an incremental (independent) API. It can can be called immediately after SHAKE_Absorb; SHAKE_Squeeze will finalize absorb phase and initiate squeeze phase; When called a signle time SHAKE_Squeeze has the same behavior as SHAKE_Final, SHAKE_Final cannot be called consecutive times; SHAKE_Squeeze can be called multiple times; SHAKE_Squeeze can be called after SHAKE_Final (to squeeze more bytes).
Allow KECCAK1600_STATE_ABSORB, KECCAK1600_STATE_SQUEEZE, KECCAK1600_STATE_FINAL state flag values to prevent incremental usage of SHAKE_Final or SHAKE_Squeeze after SHAKE_Final The cahnge is introduced for consistency reasons KECCAK1600_STATE_ABSORB corresponds to |ctx->padded| = 0 (NOT_PADDED), KECCAK1600_STATE_SQUEEZE corresponds to |ctx->padded| = 1 (PADDED), and KECCAK1600_STATE_FINAL blocks incremental Squeeze calls.
crypto/fipsmodule/sha/internal.h
Outdated
// SHA3_Absorb processes the largest multiple of |r| out of |len| bytes and | ||
// 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you exporting these functions?
|
||
// SHA3_Update processes all data blocks that don't need pad through | ||
// |SHA3_Absorb| and returns 1 and 0 on failure. | ||
// SHA3_Update check |ctx| pointer and |len| value and calls FIPS202_Update. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also why are these SHA functions exported here? As far as I can tell they are only used internally and not used in any test files that would need to be exported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree. No need to have them exported. I will address that.
crypto/fipsmodule/sha/internal.h
Outdated
// 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); | ||
// FIPS202_Reset zeros the bitstate and the amount of processed input. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can all of these FIPS202 APIs be made static and removed from this header file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a good call. I will update them.
unsigned int buflen = ML_DSA_POLY_UNIFORM_ETA_NBLOCKS_MAX * SHAKE256_RATE; | ||
uint8_t buf[ML_DSA_POLY_UNIFORM_ETA_NBLOCKS_MAX * SHAKE256_RATE]; | ||
unsigned int buflen = ML_DSA_POLY_UNIFORM_ETA_NBLOCKS_MAX * SHAKE256_BLOCKSIZE; | ||
uint8_t buf[ML_DSA_POLY_UNIFORM_ETA_NBLOCKS_MAX * SHAKE256_BLOCKSIZE]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming this buf and buflen are related:
uint8_t buf[ML_DSA_POLY_UNIFORM_ETA_NBLOCKS_MAX * SHAKE256_BLOCKSIZE]; | |
uint8_t buf[buflen]; |
unsigned int buflen = POLY_UNIFORM_NBLOCKS*SHAKE128_RATE; | ||
uint8_t buf[POLY_UNIFORM_NBLOCKS*SHAKE128_RATE + 2]; | ||
unsigned int buflen = POLY_UNIFORM_NBLOCKS*SHAKE128_BLOCKSIZE; | ||
uint8_t buf[POLY_UNIFORM_NBLOCKS*SHAKE128_BLOCKSIZE + 2]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the + 2
? Should that be reflected in buflen
?
crypto/fipsmodule/sha/sha3.c
Outdated
int FIPS202_Update(KECCAK1600_CTX *ctx, const void *data, size_t len) { | ||
uint8_t *data_ptr_copy = (uint8_t *) data; | ||
size_t block_size = ctx->block_size; | ||
size_t num, rem; | ||
|
||
if (len == 0) { | ||
return 1; | ||
} | ||
|
||
// Case |len| equals 0 is checked in SHA3/SHAKE higher level APIs | ||
// Process intermediate buffer. | ||
num = ctx->buf_load; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If FIPS202_Update isn't static we can't know for sure all callers of it will pass in valid arguments so it also needs to check that ctx is not null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated as static.
int SHA3_Update(KECCAK1600_CTX *ctx, const void *data, size_t len) { | ||
if (ctx == NULL) { | ||
return 0; | ||
} | ||
|
||
if (len == 0) { | ||
return 1; | ||
} | ||
|
||
return FIPS202_Update(ctx, data, len); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this was the plan but it looks a little weird that SHA3_update and SHAKE_Absorb are the exact same code, will they ever not be the same?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are, indeed, the same. That is the reason both - SHA3 and SHAKE were using the same SHA3_Update
function. However, it is not consistent to execute SHAKE via SHAKE_Init
, SHA3_Update
, SHAKE_Final
.
With the new design, FIPS202_
layer covers the repeated SHA3 and SHAKE functionalities.
I check the length and ctx pointer in the higher-level functions to avoid additional function calls if the input is not correct. However, I can move these to the lower-level FIPS202 as well if it simplifies the code.
crypto/fipsmodule/sha/sha3.c
Outdated
} | ||
|
||
// SHA3_Final should be called once to process final digest value | ||
// |ctx->padded| flag does not need to be updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a change from before, why doesn't it need to be updated now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The padded flag was introduced when the (block-wise) incremental XOF functionality was added. This flag should be only needed for SHAKE, since SHA3_Final should not
be called multiple times.
I actually want to change the flag to state
and add it to all SHA3 and SHAKE functions. ctx->state will be {KECCAK1600_STATE_ABSORB (not_padded), KECCAK1600_STATE_SQUEEZE (padded), KECCAK1600_STATE_FINAL(no_more_squeezes_allowed)}, where SHA3 will move from KECCAK1600_STATE_ABSORB directly to KECCAK1600_STATE_FINAL, preventing from incremental calls to SHA3_Final through EVP_DigestFinal
.
The new flag will also allow to define EVP_DigestFinalXOF
as a signle-shot API (similar to ossl) with no incremental squeezes after it. Instead, EVP_DigestSqueeze
should be only used for incremental XOF.
return 0; | ||
} | ||
} | ||
|
||
SHA3_Squeeze(ctx->A, md, ctx->md_size, block_size, ctx->padded); | ||
Keccak1600_Squeeze(ctx->A, md, len, ctx->block_size, ctx->padded); | ||
ctx->padded = 1; | ||
|
||
FIPS_service_indicator_update_state(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want to add the service indicator to SHAKE_Squeeze right now, because you've updated ML-DSA/ML-KEM to use SHAKE_squeeze this will mark it as approved. We will need to lock/unlock in ML-DSA/KEM and then have it update the service indicator if it is operating in an approved manor.
Previously ML-DSA/KEM called SHA3_Update which doesn't update the indicator it was fine. In a follow up PR when you add the service indicator for SHAKE you'll need to add more tests to all users of SHAKE_Squeeze. I'm also a little surprised the existing service indicator tests for ML-KEM didn't catch this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, some of the CIs failed when I was not updating it at the end of the (at least) first call to SHAKE_Squeeze.
For the signle-shot SHAKE API I update it at the end of the SHAKE_Final call. For the streaming API SHAKE_Squeeze I can only update it once, when the first output chunk is generated (first call to SHAKE_Squeeze).
However, previously ML-KEM and ML-DSA were calling SHAKE_Final, which calls SHA3_Final, which was updating the service indicator.
Make FIPS202 functions static; Do not export SHA3 and SHAKE internal functions
Issues:
Resolves #CryptoAlg-2810
Description of changes:
AWS-LC supports SHA3 and SHAKE algorithms though low level SHA3_init, SHA3_Update, SHA3_Final and SHAKE_init, SHAKE_Final APIs. Currently, there are two issues with the implementation and usage of SHA3 and SHAKE:
This PR addresses both of them as follows:
Call-outs:
Service indicator is updated:
All other algorithms that use SHA3/SHAKE APIs are updated:
Testing:
./crypto/crypto_test --gtest_filter="KeccakInternalTest.*"
./crypto/crypto_test --gtest_filter="SHA3Test.*"
./crypto/crypto_test --gtest_filter="SHAKETest.*"
./crypto/crypto_test --gtest_filter="All/PerKEMTest.*"
./crypto/crypto_test --gtest_filter="All/PQDSAParameterTest.*"
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.