source: trunk/third/openssh/md5crypt.c @ 22570

Revision 22570, 4.0 KB checked in by ghudson, 18 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22569, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> wrote this file.  As long as you retain this
5 * notice you can do whatever you want with this stuff. If we meet some
6 * day, and you think this stuff is worth it, you can buy me a beer in
7 * return.   Poul-Henning Kamp
8 * ----------------------------------------------------------------------------
9 */
10
11#include "includes.h"
12
13#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
14#include <openssl/md5.h>
15
16RCSID("$Id: md5crypt.c,v 1.1.1.2 2006-11-30 21:18:48 ghudson Exp $");
17
18/* 0 ... 63 => ascii - 64 */
19static unsigned char itoa64[] =
20    "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
21
22static char *magic = "$1$";
23
24static char *
25to64(unsigned long v, int n)
26{
27        static char buf[5];
28        char *s = buf;
29
30        if (n > 4)
31                return (NULL);
32
33        memset(buf, '\0', sizeof(buf));
34        while (--n >= 0) {
35                *s++ = itoa64[v&0x3f];
36                v >>= 6;
37        }
38
39        return (buf);
40}
41
42int
43is_md5_salt(const char *salt)
44{
45        return (strncmp(salt, magic, strlen(magic)) == 0);
46}
47
48char *
49md5_crypt(const char *pw, const char *salt)
50{
51        static char passwd[120], salt_copy[9], *p;
52        static const char *sp, *ep;
53        unsigned char final[16];
54        int sl, pl, i, j;
55        MD5_CTX ctx, ctx1;
56        unsigned long l;
57
58        /* Refine the Salt first */
59        sp = salt;
60
61        /* If it starts with the magic string, then skip that */
62        if(strncmp(sp, magic, strlen(magic)) == 0)
63                sp += strlen(magic);
64
65        /* It stops at the first '$', max 8 chars */
66        for (ep = sp; *ep != '$'; ep++) {
67                if (*ep == '\0' || ep >= (sp + 8))
68                        return (NULL);
69        }
70
71        /* get the length of the true salt */
72        sl = ep - sp;
73
74        /* Stash the salt */
75        memcpy(salt_copy, sp, sl);
76        salt_copy[sl] = '\0';
77
78        MD5_Init(&ctx);
79
80        /* The password first, since that is what is most unknown */
81        MD5_Update(&ctx, pw, strlen(pw));
82
83        /* Then our magic string */
84        MD5_Update(&ctx, magic, strlen(magic));
85
86        /* Then the raw salt */
87        MD5_Update(&ctx, sp, sl);
88
89        /* Then just as many characters of the MD5(pw, salt, pw) */
90        MD5_Init(&ctx1);
91        MD5_Update(&ctx1, pw, strlen(pw));
92        MD5_Update(&ctx1, sp, sl);
93        MD5_Update(&ctx1, pw, strlen(pw));
94        MD5_Final(final, &ctx1);
95
96        for(pl = strlen(pw); pl > 0; pl -= 16)
97                MD5_Update(&ctx, final, pl > 16 ? 16 : pl);
98
99        /* Don't leave anything around in vm they could use. */
100        memset(final, '\0', sizeof final);
101
102        /* Then something really weird... */
103        for (j = 0, i = strlen(pw); i != 0; i >>= 1)
104                if (i & 1)
105                        MD5_Update(&ctx, final + j, 1);
106                else
107                        MD5_Update(&ctx, pw + j, 1);
108
109        /* Now make the output string */
110        snprintf(passwd, sizeof(passwd), "%s%s$", magic, salt_copy);
111
112        MD5_Final(final, &ctx);
113
114        /*
115         * and now, just to make sure things don't run too fast
116         * On a 60 Mhz Pentium this takes 34 msec, so you would
117         * need 30 seconds to build a 1000 entry dictionary...
118         */
119        for(i = 0; i < 1000; i++) {
120                MD5_Init(&ctx1);
121                if (i & 1)
122                        MD5_Update(&ctx1, pw, strlen(pw));
123                else
124                        MD5_Update(&ctx1, final, 16);
125
126                if (i % 3)
127                        MD5_Update(&ctx1, sp, sl);
128
129                if (i % 7)
130                        MD5_Update(&ctx1, pw, strlen(pw));
131
132                if (i & 1)
133                        MD5_Update(&ctx1, final, 16);
134                else
135                        MD5_Update(&ctx1, pw, strlen(pw));
136
137                MD5_Final(final, &ctx1);
138        }
139
140        p = passwd + strlen(passwd);
141
142        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
143        strlcat(passwd, to64(l, 4), sizeof(passwd));
144        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
145        strlcat(passwd, to64(l, 4), sizeof(passwd));
146        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
147        strlcat(passwd, to64(l, 4), sizeof(passwd));
148        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
149        strlcat(passwd, to64(l, 4), sizeof(passwd));
150        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
151        strlcat(passwd, to64(l, 4), sizeof(passwd));
152        l =                    final[11]                ;
153        strlcat(passwd, to64(l, 2), sizeof(passwd));
154
155        /* Don't leave anything around in vm they could use. */
156        memset(final, 0, sizeof(final));
157        memset(salt_copy, 0, sizeof(salt_copy));
158        memset(&ctx, 0, sizeof(ctx));
159        memset(&ctx1, 0, sizeof(ctx1));
160        (void)to64(0, 4);
161
162        return (passwd);
163}
164
165#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
Note: See TracBrowser for help on using the repository browser.