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$";
86 static char passwd[120];
89 unsigned char final[16];
97 Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key));
98 Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt));
100 /* Refine the Salt first */
103 for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
106 /* get the length of the true salt */
111 /* The password first, since that is what is most unknown */
112 MD5Update(&ctx,(unsigned const char *)key,strlen(key));
114 /* Then our magic string */
115 MD5Update(&ctx,(unsigned const char *)magic,strlen(magic));
117 /* Then the raw salt */
118 MD5Update(&ctx,(unsigned const char *)sp,sl);
120 /* Then just as many characters of the MD5(key,salt,key) */
122 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
123 MD5Update(&ctx1,(unsigned const char *)sp,sl);
124 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
125 MD5Final(final,&ctx1);
126 for (pl = strlen(key); pl > 0; pl -= 16)
127 MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl);
129 /* Don't leave anything around in vm they could use. */
130 memset(final, 0, sizeof final);
132 /* Then something really weird... */
133 for (j = 0, i = strlen(key); i; i >>= 1)
135 MD5Update(&ctx, (unsigned const char *)final+j, 1);
137 MD5Update(&ctx, (unsigned const char *)key+j, 1);
139 /* Now make the output string. */
140 memset(passwd, 0, 120);
141 strncpy(passwd, sp, sl);
144 MD5Final(final,&ctx);
147 * and now, just to make sure things don't run too fast
148 * On a 60 Mhz Pentium this takes 34 msec, so you would
149 * need 30 seconds to build a 1000 entry dictionary...
151 for (i = 0; i < 1000; i++) {
155 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
157 MD5Update(&ctx1,(unsigned const char *)final,16);
160 MD5Update(&ctx1,(unsigned const char *)sp,sl);
163 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
166 MD5Update(&ctx1,(unsigned const char *)final,16);
168 MD5Update(&ctx1,(unsigned const char *)key,strlen(key));
170 MD5Final(final,&ctx1);
173 p = passwd + strlen(passwd);
175 Debug((DEBUG_DEBUG, "passwd = %s", passwd));
177 /* Turn the encrypted binary data into a BASE64 encoded string we can read
178 * and display -- hikari */
179 l = (final[0] << 16) | (final[6] << 8) | final[12];
182 l = (final[1] << 16) | (final[7] << 8) | final[13];
185 l = (final[2] << 16) | (final[8] << 8) | final[14];
188 l = (final[3] << 16) | (final[9] << 8) | final[15];
191 l = (final[4] << 16) | (final[10] << 8) | final[5];
199 /* Don't leave anything around in vm they could use. */
200 memset(final, 0, sizeof final);
205 /* end borrowed code */
207 /** Register ourself with the list of crypt mechanisms
208 * Registers the SMD5 mechanism in the list of available crypt mechanisms. When
209 * we're modular this will be the entry function for the module.
212 void ircd_register_crypt_smd5(void)
214 crypt_mech_t* crypt_mech;
216 if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL)
218 Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5"));
222 crypt_mech->mechname = "smd5";
223 crypt_mech->shortname = "crypt_smd5";
224 crypt_mech->description = "Salted MD5 password hash mechanism.";
225 crypt_mech->crypt_function = &ircd_crypt_smd5;
226 crypt_mech->crypt_token = "$SMD5$";
227 crypt_mech->crypt_token_size = 6 ;
229 ircd_crypt_register_mech(crypt_mech);