Add more code to align buffers.
[kopensolaris-gnu/glibc.git] / crypt / md5-crypt.c
1 /* One way encryption based on MD5 sum.
2    Copyright (C) 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
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.
10
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.
15
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.  */
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/param.h>
26
27 #include "md5.h"
28
29
30 /* Define our magic string to mark salt for MD5 "encryption"
31    replacement.  This is meant to be the same as for other MD5 based
32    encryption implementations.  */
33 static const char md5_salt_prefix[] = "$1$";
34
35 /* Table with characters for base64 transformation.  */
36 static const char b64t[64] =
37 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
38
39
40 /* Prototypes for local functions.  */
41 extern char *__md5_crypt_r (const char *key, const char *salt,
42                             char *buffer, int buflen);
43 extern char *__md5_crypt (const char *key, const char *salt);
44
45
46 /* This entry point is equivalent to the `crypt' function in Unix
47    libcs.  */
48 char *
49 __md5_crypt_r (key, salt, buffer, buflen)
50      const char *key;
51      const char *salt;
52      char *buffer;
53      int buflen;
54 {
55   unsigned char alt_result[16]
56     __attribute__ ((__aligned__ (__alignof__ (md5_uint32))));
57   struct md5_ctx ctx;
58   struct md5_ctx alt_ctx;
59   size_t salt_len;
60   size_t key_len;
61   size_t cnt;
62   char *cp;
63
64   /* Find beginning of salt string.  The prefix should normally always
65      be present.  Just in case it is not.  */
66   if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0)
67     /* Skip salt prefix.  */
68     salt += sizeof (md5_salt_prefix) - 1;
69
70   salt_len = MIN (strcspn (salt, "$"), 8);
71   key_len = strlen (key);
72
73   if ((key - (char *) 0) % __alignof__ (md5_uint32) != 0)
74     {
75       char *tmp = (char *) alloca (key_len + __alignof__ (md5_uint32));
76       key = memcpy (tmp + __alignof__ (md5_uint32)
77                     - (tmp - (char *) 0) % __alignof__ (md5_uint32),
78                     key, key_len);
79       assert ((key - (char *) 0) % __alignof__ (md5_uint32) == 0);
80     }
81
82   if ((salt - (char *) 0) % __alignof__ (md5_uint32) != 0)
83     {
84       char *tmp = (char *) alloca (salt_len + __alignof__ (md5_uint32));
85       salt = memcpy (tmp + __alignof__ (md5_uint32)
86                      - (tmp - (char *) 0) % __alignof__ (md5_uint32),
87                      salt, salt_len);
88       assert ((salt - (char *) 0) % __alignof__ (md5_uint32) == 0);
89     }
90
91   /* Prepare for the real work.  */
92   __md5_init_ctx (&ctx);
93
94   /* Add the key string.  */
95   __md5_process_bytes (key, key_len, &ctx);
96
97   /* Because the SALT argument need not always have the salt prefix we
98      add it separately.  */
99   __md5_process_bytes (md5_salt_prefix, sizeof (md5_salt_prefix) - 1, &ctx);
100
101   /* The last part is the salt string.  This must be at most 8
102      characters and it ends at the first `$' character (for
103      compatibility which existing solutions).  */
104   __md5_process_bytes (salt, salt_len, &ctx);
105
106
107   /* Compute alternate MD5 sum with input KEY, SALT, and KEY.  The
108      final result will be added to the first context.  */
109   __md5_init_ctx (&alt_ctx);
110
111   /* Add key.  */
112   __md5_process_bytes (key, key_len, &alt_ctx);
113
114   /* Add salt.  */
115   __md5_process_bytes (salt, salt_len, &alt_ctx);
116
117   /* Add key again.  */
118   __md5_process_bytes (key, key_len, &alt_ctx);
119
120   /* Now get result of this (16 bytes) and add it to the other
121      context.  */
122   __md5_finish_ctx (&alt_ctx, alt_result);
123
124   /* Add for any character in the key one byte of the alternate sum.  */
125   for (cnt = key_len; cnt > 16; cnt -= 16)
126     __md5_process_bytes (alt_result, 16, &ctx);
127   __md5_process_bytes (alt_result, cnt, &ctx);
128
129   /* For the following code we need a NUL byte.  */
130   *alt_result = '\0';
131
132   /* The original implementation now does something weird: for every 1
133      bit in the key the first 0 is added to the buffer, for every 0
134      bit the first character of the key.  This does not seem to be
135      what was intended but we have to follow this to be compatible.  */
136   for (cnt = key_len; cnt > 0; cnt >>= 1)
137     __md5_process_bytes ((cnt & 1) != 0 ? (const char *) alt_result : key, 1,
138                          &ctx);
139
140   /* Create intermediate result.  */
141   __md5_finish_ctx (&ctx, alt_result);
142
143   /* Now comes another weirdness.  In fear of password crackers here
144      comes a quite long loop which just processes the output of the
145      previous round again.  We cannot ignore this here.  */
146   for (cnt = 0; cnt < 1000; ++cnt)
147     {
148       /* New context.  */
149       __md5_init_ctx (&ctx);
150
151       /* Add key or last result.  */
152       if ((cnt & 1) != 0)
153         __md5_process_bytes (key, key_len, &ctx);
154       else
155         __md5_process_bytes (alt_result, 16, &ctx);
156
157       /* Add salt for numbers not divisible by 3.  */
158       if (cnt % 3 != 0)
159         __md5_process_bytes (salt, salt_len, &ctx);
160
161       /* Add key for numbers not divisible by 7.  */
162       if (cnt % 7 != 0)
163         __md5_process_bytes (key, key_len, &ctx);
164
165       /* Add key or last result.  */
166       if ((cnt & 1) != 0)
167         __md5_process_bytes (alt_result, 16, &ctx);
168       else
169         __md5_process_bytes (key, key_len, &ctx);
170
171       /* Create intermediate result.  */
172       __md5_finish_ctx (&ctx, alt_result);
173     }
174
175   /* Now we can construct the result string.  It consists of three
176      parts.  */
177   cp = __stpncpy (buffer, md5_salt_prefix, MAX (0, buflen));
178   buflen -= sizeof (md5_salt_prefix);
179
180   cp = __stpncpy (cp, salt, MIN ((size_t) buflen, salt_len));
181   buflen -= MIN ((size_t) buflen, salt_len);
182
183   if (buflen > 0)
184     {
185       *cp++ = '$';
186       --buflen;
187     }
188
189 #define b64_from_24bit(B2, B1, B0, N)                                         \
190   do {                                                                        \
191     unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0);                       \
192     int n = (N);                                                              \
193     while (n-- > 0 && buflen > 0)                                             \
194       {                                                                       \
195         *cp++ = b64t[w & 0x3f];                                               \
196         --buflen;                                                             \
197         w >>= 6;                                                              \
198       }                                                                       \
199   } while (0)
200
201
202   b64_from_24bit (alt_result[0], alt_result[6], alt_result[12], 4);
203   b64_from_24bit (alt_result[1], alt_result[7], alt_result[13], 4);
204   b64_from_24bit (alt_result[2], alt_result[8], alt_result[14], 4);
205   b64_from_24bit (alt_result[3], alt_result[9], alt_result[15], 4);
206   b64_from_24bit (alt_result[4], alt_result[10], alt_result[5], 4);
207   b64_from_24bit (0, 0, alt_result[11], 2);
208   if (buflen <= 0)
209     {
210       __set_errno (ERANGE);
211       buffer = NULL;
212     }
213   else
214     *cp = '\0';         /* Terminate the string.  */
215
216   /* Clear the buffer for the intermediate result so that people
217      attaching to processes or reading core dumps cannot get any
218      information.  */
219   memset (alt_result, '\0', sizeof (alt_result));
220
221   return buffer;
222 }
223
224
225 char *
226 __md5_crypt (const char *key, const char *salt)
227 {
228   /* We don't want to have an arbitrary limit in the size of the
229      password.  We can compute the size of the result in advance and
230      so we can prepare the buffer we pass to `md5_crypt_r'.  */
231   static char *buffer = NULL;
232   static int buflen = 0;
233   int needed = 3 + strlen (salt) + 1 + 26 + 1;
234
235   if (buflen < needed)
236     {
237       buflen = needed;
238       if ((buffer = realloc (buffer, buflen)) == NULL)
239         return NULL;
240     }
241
242   return __md5_crypt_r (key, salt, buffer, buflen);
243 }