3b2b7f71de
This effectively changes the non-DES password algoritm. If you have the "securedist" installed you will have no problems with this. (Though you might want to consider using this password-encryption instead of the DES-based if your system is likely to be hacked) If you are running a -current system without the "securedist" installed: YOU WILL NEED TO CHANGE ALL PASSWORDS !! There is no backwards mode. Suggested procedure is: Update your sources cd /usr/src/lib/libcrypt make clean make all make install passwd root <set roots new password> change password for any other users on the system. This algorithm is expected to be much better than the traditional DES- based algorithm. It uses the MD5 algorithm at what it is best at, as opposed to the DES algorithm at something it isn't good at at all. The algorithm is designed such that it should very hard to shortcut the calculations needed to build a dictionary, and to make partial knowledge (Hmm, his password starts with a 'P'...) useless. Of course if somebody breaks the MD5 algorithm this looses too. The salt is 48 bits (8 char @ base64). The encrypted password is 128 bits. And I am positively delighted to say that it takes 34 msec to crypt() a password on a Pentium/60Mhz, so building a dictionary is not really an option for hackers at the moment.
152 lines
3.6 KiB
C
152 lines
3.6 KiB
C
/*
|
|
* ----------------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
|
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
|
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#if defined(LIBC_SCCS) && !defined(lint)
|
|
static char rcsid[] = "$Header$";
|
|
#endif /* LIBC_SCCS and not lint */
|
|
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#include <md5.h>
|
|
|
|
static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
|
|
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
|
|
static void
|
|
to64(s, v, n)
|
|
char *s;
|
|
unsigned long v;
|
|
int n;
|
|
{
|
|
while (--n >= 0) {
|
|
*s++ = itoa64[v&0x3f];
|
|
v >>= 6;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* UNIX password
|
|
*
|
|
* Use MD5 for what it is best at...
|
|
*/
|
|
|
|
char *
|
|
crypt(pw, salt)
|
|
register const char *pw;
|
|
register 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[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 (j=0,i = strlen(pw); i ; i >>= 1)
|
|
if(i&1)
|
|
MD5Update(&ctx, final+j, 1);
|
|
else
|
|
MD5Update(&ctx, pw+j, 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;
|
|
}
|
|
|