From b4157181bcf941e3578e58e2ba8cbb87252e76fe Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Mon, 29 Jun 2020 15:09:14 -0700 Subject: [PATCH] src/lt256: include, build and install ltsha256 utility It's tempting to use Git's `git hash-object --stdin` function to generate hash "signature"s. It's easy, it's already guaranteed to be present and it appears to be reasonably fast. But it has issues: 1) The "git" executable is rather large and performs a bunch of unwanted setup that's irrelevant to computing a hash 2) The `git hash-object --stdin` operation creates a Git "blob" which requires the total length of the data being hashed be known in advance since the length ends up embedded at the beginning of a Git "blob" 3) The `--stdin` option to `git hash-object` causes the entire input from a pipe to first be collected in an ever-expanding memory buffer until EOF is reached at which point the length becomes known and the hash is finally computed. 4) The sha-1 hash that Git uses has been outdated and "broken" for several years now. At first glance, there doesn't seem to be an obvious alternative without requiring yet another dependency for Girocco. The LibTomCrypt code has a very liberal license that is fully compatible with GPLv2. Include the extracted sha256 computation code from LibTomCrypt and a simple utility to compute the hexadecimal sha256 hash of the input stream using the LibTomCrypt sha256 code. Test and install this utility during normal Girocco installation. The `ltsha256` utility runs plenty fast enough, does no extra unwanted setup and has extremely low memory use since it hashes the input as it reads it (no need to know the length in advance). Signed-off-by: Kyle J. McKay --- install.sh | 14 +- src/.gitignore | 3 + src/GNUmakefile | 9 +- src/lt256-LICENSE.txt | 29 ++++ src/lt256.c | 405 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lt256.h | 32 ++++ src/ltsha256-test.sh | 46 ++++++ src/ltsha256.c | 54 +++++++ 8 files changed, 590 insertions(+), 2 deletions(-) create mode 100644 src/lt256-LICENSE.txt create mode 100644 src/lt256.c create mode 100644 src/lt256.h create mode 100755 src/ltsha256-test.sh create mode 100644 src/ltsha256.c diff --git a/install.sh b/install.sh index 9eeb8de..f7d545a 100755 --- a/install.sh +++ b/install.sh @@ -172,6 +172,18 @@ if ! [ -f src/ulimit512 ] || ! [ -x src/ulimit512 ]; then echo "ERROR: perhaps you forgot to run make?" >&2 exit 1 fi +if ! [ -f src/ltsha256 ] || ! [ -x src/ltsha256 ]; then + echo "ERROR: src/ltsha256 is not built! Did you _REALLY_ read INSTALL?" >&2 + echo "ERROR: perhaps you forgot to run make?" >&2 + exit 1 +fi +sha256check="15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225" +sha256result="$(printf '%s' '123456789' | src/ltsha256)" +if [ "$sha256check" != "$sha256result" ]; then + echo "ERROR: src/ltsha256 is built, but broken!" >&2 + echo "ERROR: verifying sha256 hash of '123456789' failed!" >&2 + exit 1 +fi echo "*** Checking for ezcert..." @@ -599,7 +611,7 @@ cp cgi/*.cgi "$basedir/cgi" cp -pR Girocco jobd taskd html jobs toolbox hooks apache.conf shlib.sh bin screen "$basedir" find -H "$basedir" -type l -exec rm -f '{}' + cp -p src/can_user_push src/can_user_push_http src/get_user_uuid src/list_packs src/peek_packet \ - src/rangecgi src/readlink src/strftime src/throttle src/ulimit512 \ + src/rangecgi src/readlink src/strftime src/throttle src/ulimit512 src/ltsha256 \ ezcert.git/CACreateCert cgi/authrequired.cgi cgi/snapshot.cgi \ "$basedir/bin" cp -p gitweb/*.sh gitweb/*.perl "$basedir/gitweb" diff --git a/src/.gitignore b/src/.gitignore index 0372570..b321c54 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -17,6 +17,9 @@ list_packs.d* list_packs.o* list_packs.inc list_packs +ltsha256.d* +ltsha256.o* +ltsha256 peek_packet.d* peek_packet.o* peek_packet diff --git a/src/GNUmakefile b/src/GNUmakefile index c9b2b94..184cc5a 100644 --- a/src/GNUmakefile +++ b/src/GNUmakefile @@ -4,7 +4,7 @@ CFLAGS ?= -O .PHONY : all clean install FORCE all : can_user_push can_user_push_http getent get_user_uuid list_packs \ - peek_packet rangecgi readlink strftime throttle ulimit512 + peek_packet rangecgi readlink strftime throttle ulimit512 ltsha256 clean : rm -rf can_user_push.o* can_user_push.d* can_user_push @@ -18,10 +18,14 @@ clean : rm -rf strftime.o* strftime.d* strftime rm -rf throttle.o* throttle.d* throttle rm -rf ulimit512.o* ulimit512.d* ulimit512 + rm -rf ltsha256.o* ltsha256.d* ltsha256 rm -f GROUP-FILE PASSWD-FILE SOCKET-FILE install : +test : ltsha256 + ./ltsha256-test.sh | awk 'BEGIN{c=0} {print} /^ok [0-9]/{++c} END{if(NR!=c+1)exit 1}' + TRACK_GROUP_FILE := $(shell cd .. && . ./shlib.sh && echo "$$cfg_chroot/etc/group") export TRACK_GROUP_FILE TRACK_PASSWD_FILE := $(shell cd .. && . ./shlib.sh && echo "$$cfg_chroot/etc/passwd") @@ -82,3 +86,6 @@ throttle : throttle.c SOCKET-FILE ulimit512 : ulimit512.c $(CC) -o $@ $(CFLAGS) ulimit512.c + +ltsha256 : ltsha256.c lt256.h lt256.c + $(CC) -o $@ $(CFLAGS) ltsha256.c diff --git a/src/lt256-LICENSE.txt b/src/lt256-LICENSE.txt new file mode 100644 index 0000000..c4afbc6 --- /dev/null +++ b/src/lt256-LICENSE.txt @@ -0,0 +1,29 @@ +LibTomCrypt is licensed under DUAL licensing terms. + +Choose and use the license of your needs. + +[LICENSE #1] + +LibTomCrypt is public domain. As should all quality software be. + +Tom St Denis + +[/LICENSE #1] + +[LICENSE #2] + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + + Copyright (C) 2004 Sam Hocevar + + Everyone is permitted to copy and distribute verbatim or modified + copies of this license document, and changing it is allowed as long + as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +[/LICENSE #2] diff --git a/src/lt256.c b/src/lt256.c new file mode 100644 index 0000000..79039e9 --- /dev/null +++ b/src/lt256.c @@ -0,0 +1,405 @@ +/* LibTomCrypt, modular cryptographic library -- 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. + * + * License: public domain -or- http://www.wtfpl.net/txt/copying/ + */ + +/** + @file sha256.c + LTC_SHA256 by Tom St Denis +*/ + +#include "lt256.h" +#include +#include + +#ifndef MIN + #define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#endif + +#define CRYPT_OK 1 +#define hash_state SHA256_CTX +#define sha256_init SHA256_Init +#define sha256_process SHA256_Update +#define sha256_done SHA256_Final + +#define STORE32H(x, y) \ + do { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } while(0) + +#define LOAD32H(x, y) \ + do { x = ((uint32_t)((y)[0] & 255)<<24) | \ + ((uint32_t)((y)[1] & 255)<<16) | \ + ((uint32_t)((y)[2] & 255)<<8) | \ + ((uint32_t)((y)[3] & 255)); } while(0) + +#define STORE64H(x, y) \ +do { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } while(0) + +/* 32-bit Rotates */ +#if defined(_MSC_VER) +#define LTC_ROx_BUILTIN + +/* instrinsic rotate */ +#include +#pragma intrinsic(_rotr,_rotl) +#define ROR(x,n) _rotr(x,n) +#define RORc(x,n) ROR(x,n) + +#elif defined(LTC_HAVE_ROTATE_BUILTIN) +#define LTC_ROx_BUILTIN + +#define ROR(x,n) __builtin_rotateright32(x,n) +#define RORc(x,n) ROR(x,n) + +#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM) +#define LTC_ROx_ASM + +static inline uint32_t ROR(uint32_t word, int i) +{ + asm ("rorl %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +#ifndef LTC_NO_ROLC + +#define RORc(word,i) ({ \ + uint32_t __RORc_tmp = (word); \ + __asm__ ("rorl %2, %0" : \ + "=r" (__RORc_tmp) : \ + "0" (__RORc_tmp), \ + "I" (i)); \ + __RORc_tmp; \ + }) + +#else + +#define RORc ROR + +#endif + +#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32) +#define LTC_ROx_ASM + +static inline uint32_t ROR(uint32_t word, int i) +{ + asm ("rotlw %0,%0,%2" + :"=r" (word) + :"0" (word),"r" (32-i)); + return word; +} + +#ifndef LTC_NO_ROLC + +static inline uint32_t RORc(uint32_t word, const int i) +{ + asm ("rotrwi %0,%0,%2" + :"=r" (word) + :"0" (word),"I" (i)); + return word; +} + +#else + +#define RORc ROR + +#endif + +#else + +/* rotates the hard way */ +#define ROR(x, y) ( ((((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((y)&31)) | ((uint32_t)(x)<<(uint32_t)((32-((y)&31))&31))) & 0xFFFFFFFFUL) +#define RORc(x, y) ( ((((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((y)&31)) | ((uint32_t)(x)<<(uint32_t)((32-((y)&31))&31))) & 0xFFFFFFFFUL) + +#endif + +/* a simple macro for making hash "process" functions */ +#define HASH_PROCESS(func_name, compress_name, block_size) \ +int func_name(hash_state *md, const void *_in, size_t inlen) \ +{ \ + const unsigned char *in = (const unsigned char *)_in; \ + size_t n; \ + int err; \ + if (!md || !in) return 0; \ + if (md->curlen > sizeof(md->buf)) { \ + return 0; \ + } \ + if ((md->length + inlen) < md->length) { \ + return 0; \ + } \ + while (inlen > 0) { \ + if (md->curlen == 0 && inlen >= block_size) { \ + if ((err = compress_name(md, in)) != CRYPT_OK) { \ + return err; \ + } \ + md->length += block_size * 8; \ + in += block_size; \ + inlen -= block_size; \ + } else { \ + n = MIN(inlen, (block_size - md->curlen)); \ + memcpy(md->buf + md->curlen, in, (size_t)n); \ + md->curlen += n; \ + in += n; \ + inlen -= n; \ + if (md->curlen == block_size) { \ + if ((err = compress_name(md, md->buf)) != CRYPT_OK) { \ + return err; \ + } \ + md->length += 8*block_size; \ + md->curlen = 0; \ + } \ + } \ + } \ + return CRYPT_OK; \ +} + +#ifdef LTC_SMALL_CODE +/* the K array */ +static const uint32_t K[64] = { + 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 +}; +#endif + +/* Various logical functions */ +#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)) + +/* compress 512-bits */ +static int sha256_compress(hash_state *md, const unsigned char *buf) +{ + uint32_t S[8], W[64], t0, t1; +#ifdef LTC_SMALL_CODE + uint32_t t; +#endif + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], buf + (4*i)); + } + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + + /* Compress */ +#ifdef LTC_SMALL_CODE +#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 < 64; ++i) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } +#else +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + +#endif + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + return CRYPT_OK; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha256_init(hash_state *md) +{ + if (!md) return 0; + + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; + return CRYPT_OK; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +HASH_PROCESS(sha256_process, sha256_compress, 64) + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +int sha256_done(unsigned char *out, hash_state *md) +{ + int i; + + if (!md || !out) return 0; + + if (md->curlen >= sizeof(md->buf)) { + return 0; + } + + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < 64) { + md->buf[md->curlen++] = (unsigned char)0; + } + sha256_compress(md, md->buf); + md->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->length, md->buf+56); + sha256_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE32H(md->state[i], out+(4*i)); + } + return CRYPT_OK; +} + +unsigned char *SHA256(const void *data, size_t len, unsigned char *md) +{ + SHA256_CTX c; + + if (!SHA256_Init(&c)) return NULL; + if (!SHA256_Update(&c, data, len)) return NULL; + if (!SHA256_Final(md, &c)) return NULL; + return md; +} diff --git a/src/lt256.h b/src/lt256.h new file mode 100644 index 0000000..8c7584a --- /dev/null +++ b/src/lt256.h @@ -0,0 +1,32 @@ +/* License: public domain -or- http://www.wtfpl.net/txt/copying/ */ + +#ifndef LT256_H +#define LT256_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA256_DIGEST_LENGTH 32 + +typedef struct SHA256_CTX { + uint64_t length; + uint32_t state[8], curlen; + unsigned char buf[64]; + /*const void *data; */ +} SHA256_CTX; + +/* return value is non-zero/non-NULL on success */ +extern int SHA256_Init(SHA256_CTX *c); +extern int SHA256_Update(SHA256_CTX *c, const void *data, size_t len); +extern int SHA256_Final(unsigned char *md, SHA256_CTX *c); +extern unsigned char *SHA256(const void *data, size_t len, unsigned char *md); + +#ifdef __cplusplus +} +#endif + +#endif /* LT256_H */ diff --git a/src/ltsha256-test.sh b/src/ltsha256-test.sh new file mode 100755 index 0000000..359391d --- /dev/null +++ b/src/ltsha256-test.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +# License: public domain -or- http://www.wtfpl.net/txt/copying/ + +die() { >&2 printf 'Bail out! %s\n' "$*"; exit 1; } + +testnum=0 + +# $1 => value to hash (may contain escapes) +# $2 => lowercase sha256 hash expected +# $3... => test name +test_sha256() { + _val="$1"; shift + _hash="$1"; shift + _test="$*" + _check="$(printf '%b' "$_val" | ./ltsha256)" || + die "could not run ltsha256 utility" + _result="ok" + [ "$_check" = "$_hash" ] || _result="not ok" + testnum="$(( $testnum + 1 ))" + printf '%s %u - %s\n' "$_result" "$testnum" "$_test" +} + +echo '1..4' + +test_sha256 \ + "abc" \ + ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad \ + abc + +test_sha256 \ + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" \ + 248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1 \ + abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq + +test_sha256 \ + "123456789" \ + 15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225 \ + 123456789 + +test_sha256 \ + "The quick brown fox jumped over the lazy dog.\n" \ + 40d5c6f7fe5672fb52269f651c2b985867dfcfa4a5c5258e3d4f8736d5095037 \ + "quick brown fox" + +exit 0 diff --git a/src/ltsha256.c b/src/ltsha256.c new file mode 100644 index 0000000..83e8d56 --- /dev/null +++ b/src/ltsha256.c @@ -0,0 +1,54 @@ +/* License: public domain -or- http://www.wtfpl.net/txt/copying/ */ + +#include "lt256.h" +#include +#include +#include +#include + +#define READSIZE 32768 + +static const char hextab[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; +static char buffer[READSIZE]; + +int main(int arc, char *argv[]) +{ + SHA256_CTX c; + unsigned char md[SHA256_DIGEST_LENGTH]; + char mdhex[(2*SHA256_DIGEST_LENGTH)+1]; + ssize_t e; + unsigned i; + + if (!SHA256_Init(&c)) + return EXIT_FAILURE; + + for (;;) { + do { + e = read(STDIN_FILENO, buffer, READSIZE); + } while (e == -1 && + (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); + if (e < 0) + return EXIT_FAILURE; + if (!e) + break; + if (!SHA256_Update(&c, buffer, (size_t)e)) + return EXIT_FAILURE; + } + if (!SHA256_Final(md, &c)) + return 0; + for (i=0; i < SHA256_DIGEST_LENGTH; ++i) { + unsigned char c = md[i]; + mdhex[i<<1] = hextab[c >> 4]; + mdhex[(i<<1)+1] = hextab[c & 0xf]; + } + mdhex[2*SHA256_DIGEST_LENGTH] = '\0'; + if (puts(mdhex) < 0) + return EXIT_FAILURE; + + return 0; +} + +#include "lt256.c" -- 2.11.4.GIT