commit 36a529a9feb4f6e5b2b7135ee66475250f78fb86
parent f214688f6b723e0cc7633128ecde65f8b629c2d5
Author: vaplv <vaplv@free.fr>
Date: Mon, 5 Sep 2022 17:26:26 +0200
Major update of the sha256 API
Remove the hash256_chunked_data function and add the sha256_ctx API.
Diffstat:
| M | src/hash.c | | | 266 | +++++++++++++++++++++++++++++++++++++------------------------------------------ |
| M | src/hash.h | | | 27 | ++++++++++++++++++++++----- |
2 files changed, 148 insertions(+), 145 deletions(-)
diff --git a/src/hash.c b/src/hash.c
@@ -55,165 +55,151 @@ rrot(const uint32_t ui, const unsigned int count)
}
static void
-get_chunk512(char dst[64], const size_t ichunk512, void* ctx)
+sha256_process_chunk(struct sha256_ctx* ctx)
{
- struct buffer* buf = ctx;
- const char* chunk = NULL;
- size_t chunk_sz = 0;
- const size_t offset = ichunk512*(sizeof(char[64]));
- ASSERT(buf && offset < buf->len);
-
- chunk = buf->mem + offset;
- chunk_sz = MMIN(buf->len - offset, sizeof(char[64]));
- memcpy(dst, chunk, chunk_sz);
+ uint32_t w[64];
+ uint32_t a, b, c, d, e, f, g, h;
+ uint32_t i;
+ ASSERT(ctx);
+
+ FOR_EACH(i, 0, 16) {
+ w[i] = big_endian_32(((uint32_t*)ctx->chunk)[i]);
+ }
+ FOR_EACH(i, 16, 64) {
+ const uint32_t s0 = rrot(w[i-15],7) ^ rrot(w[i-15],18) ^ (w[i-15] >> 3);
+ const uint32_t s1 = rrot(w[i-2],17) ^ rrot(w[i-2], 19) ^ (w[i-2] >> 10);
+ w[i] = w[i-16] + s0 + w[i-7] + s1;
+ }
+
+ a = ctx->state[0];
+ b = ctx->state[1];
+ c = ctx->state[2];
+ d = ctx->state[3];
+ e = ctx->state[4];
+ f = ctx->state[5];
+ g = ctx->state[6];
+ h = ctx->state[7];
+
+ /* Compress the chunk */
+ FOR_EACH(i, 0, 64) {
+ const uint32_t s0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22);
+ const uint32_t s1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25);
+ const uint32_t ch = (e & f) ^ ((~e) & g);
+ const uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
+ const uint32_t tmp1 = h + s1 + ch + k[i] + w[i];
+ const uint32_t tmp2 = s0 + maj;
+
+ h = g;
+ g = f;
+ f = e;
+ e = d + tmp1;
+ d = c;
+ c = b;
+ b = a;
+ a = tmp1 + tmp2;
+ }
+
+ ctx->state[0] += a;
+ ctx->state[1] += b;
+ ctx->state[2] += c;
+ ctx->state[3] += d;
+ ctx->state[4] += e;
+ ctx->state[5] += f;
+ ctx->state[6] += g;
+ ctx->state[7] += h;
}
/*******************************************************************************
* Exported functions
******************************************************************************/
void
-hash_sha256
- (const void* data,
- const size_t len,
- hash256_T hash)
+sha256_ctx_init(struct sha256_ctx* ctx)
{
- struct chunked_data_desc desc = CHUNKED_DATA_DESC_NULL;
- struct buffer buf;
-
- buf.mem = data;
- buf.len = len;
-
- desc.get_chunk512 = get_chunk512;
- desc.size = len;
- desc.context = &buf;
+ /* Initial hash values: first 32 bits of the fractional parts of the square
+ * roots of the first 8 primes 2..19 */
+ ctx->state[0] = 0x6a09e667;
+ ctx->state[1] = 0xbb67ae85;
+ ctx->state[2] = 0x3c6ef372;
+ ctx->state[3] = 0xa54ff53a;
+ ctx->state[4] = 0x510e527f;
+ ctx->state[5] = 0x9b05688c;
+ ctx->state[6] = 0x1f83d9ab;
+ ctx->state[7] = 0x5be0cd19;
+ ctx->len = 0;
+ ctx->nbits = 0;
+}
- hash_sha256_chunked_data(&desc, hash);
+void
+sha256_ctx_update
+ (struct sha256_ctx* ctx,
+ const char* bytes,
+ const size_t len)
+{
+ uint32_t i;
+ ASSERT(ctx);
+ ASSERT(bytes || !len);
+
+ FOR_EACH(i, 0, len) {
+ ctx->chunk[ctx->len] = bytes[i];
+ ctx->len += 1;
+ if(ctx->len == 64) {
+ sha256_process_chunk(ctx);
+ ctx->nbits += 512;
+ ctx->len = 0;
+ }
+ }
}
void
-hash_sha256_chunked_data
- (struct chunked_data_desc* data,
- hash256_T hash)
+sha256_ctx_finalize(struct sha256_ctx* ctx, hash256_T hash)
{
- /* Actually, the size of one chunk is 64 bytes. Anyway, note that after the
- * last byte of the data to digest, one has to store 9 additionnal bytes: 1
- * to mark the end of the data and 8 used to save the effective data length.
- * Such tailing bytes can exceed the 64 bytes length of the chunk. Since the
- * overall message length must be aligned on 64 bytes we thus pre-allocate an
- * array whose size is 2 times the chunk size */
- char buffer[64*2];
-
- size_t msg_sz = 0;
- size_t ichunk = 0;
- size_t nchunks = 0;
- size_t ichunk_last_byte = 0; /* Chunk id the last data byte */
- size_t remaining_data_sz = 0;
+ uint32_t i;
- /* Initial hash values: first 32 bits of the fractional parts of the square
- * roots of the first 8 primes 2..19 */
- uint32_t h0 = 0x6a09e667;
- uint32_t h1 = 0xbb67ae85;
- uint32_t h2 = 0x3c6ef372;
- uint32_t h3 = 0xa54ff53a;
- uint32_t h4 = 0x510e527f;
- uint32_t h5 = 0x9b05688c;
- uint32_t h6 = 0x1f83d9ab;
- uint32_t h7 = 0x5be0cd19;
- ASSERT(data && hash);
-
- remaining_data_sz = data->size;
-
- /* Compute the overall size of the message */
- msg_sz = ALIGN_SIZE
- (data->size + 1/*Byte of the '1' bit*/ + 8/*message len*/, 64u);
-
- ASSERT((msg_sz % 64) == 0);
- nchunks = msg_sz / 64; /* #chunks of 512 bits */
-
- /* Index of the chunk containing the last data byte */
- ichunk_last_byte = data->size / 64;
-
- FOR_EACH(ichunk, 0, nchunks) {
- char* chunk = NULL;
- uint32_t w[64] = {0};
- uint32_t a=h0, b=h1, c=h2, d=h3, e=h4, f=h5, g=h6, h=h7;
- int i;
-
- if(ichunk > ichunk_last_byte) {
- chunk = buffer + 64;
- } else {
- chunk = buffer;
-
- /* Fetch the user data if any */
- if(remaining_data_sz) {
- ASSERT(data->get_chunk512);
- data->get_chunk512(buffer, ichunk, data->context);
- remaining_data_sz = remaining_data_sz > 64
- ? remaining_data_sz - 64 : 0;
- }
-
- /* Setup the tailing bytes of the message */
- if(ichunk == ichunk_last_byte) {
- char* remaining_msg = buffer;
- const size_t remaining_msg_sz = ichunk_last_byte==nchunks-1 ? 64 : 128;
-
- /* Id after the last data byte */
- const size_t ibyte_len = data->size % 64;
-
- /* Setup the '1' bit that marks the end of the data */
- remaining_msg[ibyte_len] = (char)0x80u;
-
- /* Clean up the bytes after the data up to the last 8 bytes */
- memset(remaining_msg + ibyte_len + 1, 0,
- remaining_msg_sz - ibyte_len - 1 - 8);
-
- /* Store the message 8*len in big endian */
- *(uint64_t*)(remaining_msg + remaining_msg_sz-8) =
- big_endian_64(data->size*8);
- }
- }
+ ASSERT(ctx && hash);
- FOR_EACH(i, 0, 16) {
- w[i] = big_endian_32(((uint32_t*)chunk)[i]);
- }
- FOR_EACH(i, 16, 64) {
- const uint32_t s0 = rrot(w[i-15],7) ^ rrot(w[i-15],18) ^ (w[i-15] >> 3);
- const uint32_t s1 = rrot(w[i-2],17) ^ rrot(w[i-2], 19) ^ (w[i-2] >> 10);
- w[i] = w[i-16] + s0 + w[i-7] + s1;
- }
+ ctx->nbits += ctx->len * 8; /* Update the message's length */
+ i = ctx->len;
- /* Compress the chunk */
- FOR_EACH(i, 0, 64) {
- const uint32_t s1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25);
- const uint32_t ch = (e & f) ^ ((~e) & g);
- const uint32_t tmp1 = h + s1 + ch + k[i] + w[i];
- const uint32_t s0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22);
- const uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
- const uint32_t tmp2 = s0 + maj;
-
- h = g;
- g = f;
- f = e;
- e = d + tmp1;
- d = c;
- c = b;
- b = a;
- a = tmp1 + tmp2;
- }
+ /* Setup the '1' bit that marks the end of the data */
+ ctx->chunk[i++] = (char)0x80;
- /* Update hash with the current compressed chunk */
- h0+=a; h1+=b; h2+=c; h3+=d; h4+=e; h5+=f; h6+=g; h7+=h;
+ /* Clean up the bytes after the data up to the last 8 bytes */
+ if(ctx->len < 56) {
+ memset(ctx->chunk+i, 0, 56-i);
+ } else {
+ memset(ctx->chunk+i, 0, 64-i);
+ sha256_process_chunk(ctx);
+ memset(ctx->chunk, 0, 56);
}
- /* Write the results */
- ((uint32_t*)hash)[0] = big_endian_32(h0);
- ((uint32_t*)hash)[1] = big_endian_32(h1);
- ((uint32_t*)hash)[2] = big_endian_32(h2);
- ((uint32_t*)hash)[3] = big_endian_32(h3);
- ((uint32_t*)hash)[4] = big_endian_32(h4);
- ((uint32_t*)hash)[5] = big_endian_32(h5);
- ((uint32_t*)hash)[6] = big_endian_32(h6);
- ((uint32_t*)hash)[7] = big_endian_32(h7);
+ /* Store the message's length in bits */
+ *((uint64_t*)(ctx->chunk + 56)) = big_endian_64(ctx->nbits);
+ sha256_process_chunk(ctx);
+
+ /* Store result the result */
+ ((uint32_t*)hash)[0] = big_endian_32(ctx->state[0]);
+ ((uint32_t*)hash)[1] = big_endian_32(ctx->state[1]);
+ ((uint32_t*)hash)[2] = big_endian_32(ctx->state[2]);
+ ((uint32_t*)hash)[3] = big_endian_32(ctx->state[3]);
+ ((uint32_t*)hash)[4] = big_endian_32(ctx->state[4]);
+ ((uint32_t*)hash)[5] = big_endian_32(ctx->state[5]);
+ ((uint32_t*)hash)[6] = big_endian_32(ctx->state[6]);
+ ((uint32_t*)hash)[7] = big_endian_32(ctx->state[7]);
+}
+
+void
+hash_sha256
+ (const void* data,
+ const size_t len,
+ hash256_T hash)
+{
+ struct sha256_ctx ctx;
+ ASSERT(hash);
+ ASSERT(data || !len);
+
+ sha256_ctx_init(&ctx);
+ sha256_ctx_update(&ctx, data, len);
+ sha256_ctx_finalize(&ctx, hash);
}
void
diff --git a/src/hash.h b/src/hash.h
@@ -20,6 +20,13 @@
struct mem_allocator;
+struct sha256_ctx {
+ char chunk[64];
+ uint32_t len; /* #bytes registered in chunk */
+ uint32_t state[8]; /* Current hash state */
+ uint64_t nbits; /* Overall size of the message in bits */
+};
+
typedef char hash256_T[32];
struct chunked_data_desc {
@@ -77,14 +84,24 @@ hash_fnv64(const void* data, const size_t len)
BEGIN_DECLS
RSYS_API void
-hash_sha256
- (const void* data,
- const size_t len,
+sha256_ctx_init
+ (struct sha256_ctx* ctx);
+
+RSYS_API void
+sha256_ctx_update
+ (struct sha256_ctx* ctx,
+ const char* bytes,
+ const size_t len); /* #bytes */
+
+RSYS_API void
+sha256_ctx_finalize
+ (struct sha256_ctx* ctx,
hash256_T hash);
RSYS_API void
-hash_sha256_chunked_data
- (struct chunked_data_desc* data,
+hash_sha256
+ (const void* data,
+ const size_t len,
hash256_T hash);
RSYS_API void