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