]>
jfr.im git - irc/quakenet/snircd.git/blob - ircd/ircd_crypt_smd5.c
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
23 * @version $Id: ircd_crypt_smd5.c,v 1.7 2005/03/20 16:06:17 entrope Exp $
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
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"
45 #include "ircd_alloc.h"
47 /* #include <assert.h> -- Now using assert in ircd_log.h */
51 static unsigned char itoa64
[] = /* 0 ... 63 => ascii - 64 */
52 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
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
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.
64 static void to64(char *s
, unsigned long v
, int n
)
67 *s
++ = itoa64
[v
& 0x3f];
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
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.
84 const char* ircd_crypt_smd5(const char* key
, const char* salt
)
86 const char *magic
= "$1$";
87 static char passwd
[120];
90 unsigned char final
[16];
98 Debug((DEBUG_DEBUG
, "ircd_crypt_smd5: key = %s", key
));
99 Debug((DEBUG_DEBUG
, "ircd_crypt_smd5: salt = %s", salt
));
101 /* Refine the Salt first */
104 for (ep
= sp
; *ep
&& *ep
!= '$' && ep
< (sp
+ 8); ep
++)
107 /* get the length of the true salt */
112 /* The password first, since that is what is most unknown */
113 MD5Update(&ctx
,(unsigned const char *)key
,strlen(key
));
115 /* Then our magic string */
116 MD5Update(&ctx
,(unsigned const char *)magic
,strlen(magic
));
118 /* Then the raw salt */
119 MD5Update(&ctx
,(unsigned const char *)sp
,sl
);
121 /* Then just as many characters of the MD5(key,salt,key) */
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
);
130 /* Don't leave anything around in vm they could use. */
131 memset(final
, 0, sizeof final
);
133 /* Then something really weird... */
134 for (j
= 0, i
= strlen(key
); i
; i
>>= 1)
136 MD5Update(&ctx
, (unsigned const char *)final
+j
, 1);
138 MD5Update(&ctx
, (unsigned const char *)key
+j
, 1);
140 /* Now make the output string. */
141 memset(passwd
, 0, 120);
142 strncpy(passwd
, sp
, sl
);
145 MD5Final(final
,&ctx
);
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...
152 for (i
= 0; i
< 1000; i
++) {
156 MD5Update(&ctx1
,(unsigned const char *)key
,strlen(key
));
158 MD5Update(&ctx1
,(unsigned const char *)final
,16);
161 MD5Update(&ctx1
,(unsigned const char *)sp
,sl
);
164 MD5Update(&ctx1
,(unsigned const char *)key
,strlen(key
));
167 MD5Update(&ctx1
,(unsigned const char *)final
,16);
169 MD5Update(&ctx1
,(unsigned const char *)key
,strlen(key
));
171 MD5Final(final
,&ctx1
);
174 p
= passwd
+ strlen(passwd
);
176 Debug((DEBUG_DEBUG
, "passwd = %s", passwd
));
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];
183 l
= (final
[1] << 16) | (final
[7] << 8) | final
[13];
186 l
= (final
[2] << 16) | (final
[8] << 8) | final
[14];
189 l
= (final
[3] << 16) | (final
[9] << 8) | final
[15];
192 l
= (final
[4] << 16) | (final
[10] << 8) | final
[5];
200 /* Don't leave anything around in vm they could use. */
201 memset(final
, 0, sizeof final
);
206 /* end borrowed code */
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.
213 void ircd_register_crypt_smd5(void)
215 crypt_mech_t
* crypt_mech
;
217 if ((crypt_mech
= (crypt_mech_t
*)MyMalloc(sizeof(crypt_mech_t
))) == NULL
)
219 Debug((DEBUG_MALLOC
, "Could not allocate space for crypt_smd5"));
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 ;
230 ircd_crypt_register_mech(crypt_mech
);