diff -ruN a/include/re_sha.h b/include/re_sha.h --- a/include/re_sha.h 2022-03-12 09:42:35.000000000 +0300 +++ b/include/re_sha.h 2023-01-26 15:39:59.205866100 +0300 @@ -4,12 +4,31 @@ * Copyright (C) 2010 Creytiv.com */ + +#ifdef USE_OPENSSL +#include +#else + +/* public api for steve reid's public domain SHA-1 implementation */ +/* this file is in the public domain */ + +/** SHA-1 Context */ +typedef struct { + uint32_t state[5]; /**< Context state */ + uint32_t count[2]; /**< Counter */ + uint8_t buffer[64]; /**< SHA-1 buffer */ +} SHA1_CTX; + +/** SHA-1 Context (OpenSSL compat) */ +typedef SHA1_CTX SHA_CTX; + /** SHA-1 Digest size in bytes */ #define SHA1_DIGEST_SIZE 20 - -#ifndef SHA_DIGEST_LENGTH /** SHA-1 Digest size in bytes (OpenSSL compat) */ #define SHA_DIGEST_LENGTH SHA1_DIGEST_SIZE -#endif -void sha1(const uint8_t *d, size_t n, uint8_t *md); +void SHA1_Init(SHA1_CTX* context); +void SHA1_Update(SHA1_CTX* context, const void *p, size_t len); +void SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA1_CTX* context); + +#endif diff -ruN a/src/hmac/hmac_sha1.c b/src/hmac/hmac_sha1.c --- a/src/hmac/hmac_sha1.c 2022-03-12 09:42:35.000000000 +0300 +++ b/src/hmac/hmac_sha1.c 2023-01-26 15:41:07.255866100 +0300 @@ -9,8 +9,8 @@ #include #include #include -#elif defined (__APPLE__) -#include +#else +#include #endif #include @@ -32,31 +32,68 @@ * @param t Size of digest output */ void hmac_sha1(const uint8_t *k, /* secret key */ - size_t lk, /* length of the key in bytes */ - const uint8_t *d, /* data */ - size_t ld, /* length of data in bytes */ - uint8_t *out, /* output buffer, at least "t" bytes */ - size_t t) + size_t lk, /* length of the key in bytes */ + const uint8_t *d, /* data */ + size_t ld, /* length of data in bytes */ + uint8_t *out, /* output buffer, at least "t" bytes */ + size_t t) { #ifdef USE_OPENSSL - (void)t; - - if (!HMAC(EVP_sha1(), k, (int)lk, d, ld, out, NULL)) - ERR_clear_error(); -#elif defined (__APPLE__) - (void)t; + (void)t; - CCHmac(kCCHmacAlgSHA1, k, lk, d, ld, out); + if (!HMAC(EVP_sha1(), k, (int)lk, d, ld, out, NULL)) + ERR_clear_error(); #else - (void)k; - (void)lk; - (void)d; - (void)ld; - (void)out; - (void)t; + SHA_CTX ictx, octx; + uint8_t isha[SHA_DIGEST_LENGTH], osha[SHA_DIGEST_LENGTH]; + uint8_t key[SHA_DIGEST_LENGTH]; + uint8_t buf[SHA_BLOCKSIZE]; + size_t i; + + if (lk > SHA_BLOCKSIZE) { + SHA_CTX tctx; + + SHA1_Init(&tctx); + SHA1_Update(&tctx, k, lk); + SHA1_Final(key, &tctx); + + k = key; + lk = SHA_DIGEST_LENGTH; + } + + /**** Inner Digest ****/ + + SHA1_Init(&ictx); + + /* Pad the key for inner digest */ + for (i = 0 ; i < lk ; ++i) + buf[i] = k[i] ^ 0x36; + for (i = lk ; i < SHA_BLOCKSIZE ; ++i) + buf[i] = 0x36; + + SHA1_Update(&ictx, buf, SHA_BLOCKSIZE); + SHA1_Update(&ictx, d, ld); + + SHA1_Final(isha, &ictx); + + /**** Outer Digest ****/ + + SHA1_Init(&octx); + + /* Pad the key for outter digest */ + + for (i = 0 ; i < lk ; ++i) + buf[i] = k[i] ^ 0x5c; + for (i = lk ; i < SHA_BLOCKSIZE ; ++i) + buf[i] = 0x5c; -#error missing HMAC-SHA1 backend + SHA1_Update(&octx, buf, SHA_BLOCKSIZE); + SHA1_Update(&octx, isha, SHA_DIGEST_LENGTH); + SHA1_Final(osha, &octx); + /* truncate and print the results */ + t = t > SHA_DIGEST_LENGTH ? SHA_DIGEST_LENGTH : t; + memcpy(out, osha, t); #endif } diff -ruN a/src/sha/mod.mk b/src/sha/mod.mk --- a/src/sha/mod.mk 2022-03-12 09:42:35.000000000 +0300 +++ b/src/sha/mod.mk 2023-01-26 15:38:20.695866100 +0300 @@ -4,4 +4,4 @@ # Copyright (C) 2010 Creytiv.com # -SRCS += sha/wrap.c +SRCS += sha/sha1.c diff -ruN a/src/sha/sha1.c b/src/sha/sha1.c --- a/src/sha/sha1.c 1970-01-01 03:00:00.000000000 +0300 +++ b/src/sha/sha1.c 2023-01-26 15:38:37.045866100 +0300 @@ -0,0 +1,270 @@ +/** + * @file sha1.c SHA-1 in C + */ + +/* +By Steve Reid +100% Public Domain + +----------------- +Modified 7/98 +By James H. Brown +Still 100% Public Domain + +Corrected a problem which generated improper hash values on 16 bit machines +Routine SHA1Update changed from + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int +len) +to + void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned +long len) + +The 'len' parameter was declared an int which works fine on 32 bit machines. +However, on 16 bit machines an int is too small for the shifts being done +against +it. This caused the hash function to generate incorrect values if len was +greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update(). + +Since the file IO in main() reads 16K at a time, any file 8K or larger would +be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million +"a"s). + +I also changed the declaration of variables i & j in SHA1Update to +unsigned long from unsigned int for the same reason. + +These changes should make no difference to any 32 bit implementations since +an +int and a long are the same size in those environments. + +-- +I also corrected a few compiler warnings generated by Borland C. +1. Added #include for exit() prototype +2. Removed unused variable 'j' in SHA1Final +3. Changed exit(0) to return(0) at end of main. + +ALL changes I made can be located by searching for comments containing 'JHB' +----------------- +Modified 8/98 +By Steve Reid +Still 100% public domain + +1- Removed #include and used return() instead of exit() +2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall) +3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net + +----------------- +Modified 4/01 +By Saul Kravitz +Still 100% PD +Modified to run on Compaq Alpha hardware. + +----------------- +Modified 07/2002 +By Ralph Giles +Still 100% public domain +modified for use with stdint types, autoconf +code cleanup, removed attribution comments +switched SHA1Final() argument order for consistency +use SHA1_ prefix for public api +move public api to sha1.h +*/ + +/* +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +#define SHA1HANDSOFF 1 + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#if defined (BYTE_ORDER) && defined(BIG_ENDIAN) && (BYTE_ORDER == BIG_ENDIAN) +#define WORDS_BIGENDIAN 1 +#endif +#ifdef _BIG_ENDIAN +#define WORDS_BIGENDIAN 1 +#endif + + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +/* FIXME: can we do this in an endian-proof way? */ +#ifdef WORDS_BIGENDIAN +#define blk0(i) block->l[i] +#else +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xff00ff00) \ + |(rol(block->l[i],8)&0x00ff00ff)) +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) \ + z+=((w&(x^y))^y)+blk0(i)+0x5a827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) \ + z+=((w&(x^y))^y)+blk(i)+0x5a827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) \ + z+=(w^x^y)+blk(i)+0x6ed9eba1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) \ + z+=(((w|x)&y)|(w&x))+blk(i)+0x8f1bbcdc+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) \ + z+=(w^x^y)+blk(i)+0xca62c1d6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ +void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64]) +{ + uint32_t a, b, c, d, e; + typedef union { + uint8_t c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + +#ifdef SHA1HANDSOFF + CHAR64LONG16 workspace; + block = &workspace; + memcpy(block, buffer, 64); +#else + block = (CHAR64LONG16*)buffer; +#endif + + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2);R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6);R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10);R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14);R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18);R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22);R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26);R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30);R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34);R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38);R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42);R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46);R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50);R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54);R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58);R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62);R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66);R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70);R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74);R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78);R4(b,c,d,e,a,79); + + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/** + * Initialize new context + * + * @param context SHA1-Context + */ +void SHA1_Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; + context->state[4] = 0xc3d2e1f0; + context->count[0] = context->count[1] = 0; +} + + +/** + * Run your data through this + * + * @param context SHA1-Context + * @param p Buffer to run SHA1 on + * @param len Number of bytes + */ +void SHA1_Update(SHA1_CTX* context, const void *p, size_t len) +{ + const uint8_t* data = p; + size_t i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += (uint32_t)(len << 3)) < (len << 3)) + context->count[1]++; + context->count[1] += (uint32_t)(len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1_Transform(context->state, data + i); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/** + * Add padding and return the message digest + * + * @param digest Generated message digest + * @param context SHA1-Context + */ +void SHA1_Final(uint8_t digest[SHA1_DIGEST_SIZE], SHA1_CTX* context) +{ + uint32_t i; + uint8_t finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); + } + SHA1_Update(context, (uint8_t *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (uint8_t *)"\0", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause SHA1_Transform */ + for (i = 0; i < SHA1_DIGEST_SIZE; i++) { + digest[i] = (uint8_t) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + + /* Wipe variables */ + i = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(finalcount, 0, 8); /* SWR */ + +#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} diff -ruN a/src/websock/websock.c b/src/websock/websock.c --- a/src/websock/websock.c 2022-03-12 09:42:35.000000000 +0300 +++ b/src/websock/websock.c 2023-01-26 17:15:14.905866100 +0300 @@ -369,24 +369,19 @@ static int accept_print(struct re_printf *pf, const struct pl *key) { - uint8_t digest[SHA_DIGEST_LENGTH]; - uint8_t *data; - size_t len = key->l + sizeof(magic)-1; + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA_CTX ctx; - data = mem_zalloc(len, NULL); - if (!data) - return ENOMEM; + SHA1_Init(&ctx); + SHA1_Update(&ctx, key->p, key->l); + SHA1_Update(&ctx, magic, sizeof(magic)-1); + SHA1_Final(digest, &ctx); - memcpy(data, key->p, key->l); - memcpy(data + key->l, magic, sizeof(magic)-1); - - sha1(data, len, digest); - mem_deref(data); - - return base64_print(pf, digest, sizeof(digest)); + return base64_print(pf, digest, sizeof(digest)); } + static void http_resp_handler(int err, const struct http_msg *msg, void *arg) { struct websock_conn *conn = arg;