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

Revision 16801, 3.8 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16800, 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 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/*
11 * Ported from FreeBSD to Linux, only minimal changes.  --marekm
12 */
13
14/*
15 * Adapted from shadow-19990607 by Tudor Bosman, tudorb@jm.nu
16 */
17
18#include "includes.h"
19
20RCSID("$Id: md5crypt.c,v 1.1.1.1 2001-11-15 19:24:15 ghudson Exp $");
21
22#if defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT)
23
24#include <openssl/md5.h>
25
26static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
27        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
28
29static char     *magic = "$1$"; /*
30                                 * This string is magic for
31                                 * this algorithm.  Having
32                                 * it this way, we can get
33                                 * get better later on
34                                 */
35
36static void
37to64(char *s, unsigned long v, int n)
38{
39        while (--n >= 0) {
40                *s++ = itoa64[v&0x3f];
41                v >>= 6;
42        }
43}
44
45int
46is_md5_salt(const char *salt)
47{
48        return (!strncmp(salt, magic, strlen(magic)));
49}
50
51/*
52 * UNIX password
53 *
54 * Use MD5 for what it is best at...
55 */
56
57char *
58md5_crypt(const char *pw, const char *salt)
59{
60        static char     passwd[120], *p;
61        static const char *sp,*ep;
62        unsigned char   final[16];
63        int sl,pl,i,j;
64        MD5_CTX ctx,ctx1;
65        unsigned long l;
66
67        /* Refine the Salt first */
68        sp = salt;
69
70        /* If it starts with the magic string, then skip that */
71        if(!strncmp(sp,magic,strlen(magic)))
72                sp += strlen(magic);
73
74        /* It stops at the first '$', max 8 chars */
75        for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
76                continue;
77
78        /* get the length of the true salt */
79        sl = ep - sp;
80
81        MD5_Init(&ctx);
82
83        /* The password first, since that is what is most unknown */
84        MD5_Update(&ctx,pw,strlen(pw));
85
86        /* Then our magic string */
87        MD5_Update(&ctx,magic,strlen(magic));
88
89        /* Then the raw salt */
90        MD5_Update(&ctx,sp,sl);
91
92        /* Then just as many characters of the MD5(pw,salt,pw) */
93        MD5_Init(&ctx1);
94        MD5_Update(&ctx1,pw,strlen(pw));
95        MD5_Update(&ctx1,sp,sl);
96        MD5_Update(&ctx1,pw,strlen(pw));
97        MD5_Final(final,&ctx1);
98        for(pl = strlen(pw); pl > 0; pl -= 16)
99                MD5_Update(&ctx,final,pl>16 ? 16 : pl);
100
101        /* Don't leave anything around in vm they could use. */
102        memset(final,0,sizeof final);
103
104        /* Then something really weird... */
105        for (j=0,i = strlen(pw); i ; i >>= 1)
106                if(i&1)
107                    MD5_Update(&ctx, final+j, 1);
108                else
109                    MD5_Update(&ctx, pw+j, 1);
110
111        /* Now make the output string */
112        strcpy(passwd,magic);
113        strncat(passwd,sp,sl);
114        strcat(passwd,"$");
115
116        MD5_Final(final,&ctx);
117
118        /*
119         * and now, just to make sure things don't run too fast
120         * On a 60 Mhz Pentium this takes 34 msec, so you would
121         * need 30 seconds to build a 1000 entry dictionary...
122         */
123        for(i=0;i<1000;i++) {
124                MD5_Init(&ctx1);
125                if(i & 1)
126                        MD5_Update(&ctx1,pw,strlen(pw));
127                else
128                        MD5_Update(&ctx1,final,16);
129
130                if(i % 3)
131                        MD5_Update(&ctx1,sp,sl);
132
133                if(i % 7)
134                        MD5_Update(&ctx1,pw,strlen(pw));
135
136                if(i & 1)
137                        MD5_Update(&ctx1,final,16);
138                else
139                        MD5_Update(&ctx1,pw,strlen(pw));
140                MD5_Final(final,&ctx1);
141        }
142
143        p = passwd + strlen(passwd);
144
145        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
146        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
147        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
148        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
149        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
150        l =                    final[11]                ; to64(p,l,2); p += 2;
151        *p = '\0';
152
153        /* Don't leave anything around in vm they could use. */
154        memset(final,0,sizeof final);
155
156        return passwd;
157}
158
159#endif /* defined(HAVE_MD5_PASSWORDS) && !defined(HAVE_MD5_CRYPT) */
Note: See TracBrowser for help on using the repository browser.