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 * @brief Routines for Salted MD5 passwords
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
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 * ----------------------------------------------------------------------------
40 #include "ircd_crypt.h"
41 #include "ircd_crypt_smd5.h"
44 #include "ircd_alloc.h"
50 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
51 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
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
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.
63 static void to64(char *s, unsigned long v, int n)
66 *s++ = itoa64[v & 0x3f];
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
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.
83 const char* ircd_crypt_smd5(const char* key, const char* salt)
85 const char *magic = "$1$";
88 unsigned char final[16];
96 Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
97 Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
99 /* Refine the Salt first */
102 if(NULL == (passwd = (char *)MyMalloc(120)))
105 memset(passwd, 0, 120);
107 for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
110 /* get the length of the true salt */
115 /* The password first, since that is what is most unknown */
116 MD5Update(&ctx,(unsigned const char *)key,strlen(key));
118 /* Then our magic string */
119 MD5Update(&ctx,(unsigned const char *)magic,strlen(magic));
121 /* Then the raw salt */
122 MD5Update(&ctx,(unsigned const char *)sp,sl);
124 /* Then just as many characters of the MD5(key,salt,key) */
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);
133 /* Don't leave anything around in vm they could use. */
134 memset(final, 0, sizeof final);
136 /* Then something really weird... */
137 for (j = 0, i = strlen(key); i; i >>= 1)
139 MD5Update(&ctx, (unsigned const char *)final+j, 1);
141 MD5Update(&ctx, (unsigned const char *)key+j, 1);
143 /* Now make the output string
144 strcpy(passwd, magic);
145 strncat(passwd, sp, sl); */
146 strncpy(passwd, sp, sl);
149 MD5Final(final,&ctx);
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...
156 for (i = 0; i < 1000; i++) {
160 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
162 MD5Update(&ctx1,(unsigned const char *)final,16);
165 MD5Update(&ctx1,(unsigned const char *)sp,sl);
168 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
171 MD5Update(&ctx1,(unsigned const char *)final,16);
173 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
175 MD5Final(final,&ctx1);
178 p = passwd + strlen(passwd);
180 Debug((DEBUG_DEBUG, "passwd = %s", passwd));
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];
187 l = (final[1] << 16) | (final[7] << 8) | final[13];
190 l = (final[2] << 16) | (final[8] << 8) | final[14];
193 l = (final[3] << 16) | (final[9] << 8) | final[15];
196 l = (final[4] << 16) | (final[10] << 8) | final[5];
204 /* Don't leave anything around in vm they could use. */
205 memset(final, 0, sizeof final);
210 /* end borrowed code */
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.
217 void ircd_register_crypt_smd5(void)
219 crypt_mech_t* crypt_mech;
221 if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
223 Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
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 ;
234 ircd_crypt_register_mech(crypt_mech);