From d245b30a36301ec7344aa193f29d4244e5511452 Mon Sep 17 00:00:00 2001 From: Paul Duncan Date: Tue, 16 Jul 2019 18:09:06 -0400 Subject: working --- Makefile | 5 +- main.c | 49 +++++++++++++--- sha256.c | 198 +++++++++++++++++++++++++++------------------------------------ sha256.h | 1 - tests.c | 50 ++++++++++++++++ tests.h | 8 +++ 6 files changed, 188 insertions(+), 123 deletions(-) create mode 100644 tests.c create mode 100644 tests.h diff --git a/Makefile b/Makefile index c4bc5c6..60f10dc 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CFLAGS=-W -Wall -Wextra -pedantic -O3 -std=c11 -OBJS=sha256.o main.o +OBJS=sha256.o main.o tests.o APP=sha256 .PHONY=all clean @@ -16,4 +16,5 @@ clean: $(RM) $(OBJS) $(APP) test: $(APP) - ./$(APP) '' + @# ./$(APP) '' 'foobar' + @./$(APP) diff --git a/main.c b/main.c index 5ef63fc..3540a32 100644 --- a/main.c +++ b/main.c @@ -1,20 +1,53 @@ #include // printf() #include // strlen() #include "sha256.h" +#include "tests.h" -static const char DEFAULT[] = "The quick brown fox jumps over the lazy dog"; +static uint8_t dst[SHA256_HASH_SIZE]; + +static void print_hash(const uint8_t * const hash) { + for (size_t i = 0; i < SHA256_HASH_SIZE; i++) { + printf("%02x", hash[i]); + } +} + +static void print_row( + const char * const src, + const uint8_t * const hash +) { + printf("\"%s\",", src); + print_hash(hash); + printf("\n"); +} + +static void on_test_fail( + const char * const src, + const uint8_t * const got_hash, + const uint8_t * const expected_hash +) { + printf("\"%s\",", src); + print_hash(got_hash); + printf(","); + print_hash(expected_hash); + printf("\n"); +} int main(int argc, char *argv[]) { - const char *src = (argc > 1) ? argv[1] : DEFAULT; - uint8_t dst[SHA256_HASH_SIZE]; + if (argc > 1) { + // if command-line parameters are given, then hash and print them + // instead of running the test vectors - sha256((const uint8_t *) src, strlen(src), dst); + for (int i = 1; i < argc; i++) { + const char * const src = argv[i]; - printf("src = \"%s\"\nhash = \"", src); - for (size_t i = 0; i < 32; i++) { - printf("%02x", dst[i]); + sha256((const uint8_t *) src, strlen(src), dst); + print_row(src, dst); + } + } else { + // no command-line parameters given. run internal tests + printf("input,result,expected\n"); + run_tests(on_test_fail); } - printf("\"\n"); return 0; } diff --git a/sha256.c b/sha256.c index 268001d..8249a0c 100644 --- a/sha256.c +++ b/sha256.c @@ -5,14 +5,8 @@ // (first 32 bits of the fractional parts of the square roots of the // first 8 primes 2..19): static const uint32_t H[8] = { - 0x6a09e667, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19, + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, }; // round constants @@ -47,39 +41,50 @@ void sha256_init(sha256_t * const ctx) { memcpy(ctx->h, H, sizeof(H)); } +// decode buffer data as 32-bit words (used for the first 16 words) +#define WI(ctx, i) ( \ + (((uint32_t) (ctx)->buf[4 * (i) + 0]) << 24) | \ + (((uint32_t) (ctx)->buf[4 * (i) + 1]) << 16) | \ + (((uint32_t) (ctx)->buf[4 * (i) + 2]) << 8) | \ + ((uint32_t) (ctx)->buf[4 * (i) + 3]) \ +) + static void -sha256_round(sha256_t * const ctx) { - for (size_t i = 0; i < 16; i++) { - ctx->w[i] = ( - (((uint32_t) ctx->buf[4 * i + 0]) << 24) | - (((uint32_t) ctx->buf[4 * i + 1]) << 16) | - (((uint32_t) ctx->buf[4 * i + 2]) << 8) | - ((uint32_t) ctx->buf[4 * i + 3]) - ); - } +sha256_block(sha256_t * const ctx) { + // init first 16 words from buffer + uint32_t w[64] = { + WI(ctx, 0), WI(ctx, 1), WI(ctx, 2), WI(ctx, 3), + WI(ctx, 4), WI(ctx, 5), WI(ctx, 6), WI(ctx, 7), + WI(ctx, 8), WI(ctx, 9), WI(ctx, 10), WI(ctx, 11), + WI(ctx, 12), WI(ctx, 13), WI(ctx, 14), WI(ctx, 15), + 0, + }; - // Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array: + // Extend the first 16 words into the remaining 48 words w[16..63] of + // the message schedule array + // // for i from 16 to 63 // s0 := (w[i-15] rr 7) xor (w[i-15] rr 18) xor (w[i-15] rs 3) // s1 := (w[i- 2] rr 17) xor (w[i- 2] rr 19) xor (w[i- 2] rs 10) // w[i] := w[i-16] + s0 + w[i-7] + s1 for (size_t i = 16; i < 64; i++) { - const uint32_t w2 = ctx->w[i - 2], - w7 = ctx->w[i - 7], - w15 = ctx->w[i - 15], - w16 = ctx->w[i - 16], + const uint32_t w2 = w[i - 2], + w7 = w[i - 7], + w15 = w[i - 15], + w16 = w[i - 16], s0 = rr(w15, 7) ^ rr(w15, 18) ^ (w15 >> 3), s1 = rr(w2, 17) ^ rr(w2, 19) ^ (w2 >> 10); - ctx->w[i] = w16 + s0 + w7 + s1; + w[i] = w16 + s0 + w7 + s1; } - // Initialize working variables to current hash value: - uint32_t hs[8]; - for (size_t i = 0; i < 8; i++) { - hs[i] = ctx->h[i]; - } + // Initialize working variables to current hash value + uint32_t hs[8] = { + ctx->h[0], ctx->h[1], ctx->h[2], ctx->h[3], + ctx->h[4], ctx->h[5], ctx->h[6], ctx->h[7], + }; - // Compression function main loop: + // Compression function main loop + // // for i from 0 to 63 // S1 := (e rightrotate 6) xor (e rightrotate 11) xor (e rightrotate 25) // ch := (e and f) xor ((not e) and g) @@ -98,8 +103,8 @@ sha256_round(sha256_t * const ctx) { // a := temp1 + temp2 for (size_t i = 0; i < 64; i++) { const uint32_t s1 = rr(hs[4], 6) ^ rr(hs[4], 11) ^ rr(hs[4], 25), - ch = (hs[4] & hs[5]) ^ (~(hs[4]) & hs[6]), - t0 = hs[7] + s1 + ch + K[i] + ctx->w[i], + ch = (hs[4] & hs[5]) ^ ((~(hs[4])) & hs[6]), + t0 = hs[7] + s1 + ch + K[i] + w[i], s0 = rr(hs[0], 2) ^ rr(hs[0], 13) ^ rr(hs[0], 22), mj = (hs[0] & hs[1]) ^ (hs[0] & hs[2]) ^ (hs[1] & hs[2]), t1 = s0 + mj; @@ -115,52 +120,38 @@ sha256_round(sha256_t * const ctx) { } // Add the compressed chunk to the current hash value - for (size_t i = 0; i < 8; i++) { - ctx->h[i] += hs[i]; - } + ctx->h[0] += hs[0]; + ctx->h[1] += hs[1]; + ctx->h[2] += hs[2]; + ctx->h[3] += hs[3]; + ctx->h[4] += hs[4]; + ctx->h[5] += hs[5]; + ctx->h[6] += hs[6]; + ctx->h[7] += hs[7]; } +#undef WI + void sha256_push( sha256_t * const ctx, - const uint8_t *src, - size_t src_len + const uint8_t * const src, + const size_t src_len ) { - ctx->num_bytes += src_len; - - if ((ctx->buf_len + src_len) >= 64) { - const size_t len = 64 - ctx->buf_len; - memcpy(ctx->buf + ctx->buf_len, src, len); - - sha256_round(ctx); - ctx->buf_len = 0; - - src += len; - src_len -= len; - } else { - memcpy(ctx->buf + ctx->buf_len, src, src_len); - ctx->buf_len += src_len; - - src += src_len; - src_len = 0; + for (size_t i = 0; i < src_len; i++) { + ctx->buf[ctx->buf_len] = src[i]; + ctx->buf_len++; + + if (ctx->buf_len == 64) { + sha256_block(ctx); + ctx->buf_len = 0; + } } - while (src_len >= 64) { - memcpy(ctx->buf, src, 64); - - sha256_round(ctx); - ctx->buf_len = 0; - - src += 64; - src_len -= 64; - } - - if (src_len > 0) { - memcpy(ctx->buf, src, src_len); - ctx->buf_len = src_len; - } + ctx->num_bytes += src_len; } -static void sha256_push_u64( +static void +sha256_push_u64( sha256_t * const ctx, const uint64_t val ) { @@ -178,7 +169,8 @@ static void sha256_push_u64( sha256_push(ctx, buf, sizeof(buf)); } -static const uint8_t FOOTER[65] = { +// end of stream padding +static const uint8_t PADDING[65] = { 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -186,60 +178,42 @@ static const uint8_t FOOTER[65] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; +#define WB(ctx, i) \ + ((ctx)->h[i] >> 24) & 0xff, \ + ((ctx)->h[i] >> 16) & 0xff, \ + ((ctx)->h[i] >> 8) & 0xff, \ + ((ctx)->h[i]) & 0xff + void sha256_fini( sha256_t * const ctx, uint8_t * const out ) { const uint64_t num_bytes = ctx->num_bytes; + const size_t pad_len = (65 - ((num_bytes + 1 + 8) % 64)); - { - // push padding - const size_t pad_len = (64 - ((num_bytes + 1 + 8) % 64)) % 64; - sha256_push(ctx, FOOTER, 1 + pad_len); - } + // fprintf(stderr, "ctx->num_bytes (before pad) = %lu\n", ctx->num_bytes); + + // push padding + sha256_push(ctx, PADDING, pad_len); + + // fprintf(stderr, "ctx->num_bytes (before len) = %lu\n", ctx->num_bytes); - // push length - sha256_push_u64(ctx, num_bytes); - - // extract result - const uint8_t src[32] = { - (ctx->h[0] >> 24) & 0xff, - (ctx->h[0] >> 16) & 0xff, - (ctx->h[0] >> 8) & 0xff, - (ctx->h[0]) & 0xff, - (ctx->h[1] >> 24) & 0xff, - (ctx->h[1] >> 16) & 0xff, - (ctx->h[1] >> 8) & 0xff, - (ctx->h[1]) & 0xff, - (ctx->h[2] >> 24) & 0xff, - (ctx->h[2] >> 16) & 0xff, - (ctx->h[2] >> 8) & 0xff, - (ctx->h[2]) & 0xff, - (ctx->h[3] >> 24) & 0xff, - (ctx->h[3] >> 16) & 0xff, - (ctx->h[3] >> 8) & 0xff, - (ctx->h[3]) & 0xff, - (ctx->h[4] >> 24) & 0xff, - (ctx->h[4] >> 16) & 0xff, - (ctx->h[4] >> 8) & 0xff, - (ctx->h[4]) & 0xff, - (ctx->h[5] >> 24) & 0xff, - (ctx->h[5] >> 16) & 0xff, - (ctx->h[5] >> 8) & 0xff, - (ctx->h[5]) & 0xff, - (ctx->h[6] >> 24) & 0xff, - (ctx->h[6] >> 16) & 0xff, - (ctx->h[6] >> 8) & 0xff, - (ctx->h[6]) & 0xff, - (ctx->h[7] >> 24) & 0xff, - (ctx->h[7] >> 16) & 0xff, - (ctx->h[7] >> 8) & 0xff, - (ctx->h[7]) & 0xff, + // push length (in bits) + sha256_push_u64(ctx, num_bytes * 8); + + // fprintf(stderr, "ctx->num_bytes (after len) = %lu\n", ctx->num_bytes); + + // extract hash + const uint8_t hash[32] = { + WB(ctx, 0), WB(ctx, 1), WB(ctx, 2), WB(ctx, 3), + WB(ctx, 4), WB(ctx, 5), WB(ctx, 6), WB(ctx, 7), }; - memcpy(out, src, sizeof(src)); + memcpy(out, hash, sizeof(hash)); } +#undef WB + void sha256( const uint8_t * const src, const size_t src_len, diff --git a/sha256.h b/sha256.h index a01e416..e805293 100644 --- a/sha256.h +++ b/sha256.h @@ -11,7 +11,6 @@ typedef struct { size_t buf_len; uint32_t h[8]; - uint32_t w[64]; uint64_t num_bytes; } sha256_t; diff --git a/tests.c b/tests.c new file mode 100644 index 0000000..a71bd7b --- /dev/null +++ b/tests.c @@ -0,0 +1,50 @@ +#include // memcmp() +#include "sha256.h" + +static const struct { + const char * const s; + const uint8_t h[32]; +} TESTS[] = {{ + .s = "", + .h = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, + }, +}, { + .s = "abc", + .h = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad, + }, +}, { + .s = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .h = { + 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, + 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, + 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, + 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1, + }, +}}; + +#define NUM_TESTS (sizeof(TESTS) / sizeof(TESTS[0])) + +unsigned int run_tests( + void (*on_fail)(const char * const, const uint8_t *, const uint8_t *) +) { + uint8_t hash[SHA256_HASH_SIZE]; + unsigned int r = 0; + + for (size_t i = 0; i < NUM_TESTS; i++) { + sha256((const uint8_t *) TESTS[i].s, strlen(TESTS[i].s), hash); + if (memcmp(hash, TESTS[i].h, sizeof(hash))) { + on_fail(TESTS[i].s, hash, TESTS[i].h); + r++; + } + } + + return r; +} diff --git a/tests.h b/tests.h new file mode 100644 index 0000000..96b8357 --- /dev/null +++ b/tests.h @@ -0,0 +1,8 @@ +#ifndef TESTS_H_ +#define TESTS_H_ + +unsigned int run_tests( + void (*on_fail)(const char * const, const uint8_t *, const uint8_t *) +); + +#endif /* TESTS_H_ */ -- cgit v1.2.3