PHP 8.1: New Sodium XChaCha20 functions

Version8.1
TypeNew Feature

Sodium extension in PHP 8.1 provides an XChaCha20 stream encryption algorithm, available since libsodium 1.0.12.

XChaCha20 is a stream cipher, and is a variant of the ChaCha20 algorithm. Sodium PHP extension already supports XChaCha20 with Poly1305 Message Authentication Code (MAC). In PHP 8.1, three new functions provide direct XChaCha20 functionality without authentication, also known as "detached mode".

Security Warning XChaCha20's encryption is unauthenticated. Without authentication, any decryption operation will be vulnerable to chosen-ciphertext attacks. PHP already provides Poly1305-authenticated XChaCha20 encryption with sodium_crypto_aead_xchacha20poly1305_ietf_encrypt / decrypt functions, available since PHP 7.2.

Additionally, there are two new PHP constants defined in the global namespace:

  • SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES, assigned 32
  • SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES, assigned 24.

sodium_crypto_stream_xchacha20_keygen

The new sodium_crypto_stream_xchacha20_keygen function in PHP 8.1's Sodium extension returns cryptographically secure random bytes of a length, suitable to be used with the XChaCha20 encryption.

sodium_crypto_stream_xchacha20_keygen function synopsis

/**
 * Returns a secure random key for use with @see sodium_crypto_stream_xchacha20
 * @return string 32-byte secure random key
 */
function sodium_crypto_stream_xchacha20_keygen(): string {}

Return value will be of length SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES constant, set to 32. It will a binary string, that cannot be printed directly without encoding it as a base64, hex, or some sort of binary encoding.

base64_encode(sodium_crypto_stream_xchacha20_keygen());
// "b0C4GUTNmJ/xzcxoXT0hgWqH7xs78f1Tc4W/9sEldbM="

sodium_crypto_stream_xchacha20

The sodium_crypto_stream_xchacha20 function returns a pseudo random stream of bytes, that can be used to encrypt a message using the new sodium_crypto_stream_xchacha20_xor function.

sodium_crypto_stream_xchacha20 function synopsis

/**
 * Expands the key and nonce into a keystream of pseudorandom bytes.
 * @param int $length Number of bytes desired
 * @param string $nonce 24-byte nonce
 * @param string $key Key, possibly generated from @see sodium_crypto_stream_xchacha20_keygen
 * @return string Pseudorandom stream that can be used with @see sodium_crypto_stream_xchacha20_xor
 */
function sodium_crypto_stream_xchacha20(int $length, string $nonce, string $key): string {}
  • string $nonce parameter must be a string containing 24 bytes (SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES).
  • string $key parameter must be a string containing 32 bytes (SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES). sodium_crypto_stream_xchacha20_keygen generates a suitable key.

Usage example:

$key = sodium_crypto_stream_xchacha20_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES);

$stream = sodium_crypto_stream_xchacha20(8, $nonce, $key);
bin2hex($stream); // "27fa21568e076f7"

$stream = sodium_crypto_stream_xchacha20(11, $nonce, $key);
bin2hex($stream); // "727fa21568e076f7f496e4"

$stream = sodium_crypto_stream_xchacha20(12, $nonce, $key);
bin2hex($stream); // "727fa21568e076f7f496e4e9"

sodium_crypto_stream_xchacha20_xor

sodium_crypto_stream_xchacha20_xor function encrypts/decrypts a given message using the nonce and key.

This encryption is unauthenticated, and does not prevent chosen-ciphertext attacks. Make sure to combine the ciphertext with a Message Authentication Code, for example with sodium_crypto_aead_xchacha20poly1305_ietf_encrypt / decrypt functions, or sodium_crypto_auth

sodium_crypto_stream_xchacha20_xor function synopsis

/**
 * Encrypts a message using a nonce and a secret key.
 * @param string $message Plain text or ciphertext
 * @param string $nonce 24-byte nonce
 * @param string $key Key, possibly generated from @see sodium_crypto_stream_xchacha20_keygen
 * @return string Ciphertext or the plain-text
 */
function sodium_crypto_stream_xchacha20_xor(string $message, string $nonce, string $key): string {}
  • string $nonce parameter must be a string containing 24 bytes (SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES).
  • string $key parameter must be a string containing 32 bytes (SODIUM_CRYPTO_STREAM_XCHACHA20_KEYBYTES). sodium_crypto_stream_xchacha20_keygen generates a suitable key.

Usage example:

$key = sodium_crypto_stream_xchacha20_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_STREAM_XCHACHA20_NONCEBYTES);
$message = 'PHP.Watch';

$ciphertext = sodium_crypto_stream_xchacha20_xor($message, $nonce, $key);
bin2hex($ciphertext); // "bbcebba4e3eefe0d69"

$message === sodium_crypto_stream_xchacha20_xor($ciphertext, $nonce, $key);
// true

Backwards Compatibility Impact

sodium_crypto_stream_xchacha20_keygen, sodium_crypto_stream_xchacha20, and sodium_crypto_stream_xchacha20_xor are new functions added to PHP 8.1.

PECL extension libsodium versions later than 2.0.23 will likely contain these new functions.

Alternately, the sodium_compat library provides a polyfill for all of these functions on any PHP version since PHP 5.2.4.


Implementation