Source File au/crypt-md5.c

    1    | /*
    2    |  * ----------------------------------------------------------------------------
    3    |  * "THE BEER-WARE LICENSE" (Revision 42):
    4    |  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
    5    |  * can do whatever you want with this stuff. If we meet some day, and you think
    6    |  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
    7    |  * ----------------------------------------------------------------------------
    8    |  */
    9    |
    10   | /* #include <sys/cdefs.h>
    11   | __FBSDID("$FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.12 2002/03/25 15:55:36 phk Exp $");
    12   | */
    13   | #include <config.h>
    14   | #include <unistd.h>
    15   | #include <stdio.h>
    16   | #include <string.h>
    17   | #include <md5.h>
    18   | /* #include <err.h> */
    19   | #include "crypt.h"
    20   |
    21   | /*
    22   |  * UNIX password
    23   |  */
    24   |
    25   | char *
    26   | crypt_md5(const char *pw, const char *salt)
    27   | {
    28   |         MD5_CTX ctx,ctx1;
    29   |         unsigned long l;
    30   |         int sl, pl;
    31   |         u_int i;
    32   |         u_char final[MD5_SIZE];
    33   |         static const char *sp, *ep;
    34   |         static char passwd[120], *p;
    35   |         static const char *magic = "$1$";       /*
    36   |                                                  * This string is magic for
    37   |                                                  * this algorithm.  Having
    38   |                                                  * it this way, we can get
    39   |                                                  * better later on.
    40   |                                                  */
    41   |
    42   |         /* Refine the Salt first */
    43   |         sp = salt;
    44   |
    45   |         /* If it starts with the magic string, then skip that */
    46   |         if(!strncmp(sp, magic, strlen(magic)))
    47   |                 sp += strlen(magic);
    48   |
    49   |         /* It stops at the first '$', max 8 chars */
    50   |         for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
    51   |                 continue;
    52   |
    53   |         /* get the length of the true salt */
    54   |         sl = ep - sp;
    55   |
    56   |         MD5Init(&ctx);
    57   |
    58   |         /* The password first, since that is what is most unknown */
    59   |         MD5Update(&ctx, (u_char *)pw, strlen(pw));
    60   |
    61   |         /* Then our magic string */
    62   |         MD5Update(&ctx, (u_char *)magic, strlen(magic));
    63   |
    64   |         /* Then the raw salt */
    65   |         MD5Update(&ctx, (u_char *)sp, (u_int)sl);
    66   |
    67   |         /* Then just as many characters of the MD5(pw,salt,pw) */
    68   |         MD5Init(&ctx1);
    69   |         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
    70   |         MD5Update(&ctx1, (u_char *)sp, (u_int)sl);
    71   |         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
    72   |         MD5Final(final, &ctx1);
    73   |         for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
    74   |                 MD5Update(&ctx, (u_char *)final,
    75   |                     (u_int)(pl > MD5_SIZE ? MD5_SIZE : pl));
    76   |
    77   |         /* Don't leave anything around in vm they could use. */
    78   |         memset(final, 0, sizeof(final));
    79   |
    80   |         /* Then something really weird... */
    81   |         for (i = strlen(pw); i; i >>= 1)
    82   |                 if(i & 1)
    83   |                     MD5Update(&ctx, (u_char *)final, 1);
    84   |                 else
    85   |                     MD5Update(&ctx, (u_char *)pw, 1);
    86   |
    87   |         /* Now make the output string */
    88   |         strcpy(passwd, magic);
    89   |         strncat(passwd, sp, (u_int)sl);
    90   |         strcat(passwd, "$");
    91   |
    92   |         MD5Final(final, &ctx);
    93   |
    94   |         /*
    95   |          * and now, just to make sure things don't run too fast
    96   |          * On a 60 Mhz Pentium this takes 34 msec, so you would
    97   |          * need 30 seconds to build a 1000 entry dictionary...
    98   |          */
    99   |         for(i = 0; i < 1000; i++) {
    100  |                 MD5Init(&ctx1);
    101  |                 if(i & 1)
    102  |                         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
    103  |                 else
    104  |                         MD5Update(&ctx1, (u_char *)final, MD5_SIZE);
    105  |
    106  |                 if(i % 3)
    107  |                         MD5Update(&ctx1, (u_char *)sp, (u_int)sl);
    108  |
    109  |                 if(i % 7)
    110  |                         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
    111  |
    112  |                 if(i & 1)
    113  |                         MD5Update(&ctx1, (u_char *)final, MD5_SIZE);
    114  |                 else
    115  |                         MD5Update(&ctx1, (u_char *)pw, strlen(pw));
    116  |                 MD5Final(final, &ctx1);
    117  |         }
    118  |
    119  |         p = passwd + strlen(passwd);
    120  |
    121  |         l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
    122  |         _crypt_to64(p, l, 4); p += 4;
    123  |         l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
    124  |         _crypt_to64(p, l, 4); p += 4;
    125  |         l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
    126  |         _crypt_to64(p, l, 4); p += 4;
    127  |         l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
    128  |         _crypt_to64(p, l, 4); p += 4;
    129  |         l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
    130  |         _crypt_to64(p, l, 4); p += 4;
    131  |         l =                    final[11]                ;
    132  |         _crypt_to64(p, l, 2); p += 2;
    133  |         *p = '\0';
    134  |
    135  |         /* Don't leave anything around in vm they could use. */
    136  |         memset(final, 0, sizeof(final));
    137  |
    138  |         return passwd;
    139  | }
    140  |
    141  |