aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2019-07-16 18:09:06 -0400
committerPaul Duncan <pabs@pablotron.org>2019-07-16 18:09:06 -0400
commitd245b30a36301ec7344aa193f29d4244e5511452 (patch)
tree83a1f6fa2acf227d658c5f2de96d1e41eb7ad00e
parentb1089d91ec8a7acef32ab588917680e77862617e (diff)
downloadsha2-d245b30a36301ec7344aa193f29d4244e5511452.tar.bz2
sha2-d245b30a36301ec7344aa193f29d4244e5511452.zip
working
-rw-r--r--Makefile5
-rw-r--r--main.c49
-rw-r--r--sha256.c198
-rw-r--r--sha256.h1
-rw-r--r--tests.c50
-rw-r--r--tests.h8
6 files changed, 188 insertions, 123 deletions
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 <stdio.h> // printf()
#include <string.h> // 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 <string.h> // 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_ */