httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Life is hard, and then you die." <ron...@innovation.ch>
Subject Re: Apache 2.0 alpha. (again) :)
Date Fri, 10 Mar 2000 04:46:49 GMT

One day, rbb@apache.org wrote:
> 
> > That's the way I understood it. However, I have no problems undoing the
> > changes and then also moving md5 from apr back to apache. Though some of
> > the md5, sha1, and base64 functions do distinguish between ascii and
> > ebcdic platforms.
> 
> Please don't move anything.  Leave the changes alone, because they are
> good changes.  The stuff in apr belongs in apr.  I personally believe the
> validate password stuff belongs in apr as well, because it makes it easy
> to validate two passwords very quickly without having to do strcmp's.  I
> suggest leaving it alone and we'll discuss it in more detail after the
> alpha.

Ok. Here are my suggested changes in more detail (wait to take a look
at it until the release is out, ApacheCon is over, and you've got
time ;-).

1) move ap/ap_sha1.c to lib/apr/lib/apr_sha1.c and include/ap_sha1.h
   to lib/apr/include/apr_sha1.h; adjust various defines and types
   in the process.
2) move ap/ap_base64 to lib/apr/lib/apr_base64 and ap_base64* declarations
   from include/ap.h to lib/apr/include/apr_base64.h; adjust various
   defines and types in the process.
3) Update lib/apr/lib/apr_md5.c and lib/apr/include/apr_md5.h to use
   apr types and defines
4) move ap_MD5Encode and ap_validate_password from lib/apr/lib/apr_md5.c
   and ap_sha1_base64 from lib/apr/lib/apr_sha1.c to new
   lib/apr/lib/apr_checkpass.c. ap_MD5Encode and ap_sha1_base64 should
   probably be renamed to something more explanatory and consistent,
   such as ap_md5_password and ap_sha1_password).

Appended are the current diffs of lib/apr/.


  Cheers,

  Ronald


------------------------------------------------------------
Index: include/apr_lib.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_lib.h,v
retrieving revision 1.22
diff -u -r1.22 apr_lib.h
--- include/apr_lib.h	2000/03/10 00:06:09	1.22
+++ include/apr_lib.h	2000/03/10 04:38:03
@@ -242,11 +242,25 @@
 			       va_list ap);
 
 
+/*
+ * Define the Magic String prefixes that identify a password as being
+ * hashed using our MD5-based algorithm or using Netscape's SHA1-based
+ * algorithm.
+ */
+#define APR_MD5PW_ID "$apr1$"
+#define APR_MD5PW_IDLEN 6
+
+#define APR_SHA1PW_ID "{SHA}"
+#define APR_SHA1PW_IDLEN 5
+
 /* A small routine to validate a plain text password with a password
- * that has been encrypted using any algorithm APR knows about.
+ * that has been encrypted using any algorithm APR knows about, and
+ * two routines to create encoded passwords.
  */
 API_EXPORT(ap_status_t) ap_validate_password(const char *passwd, const char *hash);
-
+API_EXPORT(void) ap_MD5Encode(const char *password, const char *salt,
+			      char *result, size_t nbytes);
+API_EXPORT(void) ap_sha1_base64(const char *clear, int len, char *out);
 
 /*
  * These are snprintf implementations based on ap_vformatter().
Index: include/apr_md5.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/include/apr_md5.h,v
retrieving revision 1.6
diff -u -r1.6 apr_md5.h
--- include/apr_md5.h	2000/03/10 00:06:09	1.6
+++ include/apr_md5.h	2000/03/10 04:38:03
@@ -85,8 +85,8 @@
  *
  */
 
-#ifndef APACHE_MD5_H
-#define APACHE_MD5_H
+#ifndef APR_MD5_H
+#define APR_MD5_H
 
 #include "apr_lib.h"
 
@@ -96,25 +96,23 @@
 
 /* MD5.H - header file for MD5C.C */
 
-/* UINT4 defines a four byte word */
-typedef unsigned int UINT4;
+#define APR_MD5_DIGESTSIZE 16
 
 /* MD5 context. */
 typedef struct {
-    UINT4 state[4];		/* state (ABCD) */
-    UINT4 count[2];		/* number of bits, modulo 2^64 (lsb first) */
+    ap_uint32_t state[4];	/* state (ABCD) */
+    ap_uint32_t count[2];	/* number of bits, modulo 2^64 (lsb first) */
     unsigned char buffer[64];	/* input buffer */
 } APR_MD5_CTX;
 
-API_EXPORT(ap_status_t) ap_MD5Init(APR_MD5_CTX * context);
-API_EXPORT(ap_status_t) ap_MD5Update(APR_MD5_CTX * context, const unsigned char *input,
-			   unsigned int inputLen);
-API_EXPORT(ap_status_t) ap_MD5Final(unsigned char digest[16], APR_MD5_CTX * context);
-API_EXPORT(ap_status_t) ap_MD5Encode(const char *password, const char *salt,
-			      char *result, size_t nbytes);
+API_EXPORT(void) ap_MD5Init(APR_MD5_CTX * context);
+API_EXPORT(void) ap_MD5Update(APR_MD5_CTX * context, const unsigned char *input,
+			      unsigned int inputLen);
+API_EXPORT(void) ap_MD5Final(unsigned char digest[APR_MD5_DIGESTSIZE],
+			     APR_MD5_CTX * context);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif	/* !APACHE_MD5_H */
+#endif	/* !APR_MD5_H */
Index: lib/Makefile.in
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/lib/Makefile.in,v
retrieving revision 1.9
diff -u -r1.9 Makefile.in
--- lib/Makefile.in	1999/12/20 20:02:30	1.9
+++ lib/Makefile.in	2000/03/10 04:38:03
@@ -19,7 +19,10 @@
 OBJS=apr_cpystrn.o \
 	apr_fnmatch.o \
 	apr_execve.o \
+	apr_base64.o \
 	apr_md5.o \
+	apr_sha1.o \
+	apr_checkpass.o \
 	apr_pools.o \
 	apr_signal.o \
 	apr_slack.o \
Index: lib/apr_md5.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/lib/apr/lib/apr_md5.c,v
retrieving revision 1.8
diff -u -r1.8 apr_md5.c
--- lib/apr_md5.c	2000/03/10 00:06:12	1.8
+++ lib/apr_md5.c	2000/03/10 04:38:04
@@ -88,18 +88,10 @@
  *
  */
 
-/*
- * The ap_MD5Encode() routine uses much code obtained from the FreeBSD 3.0
- * MD5 crypt() function, which is licenced as follows:
- * ----------------------------------------------------------------------------
- * "THE BEER-WARE LICENSE" (Revision 42):
- * <phk@login.dknet.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
- * ----------------------------------------------------------------------------
- */
 #ifndef WIN32
 #include "apr_config.h"
+#else
+#include "apr_winconfig.h"
 #endif
 #include "apr_md5.h"
 #include "apr_lib.h"
@@ -107,12 +99,6 @@
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
-#ifdef HAVE_CRYPT_H
-#include <crypt.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
 
 /* Constants for MD5Transform routine.
  */
@@ -134,10 +120,10 @@
 #define S43 15
 #define S44 21
 
-static void MD5Transform(UINT4 state[4], const unsigned char block[64]);
-static void Encode(unsigned char *output, const UINT4 *input,
+static void MD5Transform(ap_uint32_t state[4], const unsigned char block[64]);
+static void Encode(unsigned char *output, const ap_uint32_t *input,
 		   unsigned int len);
-static void Decode(UINT4 *output, const unsigned char *input,
+static void Decode(ap_uint32_t *output, const unsigned char *input,
 		   unsigned int len);
 
 static unsigned char PADDING[64] =
@@ -162,29 +148,29 @@
    Rotation is separate from addition to prevent recomputation.
  */
 #define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) += F ((b), (c), (d)) + (x) + (ap_uint32_t)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
   }
 #define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) += G ((b), (c), (d)) + (x) + (ap_uint32_t)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
   }
 #define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) += H ((b), (c), (d)) + (x) + (ap_uint32_t)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
   }
 #define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) += I ((b), (c), (d)) + (x) + (ap_uint32_t)(ac); \
  (a) = ROTATE_LEFT ((a), (s)); \
  (a) += (b); \
   }
 
 /* MD5 initialization. Begins an MD5 operation, writing a new context.
  */
-API_EXPORT(ap_status_t) ap_MD5Init(APR_MD5_CTX * context)
+API_EXPORT(void) ap_MD5Init(APR_MD5_CTX * context)
 {
     context->count[0] = context->count[1] = 0;
     /* Load magic initialization constants. */
@@ -192,15 +178,14 @@
     context->state[1] = 0xefcdab89;
     context->state[2] = 0x98badcfe;
     context->state[3] = 0x10325476;
-    return APR_SUCCESS;
 }
 
 /* MD5 block update operation. Continues an MD5 message-digest
    operation, processing another message block, and updating the
    context.
  */
-API_EXPORT(ap_status_t) ap_MD5Update(APR_MD5_CTX * context, const unsigned char *input,
-			   unsigned int inputLen)
+API_EXPORT(void) ap_MD5Update(APR_MD5_CTX * context, const unsigned char *input,
+			      unsigned int inputLen)
 {
     unsigned int i, idx, partLen;
 
@@ -208,9 +193,9 @@
     idx = (unsigned int) ((context->count[0] >> 3) & 0x3F);
 
     /* Update number of bits */
-    if ((context->count[0] += ((UINT4) inputLen << 3)) < ((UINT4) inputLen <<
3))
+    if ((context->count[0] += ((ap_uint32_t) inputLen << 3)) < ((ap_uint32_t)
inputLen << 3))
 	context->count[1]++;
-    context->count[1] += (UINT4) inputLen >> 29;
+    context->count[1] += (ap_uint32_t) inputLen >> 29;
 
     partLen = 64 - idx;
 
@@ -232,12 +217,12 @@
     memcpy(&context->buffer[idx], &input[i], inputLen - i);
 #else /*CHARSET_EBCDIC*/
     if (inputLen >= partLen) {
-	ebcdic2ascii_strictly(&context->buffer[idx], input, partLen);
+	ebcdic2ascii(&context->buffer[idx], input, partLen);
 	MD5Transform(context->state, context->buffer);
 
 	for (i = partLen; i + 63 < inputLen; i += 64) {
 	    unsigned char inp_tmp[64];
-	    ebcdic2ascii_strictly(inp_tmp, &input[i], 64);
+	    ebcdic2ascii(inp_tmp, &input[i], 64);
 	    MD5Transform(context->state, inp_tmp);
 	}
 
@@ -247,15 +232,15 @@
 	i = 0;
 
     /* Buffer remaining input */
-    ebcdic2ascii_strictly(&context->buffer[idx], &input[i], inputLen - i);
+    ebcdic2ascii(&context->buffer[idx], &input[i], inputLen - i);
 #endif /*CHARSET_EBCDIC*/
-    return APR_SUCCESS;
 }
 
 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
    the message digest and zeroizing the context.
  */
-API_EXPORT(ap_status_t) ap_MD5Final(unsigned char digest[16], APR_MD5_CTX * context)
+API_EXPORT(void) ap_MD5Final(unsigned char digest[APR_MD5_DIGESTSIZE],
+			     APR_MD5_CTX * context)
 {
     unsigned char bits[8];
     unsigned int idx, padLen;
@@ -288,18 +273,16 @@
     ap_MD5Update(context, bits, 8);
 
     /* Store state in digest */
-    Encode(digest, context->state, 16);
+    Encode(digest, context->state, APR_MD5_DIGESTSIZE);
 
     /* Zeroize sensitive information. */
     memset(context, 0, sizeof(*context));
-    
-    return APR_SUCCESS;
 }
 
 /* MD5 basic transformation. Transforms state based on block. */
-static void MD5Transform(UINT4 state[4], const unsigned char block[64])
+static void MD5Transform(ap_uint32_t state[4], const unsigned char block[64])
 {
-    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+    ap_uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
 
     Decode(x, block, 64);
 
@@ -384,13 +367,13 @@
     memset(x, 0, sizeof(x));
 }
 
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+/* Encodes input (ap_uint32_t) into output (unsigned char). Assumes len is
    a multiple of 4.
  */
-static void Encode(unsigned char *output, const UINT4 *input, unsigned int len)
+static void Encode(unsigned char *output, const ap_uint32_t *input, unsigned int len)
 {
     unsigned int i, j;
-    UINT4 k;
+    ap_uint32_t k;
 
     for (i = 0, j = 0; j < len; i++, j += 4) {
 	k = input[i];
@@ -401,220 +384,15 @@
     }
 }
 
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+/* Decodes input (unsigned char) into output (ap_uint32_t). Assumes len is
  * a multiple of 4.
  */
-static void Decode(UINT4 *output, const unsigned char *input, unsigned int len)
+static void Decode(ap_uint32_t *output, const unsigned char *input, unsigned int len)
 {
     unsigned int i, j;
 
     for (i = 0, j = 0; j < len; i++, j += 4)
-	output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
-	    (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
-}
-
-/*
- * Define the Magic String prefix that identifies a password as being
- * hashed using our algorithm.
- */
-static const char *apr1_id = "$apr1$";
-
-/*
- * The following MD5 password encryption code was largely borrowed from
- * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is
- * licenced as stated at the top of this file.
- */
-
-static void to64(char *s, unsigned long v, int n)
-{
-    static unsigned char itoa64[] =         /* 0 ... 63 => ASCII - 64 */
-	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-    while (--n >= 0) {
-	*s++ = itoa64[v&0x3f];
-	v >>= 6;
-    }
-}
-
-API_EXPORT(ap_status_t) ap_MD5Encode(const char *pw, const char *salt,
-			      char *result, size_t nbytes)
-{
-    /*
-     * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL,
-     * plus 4 for the '$' separators, plus the password hash itself.
-     * Let's leave a goodly amount of leeway.
-     */
-
-    char passwd[120], *p;
-    const char *sp, *ep;
-    unsigned char final[16];
-    int sl, pl, i;
-    APR_MD5_CTX ctx, ctx1;
-    unsigned long l;
-
-    /* 
-     * Refine the salt first.  It's possible we were given an already-hashed
-     * string as the salt argument, so extract the actual salt value from it
-     * if so.  Otherwise just use the string up to the first '$' as the salt.
-     */
-    sp = salt;
-
-    /*
-     * If it starts with the magic string, then skip that.
-     */
-    if (!strncmp(sp, apr1_id, strlen(apr1_id))) {
-	sp += strlen(apr1_id);
-    }
-
-    /*
-     * It stops at the first '$' or 8 chars, whichever comes first
-     */
-    for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++)
{
-	continue;
-    }
-
-    /*
-     * Get the length of the true salt
-     */
-    sl = ep - sp;
-
-    /*
-     * 'Time to make the doughnuts..'
-     */
-    ap_MD5Init(&ctx);
-
-    /*
-     * The password first, since that is what is most unknown
-     */
-    ap_MD5Update(&ctx, (unsigned char *)pw, strlen(pw));
-
-    /*
-     * Then our magic string
-     */
-    ap_MD5Update(&ctx, (unsigned char *)apr1_id, strlen(apr1_id));
-
-    /*
-     * Then the raw salt
-     */
-    ap_MD5Update(&ctx, (unsigned char *)sp, sl);
-
-    /*
-     * Then just as many characters of the MD5(pw, salt, pw)
-     */
-    ap_MD5Init(&ctx1);
-    ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw));
-    ap_MD5Update(&ctx1, (unsigned char *)sp, sl);
-    ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw));
-    ap_MD5Final(final, &ctx1);
-    for(pl = strlen(pw); pl > 0; pl -= 16) {
-	ap_MD5Update(&ctx, final, (pl > 16) ? 16 : pl);
-    }
-
-    /*
-     * Don't leave anything around in vm they could use.
-     */
-    memset(final, 0, sizeof(final));
-
-    /*
-     * Then something really weird...
-     */
-    for (i = strlen(pw); i != 0; i >>= 1) {
-	if (i & 1) {
-	    ap_MD5Update(&ctx, final, 1);
-	}
-	else {
-	    ap_MD5Update(&ctx, (unsigned char *)pw, 1);
-	}
-    }
-
-    /*
-     * Now make the output string.  We know our limitations, so we
-     * can use the string routines without bounds checking.
-     */
-    strcpy(passwd, apr1_id);
-    strncat(passwd, sp, sl);
-    strcat(passwd, "$");
-
-    ap_MD5Final(final, &ctx);
-
-    /*
-     * And now, just to make sure things don't run too fast..
-     * On a 60 Mhz Pentium this takes 34 msec, so you would
-     * need 30 seconds to build a 1000 entry dictionary...
-     */
-    for (i = 0; i < 1000; i++) {
-	ap_MD5Init(&ctx1);
-	if (i & 1) {
-	    ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw));
-	}
-	else {
-	    ap_MD5Update(&ctx1, final, 16);
-	}
-	if (i % 3) {
-	    ap_MD5Update(&ctx1, (unsigned char *)sp, sl);
-	}
-
-	if (i % 7) {
-	    ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw));
-	}
-
-	if (i & 1) {
-	    ap_MD5Update(&ctx1, final, 16);
-	}
-	else {
-	    ap_MD5Update(&ctx1, (unsigned char *)pw, strlen(pw));
-	}
-	ap_MD5Final(final,&ctx1);
-    }
-
-    p = passwd + strlen(passwd);
-
-    l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4;
-    l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4;
-    l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4;
-    l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4;
-    l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4;
-    l =                    final[11]                ; to64(p, l, 2); p += 2;
-    *p = '\0';
-
-    /*
-     * Don't leave anything around in vm they could use.
-     */
-    memset(final, 0, sizeof(final));
-
-    ap_cpystrn(result, passwd, nbytes - 1);
-    return APR_SUCCESS;
+	output[i] = ((ap_uint32_t) input[j]) | (((ap_uint32_t) input[j + 1]) << 8) |
+	    (((ap_uint32_t) input[j + 2]) << 16) | (((ap_uint32_t) input[j + 3]) <<
24);
 }
 
-/*
- * Validate a plaintext password against a smashed one.  Use either
- * crypt() (if available) or ap_MD5Encode(), depending upon the format
- * of the smashed input password.  Return APR_SUCCESS if they match, or
- * APR_EMISMATCH if they don't.
- */
-
-API_EXPORT(ap_status_t) ap_validate_password(const char *passwd, const char *hash)
-{
-    char sample[120];
-#ifndef WIN32
-    char *crypt_pw;
-#endif
-    if (!strncmp(hash, apr1_id, strlen(apr1_id))) {
-	/*
-	 * The hash was created using our custom algorithm.
-	 */
-	ap_MD5Encode(passwd, hash, sample, sizeof(sample));
-    }
-    else {
-	/*
-	 * It's not our algorithm, so feed it to crypt() if possible.
-	 */
-#if defined(WIN32) || defined(BEOS)
-	ap_cpystrn(sample, passwd, sizeof(sample) - 1);
-#else
-	crypt_pw = crypt(passwd, hash);
-	ap_cpystrn(sample, crypt_pw, sizeof(sample) - 1);
-#endif
-    }
-    return (strcmp(sample, hash) == 0) ? APR_SUCCESS : APR_EMISMATCH;
-}
------------------------------------------------------------


Mime
View raw message