Thu Jul 25 13:59:34 CEST 2002 Paolo Molaro <lupus@ximian.com>
authorPaolo Molaro <lupus@oddwiz.org>
Thu, 25 Jul 2002 12:02:04 +0000 (12:02 -0000)
committerPaolo Molaro <lupus@oddwiz.org>
Thu, 25 Jul 2002 12:02:04 +0000 (12:02 -0000)
* mono-digest.h, mono-md5.c, mono-sha1.c: MD5 and SHA1
implementations.

svn path=/trunk/mono/; revision=6169

mono/utils/ChangeLog
mono/utils/Makefile.am
mono/utils/mono-digest.h [new file with mode: 0644]
mono/utils/mono-md5.c [new file with mode: 0644]
mono/utils/mono-sha1.c [new file with mode: 0644]

index 9702e9e77d9afc552668d91a3e938f907095e48a..292d5d89057052e3f2ca1116cd4bfb4bf7ae50bb 100644 (file)
@@ -1,4 +1,9 @@
 
+Thu Jul 25 13:59:34 CEST 2002 Paolo Molaro <lupus@ximian.com>
+
+       * mono-digest.h, mono-md5.c, mono-sha1.c: MD5 and SHA1
+       implementations.
+
 Mon Jun 3 15:59:31 CEST 2002 Paolo Molaro <lupus@ximian.com>
 
        * strtod.c: make __bsd_dtoa() always return malloc()ed memory.
index ceaf6edee5c9505f7acb450aa1d24ef57a399406..525906d77179508e1b8619e47be2fc3d03e6d13a 100644 (file)
@@ -4,6 +4,8 @@ INCLUDES = $(GLIB_CFLAGS) $(GMODULE_CFLAGS) -I$(top_srcdir)     -I$(top_srcdir)/mono
 
 libmonoutils_la_SOURCES = \
        mono-hash.c     \
+       mono-md5.c      \
+       mono-sha1.c     \
        monobitset.c    \
        strtod.h        \
        strtod.c
@@ -12,6 +14,7 @@ libmonoutilsincludedir = $(includedir)/mono/utils
 
 libmonoutilsinclude_HEADERS = \
        monobitset.h    \
+       mono-digest.h   \
        mono-hash.h
 
 EXTRA_DIST = ChangeLog
diff --git a/mono/utils/mono-digest.h b/mono/utils/mono-digest.h
new file mode 100644 (file)
index 0000000..7a0cc27
--- /dev/null
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to rpmMD5Init, call rpmMD5Update as
+ * needed on buffers full of bytes, and then call rpmMD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* parts of this file are :
+ * Written March 1993 by Branko Lankester
+ * Modified June 1993 by Colin Plumb for altered md5.c.
+ * Modified October 1995 by Erik Troan for RPM
+ */
+
+
+#ifndef __MONO_DIGEST_H__
+#define __MONO_DIGEST_H__
+
+#include <glib.h>
+
+typedef struct {
+       guint32 buf[4];
+       guint32 bits[2];
+       guchar in[64];
+       gint doByteReverse;
+} MonoMD5Context;
+
+void mono_md5_get_digest (const gchar *buffer, gint buffer_size, guchar digest[16]);
+
+/* use this one when speed is needed */
+/* for use in provider code only */
+void mono_md5_get_digest_from_file (const gchar *filename, guchar digest[16]);
+
+/* raw routines */
+void mono_md5_init   (MonoMD5Context *ctx);
+void mono_md5_update (MonoMD5Context *ctx, const guchar *buf, guint32 len);
+void mono_md5_final  (MonoMD5Context *ctx, guchar digest[16]);
+
+typedef struct {
+    guint32 state[5];
+    guint32 count[2];
+    unsigned char buffer[64];
+} MonoSHA1Context;
+
+void mono_sha1_get_digest (const gchar *buffer, gint buffer_size, guchar digest [20]);
+void mono_sha1_get_digest_from_file (const gchar *filename, guchar digest [20]);
+
+void mono_sha1_init   (MonoSHA1Context* context);
+void mono_sha1_update (MonoSHA1Context* context, const guchar* data, guint32 len);
+void mono_sha1_final  (MonoSHA1Context* context, unsigned char digest[20]);
+
+#endif /* __MONO_DIGEST_H__ */
diff --git a/mono/utils/mono-md5.c b/mono/utils/mono-md5.c
new file mode 100644 (file)
index 0000000..28adc40
--- /dev/null
@@ -0,0 +1,357 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MonoMD5Context structure, pass it to mono_md5_init, call mono_md5_update as
+ * needed on buffers full of bytes, and then call md5_Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* parts of this file are :
+ * Written March 1993 by Branko Lankester
+ * Modified June 1993 by Colin Plumb for altered md5.c.
+ * Modified October 1995 by Erik Troan for RPM
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include "mono-digest.h"
+
+static void md5_transform (guint32 buf[4], const guint32 in[16]);
+
+static gint _ie = 0x44332211;
+static union _endian { gint i; gchar b[4]; } *_endian = (union _endian *)&_ie;
+#define        IS_BIG_ENDIAN()         (_endian->b[0] == '\x44')
+#define        IS_LITTLE_ENDIAN()      (_endian->b[0] == '\x11')
+
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void 
+_byte_reverse (guchar *buf, guint32 longs)
+{
+       guint32 t;
+       do {
+               t = (guint32) ((guint32) buf[3] << 8 | buf[2]) << 16 |
+                       ((guint32) buf[1] << 8 | buf[0]);
+               *(guint32 *) buf = t;
+               buf += 4;
+       } while (--longs);
+}
+
+/**
+ * mono_md5_init: Initialise an md5 context object
+ * @ctx: md5 context 
+ * 
+ * Initialise an md5 buffer. 
+ *
+ **/
+void 
+mono_md5_init (MonoMD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+       
+       ctx->bits[0] = 0;
+       ctx->bits[1] = 0;
+       
+       if (IS_BIG_ENDIAN())    
+               ctx->doByteReverse = 1;         
+       else 
+               ctx->doByteReverse = 0; 
+}
+
+
+
+/**
+ * mono_md5_update: add a buffer to md5 hash computation
+ * @ctx: conetxt object used for md5 computaion
+ * @buf: buffer to add
+ * @len: buffer length
+ * 
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes. Use this to progressively construct an md5 hash.
+ **/
+void 
+mono_md5_update (MonoMD5Context *ctx, const guchar *buf, guint32 len)
+{
+       guint32 t;
+       
+       /* Update bitcount */
+       
+       t = ctx->bits[0];
+       if ((ctx->bits[0] = t + ((guint32) len << 3)) < t)
+               ctx->bits[1]++;         /* Carry from low to high */
+       ctx->bits[1] += len >> 29;
+       
+       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+       
+       /* Handle any leading odd-sized chunks */
+       
+       if (t) {
+               guchar *p = (guchar *) ctx->in + t;
+               
+               t = 64 - t;
+               if (len < t) {
+                       memcpy (p, buf, len);
+                       return;
+               }
+               memcpy (p, buf, t);
+               if (ctx->doByteReverse)
+                       _byte_reverse (ctx->in, 16);
+               md5_transform (ctx->buf, (guint32 *) ctx->in);
+               buf += t;
+               len -= t;
+       }
+       /* Process data in 64-byte chunks */
+       
+       while (len >= 64) {
+               memcpy (ctx->in, buf, 64);
+               if (ctx->doByteReverse)
+                       _byte_reverse (ctx->in, 16);
+               md5_transform (ctx->buf, (guint32 *) ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+       
+       /* Handle any remaining bytes of data. */
+       
+       memcpy (ctx->in, buf, len);
+}
+
+
+
+
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+/**
+ * mono_md5_final: copy the final md5 hash to a bufer
+ * @digest: 16 bytes buffer
+ * @ctx: context containing the calculated md5
+ * 
+ * copy the final md5 hash to a bufer
+ **/
+void 
+mono_md5_final (MonoMD5Context *ctx, guchar digest[16])
+{
+       guint32 count;
+       guchar *p;
+       
+       /* Compute number of bytes mod 64 */
+       count = (ctx->bits[0] >> 3) & 0x3F;
+       
+       /* Set the first char of padding to 0x80.  This is safe since there is
+          always at least one byte free */
+       p = ctx->in + count;
+       *p++ = 0x80;
+       
+       /* Bytes of padding needed to make 64 bytes */
+       count = 64 - 1 - count;
+       
+       /* Pad out to 56 mod 64 */
+       if (count < 8) {
+               /* Two lots of padding:  Pad the first block to 64 bytes */
+               memset (p, 0, count);
+               if (ctx->doByteReverse)
+                       _byte_reverse (ctx->in, 16);
+               md5_transform (ctx->buf, (guint32 *) ctx->in);
+               
+               /* Now fill the next block with 56 bytes */
+               memset (ctx->in, 0, 56);
+       } else {
+               /* Pad block to 56 bytes */
+               memset (p, 0, count - 8);
+       }
+       if (ctx->doByteReverse)
+               _byte_reverse (ctx->in, 14);
+       
+       /* Append length in bits and transform */
+       ((guint32 *) ctx->in)[14] = ctx->bits[0];
+       ((guint32 *) ctx->in)[15] = ctx->bits[1];
+       
+       md5_transform (ctx->buf, (guint32 *) ctx->in);
+       if (ctx->doByteReverse)
+               _byte_reverse ((guchar *) ctx->buf, 4);
+       memcpy (digest, ctx->buf, 16);
+}
+
+
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  md5_Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void 
+md5_transform (guint32 buf[4], const guint32 in[16])
+{
+       register guint32 a, b, c, d;
+       
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+       
+       MD5STEP (F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+       MD5STEP (F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+       MD5STEP (F1, c, d, a, b, in[2] + 0x242070db, 17);
+       MD5STEP (F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+       MD5STEP (F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+       MD5STEP (F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+       MD5STEP (F1, c, d, a, b, in[6] + 0xa8304613, 17);
+       MD5STEP (F1, b, c, d, a, in[7] + 0xfd469501, 22);
+       MD5STEP (F1, a, b, c, d, in[8] + 0x698098d8, 7);
+       MD5STEP (F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+       MD5STEP (F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+       MD5STEP (F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+       MD5STEP (F1, a, b, c, d, in[12] + 0x6b901122, 7);
+       MD5STEP (F1, d, a, b, c, in[13] + 0xfd987193, 12);
+       MD5STEP (F1, c, d, a, b, in[14] + 0xa679438e, 17);
+       MD5STEP (F1, b, c, d, a, in[15] + 0x49b40821, 22);
+       
+       MD5STEP (F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+       MD5STEP (F2, d, a, b, c, in[6] + 0xc040b340, 9);
+       MD5STEP (F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+       MD5STEP (F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+       MD5STEP (F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+       MD5STEP (F2, d, a, b, c, in[10] + 0x02441453, 9);
+       MD5STEP (F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+       MD5STEP (F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+       MD5STEP (F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+       MD5STEP (F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+       MD5STEP (F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+       MD5STEP (F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+       MD5STEP (F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+       MD5STEP (F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+       MD5STEP (F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+       MD5STEP (F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+       
+       MD5STEP (F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+       MD5STEP (F3, d, a, b, c, in[8] + 0x8771f681, 11);
+       MD5STEP (F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+       MD5STEP (F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+       MD5STEP (F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+       MD5STEP (F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+       MD5STEP (F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+       MD5STEP (F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+       MD5STEP (F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+       MD5STEP (F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+       MD5STEP (F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+       MD5STEP (F3, b, c, d, a, in[6] + 0x04881d05, 23);
+       MD5STEP (F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+       MD5STEP (F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+       MD5STEP (F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+       MD5STEP (F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+       
+       MD5STEP (F4, a, b, c, d, in[0] + 0xf4292244, 6);
+       MD5STEP (F4, d, a, b, c, in[7] + 0x432aff97, 10);
+       MD5STEP (F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+       MD5STEP (F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+       MD5STEP (F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+       MD5STEP (F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+       MD5STEP (F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+       MD5STEP (F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+       MD5STEP (F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+       MD5STEP (F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+       MD5STEP (F4, c, d, a, b, in[6] + 0xa3014314, 15);
+       MD5STEP (F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+       MD5STEP (F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+       MD5STEP (F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+       MD5STEP (F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+       MD5STEP (F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+       
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+
+
+
+/**
+ * mono_md5_get_digest: get the md5 hash of a buffer
+ * @buffer: byte buffer
+ * @buffer_size: buffer size (in bytes)
+ * @digest: 16 bytes buffer receiving the hash code.
+ * 
+ * Get the md5 hash of a buffer. The result is put in 
+ * the 16 bytes buffer @digest .
+ **/
+void
+mono_md5_get_digest (const gchar *buffer, gint buffer_size, guchar digest[16])
+{      
+       MonoMD5Context ctx;
+
+       mono_md5_init (&ctx);
+       mono_md5_update (&ctx, buffer, buffer_size);
+       mono_md5_final (&ctx, digest);
+       
+}
+
+
+/**
+ * mono_md5_get_digest_from_file: get the md5 hash of a file
+ * @filename: file name
+ * @digest: 16 bytes buffer receiving the hash code.
+ * 
+ * Get the md5 hash of a file. The result is put in 
+ * the 16 bytes buffer @digest .
+ **/
+void
+mono_md5_get_digest_from_file (const gchar *filename, guchar digest[16])
+{      
+       MonoMD5Context ctx;
+       guchar tmp_buf[1024];
+       gint nb_bytes_read;
+       FILE *fp;
+
+       mono_md5_init (&ctx);
+       fp = fopen(filename, "r");
+       if (!fp) {
+               return;
+       }
+       
+       while ((nb_bytes_read = fread (tmp_buf, sizeof (guchar), 1024, fp)) > 0)
+               mono_md5_update (&ctx, tmp_buf, nb_bytes_read);
+       
+       if (ferror(fp)) {
+               fclose(fp);
+               return;
+       }
+
+       mono_md5_final (&ctx, digest);
+}
+
+
+
+
diff --git a/mono/utils/mono-sha1.c b/mono/utils/mono-sha1.c
new file mode 100644 (file)
index 0000000..642c0c8
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98 
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine mono_sha1_update changed from
+       void mono_sha1_update(MonoSHA1Context* context, unsigned char* data, unsigned int
+len)
+to
+       void mono_sha1_update(MonoSHA1Context* 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 mono_sha1_update().
+
+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 mono_sha1_update 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 <process.h> for exit() prototype
+2. Removed unused variable 'j' in mono_sha1_final
+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 <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in mono_sha1_final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.  
+
+
+*/
+
+/*
+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  */
+
+#include <stdio.h>
+#include <string.h>
+#include "mono-digest.h"
+
+#ifndef  i386   /* For ALPHA  (SAK) */
+#define LITTLE_ENDIAN 
+typedef          long int int64;
+typedef unsigned long int uint64;
+typedef          int int32;
+typedef unsigned int uint32;
+#else  /*i386*/
+#define LITTLE_ENDIAN 
+typedef          long long int int64;
+typedef unsigned long long int uint64;
+typedef          long int int32;
+typedef unsigned long int uint32;
+#endif /*i386*/
+
+
+/* #include <process.h> */     /* prototype for exit() - JHB */
+/* Using return() instead of exit() - SWR */
+
+static void SHA1Transform(guint32 state[5], const guchar buffer[64]);
+
+#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 */
+#ifdef 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 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);
+
+
+#ifdef VERBOSE  /* SAK */
+static void SHAPrintContext(MonoSHA1Context *context, char *msg){
+  printf("%s (%d,%d) %x %x %x %x %x\n",
+        msg,
+        context->count[0], context->count[1], 
+        context->state[0],
+        context->state[1],
+        context->state[2],
+        context->state[3],
+        context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+static void SHA1Transform(guint32 state[5], const guchar buffer[64])
+{
+uint32 a, b, c, d, e;
+typedef union {
+    unsigned char c[64];
+    uint32 l[16];
+} CHAR64LONG16;
+CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+static unsigned char workspace[64];
+    block = (CHAR64LONG16*)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;
+}
+
+
+/* mono_sha1_init - Initialize new context */
+
+void mono_sha1_init(MonoSHA1Context* 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 mono_sha1_update(MonoSHA1Context* context, const guchar* data, guint32 len)       /*
+JHB */
+{
+uint32 i, j;   /* JHB */
+
+#ifdef VERBOSE
+    SHAPrintContext(context, "before");
+#endif
+    j = (context->count[0] >> 3) & 63;
+    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+    context->count[1] += (len >> 29);
+    if ((j + len) > 63) {
+        memcpy(&context->buffer[j], data, (i = 64-j));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; i + 63 < len; i += 64) {
+            SHA1Transform(context->state, &data[i]);
+        }
+        j = 0;
+    }
+    else i = 0;
+    memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+    SHAPrintContext(context, "after ");
+#endif
+}
+
+
+/* Add padding and return the message digest. */
+
+void mono_sha1_final( MonoSHA1Context* context, unsigned char digest[20])
+{
+uint32 i;      /* JHB */
+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 */
+    }
+    mono_sha1_update(context, (unsigned char *)"\200", 1);
+    while ((context->count[0] & 504) != 448) {
+        mono_sha1_update(context, (unsigned char *)"\0", 1);
+    }
+    mono_sha1_update(context, finalcount, 8);  /* Should cause a SHA1Transform()
+*/
+    for (i = 0; i < 20; i++) {
+        digest[i] = (unsigned char)
+         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+    /* Wipe variables */
+    i = 0;     /* JHB */
+    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 it's own static vars */
+    SHA1Transform(context->state, context->buffer);
+#endif
+}
+void
+mono_sha1_get_digest (const gchar *buffer, gint buffer_size, guchar digest [20])
+{      
+       MonoSHA1Context ctx;
+
+       mono_sha1_init (&ctx);
+       mono_sha1_update (&ctx, buffer, buffer_size);
+       mono_sha1_final (&ctx, digest);
+       
+}
+
+void
+mono_sha1_get_digest_from_file (const gchar *filename, guchar digest [20])
+{      
+       MonoSHA1Context ctx;
+       guchar tmp_buf[1024];
+       gint nb_bytes_read;
+       FILE *fp;
+
+       mono_sha1_init (&ctx);
+       fp = fopen(filename, "r");
+       if (!fp) {
+               return;
+       }
+       
+       while ((nb_bytes_read = fread (tmp_buf, sizeof (guchar), 1024, fp)) > 0)
+               mono_sha1_update (&ctx, tmp_buf, nb_bytes_read);
+       
+       if (ferror(fp)) {
+               fclose(fp);
+               return;
+       }
+
+       mono_sha1_final (&ctx, digest);
+}
+