PHP Sodium Extension (Libsodium)
debt(d7/e3/b3/t5)
Closest to 'only careful code review or runtime testing' (d7). Nonce reuse, hardcoded keys, and unchecked return values from sodium_crypto_secretbox_open() are not caught by standard PHP linters; SAST tools like Psalm/Phan don't flag cryptographic misuse by default. Code review catches these.
Closest to 'simple parameterised fix' (e3). quick_fix describes replacing openssl_encrypt()+HMAC with sodium_crypto_secretbox() — a pattern swap, not a single line, but contained to crypto call sites.
Closest to 'localised tax' (b3). Sodium usage is typically confined to a crypto/auth module; applies_to is web/cli but the choice doesn't shape the whole system — it's a library swap with a small surface.
Closest to 'notable trap' (t5). The misconception about installation is minor, but sodium_crypto_secretbox_open() returning false instead of throwing, plus nonce-uniqueness requirements, are documented gotchas developers must learn — contradicts exception-based error handling expected elsewhere in modern PHP.
Also Known As
TL;DR
Explanation
Libsodium is an opinionated cryptography library that deliberately offers only modern, well-analysed algorithms — there are no knobs to configure cipher modes, key sizes, or padding, because the library makes the right choices for you. PHP's Sodium extension wraps it directly. For symmetric encryption, sodium_crypto_secretbox() uses XSalsa20-Poly1305 — an authenticated encryption scheme that provides both confidentiality and integrity in one function. For asymmetric encryption, sodium_crypto_box() uses X25519+XSalsa20-Poly1305. Password hashing uses Argon2id. Key generation uses /dev/urandom via sodium_crypto_secretbox_keygen(). The extension is bundled with PHP 7.2+ and requires no installation on modern systems.
Common Misconception
Why It Matters
Common Mistakes
- Reusing nonces with the same key — each encryption must use a unique nonce; use random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES) each time.
- Storing the key in source code or configuration files — use environment variables or a secrets manager (HashiCorp Vault, AWS Secrets Manager).
- Using sodium for password hashing when Argon2 via password_hash() would do — password_hash(PASSWORD_ARGON2ID) is simpler for storing user passwords; Sodium's API is better for general-purpose authenticated encryption.
- Forgetting to check the return value of sodium_crypto_secretbox_open() — it returns false on authentication failure, not an exception; always check.
Code Examples
<?php
// ❌ OpenSSL with common mistakes — ECB mode, no authentication
$key = 'mysecretkey12345'; // Weak key, wrong length
$encrypted = openssl_encrypt(
$plaintext,
'AES-128-ECB', // ECB mode — reveals patterns in data
$key
// No IV, no authentication tag — malleable ciphertext
);
<?php
// ✅ Sodium — authenticated encryption, correct by default
$key = sodium_crypto_secretbox_keygen(); // 256-bit random key
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 192-bit nonce
$ciphertext = sodium_crypto_secretbox($plaintext, $nonce, $key);
// $ciphertext is encrypted AND authenticated — any tampering is detected on decrypt
// Store: base64_encode($nonce . $ciphertext)
$combined = base64_decode($stored);
$nonce = substr($combined, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ct = substr($combined, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$plaintext = sodium_crypto_secretbox_open($ct, $nonce, $key);
if ($plaintext === false) {
throw new RuntimeException('Decryption failed — data tampered or wrong key');
}