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: