2 * IRC - Internet Relay Chat, ircd/ircd_crypt_smd5.c
3 * Copyright (C) 2002 hikari
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)
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.
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.
22 #include "ircd_crypt.h"
23 #include "ircd_crypt_smd5.h"
26 #include "ircd_alloc.h"
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
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 * ----------------------------------------------------------------------------
48 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
49 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
51 static void to64(char *s, unsigned long v, int n)
54 *s++ = itoa64[v & 0x3f];
59 const char* ircd_crypt_smd5(const char* key, const char* salt)
61 const char *magic = "$1$";
64 unsigned char final[16];
72 Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
73 Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
75 /* Refine the Salt first */
78 if(NULL == (passwd = (char *)MyMalloc(120)))
81 memset(passwd, 0, 120);
83 for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
86 /* get the length of the true salt */
89 MD5Name(MD5Init)(&ctx);
91 /* The password first, since that is what is most unknown */
92 MD5Name(MD5Update)(&ctx,(unsigned const char *)key,strlen(key));
94 /* Then our magic string */
95 MD5Name(MD5Update)(&ctx,(unsigned const char *)magic,strlen(magic));
97 /* Then the raw salt */
98 MD5Name(MD5Update)(&ctx,(unsigned const char *)sp,sl);
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);
109 /* Don't leave anything around in vm they could use. */
110 memset(final, 0, sizeof final);
112 /* Then something really weird... */
113 for (j = 0, i = strlen(key); i; i >>= 1)
115 MD5Name(MD5Update)(&ctx, (unsigned const char *)final+j, 1);
117 MD5Name(MD5Update)(&ctx, (unsigned const char *)key+j, 1);
119 /* Now make the output string */
120 // strcpy(passwd, magic);
121 // strncat(passwd, sp, sl);
122 strncpy(passwd, sp, sl);
125 MD5Name(MD5Final)(final,&ctx);
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...
132 for (i = 0; i < 1000; i++) {
133 MD5Name(MD5Init)(&ctx1);
136 MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
138 MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
141 MD5Name(MD5Update)(&ctx1,(unsigned const char *)sp,sl);
144 MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
147 MD5Name(MD5Update)(&ctx1,(unsigned const char *)final,16);
149 MD5Name(MD5Update)(&ctx1,(unsigned const char *)key,strlen(key));
151 MD5Name(MD5Final)(final,&ctx1);
154 p = passwd + strlen(passwd);
156 Debug((DEBUG_DEBUG, "passwd = %s", passwd));
158 l = (final[0] << 16) | (final[6] << 8) | final[12];
161 l = (final[1] << 16) | (final[7] << 8) | final[13];
164 l = (final[2] << 16) | (final[8] << 8) | final[14];
167 l = (final[3] << 16) | (final[9] << 8) | final[15];
170 l = (final[4] << 16) | (final[10] << 8) | final[5];
178 /* Don't leave anything around in vm they could use. */
179 memset(final, 0, sizeof final);
184 /* end borrowed code */
186 /* register ourself with the list of crypt mechanisms */
187 void ircd_register_crypt_smd5(void)
189 crypt_mech_t* crypt_mech;
191 if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
193 Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
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 ;
204 ircd_crypt_register_mech(crypt_mech);