diff --git a/LICENSE b/LICENSE index 91fcc73..701cbba 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,8 @@ MIT License -Copyright (c) 2021 Ilya O. Levin +Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +Copyright (c) 2022 Ilia Levin (ilia@levin.sg) + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c3614bc --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +CC = clang +CFLAGS= -O3 -pedantic -Wall -Wextra -std=c99 +CBMC = cbmc +TARGET = sha256 + +.PHONY: clean verify + +$(TARGET).o: sha256.c sha256.h + $(CC) $(CFLAGS) -c -o $@ $< + +test: sha256.c sha256.h + $(CC) $(CFLAGS) -o $(TARGET) -DSHA256_SELF_TEST__ $< + +all: test $(TARGET) + +clean: + rm -f $(TARGET) *.o + +verify: + $(CBMC) sha256.c -DSHA256_SELF_TEST__ -D_cbmc_ $(if $(FUNC),--function $(FUNC),) \ + --unwind 64 --partial-loops \ + --bounds-check \ + --memory-leak-check --malloc-may-fail --malloc-fail-null \ + --pointer-check --pointer-primitive-check --pointer-overflow-check \ + --div-by-zero-check --conversion-check \ + --signed-overflow-check --unsigned-overflow-check \ + --undefined-shift-check --float-overflow-check diff --git a/README.md b/README.md index 097ce06..947c53d 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,51 @@ # SHA256 -SHA-256 implementation to compliment a portable byte-oriented AES-256 -implementation in C at http://www.literatecode.com/aes256 +This is an implementation of the SHA-256 secure hash algorithm defined in +[FIPS 180-4](https://csrc.nist.gov/publications/detail/fips/180/4/final) -There is also a newer version in the [mark2](mark2) directory. This version is -cleaner and closer to a reference implementation. It no longer has -built-in support features for endianness, but you may easily adapt -the code to different endianness shall you need that. +It is not a byte-oriented implementation. Still, it may complement +a portable byte-oriented C version of AES-256 at +[www.literatecode.com/aes256](http://www.literatecode.com/aes256) -Unlike the previous implementation, the Mark 2 one is formally -verifiable with [CBMC](http://www.cprover.org/cbmc/) +## Compile + +This implementation supports `clang` (recommended) and `GCC` C compilers. +Other compilers may also work with some minor code tweaking. Apologies for +not caring about the seamless support of the MSVC compiler any longer. +Check the legacy section below if you still need that. + +Use `make` or `sh sha256.c -c -o sha256.o` to compile into an object file +that you may link with your project later. + +Use `make test` or `sh sha256.c -DSHA256_SELF_TEST__` to compile an +executable binary that will perform a few known answer tests for SHA-256. + + +## Formal verification + +We rely on [C Bounded Model Checker](http://www.cprover.org/cbmc/) to formally +verify code properties. + +Use `make verify` to verify the self-testing code. + +If you want to focus verification on a single function, use +`make verify FUNC=XYZ`, where `XYZ` is a function name. + +Check [https://github.com/diffblue/cbmc](https://github.com/diffblue/cbmc) +for the latest version of CBMC. + + +## History + +* 2010: The original code was written. +* 2013: The original code was published on [GitHub](https://github.com/ilvn/SHA256). +* 2014: The Mark 2 version was written (cleaner, closer to a reference implementation, formally verifiable). +* 2017: The Mark 2 version was added to the repository. +* 2022: The revamped Mark 2 version superseded the original code. + +### Legacy + +The original version is still available under the tag +[legacy](https://github.com/ilvn/SHA256/releases/tag/legacy) and provided +only for reference. Therefore, it is no longer supported or recommended. diff --git a/mark2/Makefile b/mark2/Makefile deleted file mode 100644 index c8224d3..0000000 --- a/mark2/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -COMPLR = $(shell which clang >/dev/null; echo $$?) -ifeq "$(COMPLR)" "0" - CC = clang - CFLAGS=-Oz -pedantic -Wall -Wextra -Weverything -else - CC = gcc - CFLAGS=-O3 -pedantic -Wall -Wextra -std=c99 -endif - -CBMCH = $(shell cbmc --help) -CBMCFLAGS = --unwind 8 --partial-loops --bounds-check --pointer-check \ - --div-by-zero-check --signed-overflow-check - -TARGET = sha256 - -$(TARGET).o: sha256.c sha256.h - $(CC) $(CFLAGS) -c -o $@ $< - -test: sha256.c sha256.h - $(CC) $(CFLAGS) -o $(TARGET) -DSELF_TEST $< - -all: $(TARGET) - -.PHONY: clean verify - -clean: - rm -f $(TARGET) *.o - -verify: - @# Unsigned overflows are deliberate, so we skip such checks to avoid - @# code complication with wrapping additions into a safeguard function - cbmc sha256.c -DSELF_TEST $(CBMCFLAGS) $(findstring --memory-leak-check,$(CBMCH)) diff --git a/mark2/sha256.c b/mark2/sha256.c deleted file mode 100644 index 290cea3..0000000 --- a/mark2/sha256.c +++ /dev/null @@ -1,298 +0,0 @@ -/* -* SHA-256 implementation, Mark 2 -* -* Copyright (c) 2010,2014 Ilya O. Levin, http://www.literatecode.com -* -* Permission to use, copy, modify, and distribute this software for any -* purpose with or without fee is hereby granted, provided that the above -* copyright notice and this permission notice appear in all copies. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -#include "sha256.h" -/* #define MINIMIZE_STACK_IMPACT */ - -#ifdef __cplusplus -extern "C" { -#endif - -#define FN_ inline static - -static const uint32_t K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -#ifdef MINIMIZE_STACK_IMPACT -static uint32_t W[64]; -#endif - -/* -------------------------------------------------------------------------- */ -FN_ uint8_t _shb(uint32_t x, uint32_t n) -{ - return ( (x >> (n & 31)) & 0xff ); -} /* _shb */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _shw(uint32_t x, uint32_t n) -{ - return ( (x << (n & 31)) & 0xffffffff ); -} /* _shw */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _r(uint32_t x, uint8_t n) -{ - return ( (x >> n) | _shw(x, 32 - n) ); -} /* _r */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _Ch(uint32_t x, uint32_t y, uint32_t z) -{ - return ( (x & y) ^ ((~x) & z) ); -} /* _Ch */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _Ma(uint32_t x, uint32_t y, uint32_t z) -{ - return ( (x & y) ^ (x & z) ^ (y & z) ); -} /* _Ma */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _S0(uint32_t x) -{ - return ( _r(x, 2) ^ _r(x, 13) ^ _r(x, 22) ); -} /* _S0 */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _S1(uint32_t x) -{ - return ( _r(x, 6) ^ _r(x, 11) ^ _r(x, 25) ); -} /* _S1 */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _G0(uint32_t x) -{ - return ( _r(x, 7) ^ _r(x, 18) ^ (x >> 3) ); -} /* _G0 */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _G1(uint32_t x) -{ - return ( _r(x, 17) ^ _r(x, 19) ^ (x >> 10) ); -} /* _G1 */ - -/* -------------------------------------------------------------------------- */ -FN_ uint32_t _word(uint8_t *c) -{ - return ( _shw(c[0], 24) | _shw(c[1], 16) | _shw(c[2], 8) | (c[3]) ); -} /* _word */ - -/* -------------------------------------------------------------------------- */ -FN_ void _addbits(sha256_context *ctx, uint32_t n) -{ - if ( ctx->bits[0] > (0xffffffff - n) ) - ctx->bits[1] = (ctx->bits[1] + 1) & 0xFFFFFFFF; - ctx->bits[0] = (ctx->bits[0] + n) & 0xFFFFFFFF; -} /* _addbits */ - -/* -------------------------------------------------------------------------- */ -static void _hash(sha256_context *ctx) -{ - register uint32_t a, b, c, d, e, f, g, h, i; - uint32_t t[2]; -#ifndef MINIMIZE_STACK_IMPACT - uint32_t W[64]; -#endif - - a = ctx->hash[0]; - b = ctx->hash[1]; - c = ctx->hash[2]; - d = ctx->hash[3]; - e = ctx->hash[4]; - f = ctx->hash[5]; - g = ctx->hash[6]; - h = ctx->hash[7]; - - for (i = 0; i < 64; i++) { - if ( i < 16 ) - W[i] = _word(&ctx->buf[_shw(i, 2)]); - else - W[i] = _G1(W[i - 2]) + W[i - 7] + _G0(W[i - 15]) + W[i - 16]; - - t[0] = h + _S1(e) + _Ch(e, f, g) + K[i] + W[i]; - t[1] = _S0(a) + _Ma(a, b, c); - h = g; - g = f; - f = e; - e = d + t[0]; - d = c; - c = b; - b = a; - a = t[0] + t[1]; - } - - ctx->hash[0] += a; - ctx->hash[1] += b; - ctx->hash[2] += c; - ctx->hash[3] += d; - ctx->hash[4] += e; - ctx->hash[5] += f; - ctx->hash[6] += g; - ctx->hash[7] += h; -} /* _hash */ - -/* -------------------------------------------------------------------------- */ -void sha256_init(sha256_context *ctx) -{ - if ( ctx != NULL ) { - ctx->bits[0] = ctx->bits[1] = 0; - ctx->len = 0; - ctx->hash[0] = 0x6a09e667; - ctx->hash[1] = 0xbb67ae85; - ctx->hash[2] = 0x3c6ef372; - ctx->hash[3] = 0xa54ff53a; - ctx->hash[4] = 0x510e527f; - ctx->hash[5] = 0x9b05688c; - ctx->hash[6] = 0x1f83d9ab; - ctx->hash[7] = 0x5be0cd19; - } -} /* sha256_init */ - -/* -------------------------------------------------------------------------- */ -void sha256_hash(sha256_context *ctx, const void *data, size_t len) -{ - register size_t i; - const uint8_t *bytes = (const uint8_t *)data; - - if ( (ctx != NULL) && (bytes != NULL) ) - for (i = 0; i < len; i++) { - ctx->buf[ctx->len] = bytes[i]; - ctx->len++; - if (ctx->len == sizeof(ctx->buf) ) { - _hash(ctx); - _addbits(ctx, sizeof(ctx->buf) * 8); - ctx->len = 0; - } - } -} /* sha256_hash */ - -/* -------------------------------------------------------------------------- */ -void sha256_done(sha256_context *ctx, uint8_t *hash) -{ - register uint32_t i, j; - - if ( ctx != NULL ) { - j = ctx->len % sizeof(ctx->buf); - ctx->buf[j] = 0x80; - for (i = j + 1; i < sizeof(ctx->buf); i++) - ctx->buf[i] = 0x00; - - if ( ctx->len > 55 ) { - _hash(ctx); - for (j = 0; j < sizeof(ctx->buf); j++) - ctx->buf[j] = 0x00; - } - - _addbits(ctx, ctx->len * 8); - ctx->buf[63] = _shb(ctx->bits[0], 0); - ctx->buf[62] = _shb(ctx->bits[0], 8); - ctx->buf[61] = _shb(ctx->bits[0], 16); - ctx->buf[60] = _shb(ctx->bits[0], 24); - ctx->buf[59] = _shb(ctx->bits[1], 0); - ctx->buf[58] = _shb(ctx->bits[1], 8); - ctx->buf[57] = _shb(ctx->bits[1], 16); - ctx->buf[56] = _shb(ctx->bits[1], 24); - _hash(ctx); - - if ( hash != NULL ) - for (i = 0, j = 24; i < 4; i++, j -= 8) { - hash[i ] = _shb(ctx->hash[0], j); - hash[i + 4] = _shb(ctx->hash[1], j); - hash[i + 8] = _shb(ctx->hash[2], j); - hash[i + 12] = _shb(ctx->hash[3], j); - hash[i + 16] = _shb(ctx->hash[4], j); - hash[i + 20] = _shb(ctx->hash[5], j); - hash[i + 24] = _shb(ctx->hash[6], j); - hash[i + 28] = _shb(ctx->hash[7], j); - } - } -} /* sha256_done */ - -/* -------------------------------------------------------------------------- */ -void sha256(const void *data, size_t len, uint8_t *hash) -{ - sha256_context ctx; - - sha256_init(&ctx); - sha256_hash(&ctx, data, len); - sha256_done(&ctx, hash); -} /* sha256 */ - - -/* ========================================================================== */ -#ifdef SELF_TEST - -#include -#include - -int main(void) -{ - char *buf[] = { - "", - "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855", - - "abc", - "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad", - - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1", - - "The quick brown fox jumps over the lazy dog", - "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592", - - "The quick brown fox jumps over the lazy cog", /* avalanche effect test */ - "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be", - - "bhn5bjmoniertqea40wro2upyflkydsibsk8ylkmgbvwi420t44cq034eou1szc1k0mk46oeb7ktzmlxqkbte2sy", - "9085df2f 02e0cc45 5928d0f5 1b27b4bf 1d9cd260 a66ed1fd a11b0a3f f5756d99" - }; - uint8_t hash[SHA256_BYTES]; - size_t i, j; - - for (i = 0; i < (sizeof(buf) / sizeof(buf[0])); i += 2) { - sha256(buf[i], strlen(buf[i]), hash); - printf("input = '%s'\ndigest: %s\nresult: ", buf[i], buf[i + 1]); - for (j = 0; j < SHA256_BYTES; j++) - printf("%02x%s", hash[j], ((j % 4) == 3) ? " " : ""); - printf("\n\n"); - } - - return 0; -} /* main */ - -#endif /* def SELF_TEST */ - -#ifdef __cplusplus -} -#endif - diff --git a/mark2/sha256.h b/mark2/sha256.h deleted file mode 100644 index 02de100..0000000 --- a/mark2/sha256.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -* SHA-256 implementation, Mark 2 -* -* Copyright (c) 2010,2014 Ilya O. Levin, http://www.literatecode.com -* -* Permission to use, copy, modify, and distribute this software for any -* purpose with or without fee is hereby granted, provided that the above -* copyright notice and this permission notice appear in all copies. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -#ifndef SHA256_H_ -#define SHA256_H_ - -#include -#ifdef _MSC_VER -#ifndef uint8_t -typedef unsigned __int8 uint8_t; -#endif -#ifndef uint32_t -typedef unsigned __int32 uint32_t; -#endif -#else -#include -#endif - -#define SHA256_BYTES 32 - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef struct { - uint8_t buf[64]; - uint32_t hash[8]; - uint32_t bits[2]; - uint32_t len; -} sha256_context; - -void sha256_init(sha256_context *ctx); -void sha256_hash(sha256_context *ctx, const void *data, size_t len); -void sha256_done(sha256_context *ctx, uint8_t *hash); - -void sha256(const void *data, size_t len, uint8_t *hash); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/sha256.c b/sha256.c index 747cc09..9f7bf2f 100644 --- a/sha256.c +++ b/sha256.c @@ -1,244 +1,327 @@ -/* -* SHA-256 implementation. -* -* Copyright (c) 2010 Ilya O. Levin, http://www.literatecode.com -* -* Permission to use, copy, modify, and distribute this software for any -* purpose with or without fee is hereby granted, provided that the above -* copyright notice and this permission notice appear in all copies. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -#define SWAP_BYTES -// #define USE_STD_MEMCPY -// #define SELF_TEST - -#ifdef USE_STD_MEMCPY -#include -#endif +//usr/bin/env clang -Ofast -Wall -Wextra -pedantic ${0} -o ${0%%.c*} $* ;exit $? +// +// SHA-256 implementation, Mark 2 +// +// Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + #include "sha256.h" +#ifndef _cbmc_ +#define __CPROVER_assume(...) do {} while(0) +#endif + #ifdef __cplusplus extern "C" { #endif -#define RL(x,n) (((x) << n) | ((x) >> (32 - n))) -#define RR(x,n) (((x) >> n) | ((x) << (32 - n))) +#define FN_ static inline __attribute__((const)) -#define S0(x) (RR((x), 2) ^ RR((x),13) ^ RR((x),22)) -#define S1(x) (RR((x), 6) ^ RR((x),11) ^ RR((x),25)) -#define G0(x) (RR((x), 7) ^ RR((x),18) ^ ((x) >> 3)) -#define G1(x) (RR((x),17) ^ RR((x),19) ^ ((x) >> 10)) +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; -#ifdef SWAP_BYTES -#define BSWP(x,y) _bswapw((uint32_t *)(x), (uint32_t)(y)) -#else -#define BSWP(p,n) -#endif -#ifdef USE_STD_MEMCPY -#define MEMCP(x,y,z) memcpy((x),(y),(z)) -#else -#define MEMCP(x,y,z) _memcp((x),(y),(z)) -#endif -#ifndef __cdecl -#define __cdecl -#endif +// ----------------------------------------------------------------------------- +FN_ uint8_t _shb(uint32_t x, uint32_t n) +{ + return ((x >> (n & 31)) & 0xff); +} // _shb -static const uint32_t K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; -/* -------------------------------------------------------------------------- */ -static void _bswapw(uint32_t *p, uint32_t i) +// ----------------------------------------------------------------------------- +FN_ uint32_t _shw(uint32_t x, uint32_t n) { - while (i--) p[i] = (RR(p[i],24) & 0x00ff00ff) | (RR(p[i],8) & 0xff00ff00); + return ((x << (n & 31)) & 0xffffffff); +} // _shw -} /* _bswapw */ -/* -------------------------------------------------------------------------- */ -#ifndef USE_STD_MEMCPY -void * __cdecl _memcp (void *d, const void *s, uint32_t sz) +// ----------------------------------------------------------------------------- +FN_ uint32_t _r(uint32_t x, uint8_t n) { - void *rv = d; + return ((x >> n) | _shw(x, 32 - n)); +} // _r - while (sz--) *(char *)d = *(char *)s, d = (char *)d + 1, s = (char *)s + 1; - return(rv); -} /* _memcp */ -#endif +// ----------------------------------------------------------------------------- +FN_ uint32_t _Ch(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) ^ ((~x) & z)); +} // _Ch -/* -------------------------------------------------------------------------- */ -static void _rtrf(uint32_t *b, uint32_t *p, uint32_t i, uint32_t j) + +// ----------------------------------------------------------------------------- +FN_ uint32_t _Ma(uint32_t x, uint32_t y, uint32_t z) { - #define B(x, y) b[(x-y) & 7] - #define P(x, y) p[(x+y) & 15] + return ((x & y) ^ (x & z) ^ (y & z)); +} // _Ma - B(7,i) += (j ? (p[i & 15] += G1(P(i,14)) + P(i,9) + G0(P(i,1))) : p[i & 15]) - + K[i+j] + S1(B(4,i)) - + (B(6,i) ^ (B(4,i) & (B(5,i) ^ B(6,i)))); - B(3,i) += B(7,i); - B(7,i) += S0(B(0,i)) + ( (B(0,i) & B(1,i)) | (B(2,i) & (B(0,i) ^ B(1,i))) ); - #undef P - #undef B -} /* _rtrf */ +// ----------------------------------------------------------------------------- +FN_ uint32_t _S0(uint32_t x) +{ + return (_r(x, 2) ^ _r(x, 13) ^ _r(x, 22)); +} // _S0 -/* -------------------------------------------------------------------------- */ -static void _hash(sha256_context *ctx) + +// ----------------------------------------------------------------------------- +FN_ uint32_t _S1(uint32_t x) { - uint32_t b[8], *p, j; + return (_r(x, 6) ^ _r(x, 11) ^ _r(x, 25)); +} // _S1 - b[0] = ctx->hash[0]; b[1] = ctx->hash[1]; b[2] = ctx->hash[2]; - b[3] = ctx->hash[3]; b[4] = ctx->hash[4]; b[5] = ctx->hash[5]; - b[6] = ctx->hash[6]; b[7] = ctx->hash[7]; - for (p = ctx->buf, j = 0; j < 64; j += 16) - _rtrf(b, p, 0, j), _rtrf(b, p, 1, j), _rtrf(b, p, 2, j), - _rtrf(b, p, 3, j), _rtrf(b, p, 4, j), _rtrf(b, p, 5, j), - _rtrf(b, p, 6, j), _rtrf(b, p, 7, j), _rtrf(b, p, 8, j), - _rtrf(b, p, 9, j), _rtrf(b, p, 10, j), _rtrf(b, p, 11, j), - _rtrf(b, p, 12, j), _rtrf(b, p, 13, j), _rtrf(b, p, 14, j), - _rtrf(b, p, 15, j); +// ----------------------------------------------------------------------------- +FN_ uint32_t _G0(uint32_t x) +{ + return (_r(x, 7) ^ _r(x, 18) ^ (x >> 3)); +} // _G0 - ctx->hash[0] += b[0]; ctx->hash[1] += b[1]; ctx->hash[2] += b[2]; - ctx->hash[3] += b[3]; ctx->hash[4] += b[4]; ctx->hash[5] += b[5]; - ctx->hash[6] += b[6]; ctx->hash[7] += b[7]; -} /* _hash */ +// ----------------------------------------------------------------------------- +FN_ uint32_t _G1(uint32_t x) +{ + return (_r(x, 17) ^ _r(x, 19) ^ (x >> 10)); +} // _G1 -/* -------------------------------------------------------------------------- */ -void sha256_init(sha256_context *ctx) + +// ----------------------------------------------------------------------------- +FN_ uint32_t _word(uint8_t *c) { - ctx->len[0] = ctx->len[1] = 0; - ctx->hash[0] = 0x6a09e667; ctx->hash[1] = 0xbb67ae85; - ctx->hash[2] = 0x3c6ef372; ctx->hash[3] = 0xa54ff53a; - ctx->hash[4] = 0x510e527f; ctx->hash[5] = 0x9b05688c; - ctx->hash[6] = 0x1f83d9ab; ctx->hash[7] = 0x5be0cd19; + return (_shw(c[0], 24) | _shw(c[1], 16) | _shw(c[2], 8) | (c[3])); +} // _word -} /* sha256_init */ -/* -------------------------------------------------------------------------- */ -void sha256_hash(sha256_context *ctx, uint8_t *dat, uint32_t sz) +// ----------------------------------------------------------------------------- +static void _addbits(sha256_context *ctx, uint32_t n) { - register uint32_t i = ctx->len[0] & 63, l, j; + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); - if ((ctx->len[0] += sz) < sz) ++(ctx->len[1]); + if (ctx->bits[0] > (0xffffffff - n)) { + ctx->bits[1] = (ctx->bits[1] + 1) & 0xFFFFFFFF; + } + ctx->bits[0] = (ctx->bits[0] + n) & 0xFFFFFFFF; +} // _addbits - for (j = 0, l = 64-i; sz >= l; j += l, sz -= l, l = 64, i = 0) - { - MEMCP((char *)ctx->buf + i, &dat[j], l); - BSWP(ctx->buf, 16 ); - _hash(ctx); + +// ----------------------------------------------------------------------------- +static void _hash(sha256_context *ctx) +{ + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + + register uint32_t a, b, c, d, e, f, g, h; + uint32_t t[2]; + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + f = ctx->hash[5]; + g = ctx->hash[6]; + h = ctx->hash[7]; + + for (uint32_t i = 0; i < 64; i++) { + if (i < 16) { + ctx->W[i] = _word(&ctx->buf[_shw(i, 2)]); + } else { + ctx->W[i] = _G1(ctx->W[i - 2]) + ctx->W[i - 7] + + _G0(ctx->W[i - 15]) + ctx->W[i - 16]; + } + + t[0] = h + _S1(e) + _Ch(e, f, g) + K[i] + ctx->W[i]; + t[1] = _S0(a) + _Ma(a, b, c); + h = g; + g = f; + f = e; + e = d + t[0]; + d = c; + c = b; + b = a; + a = t[0] + t[1]; } - MEMCP((char *)ctx->buf + i, &dat[j], sz); -} /* _hash */ + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} // _hash + -/* -------------------------------------------------------------------------- */ -void sha256_done(sha256_context *ctx, uint8_t *buf) +// ----------------------------------------------------------------------------- +void sha256_init(sha256_context *ctx) { - uint32_t i = (uint32_t)(ctx->len[0] & 63), j = ((~i) & 3) << 3; + if (ctx != NULL) { + ctx->bits[0] = ctx->bits[1] = ctx->len = 0; + ctx->hash[0] = 0x6a09e667; + ctx->hash[1] = 0xbb67ae85; + ctx->hash[2] = 0x3c6ef372; + ctx->hash[3] = 0xa54ff53a; + ctx->hash[4] = 0x510e527f; + ctx->hash[5] = 0x9b05688c; + ctx->hash[6] = 0x1f83d9ab; + ctx->hash[7] = 0x5be0cd19; + } +} // sha256_init - BSWP(ctx->buf, (i + 3) >> 2); - ctx->buf[i >> 2] &= 0xffffff80 << j; /* add padding */ - ctx->buf[i >> 2] |= 0x00000080 << j; +// ----------------------------------------------------------------------------- +void sha256_hash(sha256_context *ctx, const void *data, size_t len) +{ + const uint8_t *bytes = (const uint8_t *)data; + + if ((ctx != NULL) && (bytes != NULL) && (ctx->len < sizeof(ctx->buf))) { + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(bytes)); + __CPROVER_assume(__CPROVER_DYNAMIC_OBJECT(ctx)); + for (size_t i = 0; i < len; i++) { + ctx->buf[ctx->len++] = bytes[i]; + if (ctx->len == sizeof(ctx->buf)) { + _hash(ctx); + _addbits(ctx, sizeof(ctx->buf) * 8); + ctx->len = 0; + } + } + } +} // sha256_hash - if (i < 56) i = (i >> 2) + 1; - else ctx->buf[15] ^= (i < 60) ? ctx->buf[15] : 0, _hash(ctx), i = 0; - while (i < 14) ctx->buf[i++] = 0; +// ----------------------------------------------------------------------------- +void sha256_done(sha256_context *ctx, uint8_t *hash) +{ + register uint32_t i, j; + + if (ctx != NULL) { + j = ctx->len % sizeof(ctx->buf); + ctx->buf[j] = 0x80; + for (i = j + 1; i < sizeof(ctx->buf); i++) { + ctx->buf[i] = 0x00; + } + + if (ctx->len > 55) { + _hash(ctx); + for (j = 0; j < sizeof(ctx->buf); j++) { + ctx->buf[j] = 0x00; + } + } + + _addbits(ctx, ctx->len * 8); + ctx->buf[63] = _shb(ctx->bits[0], 0); + ctx->buf[62] = _shb(ctx->bits[0], 8); + ctx->buf[61] = _shb(ctx->bits[0], 16); + ctx->buf[60] = _shb(ctx->bits[0], 24); + ctx->buf[59] = _shb(ctx->bits[1], 0); + ctx->buf[58] = _shb(ctx->bits[1], 8); + ctx->buf[57] = _shb(ctx->bits[1], 16); + ctx->buf[56] = _shb(ctx->bits[1], 24); + _hash(ctx); - ctx->buf[14] = (ctx->len[1] << 3)|(ctx->len[0] >> 29); /* add length */ - ctx->buf[15] = ctx->len[0] << 3; + if (hash != NULL) { + for (i = 0, j = 24; i < 4; i++, j -= 8) { + hash[i + 0] = _shb(ctx->hash[0], j); + hash[i + 4] = _shb(ctx->hash[1], j); + hash[i + 8] = _shb(ctx->hash[2], j); + hash[i + 12] = _shb(ctx->hash[3], j); + hash[i + 16] = _shb(ctx->hash[4], j); + hash[i + 20] = _shb(ctx->hash[5], j); + hash[i + 24] = _shb(ctx->hash[6], j); + hash[i + 28] = _shb(ctx->hash[7], j); + } + } + } +} // sha256_done - _hash(ctx); - for (i = 0; i < 32; i++) - ctx->buf[i % 16] = 0, /* may remove this line in case of a DIY cleanup */ - buf[i] = (uint8_t)(ctx->hash[i >> 2] >> ((~i & 3) << 3)); +// ----------------------------------------------------------------------------- +void sha256(const void *data, size_t len, uint8_t *hash) +{ + sha256_context ctx; -} /* sha256_done */ + sha256_init(&ctx); + sha256_hash(&ctx, data, len); + sha256_done(&ctx, hash); +} // sha256 -#ifdef SELF_TEST -#pragma warning (push, 0) +#if 0 +#pragma mark - Self Test +#endif +#ifdef SHA256_SELF_TEST__ #include -#include #include -#pragma warning(pop) -char *buf[] = { - "", - "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855", +int main(void) +{ + char *buf[] = { + "", + "e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855", - "abc", - "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad", + "abc", + "ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad", - "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1", - "The quick brown fox jumps over the lazy dog", - "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592", + "The quick brown fox jumps over the lazy dog", + "d7a8fbb3 07d78094 69ca9abc b0082e4f 8d5651e4 6d3cdb76 2d02d0bf 37c9e592", - "The quick brown fox jumps over the lazy cog", /* avalanche effect test */ - "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be", + "The quick brown fox jumps over the lazy cog", // avalanche effect test + "e4c4d8f3 bf76b692 de791a17 3e053211 50f7a345 b46484fe 427f6acc 7ecc81be", - "bhn5bjmoniertqea40wro2upyflkydsibsk8ylkmgbvwi420t44cq034eou1szc1k0mk46oeb7ktzmlxqkbte2sy", - "9085df2f 02e0cc45 5928d0f5 1b27b4bf 1d9cd260 a66ed1fd a11b0a3f f5756d99" -}; + "bhn5bjmoniertqea40wro2upyflkydsibsk8ylkmgbvwi420t44cq034eou1szc1k0mk46oeb7ktzmlxqkbte2sy", + "9085df2f 02e0cc45 5928d0f5 1b27b4bf 1d9cd260 a66ed1fd a11b0a3f f5756d99" + }; + const size_t tests_total = sizeof(buf) / sizeof(buf[0]); + uint8_t hash[SHA256_SIZE_BYTES]; -int main(int argc, char *argv[]) -{ - sha256_context ctx; - uint8_t hv[32]; - uint32_t i, j; - - for (j = 0; j < (sizeof(buf)/sizeof(buf[0])); j += 2) - { - sha256_init(&ctx); - sha256_hash(&ctx, (uint8_t *)buf[j], (uint32_t)strlen(buf[j])); - sha256_done(&ctx, hv); - printf("input = %s\ndigest: %s\nresult: ", buf[j], buf[j+1]); - for (i = 0; i < 32; i++) printf("%02x%s", hv[i], ((i%4)==3)?" ":""); - printf("\n\n"); + if (0 != (tests_total % 2)) { + return printf("invalid tests\n"); } - for (j = 1; j < (uint32_t)argc; j++) - { - printf("argv[%d]: %s\nresult: ", (int)j, argv[j]); - sha256_init(&ctx); - sha256_hash(&ctx, (uint8_t *)argv[j], (uint32_t)strlen(argv[j])); - sha256_done(&ctx, hv); - for (i = 0; i < 32; i++) printf("%02x%s", hv[i], ((i%4)==3)?" ":""); + for (size_t i = 0; i < tests_total; i += 2) { + sha256(buf[i], strlen(buf[i]), hash); + printf("input = '%s'\ndigest: %s\nresult: ", buf[i], buf[i + 1]); + for (size_t j = 0; j < SHA256_SIZE_BYTES; j++) { + printf("%02x%s", hash[j], ((j % 4) == 3) ? " " : ""); + } printf("\n\n"); } return 0; -} /* main */ -#endif +} // main + +#endif // def SHA256_SELF_TEST__ #ifdef __cplusplus } diff --git a/sha256.h b/sha256.h index e19e56b..6df116b 100644 --- a/sha256.h +++ b/sha256.h @@ -1,50 +1,52 @@ -/* -* SHA-256 implementation. -* -* Copyright (c) 2010 Ilya O. Levin, http://www.literatecode.com -* -* Permission to use, copy, modify, and distribute this software for any -* purpose with or without fee is hereby granted, provided that the above -* copyright notice and this permission notice appear in all copies. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -#ifdef _MSC_VER -#ifndef uint8_t -typedef unsigned __int8 uint8_t; -#endif -#ifndef uint32_t -typedef unsigned __int32 uint32_t; -#endif -#ifndef uint64_t -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#endif -#else +// +// SHA-256 implementation, Mark 2 +// +// Copyright (c) 2010,2014 Literatecode, http://www.literatecode.com +// Copyright (c) 2022 Ilia Levin (ilia@levin.sg) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// + +#ifndef SHA256_H_ +#define SHA256_H_ + +#include #include -#endif + +#define SHA256_SIZE_BYTES (32) #ifdef __cplusplus extern "C" { #endif - typedef struct { - uint32_t buf[16]; - uint32_t hash[8]; - uint32_t len[2]; - } sha256_context; +typedef struct { + uint8_t buf[64]; + uint32_t hash[8]; + uint32_t bits[2]; + uint32_t len; + uint32_t rfu__; + uint32_t W[64]; +} sha256_context; + +void sha256_init(sha256_context *ctx); +void sha256_hash(sha256_context *ctx, const void *data, size_t len); +void sha256_done(sha256_context *ctx, uint8_t *hash); - void sha256_init(sha256_context *); - void sha256_hash(sha256_context *, uint8_t * /* data */, uint32_t /* len */); - void sha256_done(sha256_context *, uint8_t * /* hash */); +void sha256(const void *data, size_t len, uint8_t *hash); #ifdef __cplusplus } #endif + +#endif