Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /* |
2 | * ---------------------------------------------------------------------------- | |
3 | * "THE BEER-WARE LICENSE" (Revision 42): | |
4 | * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you | |
5 | * can do whatever you want with this stuff. If we meet some day, and you think | |
6 | * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp | |
7 | * ---------------------------------------------------------------------------- | |
8 | * | |
9 | * $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5.2.1 2001/05/24 12:20:02 markm Exp $ | |
984263bc MD |
10 | */ |
11 | ||
984263bc MD |
12 | #include <unistd.h> |
13 | #include <stdio.h> | |
14 | #include <string.h> | |
984263bc | 15 | #include <err.h> |
aeb97e6c | 16 | |
984263bc MD |
17 | #include "crypt.h" |
18 | ||
aeb97e6c | 19 | #define MD5Init _libcrypt_MD5Init |
20 | #define MD5Final _libcrypt_MD5Final | |
21 | #define MD5Pad _libcrypt_MD5Pad | |
22 | #define MD5Transform _libcrypt_MD5Transform | |
23 | #define MD5Update _libcrypt_MD5Update | |
24 | #define WITH_OPENSSL | |
25 | #include "private_md5.h" | |
26 | ||
27 | /* magic sizes, moved out from crypt.h */ | |
28 | #define MD5_SIZE 16 | |
29 | ||
984263bc MD |
30 | /* |
31 | * UNIX password | |
32 | */ | |
33 | ||
34 | char * | |
2c3b12ff | 35 | crypt_md5(const char *pw, const char *salt) |
984263bc | 36 | { |
e0369600 | 37 | static const char *magic = "$1$"; /* |
984263bc MD |
38 | * This string is magic for |
39 | * this algorithm. Having | |
40 | * it this way, we can get | |
41 | * get better later on | |
42 | */ | |
43 | static char passwd[120], *p; | |
44 | static const char *sp,*ep; | |
45 | unsigned char final[MD5_SIZE]; | |
46 | int sl,pl,i; | |
47 | MD5_CTX ctx,ctx1; | |
48 | unsigned long l; | |
49 | ||
50 | /* Refine the Salt first */ | |
51 | sp = salt; | |
52 | ||
53 | /* If it starts with the magic string, then skip that */ | |
54 | if(!strncmp(sp,magic,strlen(magic))) | |
55 | sp += strlen(magic); | |
56 | ||
57 | /* It stops at the first '$', max 8 chars */ | |
58 | for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++) | |
59 | continue; | |
60 | ||
61 | /* get the length of the true salt */ | |
62 | sl = ep - sp; | |
63 | ||
64 | MD5Init(&ctx); | |
65 | ||
66 | /* The password first, since that is what is most unknown */ | |
67 | MD5Update(&ctx,pw,strlen(pw)); | |
68 | ||
69 | /* Then our magic string */ | |
70 | MD5Update(&ctx,magic,strlen(magic)); | |
71 | ||
72 | /* Then the raw salt */ | |
73 | MD5Update(&ctx,sp,sl); | |
74 | ||
75 | /* Then just as many characters of the MD5(pw,salt,pw) */ | |
76 | MD5Init(&ctx1); | |
77 | MD5Update(&ctx1,pw,strlen(pw)); | |
78 | MD5Update(&ctx1,sp,sl); | |
79 | MD5Update(&ctx1,pw,strlen(pw)); | |
80 | MD5Final(final,&ctx1); | |
81 | for(pl = strlen(pw); pl > 0; pl -= MD5_SIZE) | |
82 | MD5Update(&ctx,final,pl>MD5_SIZE ? MD5_SIZE : pl); | |
83 | ||
84 | /* Don't leave anything around in vm they could use. */ | |
85 | memset(final,0,sizeof final); | |
86 | ||
87 | /* Then something really weird... */ | |
88 | for (i = strlen(pw); i ; i >>= 1) | |
89 | if(i&1) | |
90 | MD5Update(&ctx, final, 1); | |
91 | else | |
92 | MD5Update(&ctx, pw, 1); | |
93 | ||
94 | /* Now make the output string */ | |
95 | strcpy(passwd,magic); | |
96 | strncat(passwd,sp,sl); | |
97 | strcat(passwd,"$"); | |
98 | ||
99 | MD5Final(final,&ctx); | |
100 | ||
101 | /* | |
102 | * and now, just to make sure things don't run too fast | |
103 | * On a 60 Mhz Pentium this takes 34 msec, so you would | |
104 | * need 30 seconds to build a 1000 entry dictionary... | |
105 | */ | |
106 | for(i=0;i<1000;i++) { | |
107 | MD5Init(&ctx1); | |
108 | if(i & 1) | |
109 | MD5Update(&ctx1,pw,strlen(pw)); | |
110 | else | |
111 | MD5Update(&ctx1,final,MD5_SIZE); | |
112 | ||
113 | if(i % 3) | |
114 | MD5Update(&ctx1,sp,sl); | |
115 | ||
116 | if(i % 7) | |
117 | MD5Update(&ctx1,pw,strlen(pw)); | |
118 | ||
119 | if(i & 1) | |
120 | MD5Update(&ctx1,final,MD5_SIZE); | |
121 | else | |
122 | MD5Update(&ctx1,pw,strlen(pw)); | |
123 | MD5Final(final,&ctx1); | |
124 | } | |
125 | ||
126 | p = passwd + strlen(passwd); | |
127 | ||
128 | l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; | |
129 | _crypt_to64(p,l,4); p += 4; | |
130 | l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; | |
131 | _crypt_to64(p,l,4); p += 4; | |
132 | l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; | |
133 | _crypt_to64(p,l,4); p += 4; | |
134 | l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; | |
135 | _crypt_to64(p,l,4); p += 4; | |
136 | l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; | |
137 | _crypt_to64(p,l,4); p += 4; | |
138 | l = final[11] ; | |
139 | _crypt_to64(p,l,2); p += 2; | |
140 | *p = '\0'; | |
141 | ||
142 | /* Don't leave anything around in vm they could use. */ | |
143 | memset(final,0,sizeof final); | |
144 | ||
145 | return passwd; | |
146 | } | |
147 |