~ubuntu-branches/ubuntu/vivid/dovecot/vivid

« back to all changes in this revision

Viewing changes to src/auth/md5crypt.c

  • Committer: Bazaar Package Importer
  • Author(s): Jaldhar H. Vyas
  • Date: 2005-11-05 23:19:19 UTC
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20051105231919-ydujs4y7687fpor2
Tags: upstream-1.0.alpha4
ImportĀ upstreamĀ versionĀ 1.0.alpha4

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 "lib.h"
19
 
#include "md5.h"
20
 
#include "md5crypt.h"
21
 
 
22
 
static unsigned char itoa64[] =         /* 0 ... 63 => ascii - 64 */
23
 
        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
24
 
 
25
 
static char     *magic = "$1$"; /*
26
 
                                 * This string is magic for
27
 
                                 * this algorithm.  Having
28
 
                                 * it this way, we can get
29
 
                                 * get better later on
30
 
                                 */
31
 
 
32
 
static void
33
 
to64(char *s, unsigned long v, int n)
34
 
{
35
 
        while (--n >= 0) {
36
 
                *s++ = itoa64[v&0x3f];
37
 
                v >>= 6;
38
 
        }
39
 
}
40
 
 
41
 
/*
42
 
 * UNIX password
43
 
 *
44
 
 * Use MD5 for what it is best at...
45
 
 */
46
 
 
47
 
const char *
48
 
md5_crypt(const char *pw, const char *salt)
49
 
{
50
 
        char passwd[120], *p;
51
 
        const char *sp,*ep;
52
 
        unsigned char   final[16];
53
 
        int sl,pl,i,j;
54
 
        struct md5_context ctx,ctx1;
55
 
        unsigned long l;
56
 
 
57
 
        /* Refine the Salt first */
58
 
        sp = salt;
59
 
 
60
 
        /* If it starts with the magic string, then skip that */
61
 
        if(!strncmp(sp,magic,strlen(magic)))
62
 
                sp += strlen(magic);
63
 
 
64
 
        /* It stops at the first '$', max 8 chars */
65
 
        for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
66
 
                continue;
67
 
 
68
 
        /* get the length of the true salt */
69
 
        sl = ep - sp;
70
 
 
71
 
        md5_init(&ctx);
72
 
 
73
 
        /* The password first, since that is what is most unknown */
74
 
        md5_update(&ctx,pw,strlen(pw));
75
 
 
76
 
        /* Then our magic string */
77
 
        md5_update(&ctx,magic,strlen(magic));
78
 
 
79
 
        /* Then the raw salt */
80
 
        md5_update(&ctx,sp,sl);
81
 
 
82
 
        /* Then just as many characters of the MD5(pw,salt,pw) */
83
 
        md5_init(&ctx1);
84
 
        md5_update(&ctx1,pw,strlen(pw));
85
 
        md5_update(&ctx1,sp,sl);
86
 
        md5_update(&ctx1,pw,strlen(pw));
87
 
        md5_final(&ctx1,final);
88
 
        for(pl = strlen(pw); pl > 0; pl -= 16)
89
 
                md5_update(&ctx,final,pl>16 ? 16 : pl);
90
 
 
91
 
        /* Don't leave anything around in vm they could use. */
92
 
        memset(final,0,sizeof final);
93
 
 
94
 
        /* Then something really weird... */
95
 
        for (j=0,i = strlen(pw); i ; i >>= 1)
96
 
                if(i&1)
97
 
                    md5_update(&ctx, final+j, 1);
98
 
                else
99
 
                    md5_update(&ctx, pw+j, 1);
100
 
 
101
 
        /* Now make the output string */
102
 
        strcpy(passwd,magic);
103
 
        strncat(passwd,sp,sl);
104
 
        strcat(passwd,"$");
105
 
 
106
 
        md5_final(&ctx,final);
107
 
 
108
 
        /*
109
 
         * and now, just to make sure things don't run too fast
110
 
         * On a 60 Mhz Pentium this takes 34 msec, so you would
111
 
         * need 30 seconds to build a 1000 entry dictionary...
112
 
         */
113
 
        for(i=0;i<1000;i++) {
114
 
                md5_init(&ctx1);
115
 
                if(i & 1)
116
 
                        md5_update(&ctx1,pw,strlen(pw));
117
 
                else
118
 
                        md5_update(&ctx1,final,16);
119
 
 
120
 
                if(i % 3)
121
 
                        md5_update(&ctx1,sp,sl);
122
 
 
123
 
                if(i % 7)
124
 
                        md5_update(&ctx1,pw,strlen(pw));
125
 
 
126
 
                if(i & 1)
127
 
                        md5_update(&ctx1,final,16);
128
 
                else
129
 
                        md5_update(&ctx1,pw,strlen(pw));
130
 
                md5_final(&ctx1,final);
131
 
        }
132
 
 
133
 
        p = passwd + strlen(passwd);
134
 
 
135
 
        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;
136
 
        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;
137
 
        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;
138
 
        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;
139
 
        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;
140
 
        l =                    final[11]                ; to64(p,l,2); p += 2;
141
 
        *p = '\0';
142
 
 
143
 
        /* Don't leave anything around in vm they could use. */
144
 
        memset(final,0,sizeof final);
145
 
 
146
 
        return t_strdup(passwd);
147
 
}