PHP RFC: password_hash() function behavior

Introduction

password_hash() is introduced from PHP 5.5 as crypt() wrapper and has Blowfish(PASSWORD_BCRYPT) hash algorithm as the only hash function available.

Unlike other hash functions, Blowfish is designed to take limited length as its parameter. Bytes longer than 72 bytes are truncated to compute hash value. Current implementation does not have check against too long parameter. Therefore, too long parameter is silently ignored. Average users expect “hash” functions compute hash value based on parameter, not part of it.

Before PHP 5.3, crypt() could not be used reliably because it didn't have required hash function internally. Therefore, code like below is used commonly. Note: According to this survey 20% of PHP users are still using PHP4 and 25% of PHP5 users are using pre PHP5.3.

If user writes code like below, password_hash() does not work for authentication when SOME_STATIC_SECRET_SALT is long enough. (e.g. const = SOME_STATIC_SECRET_SLAT = hash('sha512', 'some secret string'); hash('sha512', 'str') returns 128 bytes which is longer than 72.)

In general, users are recommended to use crypt related functions as is and this is documented currently. However, SOME_STATIC_SECRET_SALT is still useful as mitigation when password database is stolen while SOME_STATIC_SECRET_SALT is _not_ stolen. (e.g. Stolen password DB via SQL injection, stolen password db backup, etc) Therefore, some organizations require to add secret salt for an additional mitigation. 72 bytes limits is real problem in this case.

This RFC is for

Changing password_hash() behavior.

How to document password hash related functions.

Proposal

password_hash() behavior:

Add E_NOTICE error to password_hash() with PASSWORD_BCRYPT and password longer than 72 bytes. (password_hash() return result with truncated password)

Add PASSWORD_SHA512 hashing to password_hash() that is compatible with crypt-sha512