Fix warnings from gcc -pedantic.
[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  * $Id$
20  */
21 #include "config.h"
22 #include "ircd_crypt.h"
23 #include "ircd_crypt_smd5.h"
24 #include "ircd_md5.h"
25 #include "s_debug.h"
26 #include "ircd_alloc.h"
27
28 #include <assert.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 /*
33  * ircd_crypt_smd5 is largely taken from md5_crypt.c from the Linux PAM 
34  * source code.  it's been modified to fit in with ircu and some of the 
35  * undeeded code has been removed.  the source file md5_crypt.c has the 
36  * following licence, so if any of our opers or admins are in Denmark
37  * they better go buy them a drink ;) -- hikari
38  *
39  * ----------------------------------------------------------------------------
40  * "THE BEER-WARE LICENSE" (Revision 42):
41  * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you
42  * can do whatever you want with this stuff. If we meet some day, and you think
43  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
44  * ----------------------------------------------------------------------------
45  *
46  */
47
48 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
49 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
50
51 static void to64(char *s, unsigned long v, int n)
52 {
53  while (--n >= 0) {
54   *s++ = itoa64[v & 0x3f];
55   v >>= 6;
56  }
57 }
58
59 const char* ircd_crypt_smd5(const char* key, const char* salt)
60 {
61 const char *magic = "$1$";
62 char *passwd, *p;
63 const char *sp, *ep;
64 unsigned char final[16];
65 int sl, pl, i, j;
66 MD5_CTX ctx, ctx1;
67 unsigned long l;
68
69  assert(NULL != key);
70  assert(NULL != salt);
71
72  Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
73  Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
74
75  /* Refine the Salt first */
76  ep = sp = salt;
77
78  if(NULL == (passwd = (char *)MyMalloc(120)))
79   return NULL;
80
81  memset(passwd, 0, 120);
82
83  for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
84   continue;
85
86  /* get the length of the true salt */
87  sl = ep - sp;
88
89  MD5Name(MD5Init)(&ctx);
90
91  /* The password first, since that is what is most unknown */
92  MD5Name(MD5Update)(&ctx,(unsigned const char *)key,strlen(key));
93
94  /* Then our magic string */
95  MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic));
96
97  /* Then the raw salt */
98  MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl);
99
100  /* Then just as many characters of the MD5(key,salt,key) */
101  MD5Name(MD5Init)(&ctx1);
102  MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
103  MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
104  MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
105  MD5Name(MD5Final)(final,&ctx1);
106  for (pl = strlen(key); pl > 0; pl -= 16)
107   MD5Name(MD5Update)(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
108
109  /* Don't leave anything around in vm they could use. */
110  memset(final, 0, sizeof final);
111
112  /* Then something really weird... */
113  for (j = 0, i = strlen(key); i; i >>= 1)
114   if (i & 1)
115    MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1);
116   else
117    MD5Name(MD5Update)(&ctx, (unsigned const char *)key+j, 1);
118
119  /* Now make the output string
120  strcpy(passwd, magic);
121  strncat(passwd, sp, sl); */
122  strncpy(passwd, sp, sl);
123  strcat(passwd, "$");
124
125  MD5Name(MD5Final)(final,&ctx);
126
127  /*
128   * and now, just to make sure things don't run too fast
129   * On a 60 Mhz Pentium this takes 34 msec, so you would
130   * need 30 seconds to build a 1000 entry dictionary...
131   */
132  for (i = 0; i < 1000; i++) {
133   MD5Name(MD5Init)(&ctx1);
134
135   if (i & 1)
136    MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
137   else
138    MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
139
140   if (i % 3)
141    MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
142
143   if (i % 7)
144    MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
145
146   if (i & 1)
147    MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
148   else
149    MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
150
151   MD5Name(MD5Final)(final,&ctx1);
152  }
153
154  p = passwd + strlen(passwd);
155
156  Debug((DEBUG_DEBUG, "passwd = %s", passwd));
157
158  l = (final[0] << 16) | (final[6] << 8) | final[12];
159  to64(p, l, 4);
160  p += 4;
161  l = (final[1] << 16) | (final[7] << 8) | final[13];
162  to64(p, l, 4);
163  p += 4;
164  l = (final[2] << 16) | (final[8] << 8) | final[14];
165  to64(p, l, 4);
166  p += 4;
167  l = (final[3] << 16) | (final[9] << 8) | final[15];
168  to64(p, l, 4);
169  p += 4;
170  l = (final[4] << 16) | (final[10] << 8) | final[5];
171  to64(p, l, 4);
172  p += 4;
173  l = final[11];
174  to64(p, l, 2);
175  p += 2;
176  *p = '\0';
177
178  /* Don't leave anything around in vm they could use. */
179  memset(final, 0, sizeof final);
180
181 return passwd;
182 }
183
184 /* end borrowed code */
185
186 /* register ourself with the list of crypt mechanisms */
187 void ircd_register_crypt_smd5(void)
188 {
189 crypt_mech_t* crypt_mech;
190
191  if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
192  {
193   Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
194   return;
195  }
196
197  crypt_mech->mechname = "smd5";
198  crypt_mech->shortname = "crypt_smd5";
199  crypt_mech->description = "Salted MD5 password hash mechanism.";
200  crypt_mech->crypt_function = &ircd_crypt_smd5;
201  crypt_mech->crypt_token = "$SMD5$";
202  crypt_mech->crypt_token_size = 6 ;
203
204  ircd_crypt_register_mech(crypt_mech);
205  
206 return;
207 }