From 5ded7135d0a25aba37b378bac2908b9cc4678f13 Mon Sep 17 00:00:00 2001 From: Hannes Matuschek Date: Mon, 8 Jun 2015 15:59:36 +0200 Subject: [PATCH] Added SHA1 implementation. --- src/CMakeLists.txt | 4 +- src/bch31_21.hh | 2 +- src/sha1.cc | 189 +++++++++++++++++++++++++++++++++++++++++++++ src/sha1.hh | 43 +++++++++++ 4 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 src/sha1.cc create mode 100644 src/sha1.hh diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index aab6bea..c835b5a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,13 +1,13 @@ # Sources of libsdr set(LIBSDR_SOURCES buffer.cc node.cc queue.cc traits.cc portaudio.cc utils.cc wavfile.cc exception.cc logger.cc - psk31.cc options.cc fsk.cc ax25.cc aprs.cc baudot.cc pocsag.cc bch31_21.cc http.cc) + psk31.cc options.cc fsk.cc ax25.cc aprs.cc baudot.cc pocsag.cc bch31_21.cc http.cc sha1.cc) set(LIBSDR_HEADERS sdr.hh math.hh buffer.hh node.hh queue.hh buffernode.hh filternode.hh traits.hh autocast.hh siggen.hh portaudio.hh utils.hh wavfile.hh demod.hh firfilter.hh fftplan.hh fftplan_native.hh exception.hh baseband.hh freqshift.hh subsample.hh combine.hh logger.hh psk31.hh interpolate.hh operators.hh options.hh fsk.hh ax25.hh - aprs.hh baudot.hh pocsag.hh bch31_21.hh http.hh) + aprs.hh baudot.hh pocsag.hh bch31_21.hh http.hh sha1.hh) if(SDR_WITH_PORTAUDIO) set(LIBSDR_SOURCES ${LIBSDR_SOURCES} portaudio.cc) diff --git a/src/bch31_21.hh b/src/bch31_21.hh index 4a81a0f..0b02b58 100644 --- a/src/bch31_21.hh +++ b/src/bch31_21.hh @@ -1,7 +1,7 @@ #ifndef __SDR_BCH31_21_HH__ #define __SDR_BCH31_21_HH__ -#include +#include namespace sdr { diff --git a/src/sha1.cc b/src/sha1.cc new file mode 100644 index 0000000..c407b15 --- /dev/null +++ b/src/sha1.cc @@ -0,0 +1,189 @@ +/* This code is public-domain - it is based on libcrypt + * placed in the public domain by Wei Dai and other contributors. + */ +// gcc -Wall -DSHA1TEST -o sha1test sha1.c && ./sha1test + +#include "sha1.hh" +#include +#include + +using namespace sdr; + +#ifdef __BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +#elif defined __LITTLE_ENDIAN__ +/* override */ +#elif defined __BYTE_ORDER +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +# endif +#else // ! defined __LITTLE_ENDIAN__ +# include // machine/endian.h +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define SHA_BIG_ENDIAN +# endif +#endif + + + + +/* code */ +#define SHA1_K0 0x5a827999 +#define SHA1_K20 0x6ed9eba1 +#define SHA1_K40 0x8f1bbcdc +#define SHA1_K60 0xca62c1d6 + +void +sdr::sha1_init(sha1 *s) { + s->state[0] = 0x67452301; + s->state[1] = 0xefcdab89; + s->state[2] = 0x98badcfe; + s->state[3] = 0x10325476; + s->state[4] = 0xc3d2e1f0; + s->byteCount = 0; + s->bufferOffset = 0; +} + +uint32_t +sdr::sha1_rol32(uint32_t number, uint8_t bits) { + return ((number << bits) | (number >> (32-bits))); +} + +void +sdr::sha1_hashBlock(sha1 *s) { + uint8_t i; + uint32_t a,b,c,d,e,t; + + a=s->state[0]; + b=s->state[1]; + c=s->state[2]; + d=s->state[3]; + e=s->state[4]; + for (i=0; i<80; i++) { + if (i>=16) { + t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15]; + s->buffer[i&15] = sha1_rol32(t,1); + } + if (i<20) { + t = (d ^ (b & (c ^ d))) + SHA1_K0; + } else if (i<40) { + t = (b ^ c ^ d) + SHA1_K20; + } else if (i<60) { + t = ((b & c) | (d & (b | c))) + SHA1_K40; + } else { + t = (b ^ c ^ d) + SHA1_K60; + } + t+=sha1_rol32(a,5) + e + s->buffer[i&15]; + e=d; + d=c; + c=sha1_rol32(b,30); + b=a; + a=t; + } + s->state[0] += a; + s->state[1] += b; + s->state[2] += c; + s->state[3] += d; + s->state[4] += e; +} + +void +sdr::sha1_addUncounted(sha1 *s, uint8_t data) { + uint8_t * const b = (uint8_t*) s->buffer; +#ifdef SHA_BIG_ENDIAN + b[s->bufferOffset] = data; +#else + b[s->bufferOffset ^ 3] = data; +#endif + s->bufferOffset++; + if (s->bufferOffset == SDR_SHA1_BLOCK_LENGTH) { + sha1_hashBlock(s); + s->bufferOffset = 0; + } +} + +void +sdr::sha1_writebyte(sha1 *s, uint8_t data) { + ++s->byteCount; + sha1_addUncounted(s, data); +} + +void +sdr::sha1_write(sha1 *s, const char *data, size_t len) { + for (;len--;) sha1_writebyte(s, (uint8_t) *data++); +} + +void +sdr::sha1_pad(sha1 *s) { + // Implement SHA-1 padding (fips180-2 ยง5.1.1) + + // Pad with 0x80 followed by 0x00 until the end of the block + sha1_addUncounted(s, 0x80); + while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00); + + // Append length in the last 8 bytes + sha1_addUncounted(s, 0); // We're only using 32 bit lengths + sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths + sha1_addUncounted(s, 0); // So zero pad the top bits + sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8 + sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as + sha1_addUncounted(s, s->byteCount >> 13); // byte. + sha1_addUncounted(s, s->byteCount >> 5); + sha1_addUncounted(s, s->byteCount << 3); +} + +uint8_t* +sdr::sha1_result(sha1 *s) { + // Pad to complete the last block + sha1_pad(s); + +#ifndef SHA_BIG_ENDIAN + // Swap byte order back + int i; + for (i=0; i<5; i++) { + s->state[i]= + (((s->state[i])<<24)& 0xff000000) + | (((s->state[i])<<8) & 0x00ff0000) + | (((s->state[i])>>8) & 0x0000ff00) + | (((s->state[i])>>24)& 0x000000ff); + } +#endif + + // Return pointer to hash (20 characters) + return (uint8_t*) s->state; +} + +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +void +sdr::sha1_initHmac(sha1 *s, const uint8_t* key, int keyLength) { + uint8_t i; + memset(s->keyBuffer, 0,SDR_SHA1_BLOCK_LENGTHH); + if (keyLength >SDR_SHA1_BLOCK_LENGTHH) { + // Hash long keys + sha1_init(s); + for (;keyLength--;) sha1_writebyte(s, *key++); + memcpy(s->keyBuffer, sha1_result(s),SDR_SHA1_HASH_LENGTHH); + } else { + // Block length keys are used as is + memcpy(s->keyBuffer, key, keyLength); + } + // Start inner hash + sha1_init(s); + for (i=0; iSDR_SHA1_BLOCK_LENGTHH; i++) { + sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_IPAD); + } +} + +uint8_t* +sdr::sha1_resultHmac(sha1 *s) { + uint8_t i; + // Complete inner hash + memcpy(s->innerHash,sha1_result(s)SDR_SHA1_HASH_LENGTHH); + // Calculate outer hash + sha1_init(s); + for (i=0; iSDR_SHA1_BLOCK_LENGTHH; i++) sha1_writebyte(s, s->keyBuffer[i] ^ HMAC_OPAD); + for (i=0; iSDR_SHA1_HASH_LENGTHH; i++) sha1_writebyte(s, s->innerHash[i]); + return sha1_result(s); +} diff --git a/src/sha1.hh b/src/sha1.hh new file mode 100644 index 0000000..cc86615 --- /dev/null +++ b/src/sha1.hh @@ -0,0 +1,43 @@ +#ifndef __SDR_SHA1_HH__ +#define __SDR_SHA1_HH__ + +#include + +namespace sdr { + +/* header */ + +#define SDR_SHA1_HASH_LENGTH 20 +#define SDR_SHA1_BLOCK_LENGTH 64 + +typedef struct { + uint32_t buffer[SDR_SHA1_BLOCK_LENGTH/4]; + uint32_t state[SDR_SHA1_HASH_LENGTH/4]; + uint32_t byteCount; + uint8_t bufferOffset; + uint8_t keyBuffer[SDR_SHA1_BLOCK_LENGTH]; + uint8_t innerHash[SDR_SHA1_HASH_LENGTH]; +} sha1; + +/** + */ +void sha1_init(sha1 *s); +/** + */ +void sha1_writebyte(sha1 *s, uint8_t data); +/** + */ +void sha1_write(sha1 *s, const char *data, size_t len); +/** + */ +uint8_t* sha1_result(sha1 *s); +/** + */ +void sha1_initHmac(sha1 *s, const uint8_t* key, int keyLength); +/** + */ +uint8_t* sha1_resultHmac(sha1 *s); + +} + +#endif // __SDR_SHA1_HH__