Since crypt
in PHP 5.2 doesn't support CRYPT_BLOWFISH, it is instead defaulting to interpreting the salt as a CRYPT_DES style salt. Notice that the output starts with "$2", which is the two character salt that CRYPT_DES chose from the salt input and prepended to the hash, and the output length matches the exact CRYPT_DES output length.
Interestingly, you can achieve the same result in later PHP versions with CRYPT_BLOWFISH support by simply truncating the salt to two characters. Ie:
crypt('password', '$2y$10$NzRQNjTRfP4jXKvb4TCO.G') /* in PHP 5.2 */
==
crypt('password', '$2') /* in PHP 5.4 */
In theory, this might come in handy for backwards-compatibility if a CRYPT_BLOWFISH style salt was used in error on PHP 5.2.
This actually caused me a bit of confusion recently because the "$" character isn't valid salt input for CRYPT_DES as per the PHP crypt documentation, which says:
Standard DES-based hash with a two character salt from the alphabet "./0-9A-Za-z". Using invalid characters in the salt will cause crypt() to fail.
But here the "$" character clearly seems to be accepted by crypt()
in both v5.2 and v5.4.
It would be both clearer and safer if crypt
actually returned a failure like the documentation says it's supposed to, rather than accepting the "$" and defaulting to CRYPT_DES.