/* sha1.c - SHA1 hash function
 *	Copyright (C) 1998, 2001, 2002 Free Software Foundation, Inc.
 *
 * This file is part of Libgcrypt.
 *
 * Libgcrypt is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * Libgcrypt 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

/* (C) 2002, 2003, 2004 Michael Buesch :
 *   Modified/deleted/added some functions.
 * 2004 further modifications by Michael Jarrett (JudgeBeavis@hotmail.com)
 */

/*  SHA1 Test vectors:
 *
 *  "abc"
 *  A999 3E36 4706 816A BA3E  2571 7850 C26C 9CD0 D89D
 *
 *  "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
 *  8498 3E44 1C3B D26E BAAE  4AA1 F951 29E5 E546 70F1
 */

#include "sha1.h"
#include "bithelp.h"

#include <stdio.h>
#include <sys/stat.h>

Sha1::Sha1()
{
	context = new SHA1_CONTEXT;
}

Sha1::~Sha1()
{
	delete context;
}

void Sha1::burn_stack(int bytes)
{
	char buf[128];
	memset(buf, 0, sizeof buf);
	bytes -= sizeof buf;
	if (bytes > 0)
		burn_stack(bytes);
}

void Sha1::sha1_init()
{
	context->h0 = 0x67452301;
	context->h1 = 0xefcdab89;
	context->h2 = 0x98badcfe;
	context->h3 = 0x10325476;
	context->h4 = 0xc3d2e1f0;
	context->nblocks = 0;
	context->count = 0;
}

/****************
 * Transform the message X which consists of 16 32-bit-words
 */
void Sha1::transform(const byte *data)
{
	uint32_t a, b, c, d, e, tm;
	uint32_t x[16];

	/* get values from the chaining vars */
	a = context->h0;
	b = context->h1;
	c = context->h2;
	d = context->h3;
	e = context->h4;

#ifdef BIG_ENDIAN_HOST
	memcpy(x, data, 64);
#else
	{
		int i;
		byte *p2;
		for (i = 0, p2 = (byte *) x; i < 16; i++, p2 += 4) {
			p2[3] = *data++;
			p2[2] = *data++;
			p2[1] = *data++;
			p2[0] = *data++;
		}
	}
#endif

#define SHA1_K1  0x5A827999L
#define SHA1_K2  0x6ED9EBA1L
#define SHA1_K3  0x8F1BBCDCL
#define SHA1_K4  0xCA62C1D6L
#define SHA1_F1(x,y,z)   ( z ^ ( x & ( y ^ z ) ) )
#define SHA1_F2(x,y,z)   ( x ^ y ^ z )
#define SHA1_F3(x,y,z)   ( ( x & y ) | ( z & ( x | y ) ) )
#define SHA1_F4(x,y,z)   ( x ^ y ^ z )

#define M(i) ( tm =   x[i&0x0f] ^ x[(i-14)&0x0f] \
		    ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f] \
	       , (x[i&0x0f] = rol(tm, 1)) )

#define SHA1_R(a,b,c,d,e,f,k,m)  do { e += rol( a, 5 )     \
				      + f( b, c, d )  \
				      + k	      \
				      + m;	      \
				 b = rol( b, 30 );    \
			       } while(0)
	SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[0]);
	SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, x[1]);
	SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, x[2]);
	SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, x[3]);
	SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, x[4]);
	SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[5]);
	SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, x[6]);
	SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, x[7]);
	SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, x[8]);
	SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, x[9]);
	SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[10]);
	SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, x[11]);
	SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, x[12]);
	SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, x[13]);
	SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, x[14]);
	SHA1_R(a, b, c, d, e, SHA1_F1, SHA1_K1, x[15]);
	SHA1_R(e, a, b, c, d, SHA1_F1, SHA1_K1, M(16));
	SHA1_R(d, e, a, b, c, SHA1_F1, SHA1_K1, M(17));
	SHA1_R(c, d, e, a, b, SHA1_F1, SHA1_K1, M(18));
	SHA1_R(b, c, d, e, a, SHA1_F1, SHA1_K1, M(19));
	SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(20));
	SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(21));
	SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(22));
	SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(23));
	SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(24));
	SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(25));
	SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(26));
	SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(27));
	SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(28));
	SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(29));
	SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(30));
	SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(31));
	SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(32));
	SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(33));
	SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(34));
	SHA1_R(a, b, c, d, e, SHA1_F2, SHA1_K2, M(35));
	SHA1_R(e, a, b, c, d, SHA1_F2, SHA1_K2, M(36));
	SHA1_R(d, e, a, b, c, SHA1_F2, SHA1_K2, M(37));
	SHA1_R(c, d, e, a, b, SHA1_F2, SHA1_K2, M(38));
	SHA1_R(b, c, d, e, a, SHA1_F2, SHA1_K2, M(39));
	SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(40));
	SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(41));
	SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(42));
	SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(43));
	SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(44));
	SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(45));
	SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(46));
	SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(47));
	SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(48));
	SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(49));
	SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(50));
	SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(51));
	SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(52));
	SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(53));
	SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(54));
	SHA1_R(a, b, c, d, e, SHA1_F3, SHA1_K3, M(55));
	SHA1_R(e, a, b, c, d, SHA1_F3, SHA1_K3, M(56));
	SHA1_R(d, e, a, b, c, SHA1_F3, SHA1_K3, M(57));
	SHA1_R(c, d, e, a, b, SHA1_F3, SHA1_K3, M(58));
	SHA1_R(b, c, d, e, a, SHA1_F3, SHA1_K3, M(59));
	SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(60));
	SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(61));
	SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(62));
	SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(63));
	SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(64));
	SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(65));
	SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(66));
	SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(67));
	SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(68));
	SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(69));
	SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(70));
	SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(71));
	SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(72));
	SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(73));
	SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(74));
	SHA1_R(a, b, c, d, e, SHA1_F4, SHA1_K4, M(75));
	SHA1_R(e, a, b, c, d, SHA1_F4, SHA1_K4, M(76));
	SHA1_R(d, e, a, b, c, SHA1_F4, SHA1_K4, M(77));
	SHA1_R(c, d, e, a, b, SHA1_F4, SHA1_K4, M(78));
	SHA1_R(b, c, d, e, a, SHA1_F4, SHA1_K4, M(79));

	/* update chainig vars */
	context->h0 += a;
	context->h1 += b;
	context->h2 += c;
	context->h3 += d;
	context->h4 += e;
}

/* Update the message digest with the contents
 * of INBUF with length INLEN.
 */
void Sha1::sha1_write(const byte *inbuf, size_t inlen)
{
	if (context->count == 64) {	/* flush the buffer */
		transform(context->buf);
		burn_stack(88 + 4 * sizeof(void *));
		context->count = 0;
		context->nblocks++;
	}
	if (unlikely(!inbuf))
		return;
	if (context->count) {
		for (; inlen && context->count < 64; inlen--)
			context->buf[context->count++] = *inbuf++;
		sha1_write(NULL, 0);
		if (!inlen)
			return;
	}

	while (inlen >= 64) {
		transform(inbuf);
		context->count = 0;
		context->nblocks++;
		inlen -= 64;
		inbuf += 64;
	}
	burn_stack(88 + 4 * sizeof(void *));
	for (; inlen && context->count < 64; inlen--)
		context->buf[context->count++] = *inbuf++;
}

/* The routine final terminates the computation and
 * returns the digest.
 * The handle is prepared for a new cycle, but adding bytes to the
 * handle will the destroy the returned buffer.
 * Returns: 20 bytes representing the digest.
 */
byte * Sha1::sha1_final()
{
	uint32_t t, msb, lsb;
	byte *p;

	sha1_write(NULL, 0); /* flush */

	t = context->nblocks;
	/* multiply by 64 to make a byte count */
	lsb = t << 6;
	msb = t >> 26;
	/* add the count */
	t = lsb;
	if ((lsb += context->count) < t)
		msb++;
	/* multiply by 8 to make a bit count */
	t = lsb;
	lsb <<= 3;
	msb <<= 3;
	msb |= t >> 29;

	if (context->count < 56) {	/* enough room */
		context->buf[context->count++] = 0x80;	/* pad */
		while (context->count < 56)
			context->buf[context->count++] = 0;	/* pad */
	} else {		/* need one extra block */
		context->buf[context->count++] = 0x80;	/* pad character */
		while (context->count < 64)
			context->buf[context->count++] = 0;
		sha1_write(NULL, 0); /* flush */
		memset(context->buf, 0, 56);	/* fill next block with zeroes */
	}
	/* append the 64 bit count */
	context->buf[56] = msb >> 24;
	context->buf[57] = msb >> 16;
	context->buf[58] = msb >> 8;
	context->buf[59] = msb;
	context->buf[60] = lsb >> 24;
	context->buf[61] = lsb >> 16;
	context->buf[62] = lsb >> 8;
	context->buf[63] = lsb;
	transform(context->buf);
	burn_stack(88 + 4 * sizeof(void *));

	p = context->buf;
#ifdef BIG_ENDIAN_HOST
#define X(a) do { *(uint32_t*)p = context->h##a ; p += 4; } while(0)
#else				/* little endian */
#define X(a) do { *p++ = context->h##a >> 24; *p++ = context->h##a >> 16;	 \
		      *p++ = context->h##a >> 8; *p++ = context->h##a; } while(0)
#endif
	X(0);
	X(1);
	X(2);
	X(3);
	X(4);
#undef X
	return context->buf;
}

bool Sha1::selfTest()
{
// TODO: Remove me proper
/*
	string test1("abc");
	string test1_md("A9993E364706816ABA3E25717850C26C9CD0D89D");
	string test2("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
	string test2_md("84983E441C3BD26EBAAE4AA1F95129E5E54670F1");
	string test3;
	test3.assign(1000000, 'a');
	string test3_md("34AA973CD4C4DAA4F61EEB2BDBAD27316534016F");

	Sha1 sha1;

	if (unlikely(sha1.calcSha1(test1) != test1_md))
		return false;
	if (unlikely(sha1.calcSha1(test2) != test2_md))
		return false;
	if (unlikely(sha1.calcSha1(test3) != test3_md))
		return false;
*/
	return true;
}

byte *Sha1::calcSha1(const byte *buf, int len)
{
	sha1_init();
	sha1_write(buf, len);
	return sha1_final();
}

