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 
11 static char base64[]=
12         "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
13 
md5_crypt_redhat(const char * pw,const char * salt)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 }
126