To use SHA1, add 'SHA1_CRYPT_ENAB yes' to /etc/login.defs. robert diff -Naur shadow-4.0.4.1.orig/configure shadow-4.0.4.1/configure --- shadow-4.0.4.1.orig/configure 2004-01-14 14:15:15.000000000 +0000 +++ shadow-4.0.4.1/configure 2007-04-29 21:32:46.000000000 +0000 @@ -21848,13 +21848,13 @@ if test "$with_libcrypt" != "no"; then - echo "$as_me:$LINENO: checking for crypt in -lcrypt" >&5 -echo $ECHO_N "checking for crypt in -lcrypt... $ECHO_C" >&6 + echo "$as_me:$LINENO: checking for DES_crypt in -lcrypto" >&5 +echo $ECHO_N "checking for DES_crypt in -lcrypto... $ECHO_C" >&6 if test "${ac_cv_lib_crypt_crypt+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lcrypt $LIBS" +LIBS="-lcrypto $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -21868,11 +21868,11 @@ #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char crypt (); +char DES_crypt (); int main () { -crypt (); +DES_crypt (); ; return 0; } @@ -21905,7 +21905,7 @@ cat >>confdefs.h <<\_ACEOF #define HAVE_LIBCRYPT 1 _ACEOF - LIBCRYPT=-lcrypt + LIBCRYPT=-lcrypto fi fi diff -Naur shadow-4.0.4.1.orig/configure.in shadow-4.0.4.1/configure.in --- shadow-4.0.4.1.orig/configure.in 2004-01-14 14:11:25.000000000 +0000 +++ shadow-4.0.4.1/configure.in 2007-04-29 21:32:46.000000000 +0000 @@ -227,7 +227,7 @@ AC_SUBST(LIBCRYPT) if test "$with_libcrypt" != "no"; then - AC_CHECK_LIB(crypt, crypt, [AC_DEFINE(HAVE_LIBCRYPT) LIBCRYPT=-lcrypt]) + AC_CHECK_LIB(crypto, DES_crypt, [AC_DEFINE(HAVE_LIBCRYPT) LIBCRYPT=-lcrypto]) fi AC_SUBST(LIBCRACK) diff -Naur shadow-4.0.4.1.orig/lib/Makefile.in shadow-4.0.4.1/lib/Makefile.in --- shadow-4.0.4.1.orig/lib/Makefile.in 2004-01-14 14:15:26.000000000 +0000 +++ shadow-4.0.4.1/lib/Makefile.in 2007-04-29 21:32:46.000000000 +0000 @@ -177,9 +177,14 @@ groupio.h \ gshadow.c \ lockpw.c \ - md5.h \ nscd.c \ nscd.h \ + openssl-hmac.c \ + openssl-md5.h \ + openssl-md5.c \ + openssl-sha1.h \ + openssl-sha1.c \ + openssl-util.c \ pam_defs.h \ port.c \ port.h \ @@ -204,7 +209,7 @@ EXTRA_libshadow_la_SOURCESS = grent.c pwent.c mkdir.c rename.c rmdir.c \ strdup.c strcasecmp.c strerror.c strstr.c putgrent.c \ putpwent.c putspent.c sgetgrent.c sgetpwent.c sgetspent.c \ - snprintf.c md5.c md5crypt.c + snprintf.c @@ -232,7 +237,8 @@ am_libshadow_la_OBJECTS = commonio.lo encrypt.lo fputsx.lo getdef.lo \ getpass.lo groupio.lo gshadow.lo lockpw.lo nscd.lo port.lo \ pwauth.lo pwio.lo rad64.lo sgetgrent.lo sgetpwent.lo \ - sgroupio.lo shadow.lo shadowio.lo utent.lo + sgroupio.lo shadow.lo shadowio.lo utent.lo \ + openssl-hmac.lo openssl-md5.lo openssl-sha1.lo openssl-util.lo libshadow_la_OBJECTS = $(am_libshadow_la_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) diff -Naur shadow-4.0.4.1.orig/lib/encrypt.c shadow-4.0.4.1/lib/encrypt.c --- shadow-4.0.4.1.orig/lib/encrypt.c 2000-08-26 18:27:17.000000000 +0000 +++ shadow-4.0.4.1/lib/encrypt.c 2007-04-29 21:32:46.000000000 +0000 @@ -35,89 +35,40 @@ #include "prototypes.h" #include "defines.h" -extern char *crypt(); -extern char *libshadow_md5_crypt(const char *, const char *); +#include "openssl-md5.h" +#include "openssl-sha1.h" +#include /* Move this somewhere else. */ char * pw_encrypt(const char *clear, const char *salt) { static char cipher[128]; char *cp; -#ifdef SW_CRYPT - static int count; -#endif -#ifdef MD5_CRYPT - /* - * If the salt string from the password file or from crypt_make_salt() - * begins with the magic string, use the new algorithm. - */ - if (strncmp(salt, "$1$", 3) == 0) - return libshadow_md5_crypt(clear, salt); -#endif - -#ifdef SW_CRYPT - /* - * Copy over the salt. It is always the first two - * characters of the string. - */ - - cipher[0] = salt[0]; - cipher[1] = salt[1]; - cipher[2] = '\0'; - - /* - * Loop up to ten times on the cleartext password. - * This is because the input limit for passwords is - * 80 characters. - * - * The initial salt is that provided by the user, or the - * one generated above. The subsequent salts are gotten - * from the first two characters of the previous encrypted - * block of characters. - */ - - for (count = 0;count < 10;count++) { - cp = crypt(clear, salt); + if (is_sha1_salt(salt)) { + cp = sha1_crypt(clear, salt); if (!cp) { - perror("crypt"); + perror("sha1_crypt() failed"); + exit(1); + } + } else + if (is_md5_salt(salt)) { + cp = md5_crypt(clear, salt); + if (!cp) { + perror("md5_crypt() failed"); exit(1); } - if (strlen(cp) != 13) - return cp; - strcat(cipher, cp + 2); - salt = cipher + 11 * count + 2; - - if (strlen(clear) > 8) - clear += 8; - else - break; - } -#else - cp = crypt(clear, salt); - if (!cp) { - /* - * Single Unix Spec: crypt() may return a null pointer, - * and set errno to indicate an error. The caller doesn't - * expect us to return NULL, so... - */ - perror("crypt"); - exit(1); } - if (strlen(cp) != 13) - return cp; /* nonstandard crypt() in libc, better bail out */ - strcpy(cipher, cp); - -#ifdef DOUBLESIZE - if (strlen (clear) > 8) { - cp = crypt(clear + 8, salt); + else { + cp = DES_crypt(clear, salt); if (!cp) { - perror("crypt"); + perror("DES_crypt() failed"); exit(1); } - strcat(cipher, cp + 2); } -#endif /* DOUBLESIZE */ -#endif /* SW_CRYPT */ + if (strlen(cp) != 13) + return cp; /* nonstandard crypt() in libc, better bail out */ + strlcpy(cipher, cp, sizeof(cipher)); + return cipher; } diff -Naur shadow-4.0.4.1.orig/lib/getdef.c shadow-4.0.4.1/lib/getdef.c --- shadow-4.0.4.1.orig/lib/getdef.c 2003-05-12 02:40:08.000000000 +0000 +++ shadow-4.0.4.1/lib/getdef.c 2007-04-29 21:32:46.000000000 +0000 @@ -104,6 +104,7 @@ { "PORTTIME_CHECKS_ENAB", NULL }, { "QMAIL_DIR", NULL }, { "QUOTAS_ENAB", NULL }, + { "SHA1_CRYPT_ENAB", NULL }, { "SULOG_FILE", NULL }, { "SU_NAME", NULL }, { "SU_WHEEL_ONLY", NULL }, diff -Naur shadow-4.0.4.1.orig/lib/md5.h shadow-4.0.4.1/lib/md5.h --- shadow-4.0.4.1.orig/lib/md5.h 1996-08-10 07:59:51.000000000 +0000 +++ shadow-4.0.4.1/lib/md5.h 1970-01-01 00:00:00.000000000 +0000 @@ -1,27 +0,0 @@ -#ifndef MD5_H -#define MD5_H - -#ifdef __alpha -typedef unsigned int uint32; -#else -typedef unsigned long uint32; -#endif - -struct MD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -void MD5Init(struct MD5Context *context); -void MD5Update(struct MD5Context *context, unsigned char const *buf, - unsigned len); -void MD5Final(unsigned char digest[16], struct MD5Context *context); -void MD5Transform(uint32 buf[4], uint32 const in[16]); - -/* - * This is needed to make RSAREF happy on some MS-DOS compilers. - */ -typedef struct MD5Context MD5_CTX; - -#endif /* !MD5_H */ diff -Naur shadow-4.0.4.1.orig/lib/openssl-hmac.c shadow-4.0.4.1/lib/openssl-hmac.c --- shadow-4.0.4.1.orig/lib/openssl-hmac.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-hmac.c 2007-04-29 21:32:46.000000000 +0000 @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2004, Juniper Networks, Inc. + * 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 copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +/* $NetBSD: hmac.c,v 1.1 2006/10/27 18:22:56 drochner Exp $ */ + +/* + * Implement HMAC as described in RFC 2104 + * + * You need to define the following before including this file. + * + * HMAC_FUNC the name of the function (hmac_sha1 or hmac_md5 etc) + * HASH_LENGTH the size of the digest (20 for SHA1, 16 for MD5) + * HASH_CTX the name of the HASH CTX + * HASH_Init + * HASH_Update + * Hash_Final + */ + +#include +#include + +/* If we want to use MD5-HMAC, then this #include needs to be + wrapped in an #ifdef. */ +#include "openssl-sha1.h" + +/* Don't change these */ +#define HMAC_IPAD 0x36 +#define HMAC_OPAD 0x5c + +/* Nor this */ +#ifndef HMAC_BLOCKSZ +# define HMAC_BLOCKSZ 64 +#endif + +/* + * The logic here is lifted straight from RFC 2104 except that + * rather than filling the pads with 0, copying in the key and then + * XOR with the pad byte, we just fill with the pad byte and + * XOR with the key. + */ +void +HMAC_FUNC (const unsigned char *text, size_t text_len, + const unsigned char *key, size_t key_len, + unsigned char *digest) +{ + HASH_CTX context; + /* Inner padding key XOR'd with ipad */ + unsigned char k_ipad[HMAC_BLOCKSZ + 1]; + /* Outer padding key XOR'd with opad */ + unsigned char k_opad[HMAC_BLOCKSZ + 1]; + /* HASH(key) if needed */ + unsigned char tk[HASH_LENGTH]; + int i; + + /* + * If key is longer than HMAC_BLOCKSZ bytes + * reset it to key=HASH(key) + */ + if (key_len > HMAC_BLOCKSZ) { + HASH_CTX tctx; + + HASH_Init(&tctx); + HASH_Update(&tctx, key, key_len); + HASH_Final(tk, &tctx); + + key = tk; + key_len = HASH_LENGTH; + } + + /* + * The HMAC_ transform looks like: + * + * HASH(K XOR opad, HASH(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte HMAC_IPAD repeated HMAC_BLOCKSZ times + * opad is the byte HMAC_OPAD repeated HMAC_BLOCKSZ times + * and text is the data being protected + */ + + /* + * Fill the pads and XOR in the key + */ + memset( k_ipad, HMAC_IPAD, sizeof k_ipad); + memset( k_opad, HMAC_OPAD, sizeof k_opad); + for (i = 0; i < key_len; i++) { + k_ipad[i] ^= key[i]; + k_opad[i] ^= key[i]; + } + + /* + * Perform inner HASH. + * Start with inner pad, + * then the text. + */ + HASH_Init(&context); + HASH_Update(&context, k_ipad, HMAC_BLOCKSZ); + HASH_Update(&context, text, text_len); + HASH_Final(digest, &context); + + /* + * Perform outer HASH. + * Start with the outer pad, + * then the result of the inner hash. + */ + HASH_Init(&context); + HASH_Update(&context, k_opad, HMAC_BLOCKSZ); + HASH_Update(&context, digest, HASH_LENGTH); + HASH_Final(digest, &context); +} + diff -Naur shadow-4.0.4.1.orig/lib/openssl-md5.c shadow-4.0.4.1/lib/openssl-md5.c --- shadow-4.0.4.1.orig/lib/openssl-md5.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-md5.c 2007-04-29 21:32:46.000000000 +0000 @@ -0,0 +1,146 @@ +/* + * ---------------------------------------------------------------------------- + * "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: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ + * $OpenBSD: md5crypt.c,v 1.14 2005/08/08 08:05:33 espie Exp $ + * + */ + +/* + * Added is_md5_salt() and modified for Linux to use libcrypto. + * Robert Connolly + */ + +#include + +#include +#include +#include +#include + +#include "openssl-md5.h" + +static unsigned char *magic = (unsigned char *)MD5_MAGIC; + +int is_md5_salt(const char *); + +int +is_md5_salt(const char *salt) +{ + return (strncmp(salt, magic, strlen(magic)) == 0); +} + +char *md5_crypt(const char *pw, const char *salt); + +char * +md5_crypt(const char *pw, const char *salt) +{ + static char passwd[120], *p; + static const unsigned char *sp, *ep; + unsigned char final[MD5_DIGEST_LENGTH]; + int sl, pl, i; + MD5_CTX ctx,ctx1; + uint32_t l; + + /* Refine the Salt. */ + sp = (const unsigned char *)salt; + + /* Skip the magic string in the salt. */ + if(!strncmp((const char *)sp, (const char *)magic, strlen((const char *)magic))) + sp += strlen((const char *)magic); + + /* The salt stops at the first '$', maximum 8 characters. */ + for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) + continue; + + /* Get the length of the true salt. */ + sl = ep - sp; + + MD5_Init(&ctx); + + /* The password first, since that is what is most unknown. */ + MD5_Update(&ctx, (const unsigned char *)pw, strlen(pw)); + + /* Then our magic string. */ + MD5_Update(&ctx, magic, strlen((const char *)magic)); + + /* Then the raw salt. */ + MD5_Update(&ctx, sp, sl); + + /* Then just as many characters of the MD5(pw, salt, pw). */ + MD5_Init(&ctx1); + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + MD5_Update(&ctx1, sp, sl); + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + MD5_Final(final, &ctx1); + for(pl = strlen(pw); pl > 0; pl -= MD5_DIGEST_LENGTH) + MD5_Update(&ctx, final, pl > MD5_DIGEST_LENGTH ? MD5_DIGEST_LENGTH : pl); + + /* Don't leave anything around in virtual memeory. */ + memset(final, 0, sizeof final); + + /* Then something really weird... */ + for (i = strlen(pw); i ; i >>= 1) + if(i & 1) + MD5_Update(&ctx, final, 1); + else + MD5_Update(&ctx, (const unsigned char *)pw, 1); + + /* Now make the output string. */ + snprintf(passwd, sizeof(passwd), "%s%.*s$", (char *)magic, + sl, (const char *)sp); + + MD5_Final(final, &ctx); + + /* + * 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++) { + MD5_Init(&ctx1); + if(i & 1) + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + else + MD5_Update(&ctx1, final, MD5_DIGEST_LENGTH); + + if(i % 3) + MD5_Update(&ctx1, sp, sl); + + if(i % 7) + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + + if(i & 1) + MD5_Update(&ctx1, final, MD5_DIGEST_LENGTH); + else + MD5_Update(&ctx1, (const unsigned char *)pw, strlen(pw)); + MD5_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[ 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 virtual memory. */ + memset(final, 0, sizeof final); + + return passwd; +} + diff -Naur shadow-4.0.4.1.orig/lib/openssl-md5.h shadow-4.0.4.1/lib/openssl-md5.h --- shadow-4.0.4.1.orig/lib/openssl-md5.h 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-md5.h 2007-04-29 21:32:46.000000000 +0000 @@ -0,0 +1,24 @@ +/* + * ---------------------------------------------------------------------------- + * "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 + * ---------------------------------------------------------------------------- + */ + +/* $Id: md5crypt.h,v 1.4 2003/05/18 14:46:46 djm Exp $ */ + +#ifndef _SHADOW_OPENSSL_MD5_H +#define _SHADOW_OPENSSL_MD5_H + +#include + +#include + +int is_md5_salt(const char *); +char *md5_crypt(const char *, const char *); + +#define MD5_MAGIC "$1$" + +#endif /* _SHADOW_OPENSSL_MD5_H */ diff -Naur shadow-4.0.4.1.orig/lib/openssl-sha1.c shadow-4.0.4.1/lib/openssl-sha1.c --- shadow-4.0.4.1.orig/lib/openssl-sha1.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-sha1.c 2007-04-29 21:32:46.000000000 +0000 @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2004, Juniper Networks, Inc. + * 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 copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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. + */ + +/* $NetBSD: crypt-sha1.c,v 1.3 2006/10/27 18:22:56 drochner Exp $ */ + +#include + +#include +#include +#include +#include +#include + +#include + +#include "openssl-sha1.h" + +/* + * The default iterations - should take >0s on a fast CPU + * but not be insane for a slow CPU. + */ +#ifndef CRYPT_SHA1_ITERATIONS +# define CRYPT_SHA1_ITERATIONS 24680 +#endif +/* + * Support a reasonably? long salt. + */ +#ifndef CRYPT_SHA1_SALT_LENGTH +# define CRYPT_SHA1_SALT_LENGTH 64 +#endif + +static unsigned char *magic = (unsigned char *)SHA1_MAGIC; + +int is_sha1_salt(const char *); + +int +is_sha1_salt(const char *salt) +{ + return (strncmp(salt, magic, strlen(magic)) == 0); +} + +/* + * This may be called from sha1_crypt or gensalt. + * + * The value returned will be slightly less than which defaults + * to 24680. The goals are that the number of iterations should take + * non-zero amount of time on a fast cpu while not taking insanely + * long on a slow cpu. The current default will take about 5 seconds + * on a 100MHz sparc, and about 0.04 seconds on a 3GHz i386. + * The number is varied to frustrate those attempting to generate a + * dictionary of pre-computed hashes. + */ +unsigned int +sha1_crypt_iterations (unsigned int hint) +{ + static int once = 1; + + /* + * We treat CRYPT_SHA1_ITERATIONS as a hint. + * Make it harder for someone to pre-compute hashes for a + * dictionary attack by not using the same iteration count for + * every entry. + */ + + if (once) { + int pid = getpid(); + + srandom(time(NULL) ^ (pid * pid)); + once = 0; + } + if (hint == 0) + hint = CRYPT_SHA1_ITERATIONS; + return hint - (random() % (hint / 4)); +} + +/* + * UNIX password using hmac_sha1 + * This is PBKDF1 from RFC 2898, but using hmac_sha1. + * + * The format of the encrypted password is: + * $$$$ + * + * where: + * is "sha1" + * is an unsigned int identifying how many rounds + * have been applied to . The number + * should vary slightly for each password to make + * it harder to generate a dictionary of + * pre-computed hashes. See crypt_sha1_iterations. + * up to 64 bytes of random data, 8 bytes is + * currently considered more than enough. + * the hashed password. + * + * NOTE: + * To be FIPS 140 compliant, the password which is used as a hmac key, + * should be between 10 and 20 characters to provide at least 80bits + * strength, and avoid the need to hash it before using as the + * hmac key. + */ +char * +sha1_crypt (const char *pw, const char *salt) +{ + static unsigned char hmac_buf[SHA_DIGEST_LENGTH]; + static char passwd[(2 * sizeof(SHA1_MAGIC)) + + CRYPT_SHA1_SALT_LENGTH + SHA_DIGEST_LENGTH]; + char *sp; + char *ep; + unsigned long ul; + int sl; + int pl; + int dl; + unsigned int iterations; + unsigned int i; + + /* + * Salt format is + * $$$salt[$] + * If it does not start with $ we use our default iterations. + */ + sp = (const unsigned char *)salt; + + /* If it starts with the magic string, then skip that */ + if (!strncmp(sp, magic, strlen(magic))) { + sp += strlen(magic); + /* and get the iteration count */ + iterations = strtoul(sp, &ep, 10); + if (*ep != '$') + return NULL; /* invalid input */ + sp = ep + 1; /* skip over the '$' */ + } else { + iterations = sha1_crypt_iterations(0); + } + + /* It stops at the next '$', max CRYPT_SHA1_ITERATIONS chars */ + for (ep = sp; *ep && *ep != '$' && ep < (sp + CRYPT_SHA1_ITERATIONS); ep++) + continue; + + /* Get the length of the actual salt */ + sl = ep - sp; + pl = strlen(pw); + + /* + * Now get to work... + * Prime the pump with + */ + dl = snprintf(passwd, sizeof (passwd), "%.*s%s%u", + sl, sp, magic, iterations); + /* + * Then hmac using as key, and repeat... + */ + ep = (const unsigned char *)pw; + hmac_sha1(passwd, dl, ep, pl, hmac_buf); + for (i = 1; i < iterations; i++) { + hmac_sha1(hmac_buf, SHA_DIGEST_LENGTH, ep, pl, hmac_buf); + } + /* Now output... */ + pl = snprintf(passwd, sizeof(passwd), "%s%u$%.*s$", + magic, iterations, sl, sp); + ep = passwd + pl; + + /* Every 3 bytes of hash gives 24 bits which is 4 base64 chars */ + for (i = 0; i < SHA_DIGEST_LENGTH - 3; i += 3) { + ul = (hmac_buf[i+0] << 16) | + (hmac_buf[i+1] << 8) | + hmac_buf[i+2]; + crypt_to64(ep, ul, 4); ep += 4; + } + /* Only 2 bytes left, so we pad with byte0 */ + ul = (hmac_buf[SHA_DIGEST_LENGTH - 2] << 16) | + (hmac_buf[SHA_DIGEST_LENGTH - 1] << 8) | + hmac_buf[0]; + crypt_to64(ep, ul, 4); ep += 4; + *ep = '\0'; + + /* Don't leave anything around in virtual memory. */ + memset(hmac_buf, 0, sizeof hmac_buf); + + return passwd; +} diff -Naur shadow-4.0.4.1.orig/lib/openssl-sha1.h shadow-4.0.4.1/lib/openssl-sha1.h --- shadow-4.0.4.1.orig/lib/openssl-sha1.h 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-sha1.h 2007-04-29 21:32:46.000000000 +0000 @@ -0,0 +1,26 @@ +/* + * hmac_sha1 - using HMAC from RFC 2104 + */ + +/* $NetBSD: hmac_sha1.c,v 1.1 2006/10/27 18:22:56 drochner Exp $ */ + +#ifndef _SHADOW_OPENSSL_SHA1_H +#define _SHADOW_OPENSSL_SHA1_H + +#include + +#include + +#define HMAC_HASH SHA1 +#define HMAC_FUNC hmac_sha1 +#define HMAC_KAT hmac_kat_sha1 + +#define HASH_LENGTH SHA_DIGEST_LENGTH +#define HASH_CTX SHA_CTX +#define HASH_Init SHA1_Init +#define HASH_Update SHA1_Update +#define HASH_Final SHA1_Final + +#define SHA1_MAGIC "$sha1$" + +#endif /* _SHADOW_OPENSSL_SHA1_H */ diff -Naur shadow-4.0.4.1.orig/lib/openssl-util.c shadow-4.0.4.1/lib/openssl-util.c --- shadow-4.0.4.1.orig/lib/openssl-util.c 1970-01-01 00:00:00.000000000 +0000 +++ shadow-4.0.4.1/lib/openssl-util.c 2007-04-29 21:32:46.000000000 +0000 @@ -0,0 +1,21 @@ +/* $NetBSD: util.c,v 1.1 2004/07/02 00:05:23 sjg Exp $ */ + +#include + +#include + +/* 0 ... 63 => ascii - 64 */ +static const unsigned char itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +void crypt_to64(char *, uint32_t, int); + +void +crypt_to64(char *s, uint32_t v, int n) +{ + + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} diff -Naur shadow-4.0.4.1.orig/libmisc/obscure.c shadow-4.0.4.1/libmisc/obscure.c --- shadow-4.0.4.1.orig/libmisc/obscure.c 2003-05-05 21:44:15.000000000 +0000 +++ shadow-4.0.4.1/libmisc/obscure.c 2007-04-29 21:32:46.000000000 +0000 @@ -231,6 +231,9 @@ Example: "password$%^&*123". So check it again, this time truncated to the maximum length. Idea from npasswd. --marekm */ + if (getdef_bool ("SHA1_CRYPT_ENAB")) + return NULL; /* unlimited password length */ + if (getdef_bool ("MD5_CRYPT_ENAB")) return NULL; /* unlimited password length */ diff -Naur shadow-4.0.4.1.orig/libmisc/salt.c shadow-4.0.4.1/libmisc/salt.c --- shadow-4.0.4.1.orig/libmisc/salt.c 2003-04-22 10:59:22.000000000 +0000 +++ shadow-4.0.4.1/libmisc/salt.c 2007-04-29 21:33:34.000000000 +0000 @@ -12,6 +12,8 @@ #include "prototypes.h" #include "defines.h" #include + + #if 1 #include "getdef.h" extern char *l64a (); @@ -28,6 +30,9 @@ static char result[40]; result[0] = '\0'; + if (getdef_bool ("SHA1_CRYPT_ENAB")) { + strcpy (result, "$sha1$8$salt$"); + } else if (getdef_bool ("MD5_CRYPT_ENAB")) { strcpy (result, "$1$"); /* magic for the new MD5 crypt() */ } diff -Naur shadow-4.0.4.1.orig/src/passwd.c shadow-4.0.4.1/src/passwd.c --- shadow-4.0.4.1.orig/src/passwd.c 2003-12-17 09:43:30.000000000 +0000 +++ shadow-4.0.4.1/src/passwd.c 2007-04-29 21:32:46.000000000 +0000 @@ -240,6 +240,9 @@ * for initial login passwords. */ + if (getdef_bool ("SHA1_CRYPT_ENAB")) + pass_max_len = 127; + else if (getdef_bool ("MD5_CRYPT_ENAB")) pass_max_len = 127; else