Handle multiple endianess.
[glibc/history.git] / md5-crypt / md5-crypt.c
blob6dd67406719f4ab63c6548aea73b89e46a584888
1 /* One way encryption based on MD5 sum.
2 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/param.h>
26 #include "md5.h"
29 /* Define our magic string to mark salt for MD5 "encryption"
30 replacement. This is meant to be the same as for other MD5 based
31 encryption implementations. */
32 static const char md5_salt_prefix[] = "$1$";
34 /* Table with characters for base64 transformation. */
35 static const char b64t[64] =
36 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
39 /* Prototypes for local functions. */
40 extern char *__md5_crypt_r __P ((const char *key, const char *salt,
41 char *buffer, int buflen));
42 extern char *md5_crypt_r __P ((const char *key, const char *salt,
43 char *buffer, int buflen));
44 extern char *__md5_crypt __P ((const char *key, const char *salt));
45 extern char *md5_crypt __P ((const char *key, const char *salt));
49 /* This entry point is equivalent to the `crypt' function in Unix
50 libcs. */
51 char *
52 __md5_crypt_r (key, salt, buffer, buflen)
53 const char *key;
54 const char *salt;
55 char *buffer;
56 int buflen;
58 unsigned char alt_result[16];
59 struct md5_ctx ctx;
60 struct md5_ctx alt_ctx;
61 size_t salt_len;
62 size_t key_len;
63 size_t cnt;
64 char *cp;
66 /* Find beginning of salt string. The prefix should normally always
67 be present. Just in case it is not. */
68 if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
69 /* Skip salt prefix. */
70 salt += sizeof (md5_salt_prefix) - 1;
72 salt_len = MIN (strcspn (salt, "$"), 8);
73 key_len = strlen (key);
75 /* Prepare for the real work. */
76 md5_init_ctx (&ctx);
78 /* Add the key string. */
79 md5_process_bytes (key, key_len, &ctx);
81 /* Because the SALT argument need not always have the salt prefix we
82 add it separately. */
83 md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1, &ctx);
85 /* The last part is the salt string. This must be at most 8
86 characters and it ends at the first `$' character (for
87 compatibility which existing solutions). */
88 md5_process_bytes (salt, salt_len, &ctx);
91 /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The
92 final result will be added to the first context. */
93 md5_init_ctx (&alt_ctx);
95 /* Add key. */
96 md5_process_bytes (key, key_len, &alt_ctx);
98 /* Add salt. */
99 md5_process_bytes (salt, salt_len, &alt_ctx);
101 /* Add key again. */
102 md5_process_bytes (key, key_len, &alt_ctx);
104 /* Now get result of this (16 bytes) and add it to the other
105 context. */
106 md5_finish_ctx (&alt_ctx, alt_result);
108 /* Add for any character in the key one byte of the alternate sum. */
109 for (cnt = key_len; cnt > 16; cnt -= 16)
110 md5_process_bytes (alt_result, 16, &ctx);
111 md5_process_bytes (alt_result, cnt, &ctx);
113 /* For the following code we need a NUL byte. */
114 *alt_result = '\0';
116 /* The original implementation now does something weird: for every 1
117 bit in the key the first 0 is added to the buffer, for every 0
118 bit the first character of the key. This does not seem to be
119 what was intended but we have to follow this to be compatible. */
120 for (cnt = key_len; cnt > 0; cnt >>= 1)
121 md5_process_bytes ((cnt & 1) != 0 ? (const char *) alt_result : key, 1,
122 &ctx);
124 /* Create intermediate result. */
125 md5_finish_ctx (&ctx, alt_result);
127 /* Now comes another weirdness. In fear of password crackers here
128 comes a quite long loop which just processes the output of the
129 previous round again. We cannot ignore this here. */
130 for (cnt = 0; cnt < 1000; ++cnt)
132 /* New context. */
133 md5_init_ctx (&ctx);
135 /* Add key or last result. */
136 if ((cnt & 1) != 0)
137 md5_process_bytes (key, key_len, &ctx);
138 else
139 md5_process_bytes (alt_result, 16, &ctx);
141 /* Add salt for numbers not divisible by 3. */
142 if (cnt % 3 != 0)
143 md5_process_bytes (salt, salt_len, &ctx);
145 /* Add key for numbers not divisible by 7. */
146 if (cnt % 7 != 0)
147 md5_process_bytes (key, key_len, &ctx);
149 /* Add key or last result. */
150 if ((cnt & 1) != 0)
151 md5_process_bytes (alt_result, 16, &ctx);
152 else
153 md5_process_bytes (key, key_len, &ctx);
155 /* Create intermediate result. */
156 md5_finish_ctx (&ctx, alt_result);
159 /* Now we can construct the result string. It consists of three
160 parts. */
161 cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
162 buflen -= sizeof (md5_salt_prefix);
164 cp = __stpncpy (cp, salt, MIN ((size_t) buflen, salt_len));
165 buflen -= MIN ((size_t) buflen, salt_len);
167 if (buflen > 0)
169 *cp++ = '$';
170 --buflen;
173 #define b64_from_24bit(B2, B1, B0, N) \
174 do { \
175 unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
176 int n = (N); \
177 while (n-- > 0 && buflen > 0) \
179 *cp++ = b64t[w & 0x3f]; \
180 --buflen; \
181 w >>= 6; \
183 } while (0)
186 b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
187 b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
188 b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
189 b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
190 b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
191 b64_from_24bit (0, 0, alt_result[11], 2);
192 if (buflen <= 0)
194 __set_errno (ERANGE);
195 buffer = NULL;
197 else
198 *cp = '\0'; /* Terminate the string. */
200 /* Clear the buffer for the intermediate result so that people
201 attaching to processes or reading core dumps cannot get any
202 information. */
203 memset (alt_result, '\0', sizeof (alt_result));
205 return buffer;
207 weak_alias (__md5_crypt_r, md5_crypt_r)
210 char *
211 __md5_crypt (key, salt)
212 const char *key;
213 const char *salt;
215 /* We don't want to have an arbitrary limit in the size of the
216 password. We can compute the size of the result in advance and
217 so we can prepare the buffer we pass to `md5_crypt_r'. */
218 static char *buffer = NULL;
219 static int buflen = 0;
220 int needed = 3 + strlen (salt) + 1 + 26 + 1;
222 if (buflen < needed)
224 buflen = needed;
225 if ((buffer = realloc (buffer, buflen)) == NULL)
226 return NULL;
229 return __md5_crypt_r (key, salt, buffer, buflen);
231 weak_alias (__md5_crypt, md5_crypt)