fixed ssl.c bug when ssl backend returns IO_BLOCKED but IO engine doesn't get informe...
[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: ircd_crypt_smd5.c 1334 2005-03-20 16:06:30Z entrope $
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  * unneeded code has been removed.  the source file md5_crypt.c has the 
28  * following license, 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_log.h"
43 #include "ircd_md5.h"
44 #include "s_debug.h"
45 #include "ircd_alloc.h"
46
47 /* #include <assert.h> -- Now using assert in ircd_log.h */
48 #include <string.h>
49 #include <unistd.h>
50
51 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
52 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
53
54 /** Converts a binary value into a BASE64 encoded string.
55  * @param s Pointer to the output string
56  * @param v The unsigned long we're working on
57  * @param n The number of bytes we're working with
58  *  
59  * This is used to produce the normal MD5 hash everyone is familiar with.  
60  * It takes the value v and converts n bytes of it it into an ASCII string in 
61  * 6-bit chunks, the resulting string is put at the address pointed to by s.
62  * 
63  */
64 static void to64(char *s, unsigned long v, int n)
65 {
66  while (--n >= 0) {
67   *s++ = itoa64[v & 0x3f];
68   v >>= 6;
69  }
70 }
71
72 /** Produces a Salted MD5 crypt of a password using the supplied salt
73  * @param key The password we're encrypting
74  * @param salt The salt we're using to encrypt it
75  * @return The Salted MD5 password of key and salt
76  * 
77  * Erm does exactly what the brief comment says.  If you think I'm writing a 
78  * description of how MD5 works, you have another think coming.  Go and read
79  * Applied Cryptography by Bruce Schneier.  The only difference is we use a 
80  * salt at the beginning of the password to perturb it so that the same password
81  * doesn't always produce the same hash.
82  * 
83  */ 
84 const char* ircd_crypt_smd5(const char* key, const char* salt)
85 {
86 const char *magic = "$1$";
87 static char passwd[120];
88 char *p;
89 const char *sp, *ep;
90 unsigned char final[16];
91 int sl, pl, i, j;
92 MD5_CTX ctx, ctx1;
93 unsigned long l;
94
95  assert(NULL != key);
96  assert(NULL != salt);
97
98  Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
99  Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
100
101  /* Refine the Salt first */
102  ep = sp = salt;
103
104  for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
105   continue;
106
107  /* get the length of the true salt */
108  sl = ep - sp;
109
110  MD5Init(&ctx);
111
112  /* The password first, since that is what is most unknown */
113  MD5Update(&ctx,(unsigned const char *)key,strlen(key));
114
115  /* Then our magic string */
116  MD5Update(&ctx,(unsigned const char *)magic,strlen(magic));
117
118  /* Then the raw salt */
119  MD5Update(&ctx,(unsigned const char *)sp,sl);
120
121  /* Then just as many characters of the MD5(key,salt,key) */
122  MD5Init(&ctx1);
123  MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
124  MD5Update(&ctx1,(unsigned const char *)sp,sl);
125  MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
126  MD5Final(final,&ctx1);
127  for (pl = strlen(key); pl > 0; pl -= 16)
128   MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
129
130  /* Don't leave anything around in vm they could use. */
131  memset(final, 0, sizeof final);
132
133  /* Then something really weird... */
134  for (j = 0, i = strlen(key); i; i >>= 1)
135   if (i & 1)
136    MD5Update(&ctx, (unsigned const char *)final+j, 1);
137   else
138    MD5Update(&ctx, (unsigned const char *)key+j, 1);
139
140  /* Now make the output string. */
141  memset(passwd, 0, 120);
142  strncpy(passwd, sp, sl);
143  strcat(passwd, "$");
144
145  MD5Final(final,&ctx);
146
147  /*
148   * and now, just to make sure things don't run too fast
149   * On a 60 Mhz Pentium this takes 34 msec, so you would
150   * need 30 seconds to build a 1000 entry dictionary...
151   */
152  for (i = 0; i < 1000; i++) {
153   MD5Init(&ctx1);
154
155   if (i & 1)
156    MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
157   else
158    MD5Update(&ctx1,(unsigned const char *)final,16);
159
160   if (i % 3)
161    MD5Update(&ctx1,(unsigned const char *)sp,sl);
162
163   if (i % 7)
164    MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
165
166   if (i & 1)
167    MD5Update(&ctx1,(unsigned const char *)final,16);
168   else
169    MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
170
171   MD5Final(final,&ctx1);
172  }
173
174  p = passwd + strlen(passwd);
175
176  Debug((DEBUG_DEBUG, "passwd = %s", passwd));
177
178  /* Turn the encrypted binary data into a BASE64 encoded string we can read
179   * and display -- hikari */
180  l = (final[0] << 16) | (final[6] << 8) | final[12];
181  to64(p, l, 4);
182  p += 4;
183  l = (final[1] << 16) | (final[7] << 8) | final[13];
184  to64(p, l, 4);
185  p += 4;
186  l = (final[2] << 16) | (final[8] << 8) | final[14];
187  to64(p, l, 4);
188  p += 4;
189  l = (final[3] << 16) | (final[9] << 8) | final[15];
190  to64(p, l, 4);
191  p += 4;
192  l = (final[4] << 16) | (final[10] << 8) | final[5];
193  to64(p, l, 4);
194  p += 4;
195  l = final[11];
196  to64(p, l, 2);
197  p += 2;
198  *p = '\0';
199
200  /* Don't leave anything around in vm they could use. */
201  memset(final, 0, sizeof final);
202
203 return passwd;
204 }
205
206 /* end borrowed code */
207
208 /** Register ourself with the list of crypt mechanisms 
209  * Registers the SMD5 mechanism in the list of available crypt mechanisms.  When 
210  * we're modular this will be the entry function for the module.
211  * 
212  */
213 void ircd_register_crypt_smd5(void)
214 {
215 crypt_mech_t* crypt_mech;
216
217  if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
218  {
219   Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
220   return;
221  }
222
223  crypt_mech->mechname = "smd5";
224  crypt_mech->shortname = "crypt_smd5";
225  crypt_mech->description = "Salted MD5 password hash mechanism.";
226  crypt_mech->crypt_function = &ircd_crypt_smd5;
227  crypt_mech->crypt_token = "$SMD5$";
228  crypt_mech->crypt_token_size = 6 ;
229
230  ircd_crypt_register_mech(crypt_mech);
231  
232 return;
233 }