digininja/DVWA · error · Exception
Decryption failed
Error message
Decryption failed
What it means
openssl_decrypt returned false for aes-128-cbc with OPENSSL_RAW_DATA, key "rainbowclimbinghigh" and the supplied (already length-checked) IV. Because the 16-byte IV check passed, the failure is cryptographic: the raw ciphertext is not a multiple of 16 bytes, a different key encrypted it, or the decrypted PKCS#7 padding did not validate after tampering.
Source
Thrown at vulnerabilities/cryptography/source/token_library_high.php:28
if (strlen ($iv) != 16) {
throw new Exception ("IV must be 16 bytes, " . strlen ($iv) . " passed");
}
$tag = "";
$e = openssl_encrypt($plaintext, ALGO, KEY, OPENSSL_RAW_DATA, $iv, $tag);
if ($e === false) {
throw new Exception ("Encryption failed");
}
return $e;
}
function decrypt ($ciphertext, $iv) {
if (strlen ($iv) != 16) {
throw new Exception ("IV must be 16 bytes, " . strlen ($iv) . " passed");
}
$e = openssl_decrypt($ciphertext, ALGO, KEY, OPENSSL_RAW_DATA, $iv);
if ($e === false) {
throw new Exception ("Decryption failed");
}
return $e;
}
// Added the debug flag so that when calling from the script
// the function can print the data used to create the token
function create_token ($debug = false) {
$token = "userid:2";
if ($debug) {
print "Clear text token: " . $token . "\n";
print "Encryption key: " . KEY . "\n";
print "IV: " . (IV) . "\n";
}
$e = encrypt ($token, IV);
$data = array (View on GitHub (pinned to 5d5c76cced)
Solutions
- Submit the originally issued token unchanged to confirm the decrypt path works before modifying anything.
- Ensure the token field is base64 of raw aes-128-cbc output (a 16-byte multiple) and the iv field is the original base64 value.
- Re-encrypt with the exact define('KEY', 'rainbowclimbinghigh') and OPENSSL_RAW_DATA, then append the base64 iv exactly as create_token() does.
- Verify the openssl extension is loaded and dump openssl_error_string() for the concrete reason.
- Note for real code: the fixed IV reused for every token here is the vulnerability being demonstrated - use random IVs in production.
Example fix
// before
$e = openssl_decrypt($ciphertext, ALGO, KEY, OPENSSL_RAW_DATA, $iv);
if ($e === false) {
throw new Exception ("Decryption failed");
}
// after
$e = openssl_decrypt($ciphertext, ALGO, KEY, OPENSSL_RAW_DATA, $iv);
if ($e === false) {
while ($err = openssl_error_string()) { error_log($err); }
throw new Exception ("Decryption failed");
} Defensive patterns
Strategy: try-catch
Validate before calling
$raw = base64_decode($data_array['token'], true);
if ($raw === false || strlen($raw) === 0 || strlen($raw) % 16 !== 0) {
return json_encode(['status' => 523, 'message' => 'Token is not valid AES-CBC ciphertext']);
} Type guard
function isRawCbcCiphertext(string $raw): bool
{
return strlen($raw) > 0 && strlen($raw) % 16 === 0;
} Try / catch
try {
$d = decrypt($ciphertext, $iv);
} catch (Exception $e) {
error_log('openssl decrypt failed: ' . $e->getMessage());
while ($err = openssl_error_string()) { error_log($err); }
$ret = ['status' => 526, 'message' => 'Unable to decrypt token'];
} Prevention
- Log openssl_error_string() on every decrypt failure - it names the real cause (key length, padding, bad decrypt).
- Use strict base64 decoding and verify block-size alignment before calling openssl functions.
- Pin cipher, key, and padding options in shared constants for both encrypt and decrypt paths.
- In production, use authenticated modes (GCM) so tampered ciphertext fails loudly instead of relying on padding errors.
When it happens
Trigger: Token base64 that decodes to a non-block-multiple length; re-encrypting the token with a different key; flipping bytes in the ciphertext which breaks padding on the final block; submitting ciphertext produced for aes-256-gcm; base64_decode of damaged input producing truncated bytes.
Common situations: Token tampering experiments (this lab's purpose); key rotation between environments; tokens generated in another language that pads the 17-character key differently than PHP's zero-padding; whitespace inside base64 values.
Related errors
- Decryption failed
- IV must be 16 bytes, {strlen($iv)} passed
- IV must be 12 bytes, {strlen($iv)} passed
- Decryption failed
- Could not decode JSON object.
AI-assisted analysis of digininja/DVWA@5d5c76cced (2026-08-21).
Data as JSON: /api/errors/e31200f9099f3d2a.
Report an issue: GitHub.