From 9bc938e5c504726347763bf8eb4fc058ff930a42 Mon Sep 17 00:00:00 2001 From: markm Date: Mon, 20 Sep 1999 12:45:49 +0000 Subject: Big code cleanup. (Inspired by Brandon Gillespie). Also move as much as possible away from secure/ to make extending easier. --- lib/libcrypt/Makefile | 50 ++++++++---- lib/libcrypt/crypt-md5.c | 142 +++++++++++++++++++++++++++++++++ lib/libcrypt/crypt-shs.c | 145 +++++++++++++++++++++++++++++++++ lib/libcrypt/crypt.3 | 203 +++++++++++++++++++++++++++++++++++++++++++++++ lib/libcrypt/crypt.c | 176 ++++++++-------------------------------- lib/libcrypt/crypt.h | 39 +++++++++ lib/libcrypt/misc.c | 46 +++++++++++ 7 files changed, 644 insertions(+), 157 deletions(-) create mode 100644 lib/libcrypt/crypt-md5.c create mode 100644 lib/libcrypt/crypt-shs.c create mode 100644 lib/libcrypt/crypt.3 create mode 100644 lib/libcrypt/crypt.h create mode 100644 lib/libcrypt/misc.c (limited to 'lib/libcrypt') diff --git a/lib/libcrypt/Makefile b/lib/libcrypt/Makefile index c34fcf3..338853d 100644 --- a/lib/libcrypt/Makefile +++ b/lib/libcrypt/Makefile @@ -2,26 +2,26 @@ # $FreeBSD$ # -LCRYPTBASE= libcrypt -LSCRYPTBASE= libscrypt +SHLIB_MAJOR= 3 +LIB= scrypt + +LCRYPTBASE= libcrypt +LSCRYPTBASE= lib${LIB} -.if ${OBJFORMAT} != elf -LCRYPTSO= ${LCRYPTBASE}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} -LSCRYPTSO= ${LSCRYPTBASE}.so.${SHLIB_MAJOR}.${SHLIB_MINOR} -.else LCRYPTSO= ${LCRYPTBASE}.so.${SHLIB_MAJOR} LSCRYPTSO= ${LSCRYPTBASE}.so.${SHLIB_MAJOR} -.endif -# called libscrypt - for scramble crypt! -.PATH: ${.CURDIR}/../libmd -LIB= scrypt -SRCS= crypt.c md5c.c -CFLAGS+= -I${.CURDIR}/../libmd -DLIBC_SCCS +.PATH: ${.CURDIR}/../libmd +SRCS= crypt.c crypt-md5.c crypt-shs.c misc.c +STATICSRCS= md5c.c sha0c.c sha1c.c +STATICOBJS= ${STATICSRCS:S/.c/.o/g} +MAN3= crypt.3 +CFLAGS+= -I${.CURDIR}/../libmd +CFLAGS+= -DLIBC_SCCS -Wall +PRECIOUSLIB= yes -.if ${OBJFORMAT} == elf -SONAME= ${LCRYPTBASE}.so.${SHLIB_MAJOR} -.endif +LDADD+= -lmd +DPADD+= ${LIBMD} # Include this early to pick up the definitions of SHLIB_MAJOR and # SHLIB_MINOR which are used in the existence tests. @@ -44,3 +44,23 @@ SYMLINKS+= ${LSCRYPTBASE}.so ${SHLIBDIR}/${LCRYPTBASE}.so .endif .include + +afterinstall: +.if !defined(NOPIC) + @cd ${DESTDIR}${SHLIBDIR}; \ + rm -f ${LCRYPTSO}; \ + ln -sf ${LSCRYPTSO} ${LCRYPTSO}; +.endif +.if !defined(NOPIC) && ${OBJFORMAT} == elf + @cd ${DESTDIR}${SHLIBDIR}; \ + rm -f ${LCRYPTBASE}.so; \ + ln -sf ${LSCRYPTBASE}.so libcrypt.so +.endif + @cd ${DESTDIR}${LIBDIR}; \ + rm -f ${LCRYPTBASE}.a; \ + ln -sf ${LSCRYPTBASE}.a libcrypt.a +.if !defined(NOPROFILE) + @cd ${DESTDIR}${LIBDIR}; \ + rm -f ${LCRYPTBASE}_p.a; \ + ln -sf ${LSCRYPTBASE}_p.a libcrypt_p.a +.endif diff --git a/lib/libcrypt/crypt-md5.c b/lib/libcrypt/crypt-md5.c new file mode 100644 index 0000000..95255e4 --- /dev/null +++ b/lib/libcrypt/crypt-md5.c @@ -0,0 +1,142 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * 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 + * ---------------------------------------------------------------------------- + * + * $FreeBSD$ + * + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$FreeBSD$"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include "crypt.h" + +/* + * UNIX password + */ + +char * +crypt_md5(pw, salt) + const char *pw; + const char *salt; +{ + static char *magic = "$1$"; /* + * This string is magic for + * this algorithm. Having + * it this way, we can get + * get better later on + */ + static char passwd[120], *p; + static const char *sp,*ep; + unsigned char final[MD5_SIZE]; + int sl,pl,i; + MD5_CTX ctx,ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(!strncmp(sp,magic,strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + MD5Init(&ctx); + + /* The password first, since that is what is most unknown */ + MD5Update(&ctx,pw,strlen(pw)); + + /* Then our magic string */ + MD5Update(&ctx,magic,strlen(magic)); + + /* Then the raw salt */ + MD5Update(&ctx,sp,sl); + + /* Then just as many characters of the MD5(pw,salt,pw) */ + MD5Init(&ctx1); + MD5Update(&ctx1,pw,strlen(pw)); + MD5Update(&ctx1,sp,sl); + MD5Update(&ctx1,pw,strlen(pw)); + MD5Final(final,&ctx1); + for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE) + MD5Update(&ctx,final,pl>MD5_SIZE ? MD5_SIZE : 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 ; i >>= 1) + if(i&1) + MD5Update(&ctx, final, 1); + else + MD5Update(&ctx, pw, 1); + + /* Now make the output string */ + strcpy(passwd,magic); + strncat(passwd,sp,sl); + strcat(passwd,"$"); + + 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++) { + MD5Init(&ctx1); + if(i & 1) + MD5Update(&ctx1,pw,strlen(pw)); + else + MD5Update(&ctx1,final,MD5_SIZE); + + if(i % 3) + MD5Update(&ctx1,sp,sl); + + if(i % 7) + MD5Update(&ctx1,pw,strlen(pw)); + + if(i & 1) + MD5Update(&ctx1,final,MD5_SIZE); + else + MD5Update(&ctx1,pw,strlen(pw)); + MD5Final(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; + _crypt_to64(p,l,4); p += 4; + l = final[11] ; + _crypt_to64(p,l,2); p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + return passwd; +} + diff --git a/lib/libcrypt/crypt-shs.c b/lib/libcrypt/crypt-shs.c new file mode 100644 index 0000000..683a3f5 --- /dev/null +++ b/lib/libcrypt/crypt-shs.c @@ -0,0 +1,145 @@ +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * 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 + * ---------------------------------------------------------------------------- + * + * $FreeBSD$ + * + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static const char rcsid[] = "$FreeBSD$"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#include "crypt.h" + +/* + * UNIX password + */ + +char * +crypt_sha(pw, salt) + const char *pw; + const char *salt; +{ + static char *magic = "$3$"; /* + * This string is magic for + * this algorithm. Having + * it this way, we can get + * get better later on + */ + static char passwd[120], *p; + static const char *sp,*ep; + unsigned char final[SHS_SIZE]; + int sl,pl,i; + SHA_CTX ctx,ctx1; + unsigned long l; + + /* Refine the Salt first */ + sp = salt; + + /* If it starts with the magic string, then skip that */ + if(!strncmp(sp,magic,strlen(magic))) + sp += strlen(magic); + + /* It stops at the first '$', max 8 chars */ + for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + SHA_Init(&ctx); + + /* The password first, since that is what is most unknown */ + SHA_Update(&ctx,pw,strlen(pw)); + + /* Then our magic string */ + SHA_Update(&ctx,magic,strlen(magic)); + + /* Then the raw salt */ + SHA_Update(&ctx,sp,sl); + + /* Then just as many characters of the SHA(pw,salt,pw) */ + SHA_Init(&ctx1); + SHA_Update(&ctx1,pw,strlen(pw)); + SHA_Update(&ctx1,sp,sl); + SHA_Update(&ctx1,pw,strlen(pw)); + SHA_Final(final,&ctx1); + for(pl = strlen(pw); pl > 0; pl -= SHS_SIZE) + SHA_Update(&ctx,final,pl>SHS_SIZE ? SHS_SIZE : 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 ; i >>= 1) + if(i&1) + SHA_Update(&ctx, final, 1); + else + SHA_Update(&ctx, pw, 1); + + /* Now make the output string */ + strcpy(passwd,magic); + strncat(passwd,sp,sl); + strcat(passwd,"$"); + + SHA_Final(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++) { + SHA_Init(&ctx1); + if(i & 1) + SHA_Update(&ctx1,pw,strlen(pw)); + else + SHA_Update(&ctx1,final,SHS_SIZE); + + if(i % 3) + SHA_Update(&ctx1,sp,sl); + + if(i % 7) + SHA_Update(&ctx1,pw,strlen(pw)); + + if(i & 1) + SHA_Update(&ctx1,final,SHS_SIZE); + else + SHA_Update(&ctx1,pw,strlen(pw)); + SHA_Final(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[16]; + _crypt_to64(p,l,4); p += 4; + l = (final[ 5]<<16) | (final[11]<<8) | final[17]; + _crypt_to64(p,l,4); p += 4; + l = (final[18]<<8) | final[19]; + _crypt_to64(p,l,3); p += 3; + + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final,0,sizeof final); + + return passwd; +} + diff --git a/lib/libcrypt/crypt.3 b/lib/libcrypt/crypt.3 new file mode 100644 index 0000000..5ce36a1 --- /dev/null +++ b/lib/libcrypt/crypt.3 @@ -0,0 +1,203 @@ +.\" FreeSec: libcrypt for NetBSD +.\" +.\" Copyright (c) 1994 David Burren +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 4. Neither the name of the author nor the names of other contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.\" Manual page, using -mandoc macros +.\" +.Dd January 19, 1997 +.Dt CRYPT 3 +.Os "FreeSec 1.0" +.Sh NAME +.Nm crypt +.Nd Trapdoor encryption +.Sh SYNOPSIS +.Ft char +.Fn *crypt "const char *key" "const char *salt" +.Sh DESCRIPTION +The +.Fn crypt +function performs password hashing with additional code added to +deter key search attempts. Different algorithms can be used to +in the hash. +.\" +.\" NOTICE: +.\" If you add more algorithms, make sure to update this list +.\" and the default used for the Traditional format, below. +.\" +Currently these include the +.Tn NBS +Data Encryption Standard (DES), MD5 or SHS. The algorithm +used will depend upon the format of the Salt--following the Modular +Crypt Format (MCF)--and if DES is installed or not. +.Pp +The first argument to +.Nm crypt +is the data to hash (usually a password), in a +.Dv null Ns -terminated +string. +The second is the salt, in one of three forms: +.Pp +.Bl -tag -width Traditional -compact -offset indent +.It Extended +If it begins with an underscore (``_'') then the DES Extended Format +is used in interpreting both the the key and the salt, as outlined below. +.It Modular +If it begins with the string ``$digit$'' then the Modular Crypt Format +is used, as outlined below. +.It Traditional +If neither of the above is true, it assumes the Traditional Format, +using the entire string as the salt (or the first portion). +.El +.Pp +All routines are designed to be time-consuming. A brief test on a +Pentium 166/MMX shows the DES crypt to do approximately 2640 crypts +a CPU second, MD5 to do about 62 crypts a CPU second and SHA1 +to do about 18 crypts a CPU second. +.Ss DES Extended Format: +.Pp +The +.Ar key +is divided into groups of 8 characters (the last group is null-padded) +and the low-order 7 bits of each each character (56 bits per group) are +used to form the DES key as follows: +the first group of 56 bits becomes the initial DES key. +For each additional group, the XOR of the encryption of the current DES +key with itself and the group bits becomes the next DES key. +.Pp +The salt is a 9-character array consisting of an underscore followed +by 4 bytes of iteration count and 4 bytes of salt. +These are encoded as printable characters, 6 bits per character, +least significant character first. +The values 0 to 63 are encoded as ``./0-9A-Za-z''. +This allows 24 bits for both +.Fa count +and +.Fa salt . +.Pp +The +.Fa salt +introduces disorder in the +.Tn DES +algorithm in one of 16777216 or 4096 possible ways +(ie. with 24 or 12 bits: if bit +.Em i +of the +.Ar salt +is set, then bits +.Em i +and +.Em i+24 +are swapped in the +.Tn DES +E-box output). +.Pp +The DES key is used to encrypt a 64-bit constant using +.Ar count +iterations of +.Tn DES . +The value returned is a +.Dv null Ns -terminated +string, 20 or 13 bytes (plus null) in length, consisting of the +.Ar salt +followed by the encoded 64-bit encryption. +.Ss "Modular" crypt: +.Pp +If the salt begins with the string +.Fa $digit$ +then the Modular Crypt Format is used. The +.Fa digit +represents which algorithm is used in encryption. Following the token is +the actual salt to use in the encryption. The length of the salt is limited +to 16 characters--because the length of the returned output is also limited +(_PASSWORD_LEN). The salt must be terminated with the end of the string +(NULL) or a dollar sign. Any characters after the dollar sign are ignored. +.Pp +Currently supported algorithms are: +.Pp +.Bl -tag -width 012345678 -compact -offset indent +.It 1 +MD5 +.It 3 +SHA1 +.El +.Pp +Other crypt formats may be easilly added. An example salt would be: +.Bl -tag -offset indent +.It Cm "$3$thesalt$rest" +.El +.Pp +.Ss "Traditional" crypt: +.Pp +The algorithm used will depend upon whether DES is installed or not. If it is, +DES will be used. Otherwise, the best algorithm is used, which is currently +.\" +.\" NOTICE: Also make sure to update this +.\" +SHA-1. +.Pp +How the salt is used will depend upon the algorithm for the hash. For +best results, specify at least two characters of salt. +.Sh RETURN VALUES +.Pp +.Fn crypt +returns a pointer to the encrypted value on success, and NULL on failure. +Note: this is not a standard behaviour, AT&T +.Fn crypt +will always return a pointer to a string. +.Sh SEE ALSO +.Xr login 1 , +.Xr passwd 1 , +.Xr getpass 3 , +.Xr passwd 5 , +.Xr shs 3 , +.Sh BUGS +The +.Fn crypt +function returns a pointer to static data, and subsequent calls to +.Fn crypt +will modify the same data. +.Sh HISTORY +A rotor-based +.Fn crypt +function appeared in +.At v6 . +The current style +.Fn crypt +first appeared in +.At v7 . +.Pp +The DES section of the code (FreeSec 1.0) was developed outside the United +States of America as an unencumbered replacement for the U.S.-only NetBSD +libcrypt encryption library. +Users should be aware that this code (and programs staticly linked with it) +may not be exported from the U.S., although it apparently can be imported. +.Sh AUTHORS +Originally written by David Burren , later additions +and changes by Brandon Gillespie, Poul-henning Kamp and Mark R V Murray. diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c index cf54cd5..8172504 100644 --- a/lib/libcrypt/crypt.c +++ b/lib/libcrypt/crypt.c @@ -1,10 +1,27 @@ /* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * 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 - * ---------------------------------------------------------------------------- + * Copyright (c) 1999 + * Mark Murray. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY MARK MURRAY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL MARK MURRAY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * * $FreeBSD$ * @@ -14,144 +31,19 @@ static char rcsid[] = "$FreeBSD$"; #endif /* LIBC_SCCS and not lint */ -#include -#include -#include -#include #include - -static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ - "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - -static void to64 __P((char *, unsigned long, int)); - -static void -to64(s, v, n) - char *s; - unsigned long v; - int n; -{ -static void to64 __P((char *, unsigned long, int)); - - while (--n >= 0) { - *s++ = itoa64[v&0x3f]; - v >>= 6; - } -} - -/* - * UNIX password - * - * Use MD5 for what it is best at... - */ +#include "crypt.h" char * -crypt(pw, salt) - register const char *pw; - register const char *salt; +crypt(char *passwd, char *salt) { - static char *magic = "$1$"; /* - * This string is magic for - * this algorithm. Having - * it this way, we can get - * get better later on - */ - static char passwd[120], *p; - static const char *sp,*ep; - unsigned char final[16]; - int sl,pl,i,j; - MD5_CTX ctx,ctx1; - unsigned long l; - - /* Refine the Salt first */ - sp = salt; - - /* If it starts with the magic string, then skip that */ - if(!strncmp(sp,magic,strlen(magic))) - sp += strlen(magic); - - /* It stops at the first '$', max 8 chars */ - for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) - continue; - - /* get the length of the true salt */ - sl = ep - sp; - - MD5Init(&ctx); - - /* The password first, since that is what is most unknown */ - MD5Update(&ctx,pw,strlen(pw)); - - /* Then our magic string */ - MD5Update(&ctx,magic,strlen(magic)); - - /* Then the raw salt */ - MD5Update(&ctx,sp,sl); - - /* Then just as many characters of the MD5(pw,salt,pw) */ - MD5Init(&ctx1); - MD5Update(&ctx1,pw,strlen(pw)); - MD5Update(&ctx1,sp,sl); - MD5Update(&ctx1,pw,strlen(pw)); - MD5Final(final,&ctx1); - for(pl = strlen(pw); pl > 0; pl -= 16) - 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 ; i >>= 1) - if(i&1) - MD5Update(&ctx, final, 1); - else - MD5Update(&ctx, pw, 1); - - /* Now make the output string */ - strcpy(passwd,magic); - strncat(passwd,sp,sl); - strcat(passwd,"$"); - - 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++) { - MD5Init(&ctx1); - if(i & 1) - MD5Update(&ctx1,pw,strlen(pw)); - else - MD5Update(&ctx1,final,16); - - if(i % 3) - MD5Update(&ctx1,sp,sl); - - if(i % 7) - MD5Update(&ctx1,pw,strlen(pw)); - - if(i & 1) - MD5Update(&ctx1,final,16); - else - MD5Update(&ctx1,pw,strlen(pw)); - 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); - - return passwd; + if (!strncmp(salt, "$1$", 3)) + return crypt_md5(passwd, salt); + if (!strncmp(salt, "$3$", 3)) + return crypt_sha(passwd, salt); +#ifdef NONEXPORTABLE_CRYPT + return crypt_des(passwd, salt); +#else + return NULL; +#endif } - diff --git a/lib/libcrypt/crypt.h b/lib/libcrypt/crypt.h new file mode 100644 index 0000000..21e7691 --- /dev/null +++ b/lib/libcrypt/crypt.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1999 + * Mark Murray. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY MARK MURRAY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL MARK MURRAY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +/* magic sizes */ +#define MD5_SIZE 16 +#define SHS_SIZE 20 + +char *crypt_des(const char *pw, const char *salt); +char *crypt_md5(const char *pw, const char *salt); +char *crypt_sha(const char *pw, const char *salt); + +extern void _crypt_to64(char *s, unsigned long v, int n); + diff --git a/lib/libcrypt/misc.c b/lib/libcrypt/misc.c new file mode 100644 index 0000000..5cad45d --- /dev/null +++ b/lib/libcrypt/misc.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 1999 + * University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void +_crypt_to64(s, v, n) + char *s; + unsigned long v; + int n; +{ + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} -- cgit v1.1