summaryrefslogtreecommitdiffstats
path: root/md5
diff options
context:
space:
mode:
authorSam Varshavchik2013-08-19 16:39:41 -0400
committerSam Varshavchik2013-08-25 14:43:51 -0400
commit9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch)
tree7a81a04cb51efb078ee350859a64be2ebc6b8813 /md5
parenta9520698b770168d1f33d6301463bb70a19655ec (diff)
downloadcourier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2
Initial checkin
Imported from subversion report, converted to git. Updated all paths in scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'md5')
-rw-r--r--md5/.gitignore1
-rw-r--r--md5/Makefile.am28
-rw-r--r--md5/configure.in99
-rw-r--r--md5/hmac.c35
-rw-r--r--md5/md5.c278
-rw-r--r--md5/md5.h65
-rw-r--r--md5/md5_hash.c67
-rw-r--r--md5/md5test.c46
-rw-r--r--md5/md5test.txt24
-rw-r--r--md5/redhat-crypt-md5.c125
10 files changed, 768 insertions, 0 deletions
diff --git a/md5/.gitignore b/md5/.gitignore
new file mode 100644
index 0000000..b81ee39
--- /dev/null
+++ b/md5/.gitignore
@@ -0,0 +1 @@
+/md5test
diff --git a/md5/Makefile.am b/md5/Makefile.am
new file mode 100644
index 0000000..2e2c8e9
--- /dev/null
+++ b/md5/Makefile.am
@@ -0,0 +1,28 @@
+#
+# Copyright 1998 - 2005 Double Precision, Inc. See COPYING for
+# distribution information.
+
+
+if HMACC
+HMAC=hmac.c
+else
+HMAC=
+endif
+
+libmd5_la_SOURCES=md5.c md5.h md5_hash.c redhat-crypt-md5.c $(HMAC)
+
+CLEANFILES=$(noinst_DATA)
+
+noinst_LTLIBRARIES=libmd5.la
+
+noinst_PROGRAMS=md5test
+
+md5test_SOURCES=md5test.c
+md5test_DEPENDENCIES=libmd5.la
+md5test_LDADD=libmd5.la
+md5test_LDFLAGS=-static
+
+EXTRA_DIST=md5test.txt hmac.c
+
+check-am:
+ ./md5test | cmp -s - $(srcdir)/md5test.txt
diff --git a/md5/configure.in b/md5/configure.in
new file mode 100644
index 0000000..7808f06
--- /dev/null
+++ b/md5/configure.in
@@ -0,0 +1,99 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright 1998 - 2004 Double Precision, Inc. See COPYING for
+dnl distribution information.
+
+AC_PREREQ(2.59)
+AC_INIT(libmd5, 1.21, courier-users@lists.sourceforge.net)
+
+>confdefs.h # Kill PACKAGE_ macros
+
+AC_CONFIG_SRCDIR([hmac.c])
+AC_CONFIG_AUX_DIR(../..)
+AM_CONFIG_HEADER([config.h])
+AM_INIT_AUTOMAKE([foreign no-define])
+
+AM_CONDITIONAL(HMACC, test -d ${srcdir}/../libhmac)
+
+dnl Checks for programs.
+AC_PROG_AWK
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_CC
+AC_PROG_LIBTOOL
+
+if test "$GCC" = yes
+then
+ CFLAGS="-Wall $CFLAGS"
+fi
+
+CFLAGS="$CFLAGS -I$srcdir/.. -I.."
+
+dnl Checks for libraries.
+
+dnl Checks for header files.
+AC_HEADER_STDC
+
+AC_CHECK_HEADERS(sys/types.h)
+
+
+AC_ARG_WITH(int32,
+[ --with-int32='type' use 'type' for an unsigned 32 bit integer type
+ ( default is 'unsigned')],
+ int32="$withval", [
+
+ AC_MSG_CHECKING(for uint32_t)
+
+ AC_TRY_COMPILE([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+ ],[
+ uint32_t i=0;
+ ], [ AC_MSG_RESULT(yes) ; int32="uint32_t"], [
+
+ AC_MSG_RESULT(no)
+ AC_MSG_CHECKING(for u_int_32_t)
+
+ AC_TRY_COMPILE([
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+ ],[
+ u_int32_t i=0;
+ ], [AC_MSG_RESULT(yes); int32="u_int32_t"],[
+
+ AC_MSG_RESULT(no)
+
+ AC_CHECK_SIZEOF(unsigned, 0)
+ if test "$ac_cv_sizeof_unsigned" != 4
+ then
+ AC_CHECK_SIZEOF(unsigned long, 0)
+ if test "$ac_cv_sizeof_unsigned_long" != 4
+ then
+ AC_CHECK_SIZEOF(unsigned short, 0)
+ if test "$ac_cv_sizeof_unsigned_short" != 4
+ then
+ AC_ERROR(--with-int32 option is required)
+ fi
+ int32="unsigned short"
+ fi
+ int32="unsigned long"
+ else
+ int32="unsigned"
+ fi
+ ])
+ ])
+ ]
+)
+UINT32="$int32"
+
+AC_DEFINE_UNQUOTED(MD5_WORD, $UINT32, [ 32 bit data type ])
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_SYS_LARGEFILE
+
+dnl Checks for library functions.
+
+AC_OUTPUT(Makefile)
diff --git a/md5/hmac.c b/md5/hmac.c
new file mode 100644
index 0000000..26589ab
--- /dev/null
+++ b/md5/hmac.c
@@ -0,0 +1,35 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#define MD5_INTERNAL
+#include "md5.h"
+#include "../libhmac/hmac.h"
+
+static void alloc_context( void (*func)(void *, void *), void *arg)
+{
+struct MD5_CONTEXT c;
+
+ (*func)((void *)&c, arg);
+}
+
+static void alloc_hash( void (*func)(unsigned char *, void *), void *arg)
+{
+unsigned char c[MD5_DIGEST_SIZE];
+
+ (*func)(c, arg);
+}
+
+struct hmac_hashinfo hmac_md5 = {
+ "md5",
+ MD5_BLOCK_SIZE,
+ MD5_DIGEST_SIZE,
+ sizeof(struct MD5_CONTEXT),
+ (void (*)(void *))md5_context_init,
+ (void (*)(void *, const void *, unsigned))md5_context_hashstream,
+ (void (*)(void *, unsigned long))md5_context_endstream,
+ (void (*)(void *, unsigned char *))md5_context_digest,
+ (void (*)(void *, const unsigned char *))md5_context_restore,
+ alloc_context,
+ alloc_hash};
diff --git a/md5/md5.c b/md5/md5.c
new file mode 100644
index 0000000..f718389
--- /dev/null
+++ b/md5/md5.c
@@ -0,0 +1,278 @@
+/*
+** Copyright 1998 - 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#define MD5_INTERNAL
+#include "md5.h"
+#include <string.h>
+#include <stdlib.h>
+
+
+#define MD5_BYTE unsigned char
+
+#define MD5_ROL(w,n) \
+ ( (w) << (n) | ( (w) >> (32-(n)) ) )
+
+static MD5_WORD T[64]={
+0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
+
+void md5_context_init(struct MD5_CONTEXT *c)
+{
+ if (sizeof(MD5_WORD) != 4) abort();
+
+ c->A=0x67452301;
+ c->B=0xefcdab89;
+ c->C=0x98badcfe;
+ c->D=0x10325476;
+
+ c->blk_ptr=0;
+}
+
+void md5_context_hash(struct MD5_CONTEXT *c,
+ const unsigned char blk[MD5_BLOCK_SIZE])
+{
+MD5_WORD x[16];
+unsigned i, j;
+MD5_WORD A, B, C, D;
+MD5_WORD zz;
+
+ for (i=j=0; i<16; i++)
+ {
+ MD5_WORD w=(MD5_WORD)blk[j++];
+
+ w |= (MD5_WORD)blk[j++] << 8;
+ w |= (MD5_WORD)blk[j++] << 16;
+ w |= (MD5_WORD)blk[j++] << 24;
+ x[i]= w;
+ }
+
+#define F(X,Y,Z) ( ((X) & (Y)) | ( (~(X)) & (Z)))
+#define G(X,Y,Z) ( ((X) & (Z)) | ( (Y) & (~(Z))))
+#define H(X,Y,Z) ( (X) ^ (Y) ^ (Z) )
+#define I(X,Y,Z) ( (Y) ^ ( (X) | (~(Z))))
+
+ A=c->A;
+ B=c->B;
+ C=c->C;
+ D=c->D;
+
+#define ROUND1(a,b,c,d,k,s,i) \
+ { zz=(a + F(b,c,d) + x[k] + T[i]); a=b+MD5_ROL(zz,s); }
+
+ ROUND1(A,B,C,D,0,7,0);
+ ROUND1(D,A,B,C,1,12,1);
+ ROUND1(C,D,A,B,2,17,2);
+ ROUND1(B,C,D,A,3,22,3);
+ ROUND1(A,B,C,D,4,7,4);
+ ROUND1(D,A,B,C,5,12,5);
+ ROUND1(C,D,A,B,6,17,6);
+ ROUND1(B,C,D,A,7,22,7);
+ ROUND1(A,B,C,D,8,7,8);
+ ROUND1(D,A,B,C,9,12,9);
+ ROUND1(C,D,A,B,10,17,10);
+ ROUND1(B,C,D,A,11,22,11);
+ ROUND1(A,B,C,D,12,7,12);
+ ROUND1(D,A,B,C,13,12,13);
+ ROUND1(C,D,A,B,14,17,14);
+ ROUND1(B,C,D,A,15,22,15);
+
+#define ROUND2(a,b,c,d,k,s,i) \
+ { zz=(a + G(b,c,d) + x[k] + T[i]); a = b + MD5_ROL(zz,s); }
+
+ ROUND2(A,B,C,D,1,5,16);
+ ROUND2(D,A,B,C,6,9,17);
+ ROUND2(C,D,A,B,11,14,18);
+ ROUND2(B,C,D,A,0,20,19);
+ ROUND2(A,B,C,D,5,5,20);
+ ROUND2(D,A,B,C,10,9,21);
+ ROUND2(C,D,A,B,15,14,22);
+ ROUND2(B,C,D,A,4,20,23);
+ ROUND2(A,B,C,D,9,5,24);
+ ROUND2(D,A,B,C,14,9,25);
+ ROUND2(C,D,A,B,3,14,26);
+ ROUND2(B,C,D,A,8,20,27);
+ ROUND2(A,B,C,D,13,5,28);
+ ROUND2(D,A,B,C,2,9,29);
+ ROUND2(C,D,A,B,7,14,30);
+ ROUND2(B,C,D,A,12,20,31);
+
+#define ROUND3(a,b,c,d,k,s,i) \
+ { zz=(a + H(b,c,d) + x[k] + T[i]); a = b + MD5_ROL(zz,s); }
+
+ ROUND3(A,B,C,D,5,4,32);
+ ROUND3(D,A,B,C,8,11,33);
+ ROUND3(C,D,A,B,11,16,34);
+ ROUND3(B,C,D,A,14,23,35);
+ ROUND3(A,B,C,D,1,4,36);
+ ROUND3(D,A,B,C,4,11,37);
+ ROUND3(C,D,A,B,7,16,38);
+ ROUND3(B,C,D,A,10,23,39);
+ ROUND3(A,B,C,D,13,4,40);
+ ROUND3(D,A,B,C,0,11,41);
+ ROUND3(C,D,A,B,3,16,42);
+ ROUND3(B,C,D,A,6,23,43);
+ ROUND3(A,B,C,D,9,4,44);
+ ROUND3(D,A,B,C,12,11,45);
+ ROUND3(C,D,A,B,15,16,46);
+ ROUND3(B,C,D,A,2,23,47);
+
+#define ROUND4(a,b,c,d,k,s,i) \
+ { zz=(a + I(b,c,d) + x[k] + T[i]); a = b + MD5_ROL(zz,s); }
+
+ ROUND4(A,B,C,D,0,6,48);
+ ROUND4(D,A,B,C,7,10,49);
+ ROUND4(C,D,A,B,14,15,50);
+ ROUND4(B,C,D,A,5,21,51);
+ ROUND4(A,B,C,D,12,6,52);
+ ROUND4(D,A,B,C,3,10,53);
+ ROUND4(C,D,A,B,10,15,54);
+ ROUND4(B,C,D,A,1,21,55);
+ ROUND4(A,B,C,D,8,6,56);
+ ROUND4(D,A,B,C,15,10,57);
+ ROUND4(C,D,A,B,6,15,58);
+ ROUND4(B,C,D,A,13,21,59);
+ ROUND4(A,B,C,D,4,6,60);
+ ROUND4(D,A,B,C,11,10,61);
+ ROUND4(C,D,A,B,2,15,62);
+ ROUND4(B,C,D,A,9,21,63);
+
+ c->A += A;
+ c->B += B;
+ c->C += C;
+ c->D += D;
+}
+
+void md5_context_hashstream(struct MD5_CONTEXT *c, const void *p, unsigned l)
+{
+const unsigned char *cp=(const unsigned char *)p;
+unsigned ll;
+
+ while (l)
+ {
+ if (c->blk_ptr == 0 && l >= MD5_BLOCK_SIZE)
+ {
+ md5_context_hash(c, cp);
+ cp += MD5_BLOCK_SIZE;
+ l -= MD5_BLOCK_SIZE;
+ continue;
+ }
+
+ ll=l;
+ if (ll > MD5_BLOCK_SIZE - c->blk_ptr)
+ ll=MD5_BLOCK_SIZE - c->blk_ptr;
+ memcpy(c->blk + c->blk_ptr, cp, ll);
+ c->blk_ptr += ll;
+ cp += ll;
+ l -= ll;
+ if (c->blk_ptr >= MD5_BLOCK_SIZE)
+ {
+ md5_context_hash(c, c->blk);
+ c->blk_ptr=0;
+ }
+ }
+}
+
+void md5_context_endstream(struct MD5_CONTEXT *c, unsigned long ll)
+{
+unsigned char buf[8];
+
+static unsigned char zero[MD5_BLOCK_SIZE-8];
+MD5_WORD l;
+
+ buf[0]=0x80;
+ md5_context_hashstream(c, buf, 1);
+ while (c->blk_ptr != MD5_BLOCK_SIZE - 8)
+ {
+ if (c->blk_ptr > MD5_BLOCK_SIZE - 8)
+ {
+ md5_context_hashstream(c, zero,
+ MD5_BLOCK_SIZE - c->blk_ptr);
+ continue;
+ }
+ md5_context_hashstream(c, zero,
+ MD5_BLOCK_SIZE - 8 - c->blk_ptr);
+ }
+
+ l= ll;
+
+ l <<= 3;
+
+ buf[0]=l;
+ l >>= 8;
+ buf[1]=l;
+ l >>= 8;
+ buf[2]=l;
+ l >>= 8;
+ buf[3]=l;
+
+ l= ll;
+ l >>= 29;
+ buf[4]=l;
+ l >>= 8;
+ buf[5]=l;
+ l >>= 8;
+ buf[6]=l;
+ l >>= 8;
+ buf[7]=l;
+
+ md5_context_hashstream(c, buf, 8);
+}
+
+void md5_context_digest(struct MD5_CONTEXT *c, MD5_DIGEST d)
+{
+unsigned char *dp=d;
+MD5_WORD w;
+
+#define PUT(c) (w=(c), *dp++ = w, w >>= 8, *dp++ = w, w >>= 8, *dp++ = w, w >>= 8, *dp++ = w)
+
+ PUT(c->A);
+ PUT(c->B);
+ PUT(c->C);
+ PUT(c->D);
+#undef PUT
+}
+
+void md5_context_restore(struct MD5_CONTEXT *c, const MD5_DIGEST d)
+{
+const unsigned char *dp=(unsigned char *)d+MD5_DIGEST_SIZE;
+MD5_WORD w;
+
+#define GET \
+ w=*--dp; w=(w << 8) | *--dp; w=(w << 8) | *--dp; w=(w << 8) | *--dp;
+
+ GET
+ c->D=w;
+ GET
+ c->C=w;
+ GET
+ c->B=w;
+ GET
+ c->A=w;
+ c->blk_ptr=0;
+}
+
+void md5_digest(const void *msg, unsigned int len, MD5_DIGEST d)
+{
+struct MD5_CONTEXT c;
+
+ md5_context_init(&c);
+ md5_context_hashstream(&c, msg, len);
+ md5_context_endstream(&c, len);
+ md5_context_digest(&c, d);
+}
diff --git a/md5/md5.h b/md5/md5.h
new file mode 100644
index 0000000..2124879
--- /dev/null
+++ b/md5/md5.h
@@ -0,0 +1,65 @@
+#ifndef md5_h
+#define md5_h
+
+/*
+** Copyright 1998 - 2001 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+/*
+** RFC 1321 MD5 Message digest calculation.
+**
+** Returns a pointer to a sixteen-byte message digest.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if HAVE_CONFIG_H
+#include "md5/config.h"
+#endif
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#define MD5_DIGEST_SIZE 16
+#define MD5_BLOCK_SIZE 64
+
+typedef unsigned char MD5_DIGEST[MD5_DIGEST_SIZE];
+
+#ifdef MD5_INTERNAL
+
+struct MD5_CONTEXT {
+
+ MD5_WORD A, B, C, D;
+
+ unsigned char blk[MD5_BLOCK_SIZE];
+ unsigned blk_ptr;
+ } ;
+
+void md5_context_init(struct MD5_CONTEXT *);
+void md5_context_hash(struct MD5_CONTEXT *,
+ const unsigned char[MD5_BLOCK_SIZE]);
+void md5_context_hashstream(struct MD5_CONTEXT *, const void *, unsigned);
+void md5_context_endstream(struct MD5_CONTEXT *, unsigned long);
+void md5_context_digest(struct MD5_CONTEXT *, MD5_DIGEST);
+
+void md5_context_restore(struct MD5_CONTEXT *, const MD5_DIGEST);
+
+#endif
+
+void md5_digest(const void *msg, unsigned int len, MD5_DIGEST);
+
+char *md5_crypt_redhat(const char *, const char *);
+#define md5_crypt md5_crypt_redhat
+
+const char *md5_hash_courier(const char *);
+const char *md5_hash_raw(const char *);
+
+#ifdef __cplusplus
+} ;
+#endif
+
+#endif
diff --git a/md5/md5_hash.c b/md5/md5_hash.c
new file mode 100644
index 0000000..fd16538
--- /dev/null
+++ b/md5/md5_hash.c
@@ -0,0 +1,67 @@
+/*
+** Copyright 2007 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "md5.h"
+#include <string.h>
+#include <stdio.h>
+
+
+static const char base64tab[]=
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+const char *md5_hash_courier(const char *passw)
+{
+MD5_DIGEST md5buf;
+static char hash_buffer[1+(sizeof(md5buf)+2)/3*4];
+int a=0,b=0,c=0;
+int i, j;
+int d, e, f, g;
+
+ md5_digest(passw, strlen(passw), md5buf);
+
+ j=0;
+
+ for (i=0; i<sizeof(md5buf); i += 3)
+ {
+ a=md5buf[i];
+ b= i+1 < sizeof(md5buf) ? md5buf[i+1]:0;
+ c= i+2 < sizeof(md5buf) ? md5buf[i+2]:0;
+
+ d=base64tab[ a >> 2 ];
+ e=base64tab[ ((a & 3 ) << 4) | (b >> 4)];
+ f=base64tab[ ((b & 15) << 2) | (c >> 6)];
+ g=base64tab[ c & 63 ];
+ if (i + 1 >= sizeof(md5buf)) f='=';
+ if (i + 2 >= sizeof(md5buf)) g='=';
+ hash_buffer[j++]=d;
+ hash_buffer[j++]=e;
+ hash_buffer[j++]=f;
+ hash_buffer[j++]=g;
+ }
+
+ hash_buffer[j]=0;
+ return (hash_buffer);
+}
+
+const char *md5_hash_raw(const char *passw)
+{
+ MD5_DIGEST digest;
+ static char hash_buffer[sizeof(digest)*2+1];
+ size_t j=0,i=0;
+
+ char
+ tmp_buf[3];
+
+ md5_digest(passw, strlen(passw), digest);
+ for (j=0; j<sizeof(digest); j++)
+ {
+ sprintf(tmp_buf,"%02x",digest[j]);
+ hash_buffer[i++]=tmp_buf[0];
+ hash_buffer[i++]=tmp_buf[1];
+ }
+ hash_buffer[i]=0;
+
+ return(hash_buffer);
+}
diff --git a/md5/md5test.c b/md5/md5test.c
new file mode 100644
index 0000000..c5c4554
--- /dev/null
+++ b/md5/md5test.c
@@ -0,0 +1,46 @@
+/*
+** Copyright 1998 - 2000 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#include "md5.h"
+#include <stdio.h>
+#include <string.h>
+
+int main()
+{
+static const char * const teststr[]={
+"",
+"a",
+"abc",
+"message digest",
+"abcdefghijklmnopqrstuvwxyz",
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+"12345678901234567890123456789012345678901234567890123456789012345678901234567890"};
+
+char *salts[4]={"abcdef","01234567","76543210","QWERTY"};
+char *passwds[4]={ "rosebud",
+ "trust noone",
+ "trust, but verify",
+ "for the world is hollow, and I have touched the sky"};
+
+int i,j;
+
+ printf("MD5 test suite:\n");
+ for (i=0; i<(int)sizeof(teststr)/sizeof(teststr[0]); i++)
+ {
+ MD5_DIGEST digest;
+
+ md5_digest(teststr[i], strlen(teststr[i]), digest);
+
+ printf("MD5 (\"%s\") = ", teststr[i]);
+ for (j=0; j<sizeof(digest); j++)
+ printf("%02x", digest[j]);
+ printf("\n");
+ }
+ for (i=0; i<sizeof(salts)/sizeof(salts[0]); i++)
+ printf("Salt: %s\nPassword: %s\nHash:%s\n\n",
+ salts[i], passwds[i],
+ md5_crypt_redhat(passwds[i], salts[i]));
+ return (0);
+}
diff --git a/md5/md5test.txt b/md5/md5test.txt
new file mode 100644
index 0000000..55efb05
--- /dev/null
+++ b/md5/md5test.txt
@@ -0,0 +1,24 @@
+MD5 test suite:
+MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
+MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
+MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
+MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
+MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
+MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f
+MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a
+Salt: abcdef
+Password: rosebud
+Hash:$1$abcdef$2XiyKFam4XUU0UKeisSUw.
+
+Salt: 01234567
+Password: trust noone
+Hash:$1$01234567$UOH93AP.QnI8/c8miDJjz/
+
+Salt: 76543210
+Password: trust, but verify
+Hash:$1$76543210$w5fc8I64uQ1gulWoDQ4vw0
+
+Salt: QWERTY
+Password: for the world is hollow, and I have touched the sky
+Hash:$1$QWERTY$DGJfam2.wuUFO90L/I9Ty.
+
diff --git a/md5/redhat-crypt-md5.c b/md5/redhat-crypt-md5.c
new file mode 100644
index 0000000..a8a37fd
--- /dev/null
+++ b/md5/redhat-crypt-md5.c
@@ -0,0 +1,125 @@
+/*
+** Copyright 1998 - 1999 Double Precision, Inc.
+** See COPYING for distribution information.
+*/
+
+#define MD5_INTERNAL
+#include "md5.h"
+#include <string.h>
+
+
+static char base64[]=
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+char *md5_crypt_redhat(const char *pw, const char *salt)
+{
+struct MD5_CONTEXT outer_context, inner_context;
+MD5_DIGEST digest;
+unsigned pwl=strlen(pw);
+unsigned l;
+unsigned i, j;
+char *p;
+static char buffer[100];
+
+ if (*salt == '$' && salt[1] == '1' && salt[2] == '$')
+ salt += 3;
+
+ for (l=0; l<8 && salt[l] && salt[l] != '$'; l++)
+ ;
+
+ md5_context_init(&inner_context);
+ md5_context_hashstream(&inner_context, pw, pwl);
+ md5_context_hashstream(&inner_context, salt, l);
+ md5_context_hashstream(&inner_context, pw, pwl);
+ md5_context_endstream(&inner_context, pwl*2+l);
+ md5_context_digest(&inner_context, digest);
+
+ md5_context_init(&outer_context);
+ md5_context_hashstream(&outer_context, pw, pwl);
+ md5_context_hashstream(&outer_context, "$1$", 3);
+ md5_context_hashstream(&outer_context, salt, l);
+
+ for (i=pwl; i; )
+ {
+ j=i;
+ if (j > 16) j=16;
+ md5_context_hashstream(&outer_context, digest, j);
+ i -= j;
+ }
+
+ j=pwl*2+l+3;
+
+ for (i=pwl; i; i >>= 1)
+ {
+ md5_context_hashstream(&outer_context, (i & 1) ? "": pw, 1);
+ ++j;
+ }
+
+
+ md5_context_endstream(&outer_context, j);
+ md5_context_digest(&outer_context, digest);
+
+ for (i=0; i<1000; i++)
+ {
+ j=0;
+
+ md5_context_init(&outer_context);
+ if (i & 1)
+ {
+ md5_context_hashstream(&outer_context, pw, pwl);
+ j += pwl;
+ }
+ else
+ {
+ md5_context_hashstream(&outer_context, digest, 16);
+ j += 16;
+ }
+
+ if (i % 3)
+ {
+ md5_context_hashstream(&outer_context, salt, l);
+ j += l;
+ }
+
+ if (i % 7)
+ {
+ md5_context_hashstream(&outer_context, pw, pwl);
+ j += pwl;
+ }
+
+ if (i & 1)
+ {
+ md5_context_hashstream(&outer_context, digest, 16);
+ j += 16;
+ }
+ else
+ {
+ md5_context_hashstream(&outer_context, pw, pwl);
+ j += pwl;
+ }
+
+ md5_context_endstream(&outer_context, j);
+ md5_context_digest(&outer_context, digest);
+ }
+
+ strcpy(buffer, "$1$");
+ strncat(buffer, salt, l);
+ strcat(buffer, "$");
+
+ p=buffer+strlen(buffer);
+ for (i=0; i<5; i++)
+ {
+ unsigned char *d=digest;
+
+ j= (d[i] << 16) | (d[i+6] << 8) | d[i == 4 ? 5:12+i];
+ *p++= base64[j & 63] ; j=j >> 6;
+ *p++= base64[j & 63] ; j=j >> 6;
+ *p++= base64[j & 63] ; j=j >> 6;
+ *p++= base64[j & 63];
+ }
+ j=digest[11];
+ *p++ = base64[j & 63]; j=j >> 6;
+ *p++ = base64[j & 63];
+ *p=0;
+ return (buffer);
+}