I've been tasked with improving the security of the password storage of a site which currently uses Openwall's PHPass. All the hashes will be converted at once, i. e. we don't want to wait for the user to log in to re-hash their password.
To achieve this I thought we could use bcrypt over the existing PHPass hashes, this way: bcrypt(phpass(password))
But we need an important intermediate step: just like bcrypt, PHPass has its own salt embedded into the hash, so we have to "carry" that salt into bcrypt if we want the operation to be repeatable when verifying the hashes.
Luckily, PHPass' salt size is smaller (6 bytes) than bcrypt's (16 bytes), so we can "share" the first 6 bytes of the salt and adding 10 additional random bytes for bcrypt.
Imagine something like this in pseudo-PHP:
$password = 'somestring123';
$hash = phpass($password)
// $hash is now '$H$9Uvsrbh2Wxo3SebfGb4xVtODMmD2K70',
// where 'Uvsrbh2W' is an encoded, random salt of 6 'raw' bytes
$raw_salt = decode(substr($hash, 4, 8));
$hash = bcrypt_with_custom_salt($hash, $raw_salt . random_bytes(10));
// $hash is now '$2y$12$Uvsrbh2WzN9HrapVpnmu2OYOdJ2jnjHt2LTwIYQPJe.BUJQKezKuO'
// whose salt uses the first 6 bytes we had in phpass,
// so that we can repeat the process when veryfing the password
// since we have all the salts available in only one hash
Barring any implementation bugs and assuming the random sources are cryptographically secure, is this a theoretically secure way to use bcrypt in a legacy context? From my understanding the result should be as secure (if not more...?) as just doing bcrypt(password)
, but I'm not an expert and I might be missing some obscure detail.