Version definitions.
[kopensolaris-gnu/glibc.git] / md5-crypt / md5-crypt.c
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.
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 <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/param.h>
25
26 #include "md5.h"
27
28
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$";
33
34 /* Table with characters for base64 transformation.  */
35 static const char b64t[64] =
36 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
37
38
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));
46
47
48
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;
57 {
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;
65
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;
71
72   salt_len = MIN (strcspn (salt, "$"), 8);
73   key_len = strlen (key);
74
75   /* Prepare for the real work.  */
76   md5_init_ctx (&ctx);
77
78   /* Add the key string.  */
79   md5_process_bytes (key, key_len, &ctx);
80
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);
84
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);
89
90
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);
94
95   /* Add key.  */
96   md5_process_bytes (key, key_len, &alt_ctx);
97
98   /* Add salt.  */
99   md5_process_bytes (salt, salt_len, &alt_ctx);
100
101   /* Add key again.  */
102   md5_process_bytes (key, key_len, &alt_ctx);
103
104   /* Now get result of this (16 bytes) and add it to the other
105      context.  */
106   md5_finish_ctx (&alt_ctx, alt_result);
107
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);
112
113   /* For the following code we need a NUL byte.  */
114   *alt_result = '\0';
115
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);
123
124   /* Create intermediate result.  */
125   md5_finish_ctx (&ctx, alt_result);
126
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)
131     {
132       /* New context.  */
133       md5_init_ctx (&ctx);
134
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);
140
141       /* Add salt for numbers not divisible by 3.  */
142       if (cnt % 3 != 0)
143         md5_process_bytes (salt, salt_len, &ctx);
144
145       /* Add key for numbers not divisible by 7.  */
146       if (cnt % 7 != 0)
147         md5_process_bytes (key, key_len, &ctx);
148
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);
154
155       /* Create intermediate result.  */
156       md5_finish_ctx (&ctx, alt_result);
157     }
158
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);
163
164   cp = __stpncpy (cp, salt, MIN ((size_t) buflen, salt_len));
165   buflen -= MIN ((size_t) buflen, salt_len);
166
167   if (buflen > 0)
168     {
169       *cp++ = '$';
170       --buflen;
171     }
172
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)                                             \
178       {                                                                       \
179         *cp++ = b64t[w & 0x3f];                                               \
180         --buflen;                                                             \
181         w >>= 6;                                                              \
182       }                                                                       \
183   } while (0)
184
185
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)
193     {
194       __set_errno (ERANGE);
195       buffer = NULL;
196     }
197   else
198     *cp = '\0';         /* Terminate the string.  */
199
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));
204
205   return buffer;
206 }
207 weak_alias (__md5_crypt_r, md5_crypt_r)
208
209
210 char *
211 __md5_crypt (key, salt)
212      const char *key;
213      const char *salt;
214 {
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;
221
222   if (buflen < needed)
223     {
224       buflen = needed;
225       if ((buffer = realloc (buffer, buflen)) == NULL)
226         return NULL;
227     }
228
229   return __md5_crypt_r (key, salt, buffer, buflen);
230 }
231 weak_alias (__md5_crypt, md5_crypt)