From f1753017d02b95b2ba29c3a3953dead09005eff3 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Wed, 16 Nov 2005 13:53:31 +0000 Subject: [PATCH] Added SHA-256. --- lib/silccrypt/sha256.c | 284 ++++++++++++++++++++++++++++++++ lib/silccrypt/sha256.h | 34 ++++ lib/silccrypt/sha256_internal.h | 37 +++++ lib/silccrypt/silchash.c | 3 + lib/silccrypt/silchmac.c | 2 + 5 files changed, 360 insertions(+) create mode 100644 lib/silccrypt/sha256.c create mode 100644 lib/silccrypt/sha256.h create mode 100644 lib/silccrypt/sha256_internal.h diff --git a/lib/silccrypt/sha256.c b/lib/silccrypt/sha256.c new file mode 100644 index 00000000..45e07f29 --- /dev/null +++ b/lib/silccrypt/sha256.c @@ -0,0 +1,284 @@ +/* Modified for SILC -Pekka */ + +/* 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. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org + */ +#include "silcincludes.h" +#include "sha256_internal.h" +#include "sha256.h" + +/* + * SILC Hash API for SHA256 + */ + +SILC_HASH_API_INIT(sha256) +{ + sha256_init(context); +} + +SILC_HASH_API_UPDATE(sha256) +{ + sha256_process(context, (unsigned char *)data, len); +} + +SILC_HASH_API_FINAL(sha256) +{ + sha256_done(context, digest); +} + +SILC_HASH_API_TRANSFORM(sha256) +{ + sha256_compress(state, (unsigned char *)buffer); +} + +SILC_HASH_API_CONTEXT_LEN(sha256) +{ + return sizeof(sha256_state); +} + +#if defined(_MSC_VER) +#pragma intrinsic(_lrotr,_lrotl) +#define RORc(x,n) _lrotr(x,n) + +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) + +static inline unsigned RORc(unsigned word, int i) +{ + asm ("rorl %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} + +#else +#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsignedlong)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) &0xFFFFFFFFUL) +#endif /* _MSC_VER */ + +/* 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 */ +int sha256_compress(SilcUInt32 *state, unsigned char *buf) +{ + SilcUInt32 S[8], W[64], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) + SILC_GET32_MSB(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 */ +#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 + + /* feedback */ + for (i = 0; i < 8; i++) { + state[i] = state[i] + S[i]; + } + return TRUE; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int sha256_init(sha256_state * md) +{ + md->length = 0; + md->curlen = 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 TRUE; +} + +#if !defined(MIN) +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +/** + 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 +*/ +int sha256_process(sha256_state * md, const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + int err, block_size = sizeof(md->buf); + + if (md->curlen > block_size) + return FALSE; + + while (inlen > 0) { + if (md->curlen == 0 && inlen >= block_size) { + if ((err = sha256_compress(md->state, (unsigned char *)in)) != TRUE) + 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 = sha256_compress(md->state, md->buf)) != TRUE) + return err; + md->length += block_size * 8; + md->curlen = 0; + } + } + } + return TRUE; +} + +/** + 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(sha256_state * md, unsigned char *out) +{ + int i; + + if (md->curlen >= sizeof(md->buf)) + return FALSE; + + /* 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->state, md->buf); + md->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char)0; + } + + /* store length */ + SILC_PUT64_MSB(md->length, md->buf + 56); + sha256_compress(md->state, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) + SILC_PUT32_MSB(md->state[i], out + (4 * i)); + + return TRUE; +} diff --git a/lib/silccrypt/sha256.h b/lib/silccrypt/sha256.h new file mode 100644 index 00000000..fe847c03 --- /dev/null +++ b/lib/silccrypt/sha256.h @@ -0,0 +1,34 @@ +/* + + sha256.h + + Author: Pekka Riikonen + + Copyright (C) 2005 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SHA256_H +#define SHA256_H + +/* + * SILC Hash API for SHA256 + */ + +SILC_HASH_API_INIT(sha256); +SILC_HASH_API_UPDATE(sha256); +SILC_HASH_API_FINAL(sha256); +SILC_HASH_API_TRANSFORM(sha256); +SILC_HASH_API_CONTEXT_LEN(sha256); + +#endif /* SHA256_H */ diff --git a/lib/silccrypt/sha256_internal.h b/lib/silccrypt/sha256_internal.h new file mode 100644 index 00000000..6f61fbb6 --- /dev/null +++ b/lib/silccrypt/sha256_internal.h @@ -0,0 +1,37 @@ +/* + + sha256_internal.h + + Author: Pekka Riikonen + + Copyright (C) 2005 Pekka Riikonen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + +*/ + +#ifndef SHA256_INTERNAL_H +#define SHA256_INTERNAL_H + +typedef struct { + SilcUInt64 length; + SilcUInt32 state[8]; + SilcUInt32 curlen; + unsigned char buf[64]; +} sha256_state; + +int sha256_init(sha256_state * md); +int sha256_process(sha256_state * md, const unsigned char *in, + unsigned long inlen); +int sha256_done(sha256_state * md, unsigned char *hash); +int sha256_compress(SilcUInt32 *state, unsigned char *buf); + +#endif /* SHA256_INTERNAL_H */ diff --git a/lib/silccrypt/silchash.c b/lib/silccrypt/silchash.c index fcf40fed..7fcbf441 100644 --- a/lib/silccrypt/silchash.c +++ b/lib/silccrypt/silchash.c @@ -22,6 +22,7 @@ #include "md5.h" #include "sha1.h" +#include "sha256.h" /* The main SILC hash structure. */ struct SilcHashStruct { @@ -39,6 +40,8 @@ const SilcHashObject silc_default_hash[] = { { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final, silc_sha1_transform, silc_sha1_context_len }, + { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final, + silc_sha256_transform, silc_sha256_context_len }, { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final, silc_md5_transform, silc_md5_context_len }, diff --git a/lib/silccrypt/silchmac.c b/lib/silccrypt/silchmac.c index e92af48a..9647aa5e 100644 --- a/lib/silccrypt/silchmac.c +++ b/lib/silccrypt/silchmac.c @@ -40,8 +40,10 @@ SilcDList silc_hmac_list = NULL; const SilcHmacObject silc_default_hmacs[] = { { "hmac-sha1-96", 12 }, + { "hmac-sha256-96", 12 }, { "hmac-md5-96", 12 }, { "hmac-sha1", 20 }, + { "hmac-sha256", 32 }, { "hmac-md5", 16 }, { NULL, 0 } -- 2.24.0