Imported Upstream version 0.66.1
[hcoop/debian/courier-authlib.git] / libs / md5 / redhat-crypt-md5.c
diff --git a/libs/md5/redhat-crypt-md5.c b/libs/md5/redhat-crypt-md5.c
new file mode 100644 (file)
index 0000000..a8a37fd
--- /dev/null
@@ -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);
+}