Age Owner TLA Line data Source code
1 : /*
2 : * File imported from FreeBSD, original by Poul-Henning Kamp.
3 : *
4 : * $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $
5 : *
6 : * contrib/pgcrypto/crypt-md5.c
7 : */
8 :
9 : #include "postgres.h"
10 :
11 : #include "px-crypt.h"
12 : #include "px.h"
13 :
14 : #define MD5_SIZE 16
15 :
16 : static const char _crypt_a64[] =
17 : "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
18 :
19 : static void
6114 neilc 20 CBC 24 : _crypt_to64(char *s, unsigned long v, int n)
21 : {
6031 bruce 22 112 : while (--n >= 0)
23 : {
6114 neilc 24 88 : *s++ = _crypt_a64[v & 0x3f];
25 88 : v >>= 6;
26 : }
27 24 : }
28 :
29 : /*
30 : * UNIX password
31 : */
32 :
33 : char *
7901 bruce 34 4 : px_crypt_md5(const char *pw, const char *salt, char *passwd, unsigned dstlen)
35 32 : {
36 : static char *magic = "$1$"; /* This string is magic for this algorithm.
37 : * Having it this way, we can get better later
38 : * on */
39 : static char *p;
40 : static const char *sp,
41 : *ep;
42 : unsigned char final[MD5_SIZE];
43 : int sl,
44 : pl,
45 : i;
46 : PX_MD *ctx,
47 : *ctx1;
48 : int err;
49 : unsigned long l;
50 :
51 4 : if (!passwd || dstlen < 120)
7901 bruce 52 UBC 0 : return NULL;
53 :
54 : /* Refine the Salt first */
7901 bruce 55 CBC 4 : sp = salt;
56 :
57 : /* If it starts with the magic string, then skip that */
4121 peter_e 58 4 : if (strncmp(sp, magic, strlen(magic)) == 0)
7901 bruce 59 4 : sp += strlen(magic);
60 :
61 : /* It stops at the first '$', max 8 chars */
62 36 : for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
63 32 : continue;
64 :
65 : /* get the length of the true salt */
66 4 : sl = ep - sp;
67 :
68 : /* we need two PX_MD objects */
69 4 : err = px_find_digest("md5", &ctx);
70 4 : if (err)
7901 bruce 71 UBC 0 : return NULL;
7901 bruce 72 CBC 4 : err = px_find_digest("md5", &ctx1);
905 tgl 73 4 : if (err)
74 : {
75 : /* this path is possible under low-memory circumstances */
905 tgl 76 UBC 0 : px_md_free(ctx);
77 0 : return NULL;
78 : }
79 :
80 : /* The password first, since that is what is most unknown */
4228 peter_e 81 CBC 4 : px_md_update(ctx, (const uint8 *) pw, strlen(pw));
82 :
83 : /* Then our magic string */
6406 tgl 84 4 : px_md_update(ctx, (uint8 *) magic, strlen(magic));
85 :
86 : /* Then the raw salt */
4228 peter_e 87 4 : px_md_update(ctx, (const uint8 *) sp, sl);
88 :
89 : /* Then just as many characters of the MD5(pw,salt,pw) */
90 4 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
91 4 : px_md_update(ctx1, (const uint8 *) sp, sl);
92 4 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
7901 bruce 93 4 : px_md_finish(ctx1, final);
94 7 : for (pl = strlen(pw); pl > 0; pl -= MD5_SIZE)
95 3 : px_md_update(ctx, final, pl > MD5_SIZE ? MD5_SIZE : pl);
96 :
97 : /* Don't leave anything around in vm they could use. */
3279 98 4 : px_memset(final, 0, sizeof final);
99 :
100 : /* Then something really weird... */
7901 101 15 : for (i = strlen(pw); i; i >>= 1)
102 11 : if (i & 1)
103 3 : px_md_update(ctx, final, 1);
104 : else
4228 peter_e 105 8 : px_md_update(ctx, (const uint8 *) pw, 1);
106 :
107 : /* Now make the output string */
7901 bruce 108 4 : strcpy(passwd, magic);
109 4 : strncat(passwd, sp, sl);
110 4 : strcat(passwd, "$");
111 :
112 4 : px_md_finish(ctx, final);
113 :
114 : /*
115 : * and now, just to make sure things don't run too fast On a 60 Mhz
116 : * Pentium this takes 34 msec, so you would need 30 seconds to build a
117 : * 1000 entry dictionary...
118 : */
119 4004 : for (i = 0; i < 1000; i++)
120 : {
121 4000 : px_md_reset(ctx1);
122 4000 : if (i & 1)
4228 peter_e 123 2000 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
124 : else
7901 bruce 125 2000 : px_md_update(ctx1, final, MD5_SIZE);
126 :
127 4000 : if (i % 3)
4228 peter_e 128 2664 : px_md_update(ctx1, (const uint8 *) sp, sl);
129 :
7901 bruce 130 4000 : if (i % 7)
4228 peter_e 131 3428 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
132 :
7901 bruce 133 4000 : if (i & 1)
134 2000 : px_md_update(ctx1, final, MD5_SIZE);
135 : else
4228 peter_e 136 2000 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
7901 bruce 137 4000 : px_md_finish(ctx1, final);
138 : }
139 :
140 4 : p = passwd + strlen(passwd);
141 :
142 4 : l = (final[0] << 16) | (final[6] << 8) | final[12];
143 4 : _crypt_to64(p, l, 4);
144 4 : p += 4;
145 4 : l = (final[1] << 16) | (final[7] << 8) | final[13];
146 4 : _crypt_to64(p, l, 4);
147 4 : p += 4;
148 4 : l = (final[2] << 16) | (final[8] << 8) | final[14];
149 4 : _crypt_to64(p, l, 4);
150 4 : p += 4;
151 4 : l = (final[3] << 16) | (final[9] << 8) | final[15];
152 4 : _crypt_to64(p, l, 4);
153 4 : p += 4;
154 4 : l = (final[4] << 16) | (final[10] << 8) | final[5];
155 4 : _crypt_to64(p, l, 4);
156 4 : p += 4;
157 4 : l = final[11];
158 4 : _crypt_to64(p, l, 2);
159 4 : p += 2;
160 4 : *p = '\0';
161 :
162 : /* Don't leave anything around in vm they could use. */
3279 163 4 : px_memset(final, 0, sizeof final);
164 :
7901 165 4 : px_md_free(ctx1);
166 4 : px_md_free(ctx);
167 :
168 4 : return passwd;
169 : }
|