Skip to content

Commit

Permalink
SHAKE Incremental Byte Squeezes && EVP_ Tests (#2155)
Browse files Browse the repository at this point in the history
### Issues:
Resolves #CryptoAlg-2835 && 
Resolves #CryptoAlg-2836

### Description of changes: 
AWS-LC supports SHA3 and SHAKE algorithms. SHAKE, as defined in FIPS202,
is an extendible output function, where the output data could be
generated by multiple calls to "squeeze" function. Currently, there are
two main features (internal and external APIs support) that are not
supported by AWS-LC:
- (Internal APIs) Currently, AWS-LC supports incremental XOF output
(internal only via SHAKE_Squeeze) generation when the requested data is
a multiple of the |block_size|. I.e.,
ceil(requested_output_bytes/block_size) full blocks will be generated
and directly outputted without internal buffering. Thus, it is the
user's (other algorithm) responsibility to manage output data when the
request is not a multiple of the |block_size|.
- Currently, AWS-LC does not support external (EVP_Digest) APIs for
incremental squeezes.

This PR add both features for incremental squeezes in arbitrary length
output requests (up to a byte):
- Internal APIs (SHAKE_) changes:
- Add support for incremental |SHAKE_Squeeze| with arbitrary size (up to
a byte) output requests via internal buffer.
- Add KECCAK600_CTX struct |state| field updates and checks yo ensure
functions are called only in the corresponding bitstate, e.g.,
|KECCAK1600_STATE_SQUEEZE| allows further bitstate squeezes,
|KECCAK1600_STATE_FINAL| does not allow further squeezes, etc.
- External APIs (EVP_Digest) changes:
- Add external API support for incremental |SHAKE_Squeeze| with
arbitrary size (up to a byte) output requests via |EVP_DigestSqueeze|.
- Restrict the number of calls to |EVP_DigestFinalXOF| to only one. For
incremental squeeze functionality |EVP_DigestSqueeze| should be used.
- Restrict the use of |EVP_DigestFinal| to hash algorithms only. For XOF
algorithms |EVP_DigestFinalXOF| and |EVP_DigestSqueeze| should be used.

This PR adds more tests for EVP_Digest XOF functionality (all test are
running through the entire NIST Test Vector list):
- External APIs (EVP_Digest) additional tests:
- Test Final - Assert fail when |EVP_DigestFinal| is called for XOF
algorithms
- Test Absorb - Assert success when |EVP_DigestUpdate| is called
byte-by-byte
- Test Squeeze - Assert success when |EVP_DigestSqueeze| is called
byte-by-byte
- Test Squeeze - Assert success when |EVP_DigestSqueeze| is called in
set byte increments
- Test Squeeze with random Input - Assert success when
|EVP_DigestSqueeze| is called on a random message
- Test Squeeze with random Input - Assert success when
|EVP_DigestSqueeze| is called on a random message in set byte increments
- Test Final XOF without Update - Assert fail when |EVP_DigestFinalXOF|
is called as a streaming API

### Call-outs:
Service indicator is updated:
- Inside SHAKE_Squeeze (Streaming XOF Squeezes output generation **does
not update** the service indicator after each extendable output update);

### Testing:
_./crypto/crypto_test --gtest_filter="SHAKETest.*"_

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.

---------

Co-authored-by: Jake Massimo <jakemas@amazon.com>
  • Loading branch information
manastasova and jakemas authored Feb 24, 2025
1 parent 1ada1e3 commit 493207c
Show file tree
Hide file tree
Showing 10 changed files with 500 additions and 68 deletions.
12 changes: 8 additions & 4 deletions crypto/digest_extra/digest_extra.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,10 @@ 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 is a void function
BLAKE2B256_Update(ctx->md_data, data, len);
return 1;
}

static void blake2b256_final(EVP_MD_CTX *ctx, uint8_t *md) {
Expand All @@ -271,14 +273,15 @@ static const EVP_MD evp_md_blake2b256 = {
blake2b256_final,
BLAKE2B_CBLOCK,
sizeof(BLAKE2B_CTX),
/*finalXOf*/ NULL,
/*finalXOf*/ NULL,
/*squeezeXOf*/ NULL
};

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) {}

Expand All @@ -291,7 +294,8 @@ static const EVP_MD evp_md_null = {
null_final,
0,
sizeof(EVP_MD_CTX),
NULL,
/*finalXOf*/ NULL,
/*squeezeXOf*/ NULL
};

const EVP_MD *EVP_md_null(void) { return &evp_md_null; }
25 changes: 22 additions & 3 deletions crypto/fipsmodule/digest/digest.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx) {

void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { EVP_MD_CTX_free(ctx); }

// EVP_DigestFinalXOF is a single-call XOF output generation function.
// The |ctx->digest| check prevents calling EVP_DigestFinalXOF consecutively.
// To catch single-call 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;
Expand All @@ -143,8 +148,23 @@ 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 ok;
}

// EVP_DigestSqueeze is a streaming XOF output squeeze function
// It can be called multiple times to generate an output of length
// |len| bytes.
int EVP_DigestSqueeze(EVP_MD_CTX *ctx, uint8_t *out, size_t len) {
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->squeezeXOF(ctx, out, len);
return 1;
}

Expand Down Expand Up @@ -273,8 +293,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) {
Expand Down
Loading

0 comments on commit 493207c

Please sign in to comment.