Age Owner Branch data 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
6485 neilc@samurai.com 20 :CBC 24 : _crypt_to64(char *s, unsigned long v, int n)
21 : : {
6402 bruce@momjian.us 22 [ + + ]: 112 : while (--n >= 0)
23 : : {
6485 neilc@samurai.com 24 : 88 : *s++ = _crypt_a64[v & 0x3f];
25 : 88 : v >>= 6;
26 : : }
27 : 24 : }
28 : :
29 : : /*
30 : : * UNIX password
31 : : */
32 : :
33 : : char *
8272 bruce@momjian.us 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)
8272 bruce@momjian.us 52 :UBC 0 : return NULL;
53 : :
54 : : /* Refine the Salt first */
8272 bruce@momjian.us 55 :CBC 4 : sp = salt;
56 : :
57 : : /* If it starts with the magic string, then skip that */
4492 peter_e@gmx.net 58 [ + - ]: 4 : if (strncmp(sp, magic, strlen(magic)) == 0)
8272 bruce@momjian.us 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)
8272 bruce@momjian.us 71 :UBC 0 : return NULL;
8272 bruce@momjian.us 72 :CBC 4 : err = px_find_digest("md5", &ctx1);
1276 tgl@sss.pgh.pa.us 73 [ - + ]: 4 : if (err)
74 : : {
75 : : /* this path is possible under low-memory circumstances */
1276 tgl@sss.pgh.pa.us 76 :UBC 0 : px_md_free(ctx);
77 : 0 : return NULL;
78 : : }
79 : :
80 : : /* The password first, since that is what is most unknown */
4599 peter_e@gmx.net 81 :CBC 4 : px_md_update(ctx, (const uint8 *) pw, strlen(pw));
82 : :
83 : : /* Then our magic string */
6777 tgl@sss.pgh.pa.us 84 : 4 : px_md_update(ctx, (uint8 *) magic, strlen(magic));
85 : :
86 : : /* Then the raw salt */
4599 peter_e@gmx.net 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));
8272 bruce@momjian.us 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. */
3650 98 : 4 : px_memset(final, 0, sizeof final);
99 : :
100 : : /* Then something really weird... */
8272 101 [ + + ]: 15 : for (i = strlen(pw); i; i >>= 1)
102 [ + + ]: 11 : if (i & 1)
103 : 3 : px_md_update(ctx, final, 1);
104 : : else
4599 peter_e@gmx.net 105 : 8 : px_md_update(ctx, (const uint8 *) pw, 1);
106 : :
107 : : /* Now make the output string */
8272 bruce@momjian.us 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)
4599 peter_e@gmx.net 123 : 2000 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
124 : : else
8272 bruce@momjian.us 125 : 2000 : px_md_update(ctx1, final, MD5_SIZE);
126 : :
127 [ + + ]: 4000 : if (i % 3)
4599 peter_e@gmx.net 128 : 2664 : px_md_update(ctx1, (const uint8 *) sp, sl);
129 : :
8272 bruce@momjian.us 130 [ + + ]: 4000 : if (i % 7)
4599 peter_e@gmx.net 131 : 3428 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
132 : :
8272 bruce@momjian.us 133 [ + + ]: 4000 : if (i & 1)
134 : 2000 : px_md_update(ctx1, final, MD5_SIZE);
135 : : else
4599 peter_e@gmx.net 136 : 2000 : px_md_update(ctx1, (const uint8 *) pw, strlen(pw));
8272 bruce@momjian.us 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. */
3650 163 : 4 : px_memset(final, 0, sizeof final);
164 : :
8272 165 : 4 : px_md_free(ctx1);
166 : 4 : px_md_free(ctx);
167 : :
168 : 4 : return passwd;
169 : : }
|