2008-06-12 16:55:59 +00:00
|
|
|
/*
|
|
|
|
* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
|
|
|
*
|
|
|
|
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
|
|
|
* rights reserved.
|
|
|
|
*
|
|
|
|
* License to copy and use this software is granted provided that it
|
|
|
|
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
|
|
|
* Algorithm" in all material mentioning or referencing this software
|
|
|
|
* or this function.
|
|
|
|
*
|
|
|
|
* License is also granted to make and use derivative works provided
|
|
|
|
* that such works are identified as "derived from the RSA Data
|
|
|
|
* Security, Inc. MD5 Message-Digest Algorithm" in all material
|
|
|
|
* mentioning or referencing the derived work.
|
|
|
|
*
|
|
|
|
* RSA Data Security, Inc. makes no representations concerning either
|
|
|
|
* the merchantability of this software or the suitability of this
|
|
|
|
* software for any particular purpose. It is provided "as is"
|
|
|
|
* without express or implied warranty of any kind.
|
|
|
|
*
|
|
|
|
* These notices must be retained in any copies of any part of this
|
|
|
|
* documentation and/or software.
|
|
|
|
*
|
|
|
|
* $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
|
|
|
|
*
|
|
|
|
* This code is the same as the code published by RSA Inc. It has been
|
|
|
|
* edited for clarity and style only.
|
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
* The md5_crypt() function was taken from freeBSD's libcrypt and contains
|
|
|
|
* this license:
|
|
|
|
* "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: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
|
|
|
|
*
|
|
|
|
* ----------------------------------------------------------------------------
|
|
|
|
* On April 19th, 2001 md5_crypt() was modified to make it reentrant
|
|
|
|
* by Erik Andersen <andersen@uclibc.org>
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* June 28, 2001 Manuel Novoa III
|
|
|
|
*
|
|
|
|
* "Un-inlined" code using loops and static const tables in order to
|
|
|
|
* reduce generated code size (on i386 from approx 4k to approx 2.5k).
|
|
|
|
*
|
|
|
|
* June 29, 2001 Manuel Novoa III
|
|
|
|
*
|
|
|
|
* Completely removed static PADDING array.
|
|
|
|
*
|
|
|
|
* Reintroduced the loop unrolling in MD5_Transform and added the
|
|
|
|
* MD5_SIZE_OVER_SPEED option for configurability. Define below as:
|
|
|
|
* 0 fully unrolled loops
|
|
|
|
* 1 partially unrolled (4 ops per loop)
|
|
|
|
* 2 no unrolling -- introduces the need to swap 4 variables (slow)
|
|
|
|
* 3 no unrolling and all 4 loops merged into one with switch
|
|
|
|
* in each loop (glacial)
|
|
|
|
* On i386, sizes are roughly (-Os -fno-builtin):
|
|
|
|
* 0: 3k 1: 2.5k 2: 2.2k 3: 2k
|
|
|
|
*
|
|
|
|
* Since SuSv3 does not require crypt_r, modified again August 7, 2002
|
|
|
|
* by Erik Andersen to remove reentrance stuff...
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* UNIX password
|
|
|
|
*
|
|
|
|
* Use MD5 for what it is best at...
|
|
|
|
*/
|
2008-06-13 15:13:41 +00:00
|
|
|
#define MD5_OUT_BUFSIZE 36
|
2008-06-12 16:55:59 +00:00
|
|
|
static char *
|
2008-06-14 22:11:29 +00:00
|
|
|
NOINLINE
|
2008-11-11 01:38:04 +00:00
|
|
|
md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
|
2008-06-12 16:55:59 +00:00
|
|
|
{
|
|
|
|
char *p;
|
2008-11-11 01:38:04 +00:00
|
|
|
unsigned char final[17]; /* final[16] exists only to aid in looping */
|
2008-06-12 16:55:59 +00:00
|
|
|
int sl, pl, i, pw_len;
|
2008-11-11 01:38:04 +00:00
|
|
|
md5_ctx_t ctx, ctx1;
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* NB: in busybox, "$1$" in salt is always present */
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* Refine the Salt first */
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* Get the length of the salt including "$1$" */
|
|
|
|
sl = 3;
|
2013-11-29 15:43:33 +00:00
|
|
|
while (sl < (3 + 8) && salt[sl] && salt[sl] != '$')
|
2008-11-11 01:38:04 +00:00
|
|
|
sl++;
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* Hash. the password first, since that is what is most unknown */
|
|
|
|
md5_begin(&ctx);
|
2008-06-12 16:55:59 +00:00
|
|
|
pw_len = strlen((char*)pw);
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx, pw, pw_len);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* Then the salt including "$1$" */
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx, salt, sl);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* Copy salt to result; skip "$1$" */
|
|
|
|
memcpy(result, salt, sl);
|
|
|
|
result[sl] = '$';
|
|
|
|
salt += 3;
|
|
|
|
sl -= 3;
|
2008-06-12 16:55:59 +00:00
|
|
|
|
|
|
|
/* Then just as many characters of the MD5(pw, salt, pw) */
|
2008-11-11 01:38:04 +00:00
|
|
|
md5_begin(&ctx1);
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, pw, pw_len);
|
|
|
|
md5_hash(&ctx1, salt, sl);
|
|
|
|
md5_hash(&ctx1, pw, pw_len);
|
|
|
|
md5_end(&ctx1, final);
|
2008-06-12 16:55:59 +00:00
|
|
|
for (pl = pw_len; pl > 0; pl -= 16)
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx, final, pl > 16 ? 16 : pl);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
|
|
|
/* Then something really weird... */
|
2008-11-11 01:38:04 +00:00
|
|
|
memset(final, 0, sizeof(final));
|
2008-06-12 16:55:59 +00:00
|
|
|
for (i = pw_len; i; i >>= 1) {
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
|
2008-06-12 16:55:59 +00:00
|
|
|
}
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_end(&ctx, final);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
/* And now, just to make sure things don't run too fast.
|
2008-06-12 16:55:59 +00:00
|
|
|
* 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++) {
|
2008-11-11 01:38:04 +00:00
|
|
|
md5_begin(&ctx1);
|
2008-06-12 16:55:59 +00:00
|
|
|
if (i & 1)
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, pw, pw_len);
|
2008-06-12 16:55:59 +00:00
|
|
|
else
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, final, 16);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
|
|
|
if (i % 3)
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, salt, sl);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
|
|
|
if (i % 7)
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, pw, pw_len);
|
2008-06-12 16:55:59 +00:00
|
|
|
|
|
|
|
if (i & 1)
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, final, 16);
|
2008-06-12 16:55:59 +00:00
|
|
|
else
|
2010-10-16 18:45:27 +00:00
|
|
|
md5_hash(&ctx1, pw, pw_len);
|
|
|
|
md5_end(&ctx1, final);
|
2008-06-12 16:55:59 +00:00
|
|
|
}
|
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
|
2008-06-12 16:55:59 +00:00
|
|
|
|
2008-06-13 15:13:41 +00:00
|
|
|
/* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
|
2008-06-12 16:55:59 +00:00
|
|
|
final[16] = final[5];
|
|
|
|
for (i = 0; i < 5; i++) {
|
2008-06-14 22:11:29 +00:00
|
|
|
unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
|
2008-11-10 18:52:35 +00:00
|
|
|
p = to64(p, l, 4);
|
2008-06-12 16:55:59 +00:00
|
|
|
}
|
2008-11-10 18:52:35 +00:00
|
|
|
p = to64(p, final[11], 2);
|
2008-06-12 16:55:59 +00:00
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
/* Don't leave anything around in vm they could use. */
|
|
|
|
memset(final, 0, sizeof(final));
|
|
|
|
|
2008-11-11 01:38:04 +00:00
|
|
|
return result;
|
2008-06-12 16:55:59 +00:00
|
|
|
}
|