openssl_encrypt()
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep and psalm as tools, and the code_pattern explicitly calls out CBC without HMAC, ECB mode, reused IVs, and missing GCM authentication tags — these are patterns that require static analysis or SAST tooling to catch; they won't surface at compile time or via a default linter.
Closest to 'simple parameterised fix' (e3). The quick_fix is a direct function-call swap to AES-256-GCM with the correct parameters. However, the fix also requires updating IV generation, storing the authentication tag alongside ciphertext, and verifying the tag before decryption — slightly more than a one-liner but well within a single-component refactor.
Closest to 'localised tax' (b3). The applies_to scope is web and cli contexts generally, but encryption usage is typically confined to specific modules (auth, storage, transmission). Once corrected, the pattern doesn't impose ongoing costs across unrelated parts of the codebase; the burden is concentrated where encryption is used.
Closest to 'serious trap' (t7). The misconception field states developers believe any AES mode is equally secure, but ECB mode leaks data patterns and unauthenticated modes allow ciphertext tampering. This contradicts intuition — the function name implies 'encryption = security' but silently omits authentication and mode correctness, which contradicts how developers reason about symmetric encryption APIs in other languages and libraries.
Also Known As
TL;DR
Explanation
openssl_encrypt($data, $cipher, $key, $options, $iv, $tag) encrypts data using OpenSSL. The recommended cipher is aes-256-gcm — an authenticated encryption mode that provides both confidentiality and integrity. Always generate a random IV with random_bytes(openssl_cipher_iv_length($cipher)) per encryption, store it alongside the ciphertext, and verify the authentication tag on decryption. Never use ECB mode (no IV, identical plaintext blocks produce identical ciphertext). Never use a static IV.
Common Misconception
Why It Matters
Common Mistakes
- Using ECB mode — it encrypts identical blocks identically, leaking data patterns.
- Reusing the same IV across encryptions with the same key — breaks semantic security.
- Not using an authenticated encryption mode (AES-256-GCM) — unauthenticated ciphertext can be tampered with.
- Storing the IV separately from the ciphertext in an inconsistent way — use a standard format: IV prepended to ciphertext.
Code Examples
// ECB mode + reused IV — insecure:
$encrypted = openssl_encrypt($data, 'AES-256-ECB', $key); // No IV, pattern-leaking
// Correct — GCM with random IV:
$iv = random_bytes(12);
$tag = '';
$encrypted = openssl_encrypt($data, 'AES-256-GCM', $key, OPENSSL_RAW_DATA, $iv, $tag);
$stored = base64_encode($iv . $tag . $encrypted);
// AES-256-GCM — authenticated encryption (confidentiality + integrity)
\$key = random_bytes(32); // 256-bit key — store in secrets manager
\$iv = random_bytes(12); // 96-bit IV — unique per encryption
\$tag = '';
\$ciphertext = openssl_encrypt(\$plaintext, 'AES-256-GCM', \$key, OPENSSL_RAW_DATA, \$iv, \$tag);
\$stored = base64_encode(\$iv . \$tag . \$ciphertext); // pack together
// Decrypt:
\$raw = base64_decode(\$stored);
\$iv = substr(\$raw, 0, 12);
\$tag = substr(\$raw, 12, 16);
\$cipher = substr(\$raw, 28);
\$decrypted = openssl_decrypt(\$cipher, 'AES-256-GCM', \$key, OPENSSL_RAW_DATA, \$iv, \$tag);
if (\$decrypted === false) throw new \RuntimeException('Decryption failed — data may be tampered');