Hi,
First of all, thank you for getting this functionality into PHP proper.
It appears that the file was very slightly out of date. crypt_blowfish
1.0.2 additionally made this change:
-#elif defined(alpha) || defined(hppa)
+#elif defined(x86_64) || defined(alpha) || defined(hppa)
which improved performance on x86_64. I recommend that you apply the
change to the copy in PHP as well.
The function php_crypt_gensalt_blowfish_rn() appears to be unused.
If so, I suggest #if 0'ing it for now.
Finally, I'd like to ask whoever made the following change about the
rationale behind it:
--- ../crypt_blowfish-1.0.2/crypt_blowfish.c 2006-05-22 23:52:41 +0000
+++ ext/standard/crypt_blowfish.c 2008-08-14 01:13:18 +0000
[...]
@@ -380,6 +387,7 @@
#define BF_safe_atoi64(dst, src)
{
tmp = (unsigned char)(src); \
-
if (tmp == '$') break;
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1;
tmp = BF_atoi64[tmp];
if (tmp > 63) return -1;
@@ -407,6 +415,9 @@ static int BF_decode(BF_word *dst, __CON
*dptr++ = ((c3 & 0x03) << 6) | c4;
} while (dptr < end); -
while (dptr < end)
-
*dptr++ = 0;
-
return 0;
}
My understanding is that this "adds support" for salt strings shorter
than those bcrypt (the password hashing method we're talking about)
normally requires, but only as long as they're terminated with a dollar
sign. Why is this needed, and is it? Do we really want to encourage
sloppy programming? I don't think this may support any extra existing
bcrypt-like hashes, which might have been generated by sloppy
implementations, because the encodings for newly computed hashes (during
authentication) would be full-length anyway. Am I missing something?
Thanks again,
Alexander
P.S. For those who don't know yet, my "upstream" version of the code is
available here:
http://www.openwall.com/crypt/
http://cvsweb.openwall.com/crypt
hi,
Hi,
First of all, thank you for getting this functionality into PHP proper.
Thank for your work, I'm the one who merged your implementation to PHP
(we had a discussion about it btw, per email if you remember :).
It appears that the file was very slightly out of date. crypt_blowfish
1.0.2 additionally made this change:-#elif defined(alpha) || defined(hppa)
+#elif defined(x86_64) || defined(alpha) || defined(hppa)which improved performance on x86_64. I recommend that you apply the
change to the copy in PHP as well.The function php_crypt_gensalt_blowfish_rn() appears to be unused.
If so, I suggest #if 0'ing it for now.
Thanks for the review and the notice, I'll update the code tomorrow
(5.3+ have it).
Finally, I'd like to ask whoever made the following change about the
rationale behind it:
Backward compatibility was the reason. I like to drop this thing in
php6 but it was not possible to do it in a minor release (I discussed
it with Stefan Esser last year). I'm not sure yet how but certainly by
providing another function or changing the API to allow one to disable
the old behavior.
--- ../crypt_blowfish-1.0.2/crypt_blowfish.c 2006-05-22 23:52:41 +0000
+++ ext/standard/crypt_blowfish.c 2008-08-14 01:13:18 +0000
[...]
@@ -380,6 +387,7 @@
#define BF_safe_atoi64(dst, src)
{
tmp = (unsigned char)(src); \
if (tmp == '$') break;
if ((unsigned int)(tmp -= 0x20) >= 0x60) return -1;
tmp = BF_atoi64[tmp];
if (tmp > 63) return -1;
@@ -407,6 +415,9 @@ static int BF_decode(BF_word *dst, __CON
*dptr++ = ((c3 & 0x03) << 6) | c4;
} while (dptr < end);while (dptr < end)
*dptr++ = 0;
return 0;
}My understanding is that this "adds support" for salt strings shorter
than those bcrypt (the password hashing method we're talking about)
normally requires, but only as long as they're terminated with a dollar
sign. Why is this needed, and is it? Do we really want to encourage
sloppy programming? I don't think this may support any extra existing
bcrypt-like hashes, which might have been generated by sloppy
implementations, because the encodings for newly computed hashes (during
authentication) would be full-length anyway. Am I missing something?Thanks again,
Alexander
P.S. For those who don't know yet, my "upstream" version of the code is
available here:http://www.openwall.com/crypt/
http://cvsweb.openwall.com/crypt
Cheers,
Pierre
Thank for your work, I'm the one who merged your implementation to PHP
(we had a discussion about it btw, per email if you remember :).
Yes, I recalled that, and this is why I CC'ed you on my posting.
Thanks for the review and the notice, I'll update the code tomorrow
(5.3+ have it).
I see that the x86_64 check went in. Thanks!
Finally, I'd like to ask whoever made the following change about the
rationale behind it:Backward compatibility was the reason. I like to drop this thing in
php6 but it was not possible to do it in a minor release (I discussed
it with Stefan Esser last year). I'm not sure yet how but certainly by
providing another function or changing the API to allow one to disable
the old behavior.
Here's what I found out:
- The documentation at http://www.php.net/manual/en/function.crypt.php
remains wrong. It says:
"CRYPT_BLOWFISH - Blowfish encryption with a sixteen character salt
starting with $2$ or $2a$"
Well, the salt string should be 22 characters (after the "$2a$nn$"
prefix, or 29 characters including this prefix). The salt is 16 bytes,
not 16 characters.
-
"Example #3 Using
crypt()
with different encryption types" at
http://www.php.net/manual/en/function.crypt.php is also wrong, in a
different way. It has:echo 'Blowfish: ' . crypt('rasmuslerdorf', '$2a$07$rasmuslerd...........$') . "\n";
Apparently, this works with the workaround in the Suhosin patch, and
thus with current PHP 5.3.0 development code, but it fails on systems
that have bcrypt hashes supported natively (in libc or libcrypt) and do
not have the workaround in there. This comment is just right:
http://www.php.net/manual/en/function.crypt.php#71748
- Yes, I now see that the workaround came from a revision of my code in
the Suhosin patch. However, it is not clear to me what exactly this
workaround was for, and backwards compatibility with what it provides
now. Is it just compatibility with the above incorrect example in the
documentation? If so, I see no problem with dropping it now, because
the example did not work universally anyway (it failed on many or
probably even on most systems that had support for bcrypt hashes at all).
I hope these observations are of some help.
A somewhat related concern: what does PHP's crypt()
return on error?
In my crypt_blowfish package, I had a higher-level wrapper function that
would guarantee return of a string not matching the input "salt" string,
thus guaranteeing that authentication will fail. I don't think PHP
currently has similar code; perhaps it should. Also, documentation
should be revised to document behavior of crypt()
on error, for both
historical and current/future versions of PHP. Because in many cases
this depends on the underlying system libraries, I suggest that advice
be given to treat any return strings shorter than 13 characters as
indicating an error.
In fact, PHP itself could start to implement the safe behavior by
checking whether the would-be crypt()
return string is shorter than 13
characters (regardless of where it came from). If so, return "*0" if
the input salt string does not start with "*0", or return "*1" if the
input salt string starts with "*0".
Here's an excerpt from wrapper.c in my crypt_blowfish package:
output[0] = '*';
output[1] = '0';
output[2] = '\0';
if (setting[0] == '*' && setting[1] == '0')
output[1] = '1';
Thanks,
Alexander
hi Alexander,
Thanks for the feedbacks! these questions are the same I had when I
was making crypt portable (having all algos available in any
situation).
Sadly I do not have the time yet to fix the behavior (remove the
workaround/BC hack or the on error behavior). If you like to (or have
the time to :), you can five it a try, that will be very helpful. Or I
can work on that next week, at the soonest.
Cheers,
Thank for your work, I'm the one who merged your implementation to PHP
(we had a discussion about it btw, per email if you remember :).Yes, I recalled that, and this is why I CC'ed you on my posting.
Thanks for the review and the notice, I'll update the code tomorrow
(5.3+ have it).I see that the x86_64 check went in. Thanks!
Finally, I'd like to ask whoever made the following change about the
rationale behind it:Backward compatibility was the reason. I like to drop this thing in
php6 but it was not possible to do it in a minor release (I discussed
it with Stefan Esser last year). I'm not sure yet how but certainly by
providing another function or changing the API to allow one to disable
the old behavior.Here's what I found out:
- The documentation at http://www.php.net/manual/en/function.crypt.php
remains wrong. It says:"CRYPT_BLOWFISH - Blowfish encryption with a sixteen character salt
starting with $2$ or $2a$"Well, the salt string should be 22 characters (after the "$2a$nn$"
prefix, or 29 characters including this prefix). The salt is 16 bytes,
not 16 characters.
- "Example #3 Using
crypt()
with different encryption types" at
http://www.php.net/manual/en/function.crypt.php is also wrong, in a
different way. It has:echo 'Blowfish: ' . crypt('rasmuslerdorf', '$2a$07$rasmuslerd...........$') . "\n";
Apparently, this works with the workaround in the Suhosin patch, and
thus with current PHP 5.3.0 development code, but it fails on systems
that have bcrypt hashes supported natively (in libc or libcrypt) and do
not have the workaround in there. This comment is just right:http://www.php.net/manual/en/function.crypt.php#71748
- Yes, I now see that the workaround came from a revision of my code in
the Suhosin patch. However, it is not clear to me what exactly this
workaround was for, and backwards compatibility with what it provides
now. Is it just compatibility with the above incorrect example in the
documentation? If so, I see no problem with dropping it now, because
the example did not work universally anyway (it failed on many or
probably even on most systems that had support for bcrypt hashes at all).I hope these observations are of some help.
A somewhat related concern: what does PHP's
crypt()
return on error?In my crypt_blowfish package, I had a higher-level wrapper function that
would guarantee return of a string not matching the input "salt" string,
thus guaranteeing that authentication will fail. I don't think PHP
currently has similar code; perhaps it should. Also, documentation
should be revised to document behavior ofcrypt()
on error, for both
historical and current/future versions of PHP. Because in many cases
this depends on the underlying system libraries, I suggest that advice
be given to treat any return strings shorter than 13 characters as
indicating an error.In fact, PHP itself could start to implement the safe behavior by
checking whether the would-becrypt()
return string is shorter than 13
characters (regardless of where it came from). If so, return "*0" if
the input salt string does not start with "*0", or return "*1" if the
input salt string starts with "*0".Here's an excerpt from wrapper.c in my crypt_blowfish package:
output[0] = '*';
output[1] = '0';
output[2] = '\0';if (setting[0] == '*' && setting[1] == '0')
output[1] = '1';Thanks,
Alexander
--
Pierre
Sadly I do not have the time yet to fix the behavior (remove the
workaround/BC hack or the on error behavior). If you like to (or have
the time to :), you can five it a try, that will be very helpful. Or I
can work on that next week, at the soonest.
I'm afraid I don't have time for much more than commenting on my code,
which I feel somewhat responsible to do. Next week sounds fine to me.
As to removing "the workaround/BC hack", I think this amounts to
removing these lines:
- if (tmp == '$') break;
... - while (dptr < end)
-
*dptr++ = 0;
(as seen in the diff I had posted). The test in crypt.phpt looks fine
to me (that is, it tests for the correct behavior already).
Thanks,
Alexander