From a7b29874fd7aec76165626c2e6ea8a66de91e0b9 Mon Sep 17 00:00:00 2001 From: Norman Ashley Date: Mon, 27 Nov 2023 17:26:08 -0500 Subject: [PATCH] SHA2 Increment with arbitrary length (non-block sizes) (#1614) * Enhanced with new SHA2 API that allows arbitary length updates * Fix style * Fix format * Document struct members * Fix comparison sign * Use OQS SHA2 API * Add nl at end * Use OQS_MEM_secure_free instead of free * Updated per review... mem check after malloc, use memcpy * Fix style --- src/common/sha2/sha2.c | 4 + src/common/sha2/sha2.h | 38 +++++ src/common/sha2/sha2_armv8.c | 99 ++++++++++-- src/common/sha2/sha2_c.c | 114 ++++++++++++-- src/common/sha2/sha2_impl.c | 8 + src/common/sha2/sha2_local.h | 10 ++ src/common/sha2/sha2_ossl.c | 5 + src/sig_stfl/lms/CMakeLists.txt | 1 - src/sig_stfl/lms/external/hash.c | 13 +- src/sig_stfl/lms/external/hash.h | 5 +- src/sig_stfl/lms/external/lms_namespace.h | 2 - src/sig_stfl/lms/external/sha256.c | 183 ---------------------- src/sig_stfl/lms/external/sha256.h | 44 ------ tests/test_hash.c | 54 ++++++- 14 files changed, 317 insertions(+), 263 deletions(-) delete mode 100644 src/sig_stfl/lms/external/sha256.c delete mode 100644 src/sig_stfl/lms/external/sha256.h diff --git a/src/common/sha2/sha2.c b/src/common/sha2/sha2.c index 9cc732d1d3..e0d3902e3b 100644 --- a/src/common/sha2/sha2.c +++ b/src/common/sha2/sha2.c @@ -22,6 +22,10 @@ void OQS_SHA2_sha256_inc_blocks(OQS_SHA2_sha256_ctx *state, const uint8_t *in, s callbacks->SHA2_sha256_inc_blocks(state, in, inblocks); } +void OQS_SHA2_sha256_inc(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t len) { + callbacks->SHA2_sha256_inc(state, in, len); +} + void OQS_SHA2_sha256_inc_finalize(uint8_t *out, OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t inlen) { callbacks->SHA2_sha256_inc_finalize(out, state, in, inlen); } diff --git a/src/common/sha2/sha2.h b/src/common/sha2/sha2.h index 41562f8f5e..cd993e69c8 100644 --- a/src/common/sha2/sha2.h +++ b/src/common/sha2/sha2.h @@ -24,6 +24,16 @@ extern "C" { #endif +/** Data structure for the state of the SHA-224 incremental hashing API. */ +typedef struct { + /** Internal state */ + void *ctx; + /** current number of bytes in data */ + size_t data_len; + /** unprocessed data buffer */ + uint8_t data[128]; +} OQS_SHA2_sha224_ctx; + /** * \brief Process a message with SHA-256 and return the hash code in the output byte array. * @@ -39,6 +49,10 @@ void OQS_SHA2_sha256(uint8_t *output, const uint8_t *input, size_t inplen); typedef struct { /** Internal state */ void *ctx; + /** current number of bytes in data */ + size_t data_len; + /** unprocessed data buffer */ + uint8_t data[128]; } OQS_SHA2_sha256_ctx; /** @@ -74,6 +88,17 @@ void OQS_SHA2_sha256_inc_ctx_clone(OQS_SHA2_sha256_ctx *dest, const OQS_SHA2_sha */ void OQS_SHA2_sha256_inc_blocks(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t inblocks); +/** + * \brief Process message bytes with SHA-256 and update the state. + * + * \warning The state must be initialized by OQS_SHA2_sha256_inc_init or OQS_SHA2_sha256_inc_ctx_clone. + * + * \param state The state to update + * \param in Message input byte array + * \param len The number of bytes of message to process + */ +void OQS_SHA2_sha256_inc(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t len); + /** * \brief Process more message bytes with SHA-256 and return the hash code in the output byte array. * @@ -113,6 +138,10 @@ void OQS_SHA2_sha384(uint8_t *output, const uint8_t *input, size_t inplen); typedef struct { /** Internal state. */ void *ctx; + /** current number of bytes in data */ + size_t data_len; + /** unprocessed data buffer */ + uint8_t data[128]; } OQS_SHA2_sha384_ctx; /** @@ -187,6 +216,10 @@ void OQS_SHA2_sha512(uint8_t *output, const uint8_t *input, size_t inplen); typedef struct { /** Internal state. */ void *ctx; + /** current number of bytes in data */ + size_t data_len; + /** unprocessed data buffer */ + uint8_t data[128]; } OQS_SHA2_sha512_ctx; /** @@ -264,6 +297,11 @@ struct OQS_SHA2_callbacks { */ void (*SHA2_sha256_inc_ctx_clone)(OQS_SHA2_sha256_ctx *dest, const OQS_SHA2_sha256_ctx *src); + /** + * Implementation of function OQS_SHA2_sha256_inc. + */ + void (*SHA2_sha256_inc)(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t len); + /** * Implementation of function OQS_SHA2_sha256_inc_blocks. */ diff --git a/src/common/sha2/sha2_armv8.c b/src/common/sha2/sha2_armv8.c index 49a63448aa..f3bbf573a1 100644 --- a/src/common/sha2/sha2_armv8.c +++ b/src/common/sha2/sha2_armv8.c @@ -3,7 +3,7 @@ #include #include "sha2_local.h" - +#include #include // ARM includes #ifndef WIN32 @@ -169,23 +169,43 @@ static size_t crypto_hashblocks_sha256_armv8(uint8_t *statebytes, return length; } + void oqs_sha2_sha256_inc_finalize_armv8(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen) { uint8_t padded[128]; - uint64_t bytes = load_bigendian_64(state->ctx + 32) + inlen; - crypto_hashblocks_sha256_armv8(state->ctx, in, inlen); - in += inlen; - inlen &= 63; - in -= inlen; + size_t new_inlen = state->data_len + inlen; + size_t tmp_len = new_inlen; + const uint8_t *new_in; + uint8_t *tmp_in = NULL; + + if (new_inlen == inlen) { + new_in = in; + } else { //Combine incremental data with final input + tmp_in = malloc(tmp_len); + if (tmp_in == NULL) { + exit(111); + } + + memcpy(tmp_in, state->data, state->data_len); + memcpy(tmp_in + state->data_len, in, inlen); + new_in = tmp_in; + } + + uint64_t bytes = load_bigendian_64(state->ctx + 32) + new_inlen; + + crypto_hashblocks_sha256_armv8(state->ctx, new_in, new_inlen); + new_in += new_inlen; + new_inlen &= 63; + new_in -= new_inlen; - for (size_t i = 0; i < inlen; ++i) { - padded[i] = in[i]; + for (size_t i = 0; i < new_inlen; ++i) { + padded[i] = new_in[i]; } - padded[inlen] = 0x80; + padded[new_inlen] = 0x80; - if (inlen < 56) { - for (size_t i = inlen + 1; i < 56; ++i) { + if (new_inlen < 56) { + for (size_t i = new_inlen + 1; i < 56; ++i) { padded[i] = 0; } padded[56] = (uint8_t) (bytes >> 53); @@ -198,7 +218,7 @@ void oqs_sha2_sha256_inc_finalize_armv8(uint8_t *out, sha256ctx *state, const ui padded[63] = (uint8_t) (bytes << 3); crypto_hashblocks_sha256_armv8(state->ctx, padded, 64); } else { - for (size_t i = inlen + 1; i < 120; ++i) { + for (size_t i = new_inlen + 1; i < 120; ++i) { padded[i] = 0; } padded[120] = (uint8_t) (bytes >> 53); @@ -216,6 +236,7 @@ void oqs_sha2_sha256_inc_finalize_armv8(uint8_t *out, sha256ctx *state, const ui out[i] = state->ctx[i]; } oqs_sha2_sha256_inc_ctx_release_c(state); + OQS_MEM_secure_free(tmp_in, tmp_len); } void oqs_sha2_sha224_inc_finalize_armv8(uint8_t *out, sha224ctx *state, const uint8_t *in, size_t inlen) { @@ -229,11 +250,63 @@ void oqs_sha2_sha224_inc_finalize_armv8(uint8_t *out, sha224ctx *state, const ui void oqs_sha2_sha256_inc_blocks_armv8(sha256ctx *state, const uint8_t *in, size_t inblocks) { uint64_t bytes = load_bigendian_64(state->ctx + 32); + const uint8_t *new_in; + size_t buf_len = 64 * inblocks; + uint8_t *tmp_in = NULL; + + /* Process any existing incremental data first */ + if (state->data_len) { + tmp_in = malloc(buf_len); + if (tmp_in == NULL) { + exit(111); + } + + memcpy(tmp_in, state->data, state->data_len); + memcpy(tmp_in + state->data_len, in, buf_len - state->data_len); + + /* store the reminder input as incremental data */ + memcpy(state->data, in + (buf_len - state->data_len), state->data_len); + new_in = tmp_in; + } else { + new_in = in; + } - crypto_hashblocks_sha256_armv8(state->ctx, in, 64 * inblocks); + crypto_hashblocks_sha256_armv8(state->ctx, new_in, 64 * inblocks); bytes += 64 * inblocks; store_bigendian_64(state->ctx + 32, bytes); + OQS_MEM_secure_free(tmp_in, buf_len); +} + +void oqs_sha2_sha256_inc_armv8(sha256ctx *state, const uint8_t *in, size_t len) { + uint64_t bytes = 0; + while (len) { + size_t incr = 64 - state->data_len; + if (incr > len) { + incr = len; + } + + for (size_t i = 0; i < incr; ++i, state->data_len++) { + state->data[state->data_len] = in[i]; + } + + if (state->data_len < 64) { + break; + } + + /* + * Process a complete block now + */ + bytes = load_bigendian_64(state->ctx + 32) + 64; + crypto_hashblocks_sha256_armv8(state->ctx, state->data, 64); + store_bigendian_64(state->ctx + 32, bytes); + + /* + * update the remaining input + */ + len -= incr; + state->data_len = 0; + } } void oqs_sha2_sha224_inc_blocks_armv8(sha224ctx *state, const uint8_t *in, size_t inblocks) { diff --git a/src/common/sha2/sha2_c.c b/src/common/sha2/sha2_c.c index 1de100c306..33863f8040 100644 --- a/src/common/sha2/sha2_c.c +++ b/src/common/sha2/sha2_c.c @@ -512,9 +512,12 @@ void oqs_sha2_sha224_inc_init_c(sha224ctx *state) { for (size_t i = 32; i < 40; ++i) { state->ctx[i] = 0; } + state->data_len = 0; + memset(state->data, 0, 128); } void oqs_sha2_sha256_inc_init_c(sha256ctx *state) { + state->data_len = 0; state->ctx = malloc(PQC_SHA256CTX_BYTES); if (state->ctx == NULL) { exit(111); @@ -525,6 +528,8 @@ void oqs_sha2_sha256_inc_init_c(sha256ctx *state) { for (size_t i = 32; i < 40; ++i) { state->ctx[i] = 0; } + state->data_len = 0; + memset(state->data, 0, 128); } void oqs_sha2_sha384_inc_init_c(sha384ctx *state) { @@ -538,6 +543,8 @@ void oqs_sha2_sha384_inc_init_c(sha384ctx *state) { for (size_t i = 64; i < 72; ++i) { state->ctx[i] = 0; } + state->data_len = 0; + memset(state->data, 0, 128); } void oqs_sha2_sha512_inc_init_c(sha512ctx *state) { @@ -551,6 +558,8 @@ void oqs_sha2_sha512_inc_init_c(sha512ctx *state) { for (size_t i = 64; i < 72; ++i) { state->ctx[i] = 0; } + state->data_len = 0; + memset(state->data, 0, 128); } void oqs_sha2_sha224_inc_ctx_clone_c(sha224ctx *stateout, const sha224ctx *statein) { @@ -558,6 +567,8 @@ void oqs_sha2_sha224_inc_ctx_clone_c(sha224ctx *stateout, const sha224ctx *state if (stateout->ctx == NULL) { exit(111); } + stateout->data_len = statein->data_len; + memcpy(stateout->data, statein->data, 128); memcpy(stateout->ctx, statein->ctx, PQC_SHA256CTX_BYTES); } @@ -566,6 +577,8 @@ void oqs_sha2_sha256_inc_ctx_clone_c(sha256ctx *stateout, const sha256ctx *state if (stateout->ctx == NULL) { exit(111); } + stateout->data_len = statein->data_len; + memcpy(stateout->data, statein->data, 128); memcpy(stateout->ctx, statein->ctx, PQC_SHA256CTX_BYTES); } @@ -574,6 +587,8 @@ void oqs_sha2_sha384_inc_ctx_clone_c(sha384ctx *stateout, const sha384ctx *state if (stateout->ctx == NULL) { exit(111); } + stateout->data_len = statein->data_len; + memcpy(stateout->data, statein->data, 128); memcpy(stateout->ctx, statein->ctx, PQC_SHA512CTX_BYTES); } @@ -582,6 +597,8 @@ void oqs_sha2_sha512_inc_ctx_clone_c(sha512ctx *stateout, const sha512ctx *state if (stateout->ctx == NULL) { exit(111); } + stateout->data_len = statein->data_len; + memcpy(stateout->data, statein->data, 128); memcpy(stateout->ctx, statein->ctx, PQC_SHA512CTX_BYTES); } @@ -607,11 +624,64 @@ void oqs_sha2_sha512_inc_ctx_release_c(sha512ctx *state) { void oqs_sha2_sha256_inc_blocks_c(sha256ctx *state, const uint8_t *in, size_t inblocks) { uint64_t bytes = load_bigendian_64(state->ctx + 32); + size_t tmp_buflen = 64 * inblocks; + const uint8_t *new_in; + uint8_t *tmp_in = NULL; + + /* Process any existing incremental data first */ + if (state->data_len) { + tmp_in = malloc(tmp_buflen); + if (tmp_in == NULL) { + exit(111); + } + + memcpy(tmp_in, state->data, state->data_len); + memcpy(tmp_in + state->data_len, in, tmp_buflen - state->data_len); + + /* store the reminder input as incremental data */ + memcpy(state->data, in + (tmp_buflen - state->data_len), state->data_len); + new_in = tmp_in; + } else { + new_in = in; + } - crypto_hashblocks_sha256_c(state->ctx, in, 64 * inblocks); + crypto_hashblocks_sha256_c(state->ctx, new_in, 64 * inblocks); bytes += 64 * inblocks; store_bigendian_64(state->ctx + 32, bytes); + OQS_MEM_secure_free(tmp_in, tmp_buflen); +} + +void oqs_sha2_sha256_inc_c(sha256ctx *state, const uint8_t *in, size_t len) { + uint64_t bytes = 0; + while (len) { + size_t incr = 64 - state->data_len; + if (incr > len) { + incr = len; + } + + for (size_t i = 0; i < incr; ++i, state->data_len++) { + state->data[state->data_len] = in[i]; + } + + if (state->data_len < 64) { + break; + } + + /* + * Process a complete block now + */ + bytes = load_bigendian_64(state->ctx + 32); + crypto_hashblocks_sha256_c(state->ctx, state->data, 64); + bytes += 64; + store_bigendian_64(state->ctx + 32, bytes); + + /* + * update the remaining input + */ + len -= incr; + state->data_len = 0; + } } void oqs_sha2_sha224_inc_blocks_c(sha224ctx *state, const uint8_t *in, size_t inblocks) { @@ -633,20 +703,39 @@ void oqs_sha2_sha384_inc_blocks_c(sha384ctx *state, const uint8_t *in, size_t in void oqs_sha2_sha256_inc_finalize_c(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen) { uint8_t padded[128]; - uint64_t bytes = load_bigendian_64(state->ctx + 32) + inlen; - crypto_hashblocks_sha256_c(state->ctx, in, inlen); - in += inlen; - inlen &= 63; - in -= inlen; + size_t new_inlen = state->data_len + inlen; + size_t tmp_len = new_inlen; + const uint8_t *new_in; + uint8_t *tmp_in = NULL; + + if (new_inlen == inlen) { + new_in = in; + } else { //Combine incremental data with final input + tmp_in = malloc(tmp_len); + if (tmp_in == NULL) { + exit(111); + } - for (size_t i = 0; i < inlen; ++i) { - padded[i] = in[i]; + memcpy(tmp_in, state->data, state->data_len); + memcpy(tmp_in + state->data_len, in, inlen); + new_in = tmp_in; } - padded[inlen] = 0x80; - if (inlen < 56) { - for (size_t i = inlen + 1; i < 56; ++i) { + uint64_t bytes = load_bigendian_64(state->ctx + 32) + new_inlen; + + crypto_hashblocks_sha256_c(state->ctx, new_in, new_inlen); + new_in += new_inlen; + new_inlen &= 63; + new_in -= new_inlen; + + for (size_t i = 0; i < new_inlen; ++i) { + padded[i] = new_in[i]; + } + padded[new_inlen] = 0x80; + + if (new_inlen < 56) { + for (size_t i = new_inlen + 1; i < 56; ++i) { padded[i] = 0; } padded[56] = (uint8_t) (bytes >> 53); @@ -659,7 +748,7 @@ void oqs_sha2_sha256_inc_finalize_c(uint8_t *out, sha256ctx *state, const uint8_ padded[63] = (uint8_t) (bytes << 3); crypto_hashblocks_sha256_c(state->ctx, padded, 64); } else { - for (size_t i = inlen + 1; i < 120; ++i) { + for (size_t i = new_inlen + 1; i < 120; ++i) { padded[i] = 0; } padded[120] = (uint8_t) (bytes >> 53); @@ -677,6 +766,7 @@ void oqs_sha2_sha256_inc_finalize_c(uint8_t *out, sha256ctx *state, const uint8_ out[i] = state->ctx[i]; } oqs_sha2_sha256_inc_ctx_release_c(state); + OQS_MEM_secure_free(tmp_in, tmp_len); } void oqs_sha2_sha224_inc_finalize_c(uint8_t *out, sha224ctx *state, const uint8_t *in, size_t inlen) { diff --git a/src/common/sha2/sha2_impl.c b/src/common/sha2/sha2_impl.c index f7f01b24f5..1d6d4fb323 100644 --- a/src/common/sha2/sha2_impl.c +++ b/src/common/sha2/sha2_impl.c @@ -31,6 +31,13 @@ static void SHA2_sha256_inc_ctx_clone(OQS_SHA2_sha256_ctx *dest, const OQS_SHA2_ oqs_sha2_sha256_inc_ctx_clone_c((sha256ctx *) dest, (const sha256ctx *) src); } +static void SHA2_sha256_inc(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t len) { + C_OR_ARM( + oqs_sha2_sha256_inc_c((sha256ctx *) state, in, len), + oqs_sha2_sha256_inc_armv8((sha256ctx *) state, in, len) + ); +} + static void SHA2_sha256_inc_blocks(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t inblocks) { C_OR_ARM( oqs_sha2_sha256_inc_blocks_c((sha256ctx *) state, in, inblocks), @@ -105,6 +112,7 @@ struct OQS_SHA2_callbacks sha2_default_callbacks = { SHA2_sha256, SHA2_sha256_inc_init, SHA2_sha256_inc_ctx_clone, + SHA2_sha256_inc, SHA2_sha256_inc_blocks, SHA2_sha256_inc_finalize, SHA2_sha256_inc_ctx_release, diff --git a/src/common/sha2/sha2_local.h b/src/common/sha2/sha2_local.h index dcb1392841..969e791d20 100644 --- a/src/common/sha2/sha2_local.h +++ b/src/common/sha2/sha2_local.h @@ -23,18 +23,26 @@ extern "C" { typedef struct { uint8_t *ctx; + size_t data_len; /* current number of bytes in data */ + uint8_t data[128]; /* msg buffer */ } sha224ctx; typedef struct { uint8_t *ctx; + size_t data_len; /* current number of bytes in data */ + uint8_t data[128]; /* msg buffer */ } sha256ctx; typedef struct { uint8_t *ctx; + size_t data_len; /* current number of bytes in data */ + uint8_t data[128]; /* msg buffer */ } sha384ctx; typedef struct { uint8_t *ctx; + size_t data_len; /* current number of bytes in data */ + uint8_t data[128]; /* msg buffer */ } sha512ctx; void oqs_sha2_sha224_inc_init_c(sha224ctx *state); @@ -46,6 +54,7 @@ void oqs_sha2_sha224_inc_ctx_release_c(sha224ctx *state); void oqs_sha2_sha256_inc_init_c(sha256ctx *state); void oqs_sha2_sha256_inc_ctx_clone_c(sha256ctx *dest, const sha256ctx *src); void oqs_sha2_sha256_inc_blocks_c(sha256ctx *state, const uint8_t *in, size_t inblocks); +void oqs_sha2_sha256_inc_c(sha256ctx *state, const uint8_t *in, size_t len); void oqs_sha2_sha256_inc_finalize_c(uint8_t *out, sha256ctx *state, const uint8_t *in, size_t inlen); void oqs_sha2_sha256_inc_ctx_release_c(sha256ctx *state); @@ -66,6 +75,7 @@ void oqs_sha2_sha512_inc_ctx_release_c(sha512ctx *state); void oqs_sha2_sha224_inc_blocks_armv8(sha224ctx *state, const uint8_t *in, size_t inblocks); void oqs_sha2_sha224_armv8(uint8_t *out, const uint8_t *in, size_t inlen); void oqs_sha2_sha256_inc_blocks_armv8(sha256ctx *state, const uint8_t *in, size_t inblocks); +void oqs_sha2_sha256_inc_armv8(sha256ctx *state, const uint8_t *in, size_t len); void oqs_sha2_sha256_armv8(uint8_t *out, const uint8_t *in, size_t inlen); void oqs_sha2_sha384_inc_init_armv8(sha384ctx *state); diff --git a/src/common/sha2/sha2_ossl.c b/src/common/sha2/sha2_ossl.c index 0953feb194..064fb61ad8 100644 --- a/src/common/sha2/sha2_ossl.c +++ b/src/common/sha2/sha2_ossl.c @@ -58,6 +58,10 @@ static void SHA2_sha256_inc_init(OQS_SHA2_sha256_ctx *state) { state->ctx = mdctx; } +static void SHA2_sha256_inc(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t len) { + OQS_OPENSSL_GUARD(EVP_DigestUpdate((EVP_MD_CTX *) state->ctx, in, len)); +} + static void SHA2_sha256_inc_blocks(OQS_SHA2_sha256_ctx *state, const uint8_t *in, size_t inblocks) { OQS_OPENSSL_GUARD(OSSL_FUNC(EVP_DigestUpdate)((EVP_MD_CTX *) state->ctx, in, inblocks * SHA2_BLOCK_SIZE)); } @@ -153,6 +157,7 @@ struct OQS_SHA2_callbacks sha2_default_callbacks = { SHA2_sha256, SHA2_sha256_inc_init, SHA2_sha256_inc_ctx_clone, + SHA2_sha256_inc, SHA2_sha256_inc_blocks, SHA2_sha256_inc_finalize, SHA2_sha256_inc_ctx_release, diff --git a/src/sig_stfl/lms/CMakeLists.txt b/src/sig_stfl/lms/CMakeLists.txt index 93fa290084..e47452eb50 100644 --- a/src/sig_stfl/lms/CMakeLists.txt +++ b/src/sig_stfl/lms/CMakeLists.txt @@ -26,7 +26,6 @@ set(SRCS external/lm_ots_sign.c external/lm_ots_verify.c external/lm_verify.c - external/sha256.c sig_stfl_lms.c sig_stfl_lms_functions.c ) diff --git a/src/sig_stfl/lms/external/hash.c b/src/sig_stfl/lms/external/hash.c index dffcdaf6a6..0fe23ecc62 100644 --- a/src/sig_stfl/lms/external/hash.c +++ b/src/sig_stfl/lms/external/hash.c @@ -1,6 +1,5 @@ #include #include "hash.h" -#include "sha256.h" #include "hss_zeroize.h" #define ALLOW_VERBOSE 0 /* 1 -> we allow the dumping of intermediate */ @@ -39,8 +38,8 @@ void hss_hash_ctx(void *result, int hash_type, union hash_context *ctx, switch (hash_type) { case HASH_SHA256: { - SHA256_Init(&ctx->sha256); - SHA256_Update(&ctx->sha256, message, message_len); + OQS_SHA2_sha256_inc_init(&ctx->sha256); + OQS_SHA2_sha256_inc(&ctx->sha256, message, message_len); SHA256_Final(result, &ctx->sha256); #if ALLOW_VERBOSE if (hss_verbose) { @@ -69,7 +68,7 @@ void hss_hash(void *result, int hash_type, void hss_init_hash_context(int h, union hash_context *ctx) { switch (h) { case HASH_SHA256: - SHA256_Init( &ctx->sha256 ); + OQS_SHA2_sha256_inc_init( &ctx->sha256 ); break; } } @@ -83,7 +82,7 @@ void hss_update_hash_context(int h, union hash_context *ctx, #endif switch (h) { case HASH_SHA256: - SHA256_Update(&ctx->sha256, msg, len_msg); + OQS_SHA2_sha256_inc(&ctx->sha256, msg, len_msg); break; } } @@ -117,3 +116,7 @@ unsigned hss_hash_blocksize(int hash_type) { } return 0; } + +void SHA256_Final(unsigned char *output, OQS_SHA2_sha256_ctx *ctx) { + OQS_SHA2_sha256_inc_finalize(output, ctx, NULL, 0); +} diff --git a/src/sig_stfl/lms/external/hash.h b/src/sig_stfl/lms/external/hash.h index 5e8fb3134d..8b1891f108 100644 --- a/src/sig_stfl/lms/external/hash.h +++ b/src/sig_stfl/lms/external/hash.h @@ -1,6 +1,6 @@ #if !defined( HASH_H__ ) #define HASH_H__ -#include "sha256.h" +#include #include #include #include "lms_namespace.h" @@ -19,7 +19,7 @@ enum { }; union hash_context { - SHA256_CTX sha256; + OQS_SHA2_sha256_ctx sha256; /* Any other hash contexts would go here */ }; @@ -54,5 +54,6 @@ void hss_update_hash_context( int h, union hash_context *ctx, const void *msg, size_t len_msg ); void hss_finalize_hash_context( int h, union hash_context *ctx, void *buffer); +void SHA256_Final(unsigned char *output, OQS_SHA2_sha256_ctx *ctx); #endif /* HASH_H__ */ diff --git a/src/sig_stfl/lms/external/lms_namespace.h b/src/sig_stfl/lms/external/lms_namespace.h index 56898589ee..c1b8f142ae 100644 --- a/src/sig_stfl/lms/external/lms_namespace.h +++ b/src/sig_stfl/lms/external/lms_namespace.h @@ -89,8 +89,6 @@ #define lm_validate_signature LMS_NAMESPACE(lm_validate_signature) #define SHA256_Final LMS_NAMESPACE(SHA256_Final) -#define SHA256_Init LMS_NAMESPACE(SHA256_Init) -#define SHA256_Update LMS_NAMESPACE(SHA256_Update) #define LMS_randombytes LMS_NAMESPACE(LMS_randombytes) #endif //_LMS_NAMESPACE_H diff --git a/src/sig_stfl/lms/external/sha256.c b/src/sig_stfl/lms/external/sha256.c deleted file mode 100644 index fb18892a31..0000000000 --- a/src/sig_stfl/lms/external/sha256.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * SHA-256 - * Implementation derived from LibTomCrypt (Tom St Denis) - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org - */ - -#include -#include "sha256.h" -#include "endian.h" - -#if !USE_OPENSSL && !defined(EXT_SHA256_H) - -/* If we don't have OpenSSL, here's a SHA256 implementation */ -#define SHA256_FINALCOUNT_SIZE 8 -#define SHA256_K_SIZE 64 -static const unsigned long K[SHA256_K_SIZE] = { - 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, - 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, - 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, - 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, - 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, - 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, - 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, - 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, - 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, - 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, - 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, - 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, - 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL -}; - -/* Various logical functions */ - -/* Rotate x right by rot bits */ -static unsigned long RORc(unsigned long x, int rot) { - rot &= 31; if (rot == 0) return x; - unsigned long right = ((x&0xFFFFFFFFUL)>>rot ); - unsigned long left = ((x&0xFFFFFFFFUL)<<(32-rot) ); - return (right|left) & 0xFFFFFFFFUL; -} -#define Ch(x,y,z) (z ^ (x & (y ^ z))) -#define Maj(x,y,z) (((x | y) & z) | (x & y)) -#define S(x, n) RORc((x),(n)) -#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) -#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) - -static void sha256_compress (SHA256_CTX * ctx, const void *buf) -{ - unsigned long S0, S1, S2, S3, S4, S5, S6, S7, W[SHA256_K_SIZE], t0, t1, t; - int i; - const unsigned char *p; - - /* copy state into S */ - S0 = ctx->h[0]; - S1 = ctx->h[1]; - S2 = ctx->h[2]; - S3 = ctx->h[3]; - S4 = ctx->h[4]; - S5 = ctx->h[5]; - S6 = ctx->h[6]; - S7 = ctx->h[7]; - - /* - * We've been asked to perform the hash computation on this 512-bit string. - * SHA256 interprets that as an array of 16 bigendian 32 bit numbers; copy - * it, and convert it into 16 unsigned long's of the CPU's native format - */ - p = buf; - for (i=0; i<16; i++) { - W[i] = get_bigendian( p, 4 ); - p += 4; - } - - /* fill W[16..63] */ - for (i = 16; i < SHA256_K_SIZE; i++) { - W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; - } - - /* Compress */ -#define RND(a,b,c,d,e,f,g,h,i) \ - t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ - t1 = Sigma0(a) + Maj(a, b, c); \ - d += t0; \ - h = t0 + t1; - - for (i = 0; i < SHA256_K_SIZE; ++i) { - RND(S0,S1,S2,S3,S4,S5,S6,S7,i); - t = S7; S7 = S6; S6 = S5; S5 = S4; - S4 = S3; S3 = S2; S2 = S1; S1 = S0; S0 = t; - } -#undef RND - - /* feedback */ - ctx->h[0] += S0; - ctx->h[1] += S1; - ctx->h[2] += S2; - ctx->h[3] += S3; - ctx->h[4] += S4; - ctx->h[5] += S5; - ctx->h[6] += S6; - ctx->h[7] += S7; -} - -void SHA256_Init (SHA256_CTX *ctx) -{ - ctx->Nl = 0; - ctx->Nh = 0; - ctx->num = 0; - ctx->h[0] = 0x6A09E667UL; - ctx->h[1] = 0xBB67AE85UL; - ctx->h[2] = 0x3C6EF372UL; - ctx->h[3] = 0xA54FF53AUL; - ctx->h[4] = 0x510E527FUL; - ctx->h[5] = 0x9B05688CUL; - ctx->h[6] = 0x1F83D9ABUL; - ctx->h[7] = 0x5BE0CD19UL; -} - -void SHA256_Update (SHA256_CTX *ctx, const void *src, unsigned int count) -{ - unsigned new_count = (ctx->Nl + (count << 3)) & 0xffffffff; - if (new_count < ctx->Nl) { - ctx->Nh += 1; - } - ctx->Nl = new_count; - - while (count) { - unsigned int this_step = 64 - ctx->num; - if (this_step > count) this_step = count; - memcpy( ctx->data + ctx->num, src, this_step); - - if (this_step + ctx->num < 64) { - ctx->num += this_step; - break; - } - - src = (const unsigned char *)src + this_step; - count -= this_step; - ctx->num = 0; - - sha256_compress( ctx, ctx->data ); - } -} - -/* - * Add padding and return the message digest. - */ -void SHA256_Final (unsigned char *digest, SHA256_CTX *ctx) -{ - unsigned int i; - unsigned char finalcount[SHA256_FINALCOUNT_SIZE]; - - put_bigendian( &finalcount[0], ctx->Nh, 4 ); - put_bigendian( &finalcount[4], ctx->Nl, 4 ); - - SHA256_Update(ctx, "\200", 1); - - if (ctx->num > 56) { - SHA256_Update(ctx, "\0\0\0\0\0\0\0\0", 8); - } - memset( ctx->data + ctx->num, 0, 56 - ctx->num ); - ctx->num = 56; - SHA256_Update(ctx, finalcount, SHA256_FINALCOUNT_SIZE); /* Should cause a sha256_compress() */ - - /* - * The final state is an array of unsigned long's; place them as a series - * of bigendian 4-byte words onto the output - */ - for (i=0; i<8; i++) { - put_bigendian( digest + 4*i, ctx->h[i], 4 ); - } -} -#endif diff --git a/src/sig_stfl/lms/external/sha256.h b/src/sig_stfl/lms/external/sha256.h deleted file mode 100644 index f7f78ad18c..0000000000 --- a/src/sig_stfl/lms/external/sha256.h +++ /dev/null @@ -1,44 +0,0 @@ -#if !defined(SHA256_H_) -#define SHA256_H_ - -#if defined( EXT_SHA256_H ) -#include EXT_SHA256_H -#else - -#define USE_OPENSSL 0 /* We use the OpenSSL implementation for SHA-256 */ - /* (which is quite a bit faster than our portable */ - /* C version) */ - -#if USE_OPENSSL - -#include - -#else -#include "lms_namespace.h" - -/* SHA256 context. */ -typedef struct { - unsigned long int h[8]; /* state; this is in the CPU native format */ - unsigned long Nl, Nh; /* number of bits processed so far */ - unsigned num; /* number of bytes within the below */ - /* buffer */ - unsigned char data[64]; /* input buffer. This is in byte vector format */ -} SHA256_CTX; - -void SHA256_Init(SHA256_CTX *); /* context */ - -void SHA256_Update(SHA256_CTX *, /* context */ - const void *, /* input block */ - unsigned int);/* length of input block */ - -void SHA256_Final(unsigned char *, - SHA256_CTX *); -#endif - -#endif /* EXT_SHA256_H */ - -#if !defined( SHA256_LEN ) -#define SHA256_LEN 32 /* The length of a SHA256 hash output */ -#endif - -#endif /* ifdef(SHA256_H_) */ diff --git a/tests/test_hash.c b/tests/test_hash.c index 022fb61a7b..3fea2f00ad 100644 --- a/tests/test_hash.c +++ b/tests/test_hash.c @@ -50,16 +50,24 @@ static int do_sha256(void) { fprintf(stderr, "ERROR reading from stdin\n"); return -1; } + // run main SHA-256 API uint8_t output[32]; OQS_SHA2_sha256(output, msg, msg_len); + // run incremental SHA-256 API uint8_t output_inc[32]; + uint8_t output_inc_2[32]; OQS_SHA2_sha256_ctx state; OQS_SHA2_sha256_inc_init(&state); + // clone state - OQS_SHA2_sha256_ctx state2; + OQS_SHA2_sha256_ctx state2, state3, state4, state5; OQS_SHA2_sha256_inc_ctx_clone(&state2, &state); + OQS_SHA2_sha256_inc_ctx_clone(&state3, &state); + OQS_SHA2_sha256_inc_ctx_clone(&state4, &state); + OQS_SHA2_sha256_inc_ctx_clone(&state5, &state); + // hash with first state if (msg_len > 64) { OQS_SHA2_sha256_inc_blocks(&state, msg, 1); @@ -67,6 +75,7 @@ static int do_sha256(void) { } else { OQS_SHA2_sha256_inc_finalize(output_inc, &state, msg, msg_len); } + if (memcmp(output, output_inc, 32) != 0) { fprintf(stderr, "ERROR: Incremental API does not match main API\n"); free(msg); @@ -84,6 +93,49 @@ static int do_sha256(void) { free(msg); return -3; } + + // hash with increment API less than block size + size_t i = 0; + for (i = 0; i < msg_len; i++) { + OQS_SHA2_sha256_inc(&state3, &msg[i], 1); + } + OQS_SHA2_sha256_inc_finalize(output_inc_2, &state3, &msg[i], 0); + if (memcmp(output, output_inc_2, 32) != 0) { + fprintf(stderr, "ERROR: Non-block Incremental API with cloned state does not match main API\n"); + free(msg); + return -4; + } + + // hash with combination of block-size increments and non block-size increments [64 bytes] + [n < 64 bytes] + if (msg_len > 64) { + OQS_SHA2_sha256_inc_blocks(&state4, msg, 1); + for (i = 0; i < (msg_len - 64); i++) { + OQS_SHA2_sha256_inc(&state4, &msg[64 + i], 1); + } + OQS_SHA2_sha256_inc_finalize(output_inc_2, &state4, &msg[msg_len - 1], 0); + } else { + OQS_SHA2_sha256_inc_finalize(output_inc_2, &state4, msg, msg_len); + } + if (memcmp(output, output_inc_2, 32) != 0) { + fprintf(stderr, "ERROR: Combined block increments with non-block size failed to match main API\n"); + free(msg); + return -5; + } + + // hash with combination of non block-size and block-size [n < 64 bytes] + [64 bytes] + if (msg_len > 64) { + OQS_SHA2_sha256_inc(&state5, msg, 1); + OQS_SHA2_sha256_inc_blocks(&state5, &msg[1], 1); + OQS_SHA2_sha256_inc_finalize(output_inc_2, &state5, &msg[65], msg_len - 65); + } else { + OQS_SHA2_sha256_inc_finalize(output_inc_2, &state5, msg, msg_len); + } + if (memcmp(output, output_inc_2, 32) != 0) { + fprintf(stderr, "ERROR: Combined non-block size and block increments failed to match main API\n"); + free(msg); + return -5; + } + //Test inc API print_hex(output, 32); free(msg); return 0;