/* * 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; }