busybox/libbb/pw_encrypt_md5.c
<<
>>
Prefs
   1/*
   2 * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
   3 *
   4 * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
   5 * rights reserved.
   6 *
   7 * License to copy and use this software is granted provided that it
   8 * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
   9 * Algorithm" in all material mentioning or referencing this software
  10 * or this function.
  11 *
  12 * License is also granted to make and use derivative works provided
  13 * that such works are identified as "derived from the RSA Data
  14 * Security, Inc. MD5 Message-Digest Algorithm" in all material
  15 * mentioning or referencing the derived work.
  16 *
  17 * RSA Data Security, Inc. makes no representations concerning either
  18 * the merchantability of this software or the suitability of this
  19 * software for any particular purpose. It is provided "as is"
  20 * without express or implied warranty of any kind.
  21 *
  22 * These notices must be retained in any copies of any part of this
  23 * documentation and/or software.
  24 *
  25 * $FreeBSD: src/lib/libmd/md5c.c,v 1.9.2.1 1999/08/29 14:57:12 peter Exp $
  26 *
  27 * This code is the same as the code published by RSA Inc.  It has been
  28 * edited for clarity and style only.
  29 *
  30 * ----------------------------------------------------------------------------
  31 * The md5_crypt() function was taken from freeBSD's libcrypt and contains
  32 * this license:
  33 *    "THE BEER-WARE LICENSE" (Revision 42):
  34 *     <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
  35 *     can do whatever you want with this stuff. If we meet some day, and you think
  36 *     this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  37 *
  38 * $FreeBSD: src/lib/libcrypt/crypt.c,v 1.7.2.1 1999/08/29 14:56:33 peter Exp $
  39 *
  40 * ----------------------------------------------------------------------------
  41 * On April 19th, 2001 md5_crypt() was modified to make it reentrant
  42 * by Erik Andersen <andersen@uclibc.org>
  43 *
  44 *
  45 * June 28, 2001             Manuel Novoa III
  46 *
  47 * "Un-inlined" code using loops and static const tables in order to
  48 * reduce generated code size (on i386 from approx 4k to approx 2.5k).
  49 *
  50 * June 29, 2001             Manuel Novoa III
  51 *
  52 * Completely removed static PADDING array.
  53 *
  54 * Reintroduced the loop unrolling in MD5_Transform and added the
  55 * MD5_SIZE_OVER_SPEED option for configurability.  Define below as:
  56 *       0    fully unrolled loops
  57 *       1    partially unrolled (4 ops per loop)
  58 *       2    no unrolling -- introduces the need to swap 4 variables (slow)
  59 *       3    no unrolling and all 4 loops merged into one with switch
  60 *               in each loop (glacial)
  61 * On i386, sizes are roughly (-Os -fno-builtin):
  62 *     0: 3k     1: 2.5k     2: 2.2k     3: 2k
  63 *
  64 * Since SuSv3 does not require crypt_r, modified again August 7, 2002
  65 * by Erik Andersen to remove reentrance stuff...
  66 */
  67
  68/*
  69 * UNIX password
  70 *
  71 * Use MD5 for what it is best at...
  72 */
  73#define MD5_OUT_BUFSIZE 36
  74static char *
  75NOINLINE
  76md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned char *salt)
  77{
  78        char *p;
  79        unsigned char final[17]; /* final[16] exists only to aid in looping */
  80        int sl, pl, i, pw_len;
  81        md5_ctx_t ctx, ctx1;
  82
  83        /* NB: in busybox, "$1$" in salt is always present */
  84
  85        /* Refine the Salt first */
  86
  87        /* Get the length of the salt including "$1$" */
  88        sl = 3;
  89        while (sl < (3 + 8) && salt[sl] && salt[sl] != '$')
  90                sl++;
  91
  92        /* Hash. the password first, since that is what is most unknown */
  93        md5_begin(&ctx);
  94        pw_len = strlen((char*)pw);
  95        md5_hash(&ctx, pw, pw_len);
  96
  97        /* Then the salt including "$1$" */
  98        md5_hash(&ctx, salt, sl);
  99
 100        /* Copy salt to result; skip "$1$" */
 101        memcpy(result, salt, sl);
 102        result[sl] = '$';
 103        salt += 3;
 104        sl -= 3;
 105
 106        /* Then just as many characters of the MD5(pw, salt, pw) */
 107        md5_begin(&ctx1);
 108        md5_hash(&ctx1, pw, pw_len);
 109        md5_hash(&ctx1, salt, sl);
 110        md5_hash(&ctx1, pw, pw_len);
 111        md5_end(&ctx1, final);
 112        for (pl = pw_len; pl > 0; pl -= 16)
 113                md5_hash(&ctx, final, pl > 16 ? 16 : pl);
 114
 115        /* Then something really weird... */
 116        memset(final, 0, sizeof(final));
 117        for (i = pw_len; i; i >>= 1) {
 118                md5_hash(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1);
 119        }
 120        md5_end(&ctx, final);
 121
 122        /* And now, just to make sure things don't run too fast.
 123         * On a 60 Mhz Pentium this takes 34 msec, so you would
 124         * need 30 seconds to build a 1000 entry dictionary...
 125         */
 126        for (i = 0; i < 1000; i++) {
 127                md5_begin(&ctx1);
 128                if (i & 1)
 129                        md5_hash(&ctx1, pw, pw_len);
 130                else
 131                        md5_hash(&ctx1, final, 16);
 132
 133                if (i % 3)
 134                        md5_hash(&ctx1, salt, sl);
 135
 136                if (i % 7)
 137                        md5_hash(&ctx1, pw, pw_len);
 138
 139                if (i & 1)
 140                        md5_hash(&ctx1, final, 16);
 141                else
 142                        md5_hash(&ctx1, pw, pw_len);
 143                md5_end(&ctx1, final);
 144        }
 145
 146        p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */
 147
 148        /* Add 5*4+2 = 22 bytes of hash, + NUL byte. */
 149        final[16] = final[5];
 150        for (i = 0; i < 5; i++) {
 151                unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
 152                p = to64(p, l, 4);
 153        }
 154        p = to64(p, final[11], 2);
 155        *p = '\0';
 156
 157        /* Don't leave anything around in vm they could use. */
 158        memset(final, 0, sizeof(final));
 159
 160        return result;
 161}
 162