Get rid of "Good" and "Broken" prefixes on MD5 functions.
[ircu2.10.12-pk.git] / ircd / ircd_crypt_smd5.c
1 /*
2  * IRC - Internet Relay Chat, ircd/ircd_crypt_smd5.c
3  * Copyright (C) 2002 hikari
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 1, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19  
20 /** 
21  * @file
22  * @brief Routines for Salted MD5 passwords
23  * @version $Id$
24  * 
25  * ircd_crypt_smd5 is largely taken from md5_crypt.c from the Linux PAM 
26  * source code.  it's been modified to fit in with ircu and some of the 
27  * undeeded code has been removed.  the source file md5_crypt.c has the 
28  * following licence, so if any of our opers or admins are in Denmark
29  * they better go buy them a drink ;) -- hikari
30  *
31  * ----------------------------------------------------------------------------
32  * "THE BEER-WARE LICENSE" (Revision 42):
33  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
34  * can do whatever you want with this stuff. If we meet some day, and you think
35  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
36  * ----------------------------------------------------------------------------
37  *
38  */
39 #include "config.h"
40 #include "ircd_crypt.h"
41 #include "ircd_crypt_smd5.h"
42 #include "ircd_md5.h"
43 #include "s_debug.h"
44 #include "ircd_alloc.h"
45
46 #include <assert.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
51 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
52
53 /** Converts a binary value into a BASE64 encoded string.
54  * @param s Pointer to the output string
55  * @param v The unsigned long we're working on
56  * @param n The number of bytes we're working with
57  *  
58  * This is used to produce the normal MD5 hash everyone is familar with.  
59  * It takes the value v and converts n bytes of it it into an ASCII string in 
60  * 6-bit chunks, the resulting string is put at the address pointed to by s.
61  * 
62  */
63 static void to64(char *s, unsigned long v, int n)
64 {
65  while (--n >= 0) {
66   *s++ = itoa64[v & 0x3f];
67   v >>= 6;
68  }
69 }
70
71 /** Produces a Salted MD5 crypt of a password using the supplied salt
72  * @param key The password we're encrypting
73  * @param salt The salt we're using to encrypt it
74  * @return The Salted MD5 password of key and salt
75  * 
76  * Erm does exactly what the brief comment says.  If you think I'm writing a 
77  * description of how MD5 works, you have another thing comming.  Go and read
78  * Applied Cryptopgraphy by Bruce Schneier.  The only difference is we use a 
79  * salt at the begining of the password to perturb it so that the same password
80  * doesn't always produce the same hash.
81  * 
82  */ 
83 const char* ircd_crypt_smd5(const char* key, const char* salt)
84 {
85 const char *magic = "$1$";
86 char *passwd, *p;
87 const char *sp, *ep;
88 unsigned char final[16];
89 int sl, pl, i, j;
90 MD5_CTX ctx, ctx1;
91 unsigned long l;
92
93  assert(NULL != key);
94  assert(NULL != salt);
95
96  Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
97  Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
98
99  /* Refine the Salt first */
100  ep = sp = salt;
101
102  if(NULL == (passwd = (char *)MyMalloc(120)))
103   return NULL;
104
105  memset(passwd, 0, 120);
106
107  for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
108   continue;
109
110  /* get the length of the true salt */
111  sl = ep - sp;
112
113  MD5Init(&ctx);
114
115  /* The password first, since that is what is most unknown */
116  MD5Update(&ctx,(unsigned const char *)key,strlen(key));
117
118  /* Then our magic string */
119  MD5Update(&ctx,(unsigned const char *)magic,strlen(magic));
120
121  /* Then the raw salt */
122  MD5Update(&ctx,(unsigned const char *)sp,sl);
123
124  /* Then just as many characters of the MD5(key,salt,key) */
125  MD5Init(&ctx1);
126  MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
127  MD5Update(&ctx1,(unsigned const char *)sp,sl);
128  MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
129  MD5Final(final,&ctx1);
130  for (pl = strlen(key); pl > 0; pl -= 16)
131   MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
132
133  /* Don't leave anything around in vm they could use. */
134  memset(final, 0, sizeof final);
135
136  /* Then something really weird... */
137  for (j = 0, i = strlen(key); i; i >>= 1)
138   if (i & 1)
139    MD5Update(&ctx, (unsigned const char *)final+j, 1);
140   else
141    MD5Update(&ctx, (unsigned const char *)key+j, 1);
142
143  /* Now make the output string
144  strcpy(passwd, magic);
145  strncat(passwd, sp, sl); */
146  strncpy(passwd, sp, sl);
147  strcat(passwd, "$");
148
149  MD5Final(final,&ctx);
150
151  /*
152   * and now, just to make sure things don't run too fast
153   * On a 60 Mhz Pentium this takes 34 msec, so you would
154   * need 30 seconds to build a 1000 entry dictionary...
155   */
156  for (i = 0; i < 1000; i++) {
157   MD5Init(&ctx1);
158
159   if (i & 1)
160    MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
161   else
162    MD5Update(&ctx1,(unsigned const char *)final,16);
163
164   if (i % 3)
165    MD5Update(&ctx1,(unsigned const char *)sp,sl);
166
167   if (i % 7)
168    MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
169
170   if (i & 1)
171    MD5Update(&ctx1,(unsigned const char *)final,16);
172   else
173    MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
174
175   MD5Final(final,&ctx1);
176  }
177
178  p = passwd + strlen(passwd);
179
180  Debug((DEBUG_DEBUG, "passwd = %s", passwd));
181
182  /* Turn the encrypted binary data into a BASE64 encoded string we can read
183   * and display -- hikari */
184  l = (final[0] << 16) | (final[6] << 8) | final[12];
185  to64(p, l, 4);
186  p += 4;
187  l = (final[1] << 16) | (final[7] << 8) | final[13];
188  to64(p, l, 4);
189  p += 4;
190  l = (final[2] << 16) | (final[8] << 8) | final[14];
191  to64(p, l, 4);
192  p += 4;
193  l = (final[3] << 16) | (final[9] << 8) | final[15];
194  to64(p, l, 4);
195  p += 4;
196  l = (final[4] << 16) | (final[10] << 8) | final[5];
197  to64(p, l, 4);
198  p += 4;
199  l = final[11];
200  to64(p, l, 2);
201  p += 2;
202  *p = '\0';
203
204  /* Don't leave anything around in vm they could use. */
205  memset(final, 0, sizeof final);
206
207 return passwd;
208 }
209
210 /* end borrowed code */
211
212 /** Register ourself with the list of crypt mechanisms 
213  * Registers the SMD5 mechanism in the list of available crypt mechanisms.  When 
214  * we're modular this will be the entry function for the module.
215  * 
216  */
217 void ircd_register_crypt_smd5(void)
218 {
219 crypt_mech_t* crypt_mech;
220
221  if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
222  {
223   Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
224   return;
225  }
226
227  crypt_mech->mechname = "smd5";
228  crypt_mech->shortname = "crypt_smd5";
229  crypt_mech->description = "Salted MD5 password hash mechanism.";
230  crypt_mech->crypt_function = &ircd_crypt_smd5;
231  crypt_mech->crypt_token = "$SMD5$";
232  crypt_mech->crypt_token_size = 6 ;
233
234  ircd_crypt_register_mech(crypt_mech);
235  
236 return;
237 }