d9898ee8 |
1 | /* |
2 | ** Copyright 1998 - 1999 Double Precision, Inc. |
3 | ** See COPYING for distribution information. |
4 | */ |
5 | |
6 | #define MD5_INTERNAL |
7 | #include "md5.h" |
8 | #include <string.h> |
9 | |
d9898ee8 |
10 | |
11 | static char base64[]= |
12 | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; |
13 | |
14 | char *md5_crypt_redhat(const char *pw, const char *salt) |
15 | { |
16 | struct MD5_CONTEXT outer_context, inner_context; |
17 | MD5_DIGEST digest; |
18 | unsigned pwl=strlen(pw); |
19 | unsigned l; |
20 | unsigned i, j; |
21 | char *p; |
22 | static char buffer[100]; |
23 | |
24 | if (*salt == '$' && salt[1] == '1' && salt[2] == '$') |
25 | salt += 3; |
26 | |
27 | for (l=0; l<8 && salt[l] && salt[l] != '$'; l++) |
28 | ; |
29 | |
30 | md5_context_init(&inner_context); |
31 | md5_context_hashstream(&inner_context, pw, pwl); |
32 | md5_context_hashstream(&inner_context, salt, l); |
33 | md5_context_hashstream(&inner_context, pw, pwl); |
34 | md5_context_endstream(&inner_context, pwl*2+l); |
35 | md5_context_digest(&inner_context, digest); |
36 | |
37 | md5_context_init(&outer_context); |
38 | md5_context_hashstream(&outer_context, pw, pwl); |
39 | md5_context_hashstream(&outer_context, "$1$", 3); |
40 | md5_context_hashstream(&outer_context, salt, l); |
41 | |
42 | for (i=pwl; i; ) |
43 | { |
44 | j=i; |
45 | if (j > 16) j=16; |
46 | md5_context_hashstream(&outer_context, digest, j); |
47 | i -= j; |
48 | } |
49 | |
50 | j=pwl*2+l+3; |
51 | |
52 | for (i=pwl; i; i >>= 1) |
53 | { |
54 | md5_context_hashstream(&outer_context, (i & 1) ? "": pw, 1); |
55 | ++j; |
56 | } |
57 | |
58 | |
59 | md5_context_endstream(&outer_context, j); |
60 | md5_context_digest(&outer_context, digest); |
61 | |
62 | for (i=0; i<1000; i++) |
63 | { |
64 | j=0; |
65 | |
66 | md5_context_init(&outer_context); |
67 | if (i & 1) |
68 | { |
69 | md5_context_hashstream(&outer_context, pw, pwl); |
70 | j += pwl; |
71 | } |
72 | else |
73 | { |
74 | md5_context_hashstream(&outer_context, digest, 16); |
75 | j += 16; |
76 | } |
77 | |
78 | if (i % 3) |
79 | { |
80 | md5_context_hashstream(&outer_context, salt, l); |
81 | j += l; |
82 | } |
83 | |
84 | if (i % 7) |
85 | { |
86 | md5_context_hashstream(&outer_context, pw, pwl); |
87 | j += pwl; |
88 | } |
89 | |
90 | if (i & 1) |
91 | { |
92 | md5_context_hashstream(&outer_context, digest, 16); |
93 | j += 16; |
94 | } |
95 | else |
96 | { |
97 | md5_context_hashstream(&outer_context, pw, pwl); |
98 | j += pwl; |
99 | } |
100 | |
101 | md5_context_endstream(&outer_context, j); |
102 | md5_context_digest(&outer_context, digest); |
103 | } |
104 | |
105 | strcpy(buffer, "$1$"); |
106 | strncat(buffer, salt, l); |
107 | strcat(buffer, "$"); |
108 | |
109 | p=buffer+strlen(buffer); |
110 | for (i=0; i<5; i++) |
111 | { |
112 | unsigned char *d=digest; |
113 | |
114 | j= (d[i] << 16) | (d[i+6] << 8) | d[i == 4 ? 5:12+i]; |
115 | *p++= base64[j & 63] ; j=j >> 6; |
116 | *p++= base64[j & 63] ; j=j >> 6; |
117 | *p++= base64[j & 63] ; j=j >> 6; |
118 | *p++= base64[j & 63]; |
119 | } |
120 | j=digest[11]; |
121 | *p++ = base64[j & 63]; j=j >> 6; |
122 | *p++ = base64[j & 63]; |
123 | *p=0; |
124 | return (buffer); |
125 | } |