: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @throws SodiumException
public static function crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit)
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
// Just grab the first 4 pieces.
$pieces = explode('$', (string) $hash);
$prefix = implode('$', array_slice($pieces, 0, 4));
// Rebuild the expected header.
$mem = (int) $memlimit >> 10;
$encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1';
// Do they match? If so, we don't need to rehash, so return false.
return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix);
* @throws SodiumException
* @psalm-suppress MixedArgument
public static function crypto_pwhash_str_verify($passwd, $hash)
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_pwhash_str_verify($passwd, $hash);
if (self::use_fallback('crypto_pwhash_str_verify')) {
return (bool) call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash);
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
* @throws SodiumException
public static function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit)
ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_pwhash_scryptsalsa208sha256(
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
return (string) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256',
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
* !Exclusive to sodium_compat!
* This returns TRUE if the native crypto_pwhash API is available by libsodium.
* This returns FALSE if only sodium_compat is available.
public static function crypto_pwhash_scryptsalsa208sha256_is_available()
if (self::useNewSodiumAPI()) {
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
* @throws SodiumException
public static function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit)
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
if (self::useNewSodiumAPI()) {
return (string) sodium_crypto_pwhash_scryptsalsa208sha256_str(
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) {
return (string) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str',
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
* @throws SodiumException
public static function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash)
ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
if (self::useNewSodiumAPI()) {
return (bool) sodium_crypto_pwhash_scryptsalsa208sha256_str_verify(
if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) {
return (bool) call_user_func(
'\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify',
// This is the best we can do.
throw new SodiumException(
'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
* Calculate the shared secret between your secret key and your
* recipient's public key.
* Algorithm: X25519 (ECDH over Curve25519)
* @param string $secretKey
* @param string $publicKey
* @throws SodiumException
* @psalm-suppress MixedArgument
public static function crypto_scalarmult($secretKey, $publicKey)
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
if (self::useNewSodiumAPI()) {
return sodium_crypto_scalarmult($secretKey, $publicKey);
if (self::use_fallback('crypto_scalarmult')) {
return (string) call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey);
/* Output validation: Forbid all-zero keys */
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
throw new SodiumException('Zero secret key is not allowed');
if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) {
throw new SodiumException('Zero public key is not allowed');
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey);
return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey);
* Calculate an X25519 public key from an X25519 secret key.
* @param string $secretKey
* @throws SodiumException
* @psalm-suppress TooFewArguments
* @psalm-suppress MixedArgument
public static function crypto_scalarmult_base($secretKey)
ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
if (self::useNewSodiumAPI()) {
return sodium_crypto_scalarmult_base($secretKey);
if (self::use_fallback('crypto_scalarmult_base')) {
return (string) call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey);
if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
throw new SodiumException('Zero secret key is not allowed');
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey);
return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey);
* Authenticated symmetric-key encryption.
* Algorithm: XSalsa20-Poly1305
* @param string $plaintext The message you're encrypting
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Ciphertext with Poly1305 MAC
* @throws SodiumException
* @psalm-suppress MixedArgument
public static function crypto_secretbox($plaintext, $nonce, $key)
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
if (self::useNewSodiumAPI()) {
return sodium_crypto_secretbox($plaintext, $nonce, $key);
if (self::use_fallback('crypto_secretbox')) {
return (string) call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key);
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key);
return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key);
* Decrypts a message previously encrypted with crypto_secretbox().
* @param string $ciphertext Ciphertext with Poly1305 MAC
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Original plaintext message
* @throws SodiumException
* @psalm-suppress MixedArgument
* @psalm-suppress MixedInferredReturnType
* @psalm-suppress MixedReturnStatement
public static function crypto_secretbox_open($ciphertext, $nonce, $key)
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
if (self::useNewSodiumAPI()) {
* @psalm-suppress InvalidReturnStatement
* @psalm-suppress FalsableReturnStatement
return sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
if (self::use_fallback('crypto_secretbox_open')) {
return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key);
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key);
return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key);
* Return a secure random key for use with crypto_secretbox
public static function crypto_secretbox_keygen()
return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES);
* Authenticated symmetric-key encryption.
* Algorithm: XChaCha20-Poly1305
* @param string $plaintext The message you're encrypting
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Ciphertext with Poly1305 MAC
* @throws SodiumException
* @psalm-suppress MixedArgument
public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key)
ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
* Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305().
* @param string $ciphertext Ciphertext with Poly1305 MAC
* @param string $nonce A Number to be used Once; must be 24 bytes
* @param string $key Symmetric encryption key
* @return string Original plaintext message
* @throws SodiumException
* @psalm-suppress MixedArgument
public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
* @return array<int, string> Returns a state and a header.
* @throws SodiumException
public static function crypto_secretstream_xchacha20poly1305_init_push($key)
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key);
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key);
* @return string Returns a state.
public static function crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
throw new SodiumException(
'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes'
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header);
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header);
* @throws SodiumException
public static function crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push(
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push(
* @return bool|array{0: string, 1: int}
* @throws SodiumException
public static function crypto_secretstream_xchacha20poly1305_pull(&$state, $msg, $aad = '')
if (PHP_INT_SIZE === 4) {
return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull(
return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull(