From 57c789cf8fe57ee01ab00f3d8b35794ac08f8069 Mon Sep 17 00:00:00 2001 From: "Kyle J. McKay" Date: Tue, 12 Jan 2021 21:17:45 -0700 Subject: [PATCH] src/lt1: include, build and test ltsha1 utility Prepare for future use of the LibTomCrypt SHA-1 implementation by including it along with a test program and script in a similar fashion to the way the LibTomCrypt SHA-256 implementation has been included. Although the standalone ltsha1 utility is not expected to be used directly (and is not installed by install.sh), it provides a means to test the implementation to verify that it's working correctly which install.sh does. Add the test script to the scripts run by "make test" in the src subdirectory. The LibTomCrypt code has a very liberal license that is fully compatible with GPLv2. Signed-off-by: Kyle J. McKay --- install.sh | 12 ++ src/.gitignore | 3 + src/GNUmakefile | 9 +- src/lt1.c | 359 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lt1.h | 32 +++++ src/ltsha1-test.sh | 46 +++++++ src/ltsha1.c | 54 ++++++++ 7 files changed, 513 insertions(+), 2 deletions(-) create mode 100644 src/lt1.c create mode 100644 src/lt1.h create mode 100755 src/ltsha1-test.sh create mode 100644 src/ltsha1.c diff --git a/install.sh b/install.sh index 1dc3ce0..31455ae 100755 --- a/install.sh +++ b/install.sh @@ -215,6 +215,18 @@ if [ "$sha256check" != "$sha256result" ]; then echo "ERROR: verifying sha256 hash of '123456789' failed!" >&2 exit 1 fi +if ! [ -f src/ltsha1 ] || ! [ -x src/ltsha1 ]; then + echo "ERROR: src/ltsha1 is not built! Did you _REALLY_ read INSTALL?" >&2 + echo "ERROR: perhaps you forgot to run make?" >&2 + exit 1 +fi +sha1check="f7c3bc1d808e04732adf679965ccc34ca7ae3441" +sha1result="$(printf '%s' '123456789' | src/ltsha1)" +if [ "$sha1check" != "$sha1result" ]; then + echo "ERROR: src/ltsha1 is built, but broken!" >&2 + echo "ERROR: verifying sha1 hash of '123456789' failed!" >&2 + exit 1 +fi var_sun_path_len="$(src/get_sun_path_len 2>/dev/null)" || : if [ -z "$var_sun_path_len" ] || diff --git a/src/.gitignore b/src/.gitignore index 8907e5c..5b4e1a7 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -21,6 +21,9 @@ list_packs.d* list_packs.o* list_packs.inc list_packs +ltsha1.d* +ltsha1.o* +ltsha1 ltsha256.d* ltsha256.o* ltsha256 diff --git a/src/GNUmakefile b/src/GNUmakefile index 1706f7e..f0ed114 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_sun_path_len get_user_uuid \ - list_packs peek_packet rangecgi readlink strftime throttle ulimit512 ltsha256 + list_packs peek_packet rangecgi readlink strftime throttle ulimit512 ltsha256 ltsha1 clean : rm -rf can_user_push.o* can_user_push.d* can_user_push @@ -20,12 +20,14 @@ clean : rm -rf throttle.o* throttle.d* throttle rm -rf ulimit512.o* ulimit512.d* ulimit512 rm -rf ltsha256.o* ltsha256.d* ltsha256 + rm -rf ltsha1.o* ltsha1.d* ltsha1 rm -f config.h GROUP-FILE PASSWD-FILE SOCKET-FILE install : -test : ltsha256 +test : ltsha256 ltsha1 ./ltsha256-test.sh | awk 'BEGIN{c=0} {print} /^ok [0-9]/{++c} END{if(NR!=c+1)exit 1}' + ./ltsha1-test.sh | awk 'BEGIN{c=0} {print} /^ok [0-9]/{++c} END{if(NR!=c+1)exit 1}' GET_CONFIG = cd .. && test ! -f config.sh || . ./config.sh && . ./shlib.sh @@ -98,3 +100,6 @@ ulimit512 : ulimit512.c ltsha256 : ltsha256.c lt256.h lt256.c $(CC) -o $@ $(CFLAGS) ltsha256.c + +ltsha1 : ltsha1.c lt1.h lt1.c + $(CC) -o $@ $(CFLAGS) ltsha1.c diff --git a/src/lt1.c b/src/lt1.c new file mode 100644 index 0000000..3351fd9 --- /dev/null +++ b/src/lt1.c @@ -0,0 +1,359 @@ +/* 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 sha1.c + LTC_SHA1 code by Tom St Denis +*/ + +#include "lt1.h" +#include +#include + +#ifndef MIN + #define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#endif + +#define CRYPT_OK 1 +#define hash_state SHA1_CTX +#define sha1_init SHA1_Init +#define sha1_process SHA1_Update +#define sha1_done SHA1_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 ROL(x,n) _rotl(x,n) +#define ROLc(x,n) ROL(x,n) + +#elif defined(LTC_HAVE_ROTATE_BUILTIN) +#define LTC_ROx_BUILTIN + +#define ROL(x,n) __builtin_rotateleft32(x,n) +#define ROLc(x,n) ROL(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 ROL(uint32_t word, int i) +{ + asm ("roll %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +#ifndef LTC_NO_ROLC + +#define ROLc(word,i) ({ \ + uint32_t ROLc_tmp = (word); \ + __asm__ ("roll %2, %0" : \ + "=r" (ROLc_tmp) : \ + "0" (ROLc_tmp), \ + "I" (i)); \ + ROLc_tmp; \ + }) + +#else + +#define ROLc ROL + +#endif + +#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32) +#define LTC_ROx_ASM + +static inline uint32_t ROL(uint32_t word, int i) +{ + asm ("rotlw %0,%0,%2" + :"=r" (word) + :"0" (word),"r" (i)); + return word; +} + +#ifndef LTC_NO_ROLC + +static inline uint32_t ROLc(uint32_t word, const int i) +{ + asm ("rotlwi %0,%0,%2" + :"=r" (word) + :"0" (word),"I" (i)); + return word; +} + +#else + +#define ROLc ROL + +#endif + +#else + +/* rotates the hard way */ +#define ROL(x, y) ( (((uint32_t)(x)<<(uint32_t)((y)&31)) | (((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((32-((y)&31))&31))) & 0xFFFFFFFFUL) +#define ROLc(x, y) ( (((uint32_t)(x)<<(uint32_t)((y)&31)) | (((uint32_t)(x)&0xFFFFFFFFUL)>>(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; \ +} + +#define F0(x,y,z) (z ^ (x & (y ^ z))) +#define F1(x,y,z) (x ^ y ^ z) +#define F2(x,y,z) ((x & y) | (z & (x | y))) +#define F3(x,y,z) (x ^ y ^ z) + +static int sha1_compress(hash_state *md, const unsigned char *buf) +{ + uint32_t a,b,c,d,e,W[80],i; +#ifdef LTC_SMALL_CODE + uint32_t t; +#endif + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], buf + (4*i)); + } + + /* copy state */ + a = md->state[0]; + b = md->state[1]; + c = md->state[2]; + d = md->state[3]; + e = md->state[4]; + + /* expand it */ + for (i = 16; i < 80; i++) { + W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); + } + + /* compress */ + /* round one */ + #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30); + #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30); + #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30); + #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30); + +#ifdef LTC_SMALL_CODE + + for (i = 0; i < 20; ) { + FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 40; ) { + FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 60; ) { + FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + + for (; i < 80; ) { + FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; + } + +#else + + for (i = 0; i < 20; ) { + FF0(a,b,c,d,e,i++); + FF0(e,a,b,c,d,i++); + FF0(d,e,a,b,c,i++); + FF0(c,d,e,a,b,i++); + FF0(b,c,d,e,a,i++); + } + + /* round two */ + for (; i < 40; ) { + FF1(a,b,c,d,e,i++); + FF1(e,a,b,c,d,i++); + FF1(d,e,a,b,c,i++); + FF1(c,d,e,a,b,i++); + FF1(b,c,d,e,a,i++); + } + + /* round three */ + for (; i < 60; ) { + FF2(a,b,c,d,e,i++); + FF2(e,a,b,c,d,i++); + FF2(d,e,a,b,c,i++); + FF2(c,d,e,a,b,i++); + FF2(b,c,d,e,a,i++); + } + + /* round four */ + for (; i < 80; ) { + FF3(a,b,c,d,e,i++); + FF3(e,a,b,c,d,i++); + FF3(d,e,a,b,c,i++); + FF3(c,d,e,a,b,i++); + FF3(b,c,d,e,a,i++); + } +#endif + + #undef FF0 + #undef FF1 + #undef FF2 + #undef FF3 + + /* store */ + md->state[0] = md->state[0] + a; + md->state[1] = md->state[1] + b; + md->state[2] = md->state[2] + c; + md->state[3] = md->state[3] + d; + md->state[4] = md->state[4] + e; + + return CRYPT_OK; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha1_init(hash_state *md) +{ + if (!md) return 0; + + md->curlen = 0; + md->length = 0; + md->state[0] = 0x67452301UL; + md->state[1] = 0xefcdab89UL; + md->state[2] = 0x98badcfeUL; + md->state[3] = 0x10325476UL; + md->state[4] = 0xc3d2e1f0UL; + 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(sha1_process, sha1_compress, 64) + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (20 bytes) + @return CRYPT_OK if successful +*/ +int sha1_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; + } + sha1_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); + sha1_compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 5; i++) { + STORE32H(md->state[i], out+(4*i)); + } + return CRYPT_OK; +} + +unsigned char *SHA1(const void *data, size_t len, unsigned char *md) +{ + SHA1_CTX c; + + if (!SHA1_Init(&c)) return NULL; + if (!SHA1_Update(&c, data, len)) return NULL; + if (!SHA1_Final(md, &c)) return NULL; + return md; +} diff --git a/src/lt1.h b/src/lt1.h new file mode 100644 index 0000000..7324461 --- /dev/null +++ b/src/lt1.h @@ -0,0 +1,32 @@ +/* License: public domain -or- http://www.wtfpl.net/txt/copying/ */ + +#ifndef LT1_H +#define LT1_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA1_DIGEST_LENGTH 20 + +typedef struct SHA1_CTX { + uint64_t length; + uint32_t state[5], curlen; + unsigned char buf[64]; + /*const void *data; */ +} SHA1_CTX; + +/* return value is non-zero/non-NULL on success */ +extern int SHA1_Init(SHA1_CTX *c); +extern int SHA1_Update(SHA1_CTX *c, const void *data, size_t len); +extern int SHA1_Final(unsigned char *md, SHA1_CTX *c); +extern unsigned char *SHA1(const void *data, size_t len, unsigned char *md); + +#ifdef __cplusplus +} +#endif + +#endif /* LT1_H */ diff --git a/src/ltsha1-test.sh b/src/ltsha1-test.sh new file mode 100755 index 0000000..1aab5e6 --- /dev/null +++ b/src/ltsha1-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_sha1() { + _val="$1"; shift + _hash="$1"; shift + _test="$*" + _check="$(printf '%b' "$_val" | ./ltsha1)" || + die "could not run ltsha1 utility" + _result="ok" + [ "$_check" = "$_hash" ] || _result="not ok" + testnum="$(( $testnum + 1 ))" + printf '%s %u - %s\n' "$_result" "$testnum" "$_test" +} + +echo '1..4' + +test_sha1 \ + "abc" \ + a9993e364706816aba3e25717850c26c9cd0d89d \ + abc + +test_sha1 \ + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" \ + 84983e441c3bd26ebaae4aa1f95129e5e54670f1 \ + abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq + +test_sha1 \ + "123456789" \ + f7c3bc1d808e04732adf679965ccc34ca7ae3441 \ + 123456789 + +test_sha1 \ + "The quick brown fox jumped over the lazy dog.\n" \ + bae5ed658ab3546aee12f23f36392f35dba1ebdd \ + "quick brown fox" + +exit 0 diff --git a/src/ltsha1.c b/src/ltsha1.c new file mode 100644 index 0000000..881e1cf --- /dev/null +++ b/src/ltsha1.c @@ -0,0 +1,54 @@ +/* License: public domain -or- http://www.wtfpl.net/txt/copying/ */ + +#include "lt1.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[]) +{ + SHA1_CTX c; + unsigned char md[SHA1_DIGEST_LENGTH]; + char mdhex[(2*SHA1_DIGEST_LENGTH)+1]; + ssize_t e; + unsigned i; + + if (!SHA1_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 (!SHA1_Update(&c, buffer, (size_t)e)) + return EXIT_FAILURE; + } + if (!SHA1_Final(md, &c)) + return 0; + for (i=0; i < SHA1_DIGEST_LENGTH; ++i) { + unsigned char c = md[i]; + mdhex[i<<1] = hextab[c >> 4]; + mdhex[(i<<1)+1] = hextab[c & 0xf]; + } + mdhex[2*SHA1_DIGEST_LENGTH] = '\0'; + if (puts(mdhex) < 0) + return EXIT_FAILURE; + + return 0; +} + +#include "lt1.c" -- 2.11.4.GIT