/*
 * Copyright 1998,1999 The OpenLDAP Foundation, Redwood City, California, USA
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted only
 * as authorized by the OpenLDAP Public License.  A copy of this
 * license is available at http://www.OpenLDAP.org/license.html or
 * in file LICENSE in the top-level directory of the distribution.
 */

/*	Acquired from:
 *	$OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $	*/

/*
 * SHA-1 in C
 * By Steve Reid <steve@edmweb.com>
 * 100% Public Domain
 *
 * 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
 */

/*
 * Modified by Tam Willacy (netwin@netwinsite.com) for
 *				inclusion into LDAPAuth, 14 March 2001
 * Consider these options ...
 *
 *  #define TESTING
 *	#define BYTE_ORDER == LITTLE_ENDIAN /*(intel)- default*/
/* 	#define BYTE_ORDER == BIG_ENDIAN
 */
/*#define SHA_TESTING*/

/*#include "portable.h"
#include <ac/string.h>
*/

/*-- TRW added --*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stddef.h>
#include <time.h>

#if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$OpenBSD: sha1hl.c,v 1.1 1997/07/12 20:06:03 millert Exp $";
#endif /* LIBC_SCCS and not lint */


#include <errno.h>
#ifndef WIN32
#include <unistd.h>
#endif

#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif

#ifdef HAVE_IO_H
#include <io.h>
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif

#define DMID 14
#include "debug.h"

#ifdef SHA_TESTING
#include <ctype.h> /*for sisascii and sisspace*/
#endif
/*#include <winsock2.h>*/
/*for open to work*/
#ifdef WIN32
#include <io.h>
#endif
#include <fcntl.h>
/*other general stuff*/
#include "ld_sha.h"
#include "lib.h"

char *sha_ncat(char *dst, char *src, int len);
void lib_abort_real(char *src, int line);
#define lib_abort() lib_abort_real(__FILE__,__LINE__)

#define sha_printf if(testing) printf
void set_sha_error(char *error,char *details);
static int testing;
int lutil_b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize);
#define SHA_ERRORSZ 450
#define CEILING(x)	((double)x > (int)x ? (int)x + 1 : (int)x)


/*-- TRW end   --*/

/* include socket.h to get sys/types.h and/or winsock2.h */
/*#include <ac/socket.h>*/

#if defined(HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif

/*#include "lutil_sha1.h"*/



void lutil_SHA1Transform(uint32 state[5], const unsigned char buffer[64]);
char *lutil_SHA1End(lutil_SHA1_CTX *, char *);
char *lutil_SHA1File(char *, char *);
char *lutil_SHA1Data(const unsigned char *, size_t, char *);


//#define SHA1HANDSOFF		/* Copies data before messing with it. */
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/*
 * blk0() and blk() perform the initial expand.
 * I got the idea of expanding during the round function from SSLeay
 */

#if defined(_BIG_ENDIAN)
#define BYTE_ORDER 99
#endif

#if BYTE_ORDER == LITTLE_ENDIAN
# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) | (rol(block->l[i],8)&0x00FF00FF))
#else
# define blk0(i) block->l[i]

#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 (rounds) 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
lutil_SHA1Transform( uint32 *state, const unsigned char *buffer )
{
    uint32 a, b, c, d, e;
    typedef union {
	unsigned char c[64];
	u_int l[16];
    } CHAR64LONG16;
    CHAR64LONG16 *block;

#ifdef SHA1HANDSOFF // THIS APPEARS TO BE EVIL AND BREAKS THREADED CODE, SO CHRISP DISABLING.
	EVIL FAIL EVIL FAIL....
    static unsigned char workspace[64];
    block = (CHAR64LONG16 *)workspace;
    (void)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;
}


/*
 * lutil_SHA1Init - Initialize new context
 */
void
lutil_SHA1Init( lutil_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.
 */
void
lutil_SHA1Update(
    lutil_SHA1_CTX	*context,
    const unsigned char	*data,
    u_int		len
)
{
    u_int i, j;

    j = context->count[0];
    if ((context->count[0] += len << 3) < j)
	context->count[1] += (len>>29)+1;
    j = (j >> 3) & 63;
    if ((j + len) > 63) {
	(void)memcpy(&context->buffer[j], data, (i = 64-j));
	lutil_SHA1Transform(context->state, context->buffer);
	for ( ; i + 63 < len; i += 64)
	    lutil_SHA1Transform(context->state, &data[i]);
	j = 0;
    } else {
	i = 0;
    }
    (void)memcpy(&context->buffer[j], &data[i], len - i);
}


/*
 * Add padding and return the message digest.
 */
void
lutil_SHA1Final( unsigned char *digest, lutil_SHA1_CTX *context )
{
    u_int i;
    unsigned char finalcount[8];

    for (i = 0; i < 8; i++) {
	finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
	 >> ((3-(i & 3)) * 8) ) & 255);	 /* Endian independent */
    }
    lutil_SHA1Update(context, (unsigned char *)"\200", 1);
    while ((context->count[0] & 504) != 448)
	lutil_SHA1Update(context, (unsigned char *)"\0", 1);
    lutil_SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */

    if (digest) {
	for (i = 0; i < 20; i++)
	    digest[i] = (unsigned char)
		((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
    }
}


/* sha1hl.c
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <phk@login.dkuug.dk> wrote this file.  As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
 * ----------------------------------------------------------------------------
 */



/* ARGSUSED */
char *
lutil_SHA1End( lutil_SHA1_CTX *ctx, char *buf )
{
    int i;
    char *p = buf;
    unsigned char digest[20];
    static const char hex[]="0123456789abcdef";

    if (p == NULL && (p = malloc(41)) == NULL)
	return 0;

    lutil_SHA1Final(digest,ctx);
    for (i = 0; i < 20; i++) {
	p[i + i] = hex[digest[i] >> 4];
	p[i + i + 1] = hex[digest[i] & 0x0f];
    }
    p[i + i] = '\0';
    return(p);
}

char *
lutil_SHA1File( char *filename, char *buf )
{
    unsigned char buffer[BUFSIZ];
    lutil_SHA1_CTX ctx;
    int fd, num, oerrno;

    lutil_SHA1Init(&ctx);

    if ((fd = open(filename,O_RDONLY)) < 0)
	return(0);

    while ((num = read(fd, buffer, sizeof(buffer))) > 0)
	lutil_SHA1Update(&ctx, buffer, num);

    oerrno = errno;
    close(fd);
    errno = oerrno;
    return(num < 0 ? 0 : lutil_SHA1End(&ctx, buf));
}

char *
lutil_SHA1Data( const unsigned char *data, size_t len, char *buf )
{
    lutil_SHA1_CTX ctx;

    lutil_SHA1Init(&ctx);
    lutil_SHA1Update(&ctx, data, (int)len);
    return(lutil_SHA1End(&ctx, buf));
}


/*
 * Modified by Tam Willacy (netwin@netwinsite.com) for
 *				inclusion into LDAPAuth, 14 March 2001
 */
/*
 * Modified by Kurt D. Zeilenga for inclusion into OpenLDAP
 */

/*
 * Copyright (c) 1996, 1998 by Internet Software Consortium.
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/*
 * Portions Copyright (c) 1995 by International Business Machines, Inc.
 *
 * International Business Machines, Inc. (hereinafter called IBM) grants
 * permission under its copyrights to use, copy, modify, and distribute this
 * Software with or without fee, provided that the above copyright notice and
 * all paragraphs of this notice appear in all copies, and that the name of IBM
 * not be used in connection with the marketing of any product incorporating
 * the Software or modifications thereof, without specific, written prior
 * permission.
 *
 * To the extent it has a right to do so, IBM grants an immunity from suit
 * under its patents, if any, for the use, sale or manufacture of products to
 * the extent that such products are used for performing Domain Name System
 * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
 * granted for any product per se or for any other function of any product.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
 * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
 * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */

/*#define Assert(Cond) if (!(Cond)) set_sha_error("base 64 Abort",""); abort()*/
void sha_abort(void){
	set_sha_error("base 64 Abort","");
	lib_abort();
}
#define Assert(Cond) if (!(Cond)) sha_abort()
static const char Base64[] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
int
lutil_b64_ntop(
	u_char const *src,
	size_t srclength,
	char *target,
	size_t targsize)
{
	size_t datalength = 0;
	u_char input[3];
	u_char output[4];
	size_t i;

	while (2 < srclength) {
		input[0] = *src++;
		input[1] = *src++;
		input[2] = *src++;
		srclength -= 3;

		output[0] = input[0] >> 2;
		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
		output[3] = input[2] & 0x3f;
		Assert(output[0] < 64);
		Assert(output[1] < 64);
		Assert(output[2] < 64);
		Assert(output[3] < 64);

		if (datalength + 4 > targsize){
			set_sha_error("Datalength too long 1","");
			return (-1);
		}
		target[datalength++] = Base64[output[0]];
		target[datalength++] = Base64[output[1]];
		target[datalength++] = Base64[output[2]];
		target[datalength++] = Base64[output[3]];
	}

	/* Now we worry about padding. */
	if (0 != srclength) {
		/* Get what's left. */
		input[0] = input[1] = input[2] = '\0';
		for (i = 0; i < srclength; i++)
			input[i] = *src++;

		output[0] = input[0] >> 2;
		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
		Assert(output[0] < 64);
		Assert(output[1] < 64);
		Assert(output[2] < 64);

		if (datalength + 4 > targsize){
			set_sha_error("Datalength too long 2","");
			return (-1);
		}
		target[datalength++] = Base64[output[0]];
		target[datalength++] = Base64[output[1]];
		if (srclength == 1)
			target[datalength++] = Pad64;
		else
			target[datalength++] = Base64[output[2]];
		target[datalength++] = Pad64;
	}
	if (datalength >= targsize){
		set_sha_error("Datalength too long 3","");
		return (-1);
	}
	target[datalength] = '\0';	/* Returned value doesn't count \0. */
	return (int)(datalength);
}
/* skips all whitespace anywhere.
   converts characters, four at a time, starting at (or after)
   src from base - 64 numbers into three 8 bit bytes in the target area.
   it returns the number of data bytes stored at the target, or -1 on error.
 */
int lutil_b64_pton(char const *src,u_char *target, size_t targsize)
{
	int tarindex, state, ch;
	char *pos;

	state = 0;
	tarindex = 0;

	while ((ch = *src++) != '\0') {
		if (sisascii(ch) && sisspace(ch))	/* Skip whitespace anywhere. */
			continue;

		if (ch == Pad64)
			break;

		pos = strchr(Base64, ch);
		if (pos == 0) 		/* A non-base64 character. */
			return (-1);

		switch (state) {
		case 0:
			if (target) {
				if ((size_t)tarindex >= targsize)
					return (-1);
				target[tarindex] = (int)(pos - Base64) << 2;
			}
			state = 1;
			break;
		case 1:
			if (target) {
				if ((size_t)tarindex + 1 >= targsize)
					return (-1);
				target[tarindex]   |=  (pos - Base64) >> 4;
				target[tarindex+1]  = ((pos - Base64) & 0x0f)
							<< 4 ;
			}
			tarindex++;
			state = 2;
			break;
		case 2:
			if (target) {
				if ((size_t)tarindex + 1 >= targsize)
					return (-1);
				target[tarindex]   |=  (pos - Base64) >> 2;
				target[tarindex+1]  = ((pos - Base64) & 0x03)
							<< 6;
			}
			tarindex++;
			state = 3;
			break;
		case 3:
			if (target) {
				if ((size_t)tarindex >= targsize)
					return (-1);
				target[tarindex] |= (pos - Base64);
			}
			tarindex++;
			state = 0;
			break;
		default:
			return -1; // used to be 'abort'... 
		}
	}

	/*
	 * We are done decoding Base-64 chars.  Let's see if we ended
	 * on a byte boundary, and/or with erroneous trailing characters.
	 */

	if (ch == Pad64) {		/* We got a pad char. */
		ch = *src++;		/* Skip it, get next. */
		switch (state) {
		case 0:		/* Invalid = in first position */
		case 1:		/* Invalid = in second position */
			return (-1);

		case 2:		/* Valid, means one byte of info */
			/* Skip any number of spaces. */
			for ((void)NULL; ch != '\0'; ch = *src++)
				if (! (sisascii(ch) && sisspace(ch)))
					break;
			/* Make sure there is another trailing = sign. */
			if (ch != Pad64)
				return (-1);
			ch = *src++;		/* Skip the = */
			/* Fall through to "single trailing =" case. */
			/* FALLTHROUGH */

		case 3:		/* Valid, means two bytes of info */
			/*
			 * We know this char is an =.  Is there anything but
			 * whitespace after it?
			 */
			for ((void)NULL; ch != '\0'; ch = *src++)
				if (! (sisascii(ch) && sisspace(ch)))
					return (-1);

			/*
			 * Now make sure for cases 2 and 3 that the "extra"
			 * bits that slopped past the last full byte were
			 * zeros.  If we don't check them, they become a
			 * subliminal channel.
			 */
			if (target && target[tarindex] != 0)
				return (-1);
		}
	} else {
		/*
		 * We ended by seeing the end of the string.  Make sure we
		 * have no partial bytes lying around.
		 */
		if (state != 0)
			return (-1);
	}

	return (tarindex);
}
char *sha_ncat(char *dst, char *src, int len)
{
        char *xdst = dst;
        int xlen = len;
	int r = strlen(dst);

	len -= r;
	dst += r;
        for (;(*src !=0) && (len>0); ) {*dst++  = *src++; len--;}
        *dst++ = 0;
        xdst[xlen] = 0;
        return xdst;
}

char *sha_ncpy(char *dst, const char *src, int len)
/*
Copies up (and including) len chars. Terminates with a null char.
So the size of dst should be at least (len+1)
*/
{
        char *xdst = dst;
        int xlen = len;
		if (!dst) return dst;
		if (!src) {
			*dst=0;
			return dst;
		}
/*        for (;(*src !=0) && (len>0); ) {*dst++  = *src++; len--;}*/
        for (;(len>0) && (*src !=0); ) {*dst++  = *src++; len--;}
		/* Changed from previous line by Matt since when len==0, should not try and read memory pointed to be src - BoundsChecker complained*/
        *dst++ = 0;
        xdst[xlen] = 0;
        return xdst;
}
static char sha_error[2000];
static int sha_error_init=0;
char *get_sha_error(void){
	return sha_error;
}

void set_sha_error(char *error,char *details){
	/*first half is always details of what tested, second half is error string*/
	static char detail[210]="";
	if (*details=='\0') sha_ncpy(detail,details,200);/*so can set error without deleting details*/
	sprintf(sha_error,"details:(%.200s) error:(%.200s)",details,error);
}

/*This is the main function to use for SHA (although SSHA is probably better to use)*/
int create_sha_base64_digest(char *passwd,char *ret,int ret_sz){
	/*if returns 1, has filled given buffer with the given password digested using SHA and then base64 encoded*/
	lutil_SHA1_CTX	SHA1context;
	unsigned char	SHA1digest[20];
	char		base64digest[29];  /* ceiling(sizeof(input)/3) * 4 + 1 */
	char			details[SHA_BFSZ];
	char			bf[SHA_BFSZ];
	char			cred[SHA_BFSZ];
	int				i,j;

	memset(base64digest,0,29);
	set_sha_error("No Errors","No Details"); sha_error_init=1;
	sha_ncpy(cred,passwd,SHA_BFSZ-1);
	sha_ncpy(ret,passwd,ret_sz-1);
	sprintf(details,"digesting password of (%.100s),",cred);

	lutil_SHA1Init(&SHA1context);
	lutil_SHA1Update(&SHA1context,(const unsigned char *) cred, lib_strlen(cred));
	lutil_SHA1Final(SHA1digest, &SHA1context);
	/*NB: digest is in hex at this stage so be careful not to use string routines on it until b64 encoded!*/

	/*Examine digest parts, only for putting in debug string*/
	sha_ncat(details,"Digest is:",SHA_BFSZ-1);
	for (i = 0; i < 5; i++) {
        for (j = 0; j < 4; j++) {
            sprintf(bf,"%02X", SHA1digest[i*4+j]);
			sha_ncat(details,bf,SHA_BFSZ-1);
        }
        sha_ncat(details," ",SHA_BFSZ-1);
    }
	set_sha_error("No Errors",details);/*record the details in the first half of error string*/
	sha_ncpy(bf,SHA1digest,sizeof(SHA1digest));/*deliberately truncate in case not null terminated*/
	sha_printf("digest is (%s)\n",bf);

	/*Do the base 64 encoding of the digest*/
	if (lutil_b64_ntop(SHA1digest, sizeof(SHA1digest),
		base64digest, sizeof(base64digest)) < 0)
	{
		return 0;/*ret contains original password*/
	}

	/*put result into return buffer*/
	sha_ncpy(ret,base64digest,ret_sz-1);
	return 1;
}
int create_sha_digest(char *cred, int cred_len, char *digest)
{
	lutil_SHA1_CTX	SHA1context;
	unsigned char	SHA1digest[20];
	char			details[SHA_BFSZ];

	set_sha_error("No Errors","No Details"); sha_error_init=1;
	lutil_SHA1Init(&SHA1context);
	lutil_SHA1Update(&SHA1context,(const unsigned char *) cred, cred_len);
	lutil_SHA1Final(SHA1digest, &SHA1context);
	set_sha_error("No Errors",details);/*record the details in the first half of error string*/
	memcpy(digest,SHA1digest,20);
	return 1;
}
int th_pid(void);
unsigned char *make_salt (unsigned char * salt, unsigned int len) {
	/*/
	/*struct timeval  tv;*/
	int i;

	/* seed random number generator */
	/*gettimeofday (&tv, NULL);
	srand (tv.tv_usec);*/
	srand((int)time(NULL) + th_pid());

	/*salt = (unsigned char *)malloc (len);*/
	salt = (unsigned char *)malloc (len+1);/*+1 so space to \0 terminate in case want to printf it*/
	if (salt==NULL) {
		set_sha_error("Could not create salt- malloc failed","");
		return NULL;
	}
	for (i = 0; (unsigned int)i <  len; i++)
		/*salt[i] = (tv.tv_usec ^ rand ()) & 0xff;*/
		salt[i] = (rand ()) & 0xff;
	salt[i]='\0';
	if (salt==NULL) {
		set_sha_error("Could not create salt","");
		return NULL;
	}
	return salt;
}
unsigned char * free_salt (unsigned char * salt) {
	if (salt) free(salt);
	salt=NULL;
	return salt;
}

int ssha_test(void)
{
	char bf2[SHA_BFSZ];
	char *test = "{ssha}VmjujDEYInuNIXMHyNUJu9FQ1KKOwX90";
	strcpy(bf2,"");
	raw_create_ssha("test",bf2,SHA_BFSZ-10,test+6);
	if (strcmp(bf2,test+6)==0) return 1;
	return 0;

}



/*This is the main function to use for SSHA (has added salt over SHA)*/
int create_ssha_base64_digest(char *passwd,char *ret,int ret_sz)
{
	return raw_create_ssha(passwd,ret,ret_sz,NULL);
}
int raw_create_ssha(char *passwd,char *ret,int ret_sz, char *old_digest)
{
	/*if returns 1, has filled given buffer with the given password digested using SSHA and then base64 encoded*/
	lutil_SHA1_CTX	SHA1context;
	unsigned char	SHA1digest[20];
	char		*base64digest=NULL; /*dynamic in case salt size different*/
	unsigned int	b64_len;
	char			cred[SHA_BFSZ];
	int				i,j;
	unsigned char	*salt=NULL;
	unsigned int	len_salt=4;  /*salt length for SSHA*/
	unsigned char	*hexbf=NULL;
	int				hexbf_len=0;
	char *rsalt;
	char			details[SHA_BFSZ];
	char			bf[SHA_BFSZ];
	int				bf_len=0;
	char old_salt[SHA_BFSZ];
	char orig[SHA_BFSZ];

#ifdef SHA_TESTING
	unsigned char	*orig_pass = NULL;
	int				pw_len=0;
#endif

	/*clear error/debug buffer etc.*/
	set_sha_error("No Errors","No Details"); sha_error_init=1;
	sha_ncpy(cred,passwd,SHA_BFSZ-1);
	sha_ncpy(ret,passwd,ret_sz-1);
	sprintf(details,"SSHA digesting password of (%.100s),",cred);

	/* create salt */
	rsalt = salt = make_salt(salt,len_salt);/*malloc space for salt*/
	if (old_digest!=NULL) {
		lutil_b64_pton(old_digest, orig,SHA_BFSZ-1);
		//sha_ncpy(bf,orig,(((lib_strlen(old_digest) * 3)/4) + 1)-1);/*terminate the unencoded string*/
		memcpy(old_salt,orig+20,4);
		old_salt[4] = 0;
		salt = old_salt;
	}
	/*printf("salt (%s)\n",salt);*/
	sha_ncat(details,"SSHA salt is:",SHA_BFSZ-1);
	if(salt==NULL)
		return 0;/*ret contains original password*/

	sha_ncat(details,"(",SHA_BFSZ-1); sha_ncat(details,salt,SHA_BFSZ-1); sha_ncat(details,")",SHA_BFSZ-1);

	/* hash credentials with salt */
	lutil_SHA1Init(&SHA1context);
	lutil_SHA1Update(&SHA1context,(const unsigned char *) cred, lib_strlen(cred));
	lutil_SHA1Update(&SHA1context,(const unsigned char *) salt,len_salt);
	lutil_SHA1Final(SHA1digest, &SHA1context);
	/*NB: digest is in hex at this stage so be careful not to use string routines on it until b64 encoded!*/

	/*Examine digest parts, only for putting in debug string*/
	sha_ncat(details,"SSHA Digest is:",SHA_BFSZ-1);
	for (i = 0; i < 5; i++) {
        for (j = 0; j < 4; j++) {
            sprintf(bf,"%02X", SHA1digest[i*4+j]);
			sha_ncat(details,bf,SHA_BFSZ-1);
        }
        sha_ncat(details," ",SHA_BFSZ-1);
    }
	set_sha_error("No Errors",details);/*record the debug details in the first half of error string*/

	/*join passwd and salt and make base64 buffer big enough for both*/
	hexbf_len=sizeof(SHA1digest)+len_salt;
	if (hexbf != NULL) free(hexbf);
	hexbf = (unsigned char *)malloc (hexbf_len);
	memcpy(hexbf,SHA1digest,sizeof(SHA1digest));
	memcpy(hexbf+sizeof(SHA1digest),salt,len_salt);

	sha_ncpy(bf,hexbf,hexbf_len);/*deliberately truncate at 20 chars as not null terminated!*/
	sha_printf("digest and salt is (%s)\n",bf);
	bf_len=sizeof(SHA1digest)+len_salt;

	b64_len = CEILING (bf_len / 3) * 4 + 1;
	sha_printf("bf_len (%d), b64_len (%d) hexbf_len (%d)\n",bf_len,b64_len,hexbf_len);
	if (base64digest != NULL) free(base64digest);
	base64digest = (unsigned char *)malloc (b64_len);
	if(base64digest==NULL){
		set_sha_error("SSHA: Could not create base64digest buffer - malloc failed","");
		free(hexbf);
		return 0;/*ret contains original password*/
	}

	/*Do the base 64 encoding of the digest with the salt added onto end*/
	if (lutil_b64_ntop(hexbf, hexbf_len, base64digest, b64_len) < 0)
	{
		rsalt=free_salt(rsalt);
		free(hexbf);
		free(base64digest);
		return 0;/*ret contains original password*/
	}
	/*put result into return buffer*/
	sha_ncpy(ret,base64digest,ret_sz-1);
#ifdef SHA_TESTING
	if (testing){
	/*try to unencode and separate and check still same salt and digest*/
		/* base64 un-encode password */
		pw_len=lib_strlen(base64digest);
		orig_pass = (unsigned char *)malloc(((pw_len * 3)/4) + 1);
		sha_printf("Unencode base64digest (%s) pw_len(%d) (%d)\n",base64digest,pw_len,((pw_len * 3)/4) + 1);
		if (lutil_b64_pton(base64digest, orig_pass,pw_len) < 0)
		{
			set_sha_error("SSHA Testing: Could not b64 unencode","");
			free(orig_pass);
			rsalt=free_salt(rsalt);
			free(hexbf);
			free(base64digest);
			return 0;
		}
		sha_ncpy(bf,orig_pass,(((pw_len * 3)/4) + 1)-1);/*terminate the unencoded string*/
		sha_printf("Unencoded base64digest plus salt (last 4 chars) (%s)\n",bf);
		for (i = 0; i < 5; i++) {
			for (j = 0; j < 4; j++) {
				sha_printf("%02X", orig_pass[i*4+j]);

			}
			sha_printf(" ");
		}
		sha_printf("\n");
		free(orig_pass);
	}
#endif
	salt=free_salt(rsalt);
	free(hexbf);
	free(base64digest);
	return 1;
}


#ifdef SHA_TESTINGx
int main (int argc,char **argv){
	char	given[SHA_BFSZ],bf[SHA_BFSZ];

	strcpy(given,"abc");
	strcpy(bf,"");
	testing=1;
	if (argc>1)
		strncpy(given,argv[1],SHA_BFSZ-1);
	else
		sha_printf("Usage:  shatest_oldap [credential]\nIf credential (password) not given will use \"abc\"\n\n");
	sha_printf("Testing with password (%s)\n",given);

	/* SHA */

	if (!create_sha_base64_digest(given,bf,SHA_BFSZ-1)){
		sha_printf("base 64 SHA1 digest creation failed! (%.400s)",get_sha_error());
		return 0;
	}

	/*access the error string for debug information*/
	sha_printf("\nDEBUG: get_sha_error(): \n(%.400s)\n\n",get_sha_error());

	/*printf a bunch of stuff to help with testing*/
	sha_printf("\nCheck against these Test Vectors (from FIPS PUB 180-1)\n\n");
	sha_printf("1. \"abc\"\n");
	sha_printf("A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D\n\n");
	sha_printf("2. \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\"\n");
	sha_printf("84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1\n\n");
	sha_printf("3. A million repetitions of \"a\"\n");
	sha_printf("34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F\n\n");

	/*print actual output with {sha} on front as needed for openldap*/
	sha_printf("RESULT:\n",bf);
	sha_printf("base64 SHA1 digest for oldap is --> ( {sha}%s )\n",bf);


	/* SSHA = SHA with salt*/

	if (!create_ssha_base64_digest(given,bf,SHA_BFSZ-1)){
		sha_printf("base64 SSHA1 digest creation failed! (%.400s)",get_sha_error());
		return 0;
	}
	/*access the error string just for debug information*/
	sha_printf("\nDEBUG: get_sha_error(): \n(%.400s)\n\n",get_sha_error());
	/*print actual output with {sha} on front as needed for openldap*/
	sha_printf("RESULT:\n",bf);
	sha_printf("base64 SSHA1 digest for oldap is --> ( {ssha}%s )\n",bf);

	return 0;
}
#endif



#ifndef SHA_DIGESTSIZE
#define SHA_DIGESTSIZE  20
#endif

#ifndef SHA_BLOCKSIZE
#define SHA_BLOCKSIZE   64
#endif



#define BFSZ 1000
char *mylib_bin_to_hex(char *bin, int binlen, char *out, int outlen)
{
	unsigned char *ubin=(unsigned char *) bin;
	int i;
	int z;
	char *out_start = out;
	for (i=0; i<binlen; i++,ubin++)  {
	      sprintf(out,"%02x",(unsigned int) *ubin);
	      z = lib_strlen(out);
	      out += z;
	      outlen -= z;
	      if (outlen<20) break;
	 }
	*out = 0;
	 return out_start;
}

int hmac_sha_test(void)
{
	char bf[BFSZ];
	char digest[BFSZ];
	int len;
	char *key =         "Jefe";
	char *data =        "what do ya want for nothing?";
	char *digest_text =      "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79";



	hmac_sha(data,lib_strlen(data),key,lib_strlen(key),digest,&len);
	mylib_bin_to_hex(digest,len,bf,BFSZ);
	//printf("Hex (%s)\n",bf);
	//printf("Hex (%s)\n",digest_text);
	if (strcmp(bf,digest_text)!=0) printf("HMAC_TEST FAILED\n");
	//else printf("HMAC WORKED\n");
	return 1;
}



void hmac_sha(char *d, int ld, char *k, int lk, char *out, int *outsz) 
{
	lutil_SHA1_CTX ictx, octx ;
	char    isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ;
	char    key[SHA_DIGESTSIZE] ;
	char    buf[SHA_BLOCKSIZE] ;
	int     i ;

	if (lk > SHA_BLOCKSIZE) {

		   lutil_SHA1_CTX         tctx ;

		   lutil_SHA1Init(&tctx) ;
		   lutil_SHA1Update(&tctx, k, lk) ;
		   lutil_SHA1Final(key, &tctx) ;

		   k = key ;
		   lk = SHA_DIGESTSIZE ;
	}

	/**** Inner Digest ****/

	lutil_SHA1Init(&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 ;

	lutil_SHA1Update(&ictx, buf, SHA_BLOCKSIZE) ;
	lutil_SHA1Update(&ictx, d, ld) ;

	lutil_SHA1Final(isha, &ictx) ;

	/**** Outter Digest ****/

	lutil_SHA1Init(&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 ;

	lutil_SHA1Update(&octx, buf, SHA_BLOCKSIZE) ;
	lutil_SHA1Update(&octx, isha, SHA_DIGESTSIZE) ;

	lutil_SHA1Final(osha, &octx) ;

	*outsz = SHA_DIGESTSIZE;
	memcpy(out,osha,SHA_DIGESTSIZE);
}
