The new libsodium extension has brought an easy to use - hard to misconfigure - password hashing algorithm called Argon2. But, it's not exactly perfect.

libsodium aims to provide modern cryptography with all the right defaults selected. The inclusion of libsodium by default in PHP 7.2 is great. It adds a new algorithm choice to the standard password_hash() function: PASSWORD_ARGON2I. Argon2 was the winner of a password hashing contest in 2015.

But, the libsodium extension also provides its own set of functions available with the prefix sodium_crypto_*. It is noteworthy that password_hash() and password_verify() are NOT entirely compatible with the libsodium extension's sodium_crypto_pwhash_str_verify().

This is because sodium_crypto_pwhash_str() uses Argon2id and password_hash() uses Argon2i

$raw = "\0abc";
$h1 = password_hash($raw, PASSWORD_ARGON2I);
$h2 = sodium_crypto_pwhash_str(

echo "h1: " .$h1 ."\n";
echo "h2: " .$h2 ."\n";
if ( ! password_verify($raw, $h1) ) {
    echo "password_verify() false\n";

if ( ! sodium_crypto_pwhash_str_verify($h2, $raw) ) {
    echo "sodium_crypto_pwhash_str_verify() false\n";

if ( sodium_crypto_pwhash_str_verify($h1, $raw) ) {
    echo "CROSS sodium_crypto_pwhash_str_verify() can verify password_hash() 2i\n";
} else {
    echo "CROSS sodium_crypto_pwhash_str_verify() cannot verify password_hash() 2i\n";

if ( ! password_verify($raw, $h2) ) {
    echo "CROSS password_verify() cannot verify sodium_* hashed 2id\n";

h1: $argon2i$v=19$m=1024,t=2,p=2$Slg1bjlFeVY1ZWVvQ0lSQw$KOzzqmPm9B90YDWm+aEu1yJFc9sQhScrvEW52BlHx2g
h2: $argon2id$v=19$m=65536,t=2,p=1$Q/Rf5tJNZAiMJ7w+f/l62Q$r6rPzx/t0TaE3MqmTVl5s2D3giFBfHydA9AQeP9iKE0
CROSS sodium_crypto_pwhash_str_verify can verify password_hash() 2i
CROSS password_verify() cannot verify sodium_* hashed 2id

Summary Table

password_hash (Argon2i)sodium_crypto_pwhash_str (Argon2id)


password_hash() is great because you can drop in different algorithms. BUT, the recommendation is to use 2id unless you have a particular need to use either 2i or 2d. I would recommend sticking with password_hash() if you are already using it and only use sodium_crypto_* functions for brand new develoment. Maybe in the future we will get a PASSWORD_ARGON2ID constant for password_hash().