162 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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...
 | |
|  */
 | |
| #define MD5_OUT_BUFSIZE 36
 | |
| static char *
 | |
| NOINLINE
 | |
| md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
 | |
| {
 | |
| 	char *p;
 | |
| 	unsigned char final[17]; /* final[16] exists only to aid in looping */
 | |
| 	int sl, pl, i, pw_len;
 | |
| 	md5_ctx_t ctx, ctx1;
 | |
| 
 | |
| 	/* NB: in busybox, "$1$" in salt is always present */
 | |
| 
 | |
| 	/* Refine the Salt first */
 | |
| 
 | |
| 	/* Get the length of the salt including "$1$" */
 | |
| 	sl = 3;
 | |
| 	while (sl < (3 + 8) && salt[sl] && salt[sl] != '$')
 | |
| 		sl++;
 | |
| 
 | |
| 	/* Hash. the password first, since that is what is most unknown */
 | |
| 	md5_begin(&ctx);
 | |
| 	pw_len = strlen((char*)pw);
 | |
| 	md5_hash(&ctx, pw, pw_len);
 | |
| 
 | |
| 	/* Then the salt including "$1$" */
 | |
| 	md5_hash(&ctx, salt, sl);
 | |
| 
 | |
| 	/* Copy salt to result; skip "$1$" */
 | |
| 	memcpy(result, salt, sl);
 | |
| 	result[sl] = '$';
 | |
| 	salt += 3;
 | |
| 	sl -= 3;
 | |
| 
 | |
| 	/* Then just as many characters of the MD5(pw, salt, pw) */
 | |
| 	md5_begin(&ctx1);
 | |
| 	md5_hash(&ctx1, pw, pw_len);
 | |
| 	md5_hash(&ctx1, salt, sl);
 | |
| 	md5_hash(&ctx1, pw, pw_len);
 | |
| 	md5_end(&ctx1, final);
 | |
| 	for (pl = pw_len; pl > 0; pl -= 16)
 | |
| 		md5_hash(&ctx, final, pl > 16 ? 16 : pl);
 | |
| 
 | |
| 	/* Then something really weird... */
 | |
| 	memset(final, 0, sizeof(final));
 | |
| 	for (i = pw_len; i; i >>= 1) {
 | |
| 		md5_hash(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
 | |
| 	}
 | |
| 	md5_end(&ctx, final);
 | |
| 
 | |
| 	/* 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++) {
 | |
| 		md5_begin(&ctx1);
 | |
| 		if (i & 1)
 | |
| 			md5_hash(&ctx1, pw, pw_len);
 | |
| 		else
 | |
| 			md5_hash(&ctx1, final, 16);
 | |
| 
 | |
| 		if (i % 3)
 | |
| 			md5_hash(&ctx1, salt, sl);
 | |
| 
 | |
| 		if (i % 7)
 | |
| 			md5_hash(&ctx1, pw, pw_len);
 | |
| 
 | |
| 		if (i & 1)
 | |
| 			md5_hash(&ctx1, final, 16);
 | |
| 		else
 | |
| 			md5_hash(&ctx1, pw, pw_len);
 | |
| 		md5_end(&ctx1, final);
 | |
| 	}
 | |
| 
 | |
| 	p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
 | |
| 
 | |
| 	/* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
 | |
| 	final[16] = final[5];
 | |
| 	for (i = 0; i < 5; i++) {
 | |
| 		unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
 | |
| 		p = to64(p, l, 4);
 | |
| 	}
 | |
| 	p = to64(p, final[11], 2);
 | |
| 	*p = '\0';
 | |
| 
 | |
| 	/* Don't leave anything around in vm they could use. */
 | |
| 	memset(final, 0, sizeof(final));
 | |
| 
 | |
| 	return result;
 | |
| }
 | 
