Subject: lib/1709: [dM] libcrypt improvements
To: None <gnats-bugs@gnats.netbsd.org>
From: der Mouse <mouse@Collatz.McRCIM.McGill.EDU>
List: netbsd-bugs
Date: 10/31/1995 16:29:32
>Number:         1709
>Category:       lib
>Synopsis:       [dM] libcrypt improvements
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    lib-bug-people (Library Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Oct 31 17:05:17 1995
>Last-Modified:
>Originator:     der Mouse
>Organization:
	Dis-
>Release:        -current as of October 30 AM
>Environment:
	Any (SPARC IPC, Sun-3/150)
>Description:
	Briefly, I'm finally getting around to sending in my libcrypt
	stuff as a PR. :-)

	libcrypt uses DES-based algorithms, which are disturbingly
	close to inscure, and may be non-exportable from some places
	(though apparently not from the USA).  This patch makes an
	MD5-based hash available, and also improves the API so as to
	make it possible to isolate password-changing programs from the
	details of salt strings.  Patches to passwd to use the new
	libcrypt are also included; that was the only program I found
	at the time that needed any changes to work with the new code.
	Only programs that generate new hashed passwords need any
	changes; code that just does strcmp(crypt(foo,bar),bar) should
	work fine unless it makes bonehead assumptions like assuming
	bar is always 13 characters long.  Fortunately NetBSD already
	supports a longer hash, so such code should already have been
	smoked out. :-)
>How-To-Repeat:
	NA
>Fix:

Unpack this shar, then run "sh apply-script", presumably examining it
first. :-)

If this stuff goes into the tree, it might be a good idea to rename
crypt.c to descrypt.c and realcrypt.c to crypt.c; I didn't do that so
as to avoid including all of crypt.c twice in the patches.

					der Mouse

			    mouse@collatz.mcrcim.mcgill.edu

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Tue Oct 31 15:48:51 1995
# Run this through sh to create:
#	apply-script
#	patch-lib-libcrypt-Makefile
#	patch-lib-libcrypt-crypt.3
#	patch-lib-libcrypt-crypt.c
#	patch-lib-libcrypt-md5crypt.c
#	patch-lib-libcrypt-realcrypt.c
#	patch-usr.bin-passwd-local_passwd.c
#	patch-usr.bin-passwd-yp_passwd.c
echo x - apply-script \(603 characters\)
sed 's/^X//' > apply-script << \EOF
X#!/bin/sh
Xcase $# in
X	1)	;;
X	*)	echo "Usage: $0 base-directory-to-patch" 1>&2
X		echo "eg:    $0 /usr/src" 1>&2
X		exit 1
X		;;
Xesac
Xpatch "$1"/lib/libcrypt/Makefile < patch-lib-libcrypt-Makefile
Xpatch "$1"/lib/libcrypt/crypt.3 < patch-lib-libcrypt-crypt.3
Xpatch "$1"/lib/libcrypt/crypt.c < patch-lib-libcrypt-crypt.c
Xpatch "$1"/lib/libcrypt/md5crypt.c < patch-lib-libcrypt-md5crypt.c
Xpatch "$1"/lib/libcrypt/realcrypt.c < patch-lib-libcrypt-realcrypt.c
Xpatch "$1"/usr.bin/passwd/local_passwd.c < patch-usr.bin-passwd-local_passwd.c
Xpatch "$1"/usr.bin/passwd/yp_passwd.c < patch-usr.bin-passwd-yp_passwd.c
EOF
if test 603 -ne "`wc -c apply-script`"
then
echo shar: error transmitting apply-script \(should have been 603 characters\)
fi
echo x - patch-lib-libcrypt-Makefile \(389 characters\)
sed 's/^X//' > patch-lib-libcrypt-Makefile << \EOF
X+++ NEW/lib/libcrypt/Makefile	Thu Jan  1 00:00:00 1970
X@@ -7,9 +7,9 @@
X 
X LIB=	crypt
X 
X-SRCS=	crypt.c
X+SRCS=	crypt.c realcrypt.c md5crypt.c
X 
X MAN=	crypt.3
X-MLINKS= crypt.3 encrypt.3 crypt.3 setkey.3
X+MLINKS= crypt.3 encrypt.3 crypt.3 setkey.3 crypt.3 crypt_makesalt.3 crypt.3 des_crypt.3 crypt.3 md5_crypt.3
X 
X .include <bsd.lib.mk>
EOF
if test 389 -ne "`wc -c patch-lib-libcrypt-Makefile`"
then
echo shar: error transmitting patch-lib-libcrypt-Makefile \(should have been 389 characters\)
fi
echo x - patch-lib-libcrypt-crypt.3 \(4716 characters\)
sed 's/^X//' > patch-lib-libcrypt-crypt.3 << \EOF
X+++ NEW/lib/libcrypt/crypt.3	Thu Jan  1 00:00:00 1970
X@@ -38,14 +38,23 @@
X .Os
X .Sh NAME
X .Nm crypt ,
X+.Nm crypt_makesalt ,
X+.Nm md5_crypt ,
X+.Nm des_crypt ,
X .Nm setkey ,
X .Nm encrypt ,
X .Nm des_setkey ,
X .Nm des_cipher
X-.Nd DES encryption
X+.Nd password and DES encryption
X .Sh SYNOPSIS
X .Ft char
X-.Fn *crypt "const char *key" "const char *setting"
X+.Fn *crypt_makesalt "void"
X+.Ft char
X+.Fn *crypt "const char *key" "const char *hash"
X+.Ft char
X+.Fn *md5_crypt "const char *key" "const char *hash"
X+.Ft char
X+.Fn *des_crypt "const char *key" "const char *setting"
X .Ft int
X .Fn setkey "char *key"
X .Ft int
X@@ -56,16 +65,90 @@
X .Fn des_cipher "const char *in" "char *out" "long salt" "int count"
X .Sh DESCRIPTION
X The
X-.Xr crypt
X+.Fn crypt
X+function performs password hashing.  It is based on the MD5
X+message-digest algorithm (see RFC1321).  The first argument to
X+.Fn crypt
X+is a
X+.Dv NUL Ns -terminated
X+cleartext password (normally obtained from the user).  The second is
X+either a hashed password (obtained from wherever it was stored when it
X+was initially set) or a salt string, typically returned by
X+.Eo \&
X+.Fn crypt_makesalt
X+.Ec ,
X+though you can pass your own salt string; see below.  (The first form
X+is normally used when checking a password, the second when setting
X+one.)
X+.Fn crypt
X+understands three types of hashed passwords: old
X+.Dq traditional
X+DES-style hashed passwords, such as most other UNIX-related systems
X+use, new DES-style hashed passwords, such as previous versions of
X+NetBSD used, and new MD5-style hashed passwords.
X+This is done by testing the
X+.Fa hash
X+argument; if it fits the syntax of either of the two DES-style hashed
X+passwords, or the salt strings typically used with them,
X+.Fn crypt
X+simply calls
X+.Fn des_crypt
X+and returns the result.  Otherwise,
X+.Fn crypt
X+calls
X+.Fn md5_crypt
X+and returns the result.
X+.Pp
X+.Fn md5_crypt
X+is just like
X+.Eo \&
X+.Fn crypt
X+.Ec ,
X+except that it does not check its salt string to see if it's a
X+DES-style hashed password.
X+.Pp
X+.Fn crypt_makesalt
X+constructs and returns a salt string suitable for passing to
X+.Fn crypt
X+as the
X+.Fa hash
X+argument; it obtains the salt values from the exact time of day, the
X+process ID, and any other convenient values it thinks may be useful in
X+producing a
X+.Dq random
X+string.  If you have on hand other strings you feel may help make the
X+salt string even more
X+.Do
X+random
X+.Dc ,
X+you can build a longer string yourself, including them, and pass that
X+to
X+.Eo \&
X+.Fn crypt
X+.Ec .
X+The only restriction is that the string you ultimately pass to
X+.Fn crypt
X+must not be confusable with a hashed password.  The simplest way to
X+ensure this is to pass a string including a
X+.Do
X+.Li :
X+.Dc ,
X+because colons can never appear in a hashed password.
X+Any string beginning with a string returned by
X+.Fn crypt_makesalt
X+will always be suitable.
X+.Pp
X+The
X+.Xr des_crypt
X function
X-performs password encryption.
X+performs old-style password encryption.
X It is derived from the
X .Tn NBS
X Data Encryption Standard.
X Additional code has been added to deter
X key search attempts.
X The first argument to
X-.Nm crypt
X+.Nm des_crypt
X is
X a
X .Dv NUL Ns -terminated
X@@ -206,9 +289,11 @@
X .Tn DES
X as described above.
X .Pp
X-The function
X+The functions
X .Fn crypt
X-returns a pointer to the encrypted value on success and NULL on failure.
X+and
X+.Fn des_crypt
X+return a pointer to the encrypted value on success and NULL on failure.
X The functions
X .Fn setkey ,
X .Fn encrypt ,
X@@ -216,6 +301,12 @@
X and
X .Fn des_cipher
X return 0 on success and 1 on failure.
X+The function
X+.Fn crypt_makesalt
X+returns a pointer to the generated salt string; it
X+.Do
X+cannot fail
X+.Dc .
X Historically, the functions
X .Fn setkey
X and
X@@ -259,21 +350,31 @@
X .Fn crypt
X function appeared in
X .At v6 .
X-The current style
X+DES-based
X .Fn crypt
X first appeared in
X .At v7 .
X+The current MD5-based
X+.Fn crypt
X+first appeared post-1.0 NetBSD.
X .Sh BUGS
X+.Fn crypt_makesalt ,
X+.Fn des_crypt ,
X+and
X+.Fn md5_crypt
X+return pointers to internal static strings.  The string returned by one
X+of these functions is valid only until the next time that function is
X+called again, at which point the string will be modified by the return
X+string from the later call.  (Note that since
X+.Fn crypt
X+always simply calls either
X+.Fn md5_crypt
X+or
X+.Fn des_crypt ,
X+similar remarks apply to it as well.)
X+.Pp
X Dropping the
X .Em least
X significant bit in each character of the argument to
X .Fn des_setkey
X is ridiculous.
X-.Pp
X-The
X-.Fn crypt
X-function leaves its result in an internal static object and returns
X-a pointer to that object.
X-Subsequent calls to
X-.Fn crypt
X-will modify the same object.
EOF
if test 4716 -ne "`wc -c patch-lib-libcrypt-crypt.3`"
then
echo shar: error transmitting patch-lib-libcrypt-crypt.3 \(should have been 4716 characters\)
fi
echo x - patch-lib-libcrypt-crypt.c \(317 characters\)
sed 's/^X//' > patch-lib-libcrypt-crypt.c << \EOF
X+++ NEW/lib/libcrypt/crypt.c	Thu Jan  1 00:00:00 1970
X@@ -465,7 +465,7 @@
X  * followed by an encryption produced by the "key" and "setting".
X  */
X char *
X-crypt(key, setting)
X+des_crypt(key, setting)
X 	register const char *key;
X 	register const char *setting;
X {
EOF
if test 317 -ne "`wc -c patch-lib-libcrypt-crypt.c`"
then
echo shar: error transmitting patch-lib-libcrypt-crypt.c \(should have been 317 characters\)
fi
echo x - patch-lib-libcrypt-md5crypt.c \(10202 characters\)
sed 's/^X//' > patch-lib-libcrypt-md5crypt.c << \EOF
X+++ NEW/lib/libcrypt/md5crypt.c	Thu Jan  1 00:00:00 1970
X@@ -0,0 +1,348 @@
X+#include <stdio.h>
X+#include <sys/time.h>
X+
X+#define VERSION_MD5 1
X+
X+#define DEF_VERSION VERSION_MD5
X+
X+#define MIN_ROUNDS 2
X+#define DEF_ROUNDS 64
X+#define MAX_ROUNDS 10240
X+
X+/* MD5 stuff, mostly straight out of the RFC */
X+
X+typedef unsigned long int U32; /* unsigned, 32 bits */
X+
X+/* T[i] = floor((1<<32)*abs(sin(i+1))), where sin arg is in radians */
X+static U32 T[64] = {
X+	0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
X+	0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
X+	0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
X+	0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
X+	0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
X+	0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
X+	0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
X+	0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
X+	0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
X+	0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
X+	0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
X+	0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
X+	0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
X+	0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
X+	0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
X+	0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
X+
X+typedef struct state STATE;
X+struct state {
X+  U32 A;
X+  U32 B;
X+  U32 C;
X+  U32 D;
X+  U32 X[16];
X+  int xfill; /* # of bytes added since last crunch_block() */
X+  U32 bitlen_l;
X+  U32 bitlen_h;
X+  } ;
X+
X+#define F(X,Y,Z) (((X)&(Y))|((~(X))&(Z)))
X+#define G(X,Y,Z) (((X)&(Z))|((Y)&(~(Z))))
X+#define H(X,Y,Z) ((X)^(Y)^(Z))
X+#define I(X,Y,Z) ((Y)^((X)|(~(Z))))
X+
X+/* rotate v left nbits bits */
X+inline static U32 ROTLEFT(U32 v, unsigned int nbits)
X+{
X+ return((v<<nbits)|(v>>(32-nbits)));
X+}
X+
X+/*
X+ * A block of 64 input bytes has been accumulated in X[]; crunch it
X+ *  through the hash machine.  Essentially a transcription of the RFC
X+ *  algorithm into C.
X+ */
X+static void crunch_block(STATE *state)
X+{
X+ U32 A;
X+ U32 B;
X+ U32 C;
X+ U32 D;
X+ U32 *X;
X+
X+ A = state->A;
X+ B = state->B;
X+ C = state->C;
X+ D = state->D;
X+ X = &state->X[0];
X+#define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+F(b,c,d)+X[k]+T[i-1],s)
X+ OP(A,B,C,D, 0, 7, 1);OP(D,A,B,C, 1,12, 2);OP(C,D,A,B, 2,17, 3);OP(B,C,D,A, 3,22, 4);
X+ OP(A,B,C,D, 4, 7, 5);OP(D,A,B,C, 5,12, 6);OP(C,D,A,B, 6,17, 7);OP(B,C,D,A, 7,22, 8);
X+ OP(A,B,C,D, 8, 7, 9);OP(D,A,B,C, 9,12,10);OP(C,D,A,B,10,17,11);OP(B,C,D,A,11,22,12);
X+ OP(A,B,C,D,12, 7,13);OP(D,A,B,C,13,12,14);OP(C,D,A,B,14,17,15);OP(B,C,D,A,15,22,16);
X+#undef OP
X+#define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+G(b,c,d)+X[k]+T[i-1],s)
X+ OP(A,B,C,D, 1, 5,17);OP(D,A,B,C, 6, 9,18);OP(C,D,A,B,11,14,19);OP(B,C,D,A, 0,20,20);
X+ OP(A,B,C,D, 5, 5,21);OP(D,A,B,C,10, 9,22);OP(C,D,A,B,15,14,23);OP(B,C,D,A, 4,20,24);
X+ OP(A,B,C,D, 9, 5,25);OP(D,A,B,C,14, 9,26);OP(C,D,A,B, 3,14,27);OP(B,C,D,A, 8,20,28);
X+ OP(A,B,C,D,13, 5,29);OP(D,A,B,C, 2, 9,30);OP(C,D,A,B, 7,14,31);OP(B,C,D,A,12,20,32);
X+#undef OP
X+#define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+H(b,c,d)+X[k]+T[i-1],s)
X+ OP(A,B,C,D, 5, 4,33);OP(D,A,B,C, 8,11,34);OP(C,D,A,B,11,16,35);OP(B,C,D,A,14,23,36);
X+ OP(A,B,C,D, 1, 4,37);OP(D,A,B,C, 4,11,38);OP(C,D,A,B, 7,16,39);OP(B,C,D,A,10,23,40);
X+ OP(A,B,C,D,13, 4,41);OP(D,A,B,C, 0,11,42);OP(C,D,A,B, 3,16,43);OP(B,C,D,A, 6,23,44);
X+ OP(A,B,C,D, 9, 4,45);OP(D,A,B,C,12,11,46);OP(C,D,A,B,15,16,47);OP(B,C,D,A, 2,23,48);
X+#undef OP
X+#define OP(a,b,c,d,k,s,i) a = b + ROTLEFT(a+I(b,c,d)+X[k]+T[i-1],s)
X+ OP(A,B,C,D, 0, 6,49);OP(D,A,B,C, 7,10,50);OP(C,D,A,B,14,15,51);OP(B,C,D,A, 5,21,52);
X+ OP(A,B,C,D,12, 6,53);OP(D,A,B,C, 3,10,54);OP(C,D,A,B,10,15,55);OP(B,C,D,A, 1,21,56);
X+ OP(A,B,C,D, 8, 6,57);OP(D,A,B,C,15,10,58);OP(C,D,A,B, 6,15,59);OP(B,C,D,A,13,21,60);
X+ OP(A,B,C,D, 4, 6,61);OP(D,A,B,C,11,10,62);OP(C,D,A,B, 2,15,63);OP(B,C,D,A, 9,21,64);
X+#undef OP
X+ state->A += A;
X+ state->B += B;
X+ state->C += C;
X+ state->D += D;
X+}
X+
X+/*
X+ * Feed some bytes to MD5.  Accumulates them into X[], calling
X+ *  crunch_block() at each 64-byte boundary to process them.
X+ */
X+static void crunch_bytes(STATE *state, const unsigned char *buf, unsigned int nbytes)
X+{
X+ int xfill;
X+ U32 *X;
X+
X+ xfill = state->xfill;
X+ X = &state->X[0];
X+ for (;nbytes>0;nbytes--)
X+  { switch (xfill % 4)
X+     { case 0:
X+	  X[xfill/4] = *buf;
X+	  break;
X+       case 1:
X+	  X[xfill/4] |= ((U32)*buf) << 8;
X+	  break;
X+       case 2:
X+	  X[xfill/4] |= ((U32)*buf) << 16;
X+	  break;
X+       case 3:
X+	  X[xfill/4] |= ((U32)*buf) << 24;
X+	  break;
X+     }
X+    buf ++;
X+    xfill ++;
X+    if (xfill >= 64)
X+     { crunch_block(state);
X+       xfill = 0;
X+     }
X+  }
X+ state->xfill = xfill;
X+}
X+
X+/*
X+ * Initialize the state, per the RFC.
X+ */
X+static void md5_init(STATE *s)
X+{
X+ s->A = 0x67452301;
X+ s->B = 0xefcdab89;
X+ s->C = 0x98badcfe;
X+ s->D = 0x10325476;
X+ s->xfill = 0;
X+ s->bitlen_l = 0;
X+ s->bitlen_h = 0;
X+}
X+
X+/*
X+ * Process some bytes.  Feed them to crunch_bytes() and also update the
X+ *  bitlen values to reflect the number of bits fed in.
X+ */
X+static void md5_process_bytes(STATE *s, const void *vbuf, unsigned int nbytes)
X+{
X+ U32 ltmp;
X+ U32 lsum;
X+
X+ crunch_bytes(s,vbuf,nbytes);
X+ s->bitlen_h += ((U32)nbytes) >> 29;
X+ ltmp = ((U32)nbytes) << 3;
X+ lsum = ltmp + s->bitlen_l;
X+ if ( (ltmp & s->bitlen_l & 0x80000000) ||
X+      ( ((ltmp|s->bitlen_l) & 0x80000000) &&
X+	!(lsum & 0x80000000) ) )
X+  { s->bitlen_h ++;
X+  }
X+ s->bitlen_l = lsum;
X+#undef s
X+}
X+
X+/*
X+ * Finish the MD5 algorithm; insert padding and the bitstring length,
X+ *  then extract the result into the supplied 16-byte buffer.
X+ */
X+static void md5_result(STATE *s, unsigned char *result)
X+{
X+ unsigned char lenbytes[8];
X+
X+ crunch_bytes(s,"\200",1);
X+ while (s->xfill != 56) crunch_bytes(s,"\0",1);
X+ lenbytes[0] =  s->bitlen_l        & 0xff;
X+ lenbytes[1] = (s->bitlen_l >>  8) & 0xff;
X+ lenbytes[2] = (s->bitlen_l >> 16) & 0xff;
X+ lenbytes[3] = (s->bitlen_l >> 24) & 0xff;
X+ lenbytes[4] =  s->bitlen_h        & 0xff;
X+ lenbytes[5] = (s->bitlen_h >>  8) & 0xff;
X+ lenbytes[6] = (s->bitlen_h >> 16) & 0xff;
X+ lenbytes[7] = (s->bitlen_h >> 24) & 0xff;
X+ crunch_bytes(s,&lenbytes[0],8);
X+ result[ 0] =  s->A        & 0xff;
X+ result[ 1] = (s->A >>  8) & 0xff;
X+ result[ 2] = (s->A >> 16) & 0xff;
X+ result[ 3] = (s->A >> 24) & 0xff;
X+ result[ 4] =  s->B        & 0xff;
X+ result[ 5] = (s->B >>  8) & 0xff;
X+ result[ 6] = (s->B >> 16) & 0xff;
X+ result[ 7] = (s->B >> 24) & 0xff;
X+ result[ 8] =  s->C        & 0xff;
X+ result[ 9] = (s->C >>  8) & 0xff;
X+ result[10] = (s->C >> 16) & 0xff;
X+ result[11] = (s->C >> 24) & 0xff;
X+ result[12] =  s->D        & 0xff;
X+ result[13] = (s->D >>  8) & 0xff;
X+ result[14] = (s->D >> 16) & 0xff;
X+ result[15] = (s->D >> 24) & 0xff;
X+}
X+
X+/* End MD5 stuff */
X+
X+/* Base 64 conversion */
X+
X+static const char base64[64] = "./1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM";
X+
X+/*
X+ * Convert "from" to base 64 and store it in "to".  Returns a pointer
X+ *  to just after the last byte of "to" that was modified.  (This will
X+ *  always be to+ceil((nfb*4)/3).)
X+ */
X+static char *to64(unsigned char *from, char *to, unsigned int nfb)
X+{
X+ unsigned long int cvbuf;
X+ int cvbits;
X+
X+ cvbuf = 0;
X+ cvbits = 0;
X+ while (1)
X+  { if (cvbits < 6)
X+     { if (nfb < 1)
X+	{ if (cvbits > 0) *to++ = base64[cvbuf];
X+	  break;
X+	}
X+       cvbuf |= (*from++ << cvbits);
X+       cvbits += 8;
X+       nfb --;
X+     }
X+    *to++ = base64[cvbuf&63];
X+    cvbuf >>= 6;
X+    cvbits -= 6;
X+  }
X+ return(to);
X+}
X+
X+/* End base 64 conversion */
X+
X+/*
X+ * Publicized interface: make a salt string.  This returns something
X+ *  suitable to hand to crypt()'s second argument, when hashing a
X+ *  new password to store somewhere.
X+ */
X+char *crypt_makesalt(void)
X+{
X+ static char saltbuf[256];
X+ unsigned char tmp[256];
X+ struct timeval tv;
X+ STATE s;
X+
X+ gettimeofday(&tv,0);
X+ sprintf(&tmp[0],"%lu %lu %d %d",
X+	(unsigned long int)tv.tv_sec,
X+	(unsigned long int)tv.tv_usec,
X+	(int)getpid(),
X+	(int)getppid());
X+ md5_init(&s);
X+ md5_process_bytes(&s,&tmp[0],sizeof(tmp)); /* deliberately use stack trash */
X+ md5_result(&s,&tmp[0]);
X+ saltbuf[0] = ':';
X+ to64(&tmp[0],&saltbuf[1],16);
X+ saltbuf[23] = '\0';
X+ return(&saltbuf[0]);
X+}
X+
X+/*
X+ * Encrypt a password.  key is the cleartext password; hash is either
X+ *  the hashed password, from wherever it was stored, or some salt string,
X+ *  such as one returned by crypt_makesalt().
X+ *
X+ * Returned string has the format "=%d.%d.%s%s", where the first number
X+ *  is the format version (currently 1) and the second is the number of
X+ *  rounds.  The first string is the salt string, the second the hash
X+ *  string; both strings will always be 22 bytes long.  If the hash
X+ *  argument appears to match this format, it is assumed to be a hashed
X+ *  password; otherwise, it is taken as an arbitrary string and is
X+ *  MD5-hashed down to a 22-byte salt string that's used.
X+ */
X+char *md5_crypt(key,hash)
X+const char *key;
X+const char *hash;
X+{
X+ static char rvbuf[256];
X+ char saltbuf[22];
X+ unsigned char md5res[16];
X+ char databuf[22];
X+ const char *data;
X+ int datalen;
X+ int keylen;
X+ STATE s;
X+ int v;
X+ int r;
X+ int i;
X+ char *hp;
X+ char *salt;
X+
X+ salt = 0;
X+ if (hash[0] == '=')
X+  { v = strtol(hash+1,&hp,10);
X+    if ((v == VERSION_MD5) && (*hp == '.'))
X+     { r = strtol(hp+1,&hp,10);
X+       if ((r >= MIN_ROUNDS) && (r <= MAX_ROUNDS) && (*hp == '.'))
X+	{ if ((strlen(hp) == 45) && __crypt_tst64stringp(hp+1))
X+	   { salt = hp + 1;
X+	   }
X+	}
X+     }
X+  }
X+ if (! salt)
X+  { md5_init(&s);
X+    md5_process_bytes(&s,hash,strlen(hash));
X+    md5_result(&s,&md5res[0]);
X+    to64(&md5res[0],&saltbuf[0],16);
X+    salt = &saltbuf[0];
X+    v = DEF_VERSION;
X+    r = DEF_ROUNDS;
X+  }
X+ keylen = strlen(key);
X+ data = key;
X+ datalen = keylen;
X+ for (i=0;i<r;i++)
X+  { md5_init(&s);
X+    md5_process_bytes(&s,data,datalen);
X+    md5_process_bytes(&s,salt,22);
X+    md5_process_bytes(&s,data,datalen);
X+    md5_process_bytes(&s,key,keylen);
X+    md5_process_bytes(&s,data,datalen);
X+    md5_result(&s,&md5res[0]);
X+    to64(&md5res[0],&databuf[0],16);
X+    data = &databuf[0];
X+    datalen = 22;
X+  }
X+ sprintf(&rvbuf[0],"=%d.%d.%.22s%.22s",v,r,salt,data);
X+ return(&rvbuf[0]);
X+}
EOF
if test 10202 -ne "`wc -c patch-lib-libcrypt-md5crypt.c`"
then
echo shar: error transmitting patch-lib-libcrypt-md5crypt.c \(should have been 10202 characters\)
fi
echo x - patch-lib-libcrypt-realcrypt.c \(955 characters\)
sed 's/^X//' > patch-lib-libcrypt-realcrypt.c << \EOF
X+++ NEW/lib/libcrypt/realcrypt.c	Thu Jan  1 00:00:00 1970
X@@ -0,0 +1,31 @@
X+#include <string.h>
X+
X+extern char *des_crypt(const char *, const char *);
X+extern char *md5_crypt(const char *, const char *);
X+
X+int __crypt_tst64stringp(const void *sarg)
X+{
X+ const unsigned char *s;
X+ static unsigned char v[] = {   0,  0,  0,  0,  0,192,255,  3, /*  0.. 63*/
X+			      254,255,255,  7,254,255,255,  7, /* 64..127*/
X+			      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*128..255*/
X+			      };
X+
X+ for (s=sarg;*s;s++) if (! (v[*s/8] & (1<<(*s%8)))) return(0);
X+ return(1);
X+}
X+
X+char *crypt(const char *key, const char *salt)
X+{
X+ int saltlen;
X+
X+ saltlen = strlen(salt);
X+ if ( ( ((saltlen == 13) || (saltlen == 2)) &&
X+	__crypt_tst64stringp(salt) ) ||
X+      ( (salt[0] == '_') &&
X+	((saltlen == 20) || (saltlen == 9)) &&
X+	__crypt_tst64stringp(salt+1) ) )
X+  { return(des_crypt(key,salt));
X+  }
X+ return(md5_crypt(key,salt));
X+}
EOF
if test 955 -ne "`wc -c patch-lib-libcrypt-realcrypt.c`"
then
echo shar: error transmitting patch-lib-libcrypt-realcrypt.c \(should have been 955 characters\)
fi
echo x - patch-usr.bin-passwd-local_passwd.c \(913 characters\)
sed 's/^X//' > patch-usr.bin-passwd-local_passwd.c << \EOF
X+++ NEW/usr.bin/passwd/local_passwd.c	Thu Jan  1 00:00:00 1970
X@@ -93,7 +93,9 @@
X {
X 	register char *p, *t;
X 	int tries;
X-	char buf[_PASSWORD_LEN+1], salt[9], *crypt(), *getpass();
X+	char buf[_PASSWORD_LEN+1], salt[9], *getpass();
X+	extern char *crypt();
X+	extern char *crypt_makesalt();
X 
X 	(void)printf("Changing local password for %s.\n", pw->pw_name);
X 
X@@ -124,16 +126,7 @@
X 			break;
X 		(void)printf("Mismatch; try again, EOF to quit.\n");
X 	}
X-	/* grab a random printable character that isn't a colon */
X-	(void)srandom((int)time((time_t *)NULL));
X-#ifdef NEWSALT
X-	salt[0] = _PASSWORD_EFMT1;
X-	to64(&salt[1], (long)(29 * 25), 4);
X-	to64(&salt[5], random(), 4);
X-#else
X-	to64(&salt[0], random(), 2);
X-#endif
X-	return(crypt(buf, salt));
X+	return(crypt(buf,crypt_makesalt()));
X }
X 
X static unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
EOF
if test 913 -ne "`wc -c patch-usr.bin-passwd-local_passwd.c`"
then
echo shar: error transmitting patch-usr.bin-passwd-local_passwd.c \(should have been 913 characters\)
fi
echo x - patch-usr.bin-passwd-yp_passwd.c \(760 characters\)
sed 's/^X//' > patch-usr.bin-passwd-yp_passwd.c << \EOF
X+++ NEW/usr.bin/passwd/yp_passwd.c	Thu Jan  1 00:00:00 1970
X@@ -188,6 +188,7 @@
X 	register char *p, *t;
X 	int tries;
X 	char salt[9], *crypt(), *getpass();
X+	char *crypt_makesalt();
X 	
X 	(void)printf("Changing YP password for %s.\n", pw->pw_name);
X 
X@@ -226,13 +227,11 @@
X 			break;
X 		(void)printf("Mismatch; try again, EOF to quit.\n");
X 	}
X+#ifdef NEW_YP_ENTRIES
X+	salt = crypt_makesalt();
X+#else
X 	/* grab a random printable character that isn't a colon */
X 	(void)srandom((int)time((time_t *)NULL));
X-#ifdef NEWSALT
X-	salt[0] = _PASSWORD_EFMT1;
X-	to64(&salt[1], (long)(29 * 25), 4);
X-	to64(&salt[5], random(), 4);
X-#else
X 	to64(&salt[0], random(), 2);
X #endif
X 	return(strdup(crypt(buf, salt)));
EOF
if test 760 -ne "`wc -c patch-usr.bin-passwd-yp_passwd.c`"
then
echo shar: error transmitting patch-usr.bin-passwd-yp_passwd.c \(should have been 760 characters\)
fi
exit 0
# end of shell archive
>Audit-Trail:
>Unformatted: