freebsd-dev/lib/libcrypt/crypt-md5.c
Peter Wemm 9886bcdf93 Merge into a single US-exportable libcrypt, which only provides
one-way hash functions for authentication purposes.  There is no more
"set the libcrypt->libXXXcrypt" nightmare.
- Undo the libmd.so hack, use -D to hide the md5c.c internals.
- Remove the symlink hacks in release/Makefile
- the algorthm is set by set_crypt_format() as before.  If this is
  not called, it tries to heuristically figure out the hash format, and
  if all else fails, it uses the optional auth.conf entry to chose the
  overall default hash.
- Since source has non-hidden crypto in it there may be some issues with
  having the source it in some countries, so preserve the "secure/*"
  division.  You can still build a des-free libcrypt library if you want
  to badly enough.  This should not be a problem in the US or exporting
  from the US as freebsd.org had notified BXA some time ago.  That makes
  this stuff re-exportable by anyone.
- For consistancy, the default in absence of any other clues is md5.  This
  is to try and minimize POLA across buildworld where folk may suddenly
  be activating des-crypt()-hash support.  Since the des hash may not
  always be present, it seemed sensible to make the stronger md5 algorithm
  the default.
All things being equal, no functionality is lost.

Reviewed-by: jkh

(flame-proof suit on)
2000-12-28 10:32:02 +00:00

145 lines
3.4 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
* ----------------------------------------------------------------------------
*
* $FreeBSD$
*
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = \
"$FreeBSD$";
#endif /* LIBC_SCCS and not lint */
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <md5.h>
#include <err.h>
#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;
}