2
Origin: http://svn.php.net/viewvc?view=revision&revision=313406
3
Subject: update crypt_blowfish to 1.2. (CVE-2011-2483) (Solar Designer)
5
- update blowfish to 1.2 (Solar Designer)
9
[Ubuntu note: patch differs from upstream commit in that the added
10
header crypt_blowfish.h has been dropped, to prevent possible 3rd
11
party build problems by introducing the new header. Also, the changes
12
to the News file have been dropped to reduce conflicts. --sbeattie]
15
README.REDIST.BINS | 27 ++
16
ext/standard/crypt_blowfish.c | 379 +++++++++++++++++++++++++++++-------------
17
ext/standard/crypt_blowfish.h | 32 +++
18
ext/standard/php_crypt_r.h | 4
19
4 files changed, 320 insertions(+), 122 deletions(-)
21
Index: b/README.REDIST.BINS
22
===================================================================
23
--- a/README.REDIST.BINS
24
+++ b/README.REDIST.BINS
25
@@ -51,27 +51,40 @@ SUCH DAMAGE.
27
6. ext/standard crypt's blowfish implementation
29
+The crypt_blowfish homepage is:
31
+http://www.openwall.com/crypt/
33
This code comes from John the Ripper password cracker, with reentrant
34
and crypt(3) interfaces added, but optimizations specific to password
37
-Written by Solar Designer <solar at openwall.com> in 1998-2002 and
38
-placed in the public domain.
39
+Written by Solar Designer <solar at openwall.com> in 1998-2011.
40
+No copyright is claimed, and the software is hereby placed in the public
41
+domain. In case this attempt to disclaim copyright and place the software
42
+in the public domain is deemed null and void, then the software is
43
+Copyright (c) 1998-2011 Solar Designer and it is hereby released to the
44
+general public under the following terms:
46
+Redistribution and use in source and binary forms, with or without
47
+modification, are permitted.
49
-There's absolutely no warranty.
50
+There's ABSOLUTELY NO WARRANTY, express or implied.
52
It is my intent that you should be able to use this on your system,
53
-as a part of a software package, or anywhere else to improve security,
54
+as part of a software package, or anywhere else to improve security,
55
ensure compatibility, or for any other purpose. I would appreciate
56
it if you give credit where it is due and keep your modifications in
57
the public domain as well, but I don't require that in order to let
58
you place this code and any modifications you make under a license
61
-This implementation is compatible with OpenBSD bcrypt.c (version 2a)
62
-by Niels Provos <provos at citi.umich.edu>, and uses some of his
63
+This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix
64
+"$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
65
ideas. The password hashing algorithm was designed by David Mazieres
67
+<dm at lcs.mit.edu>. For more information on the level of compatibility,
68
+please refer to the comments in BF_set_key() and to the crypt(3) man page
69
+included in the crypt_blowfish tarball.
71
There's a paper on the algorithm that explains its design decisions:
73
Index: b/ext/standard/crypt_blowfish.c
74
===================================================================
75
--- a/ext/standard/crypt_blowfish.c
76
+++ b/ext/standard/crypt_blowfish.c
78
+/* $Id: crypt_blowfish.c 313406 2011-07-18 21:26:29Z pajoye $ */
80
- $Id: crypt_blowfish.c 295339 2010-02-21 23:47:14Z pajoye $
83
+ * The crypt_blowfish homepage is:
85
+ * http://www.openwall.com/crypt/
87
* This code comes from John the Ripper password cracker, with reentrant
88
* and crypt(3) interfaces added, but optimizations specific to password
91
- * Written by Solar Designer <solar at openwall.com> in 1998-2002 and
92
- * placed in the public domain.
93
+ * Written by Solar Designer <solar at openwall.com> in 1998-2011.
94
+ * No copyright is claimed, and the software is hereby placed in the public
95
+ * domain. In case this attempt to disclaim copyright and place the software
96
+ * in the public domain is deemed null and void, then the software is
97
+ * Copyright (c) 1998-2011 Solar Designer and it is hereby released to the
98
+ * general public under the following terms:
100
- * There's absolutely no warranty.
101
+ * Redistribution and use in source and binary forms, with or without
102
+ * modification, are permitted.
104
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
106
* It is my intent that you should be able to use this on your system,
107
- * as a part of a software package, or anywhere else to improve security,
108
+ * as part of a software package, or anywhere else to improve security,
109
* ensure compatibility, or for any other purpose. I would appreciate
110
* it if you give credit where it is due and keep your modifications in
111
* the public domain as well, but I don't require that in order to let
112
* you place this code and any modifications you make under a license
115
- * This implementation is compatible with OpenBSD bcrypt.c (version 2a)
116
- * by Niels Provos <provos at citi.umich.edu>, and uses some of his
117
+ * This implementation is mostly compatible with OpenBSD's bcrypt.c (prefix
118
+ * "$2a$") by Niels Provos <provos at citi.umich.edu>, and uses some of his
119
* ideas. The password hashing algorithm was designed by David Mazieres
120
- * <dm at lcs.mit.edu>.
121
+ * <dm at lcs.mit.edu>. For more information on the level of compatibility,
122
+ * please refer to the comments in BF_set_key() below and to the crypt(3)
123
+ * man page included in the crypt_blowfish tarball.
125
* There's a paper on the algorithm that explains its design decisions:
128
#define __set_errno(val) errno = (val)
134
-#define __CONST __const
139
-#define __CONST __const
141
+/* Just to make sure the prototypes match the actual definitions */
142
+// skip including "crypt_blowfish.h" as it's been dropped -sbeattie
149
typedef unsigned int BF_word;
150
+typedef signed int BF_word_signed;
152
/* Number of Blowfish rounds, this is also hardcoded into a few places */
154
@@ -370,35 +374,21 @@ static unsigned char BF_atoi64[0x60] = {
155
43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 64, 64, 64, 64, 64
159
- * This may be optimized out if built with function inlining and no BF_ASM.
161
-static void clean(void *data, int size)
164
- extern void _BF_clean(void *data);
166
- memset(data, 0, size);
172
#define BF_safe_atoi64(dst, src) \
174
tmp = (unsigned char)(src); \
175
- if (tmp == '$') break; \
176
+ if (tmp == '$') break; /* PHP hack */ \
177
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1; \
178
tmp = BF_atoi64[tmp]; \
179
if (tmp > 63) return -1; \
183
-static int BF_decode(BF_word *dst, __CONST char *src, int size)
184
+static int BF_decode(BF_word *dst, const char *src, int size)
186
unsigned char *dptr = (unsigned char *)dst;
187
unsigned char *end = dptr + size;
188
- unsigned char *sptr = (unsigned char *)src;
189
+ const unsigned char *sptr = (const unsigned char *)src;
190
unsigned int tmp, c1, c2, c3, c4;
193
@@ -415,16 +405,16 @@ static int BF_decode(BF_word *dst, __CON
194
*dptr++ = ((c3 & 0x03) << 6) | c4;
195
} while (dptr < end);
198
+ while (dptr < end) /* PHP hack */
204
-static void BF_encode(char *dst, __CONST BF_word *src, int size)
205
+static void BF_encode(char *dst, const BF_word *src, int size)
207
- unsigned char *sptr = (unsigned char *)src;
208
- unsigned char *end = sptr + size;
209
+ const unsigned char *sptr = (const unsigned char *)src;
210
+ const unsigned char *end = sptr + size;
211
unsigned char *dptr = (unsigned char *)dst;
214
@@ -555,32 +545,117 @@ static void BF_swap(BF_word *x, int coun
215
} while (ptr < &data.ctx.S[3][0xFF]);
218
-static void BF_set_key(__CONST char *key, BF_key expanded, BF_key initial)
219
+static void BF_set_key(const char *key, BF_key expanded, BF_key initial,
220
+ unsigned char flags)
222
- __CONST char *ptr = key;
225
+ const char *ptr = key;
226
+ unsigned int bug, i, j;
227
+ BF_word safety, sign, diff, tmp[2];
230
+ * There was a sign extension bug in older revisions of this function. While
231
+ * we would have liked to simply fix the bug and move on, we have to provide
232
+ * a backwards compatibility feature (essentially the bug) for some systems and
233
+ * a safety measure for some others. The latter is needed because for certain
234
+ * multiple inputs to the buggy algorithm there exist easily found inputs to
235
+ * the correct algorithm that produce the same hash. Thus, we optionally
236
+ * deviate from the correct algorithm just enough to avoid such collisions.
237
+ * While the bug itself affected the majority of passwords containing
238
+ * characters with the 8th bit set (although only a percentage of those in a
239
+ * collision-producing way), the anti-collision safety measure affects
240
+ * only a subset of passwords containing the '\xff' character (not even all of
241
+ * those passwords, just some of them). This character is not found in valid
242
+ * UTF-8 sequences and is rarely used in popular 8-bit character encodings.
243
+ * Thus, the safety measure is unlikely to cause much annoyance, and is a
244
+ * reasonable tradeoff to use when authenticating against existing hashes that
245
+ * are not reliably known to have been computed with the correct algorithm.
247
+ * We use an approach that tries to minimize side-channel leaks of password
248
+ * information - that is, we mostly use fixed-cost bitwise operations instead
249
+ * of branches or table lookups. (One conditional branch based on password
250
+ * length remains. It is not part of the bug aftermath, though, and is
251
+ * difficult and possibly unreasonable to avoid given the use of C strings by
252
+ * the caller, which results in similar timing leaks anyway.)
254
+ * For actual implementation, we set an array index in the variable "bug"
255
+ * (0 means no bug, 1 means sign extension bug emulation) and a flag in the
256
+ * variable "safety" (bit 16 is set when the safety measure is requested).
257
+ * Valid combinations of settings are:
259
+ * Prefix "$2a$": bug = 0, safety = 0x10000
260
+ * Prefix "$2x$": bug = 1, safety = 0
261
+ * Prefix "$2y$": bug = 0, safety = 0
263
+ bug = (unsigned int)flags & 1;
264
+ safety = ((BF_word)flags & 2) << 15;
268
for (i = 0; i < BF_N + 2; i++) {
270
+ tmp[0] = tmp[1] = 0;
271
for (j = 0; j < 4; j++) {
275
- if (!*ptr) ptr = key; else ptr++;
277
+ tmp[0] |= (unsigned char)*ptr; /* correct */
279
+ tmp[1] |= (BF_word_signed)(signed char)*ptr; /* bug */
281
+ * Sign extension in the first char has no effect - nothing to overwrite yet,
282
+ * and those extra 24 bits will be fully shifted out of the 32-bit word. For
283
+ * chars 2, 3, 4 in each four-char block, we set bit 7 of "sign" if sign
284
+ * extension in tmp[1] occurs. Once this flag is set, it remains set.
287
+ sign |= tmp[1] & 0x80;
293
+ diff |= tmp[0] ^ tmp[1]; /* Non-zero on any differences */
296
- initial[i] = BF_init_state.P[i] ^ tmp;
297
+ expanded[i] = tmp[bug];
298
+ initial[i] = BF_init_state.P[i] ^ tmp[bug];
302
+ * At this point, "diff" is zero iff the correct and buggy algorithms produced
303
+ * exactly the same result. If so and if "sign" is non-zero, which indicates
304
+ * that there was a non-benign sign extension, this means that we have a
305
+ * collision between the correctly computed hash for this password and a set of
306
+ * passwords that could be supplied to the buggy algorithm. Our safety measure
307
+ * is meant to protect from such many-buggy to one-correct collisions, by
308
+ * deviating from the correct algorithm in such cases. Let's check for this.
310
+ diff |= diff >> 16; /* still zero iff exact match */
311
+ diff &= 0xffff; /* ditto */
312
+ diff += 0xffff; /* bit 16 set iff "diff" was non-zero (on non-match) */
313
+ sign <<= 9; /* move the non-benign sign extension flag to bit 16 */
314
+ sign &= ~diff & safety; /* action needed? */
317
+ * If we have determined that we need to deviate from the correct algorithm,
318
+ * flip bit 16 in initial expanded key. (The choice of 16 is arbitrary, but
319
+ * let's stick to it now. It came out of the approach we used above, and it's
320
+ * not any worse than any other choice we could make.)
322
+ * It is crucial that we don't do the same to the expanded key used in the main
323
+ * Eksblowfish loop. By doing it to only one of these two, we deviate from a
324
+ * state that could be directly specified by a password to the buggy algorithm
325
+ * (and to the fully correct one as well, but that's a side-effect).
327
+ initial[0] ^= sign;
330
-char *php_crypt_blowfish_rn(__CONST char *key, __CONST char *setting,
331
- char *output, int size)
332
+static char *BF_crypt(const char *key, const char *setting,
333
+ char *output, int size,
337
extern void _BF_body_r(BF_ctx *ctx);
339
+ static const unsigned char flags_by_subtype[26] =
340
+ {2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
341
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 0};
345
@@ -602,7 +677,8 @@ char *php_crypt_blowfish_rn(__CONST char
347
if (setting[0] != '$' ||
349
- setting[2] != 'a' ||
350
+ setting[2] < 'a' || setting[2] > 'z' ||
351
+ !flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a'] ||
353
setting[4] < '0' || setting[4] > '3' ||
354
setting[5] < '0' || setting[5] > '9' ||
355
@@ -613,15 +689,14 @@ char *php_crypt_blowfish_rn(__CONST char
358
count = (BF_word)1 << ((setting[4] - '0') * 10 + (setting[5] - '0'));
359
- if (count < 16 || BF_decode(data.binary.salt, &setting[7], 16)) {
360
- clean(data.binary.salt, sizeof(data.binary.salt));
361
+ if (count < min || BF_decode(data.binary.salt, &setting[7], 16)) {
366
BF_swap(data.binary.salt, 4);
368
- BF_set_key(key, data.expanded_key, data.ctx.P);
369
+ BF_set_key(key, data.expanded_key, data.ctx.P,
370
+ flags_by_subtype[(unsigned int)(unsigned char)setting[2] - 'a']);
372
memcpy(data.ctx.S, BF_init_state.S, sizeof(data.ctx.S));
374
@@ -651,51 +726,33 @@ char *php_crypt_blowfish_rn(__CONST char
375
} while (ptr < &data.ctx.S[3][0xFF]);
378
- data.ctx.P[0] ^= data.expanded_key[0];
379
- data.ctx.P[1] ^= data.expanded_key[1];
380
- data.ctx.P[2] ^= data.expanded_key[2];
381
- data.ctx.P[3] ^= data.expanded_key[3];
382
- data.ctx.P[4] ^= data.expanded_key[4];
383
- data.ctx.P[5] ^= data.expanded_key[5];
384
- data.ctx.P[6] ^= data.expanded_key[6];
385
- data.ctx.P[7] ^= data.expanded_key[7];
386
- data.ctx.P[8] ^= data.expanded_key[8];
387
- data.ctx.P[9] ^= data.expanded_key[9];
388
- data.ctx.P[10] ^= data.expanded_key[10];
389
- data.ctx.P[11] ^= data.expanded_key[11];
390
- data.ctx.P[12] ^= data.expanded_key[12];
391
- data.ctx.P[13] ^= data.expanded_key[13];
392
- data.ctx.P[14] ^= data.expanded_key[14];
393
- data.ctx.P[15] ^= data.expanded_key[15];
394
- data.ctx.P[16] ^= data.expanded_key[16];
395
- data.ctx.P[17] ^= data.expanded_key[17];
399
- tmp1 = data.binary.salt[0];
400
- tmp2 = data.binary.salt[1];
401
- tmp3 = data.binary.salt[2];
402
- tmp4 = data.binary.salt[3];
403
- data.ctx.P[0] ^= tmp1;
404
- data.ctx.P[1] ^= tmp2;
405
- data.ctx.P[2] ^= tmp3;
406
- data.ctx.P[3] ^= tmp4;
407
- data.ctx.P[4] ^= tmp1;
408
- data.ctx.P[5] ^= tmp2;
409
- data.ctx.P[6] ^= tmp3;
410
- data.ctx.P[7] ^= tmp4;
411
- data.ctx.P[8] ^= tmp1;
412
- data.ctx.P[9] ^= tmp2;
413
- data.ctx.P[10] ^= tmp3;
414
- data.ctx.P[11] ^= tmp4;
415
- data.ctx.P[12] ^= tmp1;
416
- data.ctx.P[13] ^= tmp2;
417
- data.ctx.P[14] ^= tmp3;
418
- data.ctx.P[15] ^= tmp4;
419
- data.ctx.P[16] ^= tmp1;
420
- data.ctx.P[17] ^= tmp2;
424
+ for (i = 0; i < BF_N + 2; i += 2) {
425
+ data.ctx.P[i] ^= data.expanded_key[i];
426
+ data.ctx.P[i + 1] ^= data.expanded_key[i + 1];
436
+ tmp1 = data.binary.salt[0];
437
+ tmp2 = data.binary.salt[1];
438
+ tmp3 = data.binary.salt[2];
439
+ tmp4 = data.binary.salt[3];
440
+ for (i = 0; i < BF_N; i += 4) {
441
+ data.ctx.P[i] ^= tmp1;
442
+ data.ctx.P[i + 1] ^= tmp2;
443
+ data.ctx.P[i + 2] ^= tmp3;
444
+ data.ctx.P[i + 3] ^= tmp4;
446
+ data.ctx.P[16] ^= tmp1;
447
+ data.ctx.P[17] ^= tmp2;
451
for (i = 0; i < 6; i += 2) {
452
@@ -721,19 +778,114 @@ char *php_crypt_blowfish_rn(__CONST char
453
BF_encode(&output[7 + 22], data.binary.output, 23);
454
output[7 + 22 + 31] = '\0';
456
-/* Overwrite the most obvious sensitive data we have on the stack. Note
457
- * that this does not guarantee there's no sensitive data left on the
458
- * stack and/or in registers; I'm not aware of portable code that does. */
459
- clean(&data, sizeof(data));
464
-char *php_crypt_gensalt_blowfish_rn(unsigned long count,
465
- __CONST char *input, int size, char *output, int output_size)
466
+static int _crypt_output_magic(const char *setting, char *output, int size)
475
+ if (setting[0] == '*' && setting[1] == '0')
482
+ * Please preserve the runtime self-test. It serves two purposes at once:
484
+ * 1. We really can't afford the risk of producing incompatible hashes e.g.
485
+ * when there's something like gcc bug 26587 again, whereas an application or
486
+ * library integrating this code might not also integrate our external tests or
487
+ * it might not run them after every build. Even if it does, the miscompile
488
+ * might only occur on the production build, but not on a testing build (such
489
+ * as because of different optimization settings). It is painful to recover
490
+ * from incorrectly-computed hashes - merely fixing whatever broke is not
491
+ * enough. Thus, a proactive measure like this self-test is needed.
493
+ * 2. We don't want to leave sensitive data from our actual password hash
494
+ * computation on the stack or in registers. Previous revisions of the code
495
+ * would do explicit cleanups, but simply running the self-test after hash
496
+ * computation is more reliable.
498
+ * The performance cost of this quick self-test is around 0.6% at the "$2a$08"
501
+char *php_crypt_blowfish_rn(const char *key, const char *setting,
502
+ char *output, int size)
504
+ const char *test_key = "8b \xd0\xc1\xd2\xcf\xcc\xd8";
505
+ const char *test_setting = "$2a$00$abcdefghijklmnopqrstuu";
506
+ static const char * const test_hash[2] =
507
+ {"VUrPmXD6q/nVSSp7pNDhCR9071IfIRe\0\x55", /* $2x$ */
508
+ "i1D709vfamulimlGcq0qq3UvuUasvEa\0\x55"}; /* $2a$, $2y$ */
511
+ int save_errno, ok;
513
+ char s[7 + 22 + 1];
514
+ char o[7 + 22 + 31 + 1 + 1 + 1];
517
+/* Hash the supplied password */
518
+ _crypt_output_magic(setting, output, size);
519
+ retval = BF_crypt(key, setting, output, size, 16);
520
+ save_errno = errno;
523
+ * Do a quick self-test. It is important that we make both calls to BF_crypt()
524
+ * from the same scope such that they likely use the same stack locations,
525
+ * which makes the second call overwrite the first call's sensitive data on the
526
+ * stack and makes it more likely that any alignment related issues would be
527
+ * detected by the self-test.
529
+ memcpy(buf.s, test_setting, sizeof(buf.s));
531
+ buf.s[2] = setting[2];
532
+ memset(buf.o, 0x55, sizeof(buf.o));
533
+ buf.o[sizeof(buf.o) - 1] = 0;
534
+ p = BF_crypt(test_key, buf.s, buf.o, sizeof(buf.o) - (1 + 1), 1);
536
+ ok = (p == buf.o &&
537
+ !memcmp(p, buf.s, 7 + 22) &&
538
+ !memcmp(p + (7 + 22),
539
+ test_hash[(unsigned int)(unsigned char)buf.s[2] & 1],
543
+ const char *k = "\xff\xa3" "34" "\xff\xff\xff\xa3" "345";
544
+ BF_key ae, ai, ye, yi;
545
+ BF_set_key(k, ae, ai, 2); /* $2a$ */
546
+ BF_set_key(k, ye, yi, 4); /* $2y$ */
547
+ ai[0] ^= 0x10000; /* undo the safety (for comparison) */
548
+ ok = ok && ai[0] == 0xdb9c59bc && ye[17] == 0x33343500 &&
549
+ !memcmp(ae, ye, sizeof(ae)) &&
550
+ !memcmp(ai, yi, sizeof(ai));
553
+ __set_errno(save_errno);
557
+/* Should not happen */
558
+ _crypt_output_magic(setting, output, size);
559
+ __set_errno(EINVAL); /* pretend we don't support this hash type */
564
+char *_crypt_gensalt_blowfish_rn(const char *prefix, unsigned long count,
565
+ const char *input, int size, char *output, int output_size)
567
if (size < 16 || output_size < 7 + 22 + 1 ||
568
- (count && (count < 4 || count > 31))) {
569
+ (count && (count < 4 || count > 31)) ||
570
+ prefix[0] != '$' || prefix[1] != '2' ||
571
+ (prefix[2] != 'a' && prefix[2] != 'y')) {
572
if (output_size > 0) output[0] = '\0';
573
__set_errno((output_size < 7 + 22 + 1) ? ERANGE : EINVAL);
575
@@ -743,14 +895,15 @@ char *php_crypt_gensalt_blowfish_rn(unsi
580
+ output[2] = prefix[2];
582
output[4] = '0' + count / 10;
583
output[5] = '0' + count % 10;
586
- BF_encode(&output[7], (BF_word *)input, 16);
587
+ BF_encode(&output[7], (const BF_word *)input, 16);
588
output[7 + 22] = '\0';