MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
crypt_genhash_impl.cc
1 /* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 
17 // First include (the generated) my_config.h, to get correct platform defines.
18 #include "my_config.h"
19 
20 #ifdef HAVE_OPENSSL
21 
22 #ifdef HAVE_YASSL
23 #include <sha.hpp>
24 #include <openssl/ssl.h>
25 #else
26 #include <openssl/sha.h>
27 #include <openssl/rand.h>
28 #endif
29 
30 #include "crypt_genhash_impl.h"
31 
32 /* Pre VS2010 compilers doesn't support stdint.h */
33 #ifdef HAVE_STDINT_H
34 #include <stdint.h>
35 #else
36 #ifndef uint32_t
37 typedef unsigned long uint32_t;
38 #endif
39 #ifndef uint8_t
40 typedef unsigned char uint8_t;
41 #endif
42 #endif // !HAVE_STDINT_H
43 
44 #include <time.h>
45 #include <string.h>
46 
47 
48 
49 #ifndef HAVE_YASSL
50 #define DIGEST_CTX SHA256_CTX
51 #define DIGESTInit SHA256_Init
52 #define DIGESTUpdate SHA256_Update
53 #define DIGESTFinal SHA256_Final
54 #define DIGEST_LEN SHA256_DIGEST_LENGTH
55 #else
56 #define DIGEST_CTX TaoCrypt::SHA256
57 #define DIGEST_LEN 32
58 void DIGESTInit(DIGEST_CTX *ctx)
59 {
60  ctx->Init();
61 }
62 
63 void DIGESTUpdate(DIGEST_CTX *ctx, const void *plaintext, int len)
64 {
65  ctx->Update((const TaoCrypt::byte *)plaintext, len);
66 }
67 
68 void DIGESTFinal(void *txt, DIGEST_CTX *ctx)
69 {
70  ctx->Final((TaoCrypt::byte *)txt);
71 }
72 
73 #endif // HAVE_YASSL
74 
75 static const char crypt_alg_magic[] = "$5";
76 
77 #ifndef MAX
78 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
79 #endif
80 #ifndef MIN
81 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
82 #endif
83 
84 
90 size_t
91 strlcat(char *dst, const char *src, size_t siz)
92 {
93  char *d= dst;
94  const char *s= src;
95  size_t n= siz;
96  size_t dlen;
97  /* Find the end of dst and adjust bytes left but don't go past end */
98  while (n-- != 0 && *d != '\0')
99  d++;
100  dlen= d - dst;
101  n= siz - dlen;
102  if (n == 0)
103  return(dlen + siz);
104  while (*s != '\0')
105  {
106  if (n != 1)
107  {
108  *d++= *s;
109  n--;
110  }
111  s++;
112  }
113  *d= '\0';
114  return(dlen + (s - src)); /* count does not include NUL */
115 }
116 
117 static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1;
118 
119 static unsigned char b64t[] = /* 0 ... 63 => ascii - 64 */
120  "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
121 
122 #define b64_from_24bit(B2, B1, B0, N) \
123 { \
124  uint32_t w = ((B2) << 16) | ((B1) << 8) | (B0); \
125  int n = (N); \
126  while (--n >= 0 && ctbufflen > 0) { \
127  *p++ = b64t[w & 0x3f]; \
128  w >>= 6; \
129  ctbufflen--; \
130 } \
131 }
132 
133 #define ROUNDS "rounds="
134 #define ROUNDSLEN (sizeof (ROUNDS) - 1)
135 
141 static uint getrounds(const char *s)
142 {
143  const char *r;
144  const char *p;
145  char *e;
146  long val;
147 
148  if (s == NULL)
149  return (0);
150 
151  if ((r = strstr(s, ROUNDS)) == NULL)
152  {
153  return (0);
154  }
155 
156  if (strncmp(r, ROUNDS, ROUNDSLEN) != 0)
157  {
158  return (0);
159  }
160 
161  p= r + ROUNDSLEN;
162  errno= 0;
163  val= strtol(p, &e, 10);
164  /*
165  An error occurred or there is non-numeric stuff at the end
166  which isn't one of the crypt(3c) special chars ',' or '$'
167  */
168  if (errno != 0 || val < 0 || !(*e == '\0' || *e == ',' || *e == '$'))
169  {
170  return (0);
171  }
172 
173  return ((uint32_t) val);
174 }
175 
189 int extract_user_salt(char **salt_begin,
190  char **salt_end)
191 {
192  char *it= *salt_begin;
193  int delimiter_count= 0;
194  while(it != *salt_end)
195  {
196  if (*it == '$')
197  {
198  ++delimiter_count;
199  if (delimiter_count == 2)
200  {
201  *salt_begin= it + 1;
202  }
203  if (delimiter_count == 3)
204  break;
205  }
206  ++it;
207  }
208  *salt_end= it;
209  return *salt_end - *salt_begin;
210 }
211 
212 const char *sha256_find_digest(char *pass)
213 {
214  int sz= strlen(pass);
215  return pass + sz - SHA256_HASH_LENGTH;
216 }
217 
218 /*
219  * Portions of the below code come from crypt_bsdmd5.so (bsdmd5.c) :
220  * ----------------------------------------------------------------------------
221  * "THE BEER-WARE LICENSE" (Revision 42):
222  * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
223  * can do whatever you want with this stuff. If we meet some day, and you think
224  * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
225  * ----------------------------------------------------------------------------
226  *
227  * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
228  *
229  */
230 
231 /*
232  * The below code implements the specification from:
233  *
234  * From http://people.redhat.com/drepper/SHA-crypt.txt
235  *
236  * Portions of the code taken from inspired by or verified against the
237  * source in the above document which is licensed as:
238  *
239  * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>."
240  */
241 
242 /*
243  Due to a Solaris namespace bug DS is a reserved word. To work around this
244  DS is undefined.
245 */
246 #undef DS
247 
248 /* ARGSUSED4 */
249 extern "C"
250 char *
251 my_crypt_genhash(char *ctbuffer,
252  size_t ctbufflen,
253  const char *plaintext,
254  int plaintext_len,
255  const char *switchsalt,
256  const char **params)
257 {
258  int salt_len, i;
259  char *salt;
260  unsigned char A[DIGEST_LEN];
261  unsigned char B[DIGEST_LEN];
262  unsigned char DP[DIGEST_LEN];
263  unsigned char DS[DIGEST_LEN];
264  DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS;
265  int rounds = ROUNDS_DEFAULT;
266  int srounds = 0;
267  bool custom_rounds= false;
268  char *p;
269  char *P, *Pp;
270  char *S, *Sp;
271 
272  /* Refine the salt */
273  salt = (char *)switchsalt;
274 
275  /* skip our magic string */
276  if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0)
277  {
278  salt += crypt_alg_magic_len + 1;
279  }
280 
281  srounds = getrounds(salt);
282  if (srounds != 0) {
283  rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
284  custom_rounds= true;
285  p = strchr(salt, '$');
286  if (p != NULL)
287  salt = p + 1;
288  }
289 
290  salt_len = MIN(strcspn(salt, "$"), CRYPT_SALT_LENGTH);
291  //plaintext_len = strlen(plaintext);
292 
293  /* 1. */
294  DIGESTInit(&ctxA);
295 
296  /* 2. The password first, since that is what is most unknown */
297  DIGESTUpdate(&ctxA, plaintext, plaintext_len);
298 
299  /* 3. Then the raw salt */
300  DIGESTUpdate(&ctxA, salt, salt_len);
301 
302  /* 4. - 8. */
303  DIGESTInit(&ctxB);
304  DIGESTUpdate(&ctxB, plaintext, plaintext_len);
305  DIGESTUpdate(&ctxB, salt, salt_len);
306  DIGESTUpdate(&ctxB, plaintext, plaintext_len);
307  DIGESTFinal(B, &ctxB);
308 
309  /* 9. - 10. */
310  for (i= plaintext_len; i > MIXCHARS; i -= MIXCHARS)
311  DIGESTUpdate(&ctxA, B, MIXCHARS);
312  DIGESTUpdate(&ctxA, B, i);
313 
314  /* 11. */
315  for (i= plaintext_len; i > 0; i >>= 1) {
316  if ((i & 1) != 0)
317  {
318  DIGESTUpdate(&ctxA, B, MIXCHARS);
319  }
320  else
321  {
322  DIGESTUpdate(&ctxA, plaintext, plaintext_len);
323  }
324  }
325 
326  /* 12. */
327  DIGESTFinal(A, &ctxA);
328 
329  /* 13. - 15. */
330  DIGESTInit(&ctxDP);
331  for (i= 0; i < plaintext_len; i++)
332  DIGESTUpdate(&ctxDP, plaintext, plaintext_len);
333  DIGESTFinal(DP, &ctxDP);
334 
335  /* 16. */
336  Pp= P= (char *)alloca(plaintext_len);
337  for (i= plaintext_len; i >= MIXCHARS; i -= MIXCHARS)
338  {
339  Pp= (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS;
340  }
341  (void) memcpy(Pp, DP, i);
342 
343  /* 17. - 19. */
344  DIGESTInit(&ctxDS);
345  for (i= 0; i < 16 + (uint8_t)A[0]; i++)
346  DIGESTUpdate(&ctxDS, salt, salt_len);
347  DIGESTFinal(DS, &ctxDS);
348 
349  /* 20. */
350  Sp= S= (char *)alloca(salt_len);
351  for (i= salt_len; i >= MIXCHARS; i -= MIXCHARS)
352  {
353  Sp= (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS;
354  }
355  (void) memcpy(Sp, DS, i);
356 
357  /* 21. */
358  for (i= 0; i < rounds; i++)
359  {
360  DIGESTInit(&ctxC);
361 
362  if ((i & 1) != 0)
363  {
364  DIGESTUpdate(&ctxC, P, plaintext_len);
365  }
366  else
367  {
368  if (i == 0)
369  DIGESTUpdate(&ctxC, A, MIXCHARS);
370  else
371  DIGESTUpdate(&ctxC, DP, MIXCHARS);
372  }
373 
374  if (i % 3 != 0) {
375  DIGESTUpdate(&ctxC, S, salt_len);
376  }
377 
378  if (i % 7 != 0) {
379  DIGESTUpdate(&ctxC, P, plaintext_len);
380  }
381 
382  if ((i & 1) != 0)
383  {
384  if (i == 0)
385  DIGESTUpdate(&ctxC, A, MIXCHARS);
386  else
387  DIGESTUpdate(&ctxC, DP, MIXCHARS);
388  }
389  else
390  {
391  DIGESTUpdate(&ctxC, P, plaintext_len);
392  }
393  DIGESTFinal(DP, &ctxC);
394  }
395 
396  /* 22. Now make the output string */
397  if (custom_rounds)
398  {
399  (void) snprintf(ctbuffer, ctbufflen,
400  "%s$rounds=%zu$", crypt_alg_magic, (size_t)rounds);
401  }
402  else
403  {
404  (void) snprintf(ctbuffer, ctbufflen,
405  "%s$", crypt_alg_magic);
406  }
407  (void) strncat(ctbuffer, (const char *)salt, salt_len);
408  (void) strlcat(ctbuffer, "$", ctbufflen);
409 
410  p= ctbuffer + strlen(ctbuffer);
411  ctbufflen -= strlen(ctbuffer);
412 
413  b64_from_24bit(DP[ 0], DP[10], DP[20], 4);
414  b64_from_24bit(DP[21], DP[ 1], DP[11], 4);
415  b64_from_24bit(DP[12], DP[22], DP[ 2], 4);
416  b64_from_24bit(DP[ 3], DP[13], DP[23], 4);
417  b64_from_24bit(DP[24], DP[ 4], DP[14], 4);
418  b64_from_24bit(DP[15], DP[25], DP[ 5], 4);
419  b64_from_24bit(DP[ 6], DP[16], DP[26], 4);
420  b64_from_24bit(DP[27], DP[ 7], DP[17], 4);
421  b64_from_24bit(DP[18], DP[28], DP[ 8], 4);
422  b64_from_24bit(DP[ 9], DP[19], DP[29], 4);
423  b64_from_24bit(0, DP[31], DP[30], 3);
424  *p= '\0';
425 
426  (void) memset(A, 0, sizeof (A));
427  (void) memset(B, 0, sizeof (B));
428  (void) memset(DP, 0, sizeof (DP));
429  (void) memset(DS, 0, sizeof (DS));
430 
431  return (ctbuffer);
432 }
433 
434 
440 extern "C"
441 void generate_user_salt(char *buffer, int buffer_len)
442 {
443  char *end= buffer + buffer_len - 1;
444 #ifdef HAVE_YASSL
445  yaSSL::RAND_bytes((unsigned char *) buffer, buffer_len);
446 #else
447  RAND_bytes((unsigned char *) buffer, buffer_len);
448 #endif
449 
450  /* Sequence must be a legal UTF8 string */
451  for (; buffer < end; buffer++)
452  {
453  *buffer &= 0x7f;
454  if (*buffer == '\0' || *buffer == '$')
455  *buffer= *buffer + 1;
456  }
457  /* Make sure the buffer is terminated properly */
458  *end= '\0';
459 }
460 
461 void xor_string(char *to, int to_len, char *pattern, int pattern_len)
462 {
463  int loop= 0;
464  while(loop <= to_len)
465  {
466  *(to + loop) ^= *(pattern + loop % pattern_len);
467  ++loop;
468  }
469 }
470 
471 #endif // HAVE_OPENSSL