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

  1. Submit the originally issued token unchanged to confirm the decrypt path works before modifying anything.
  2. 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.
  3. Re-encrypt with the exact define('KEY', 'rainbowclimbinghigh') and OPENSSL_RAW_DATA, then append the base64 iv exactly as create_token() does.
  4. Verify the openssl extension is loaded and dump openssl_error_string() for the concrete reason.
  5. 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

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


AI-assisted analysis of digininja/DVWA@5d5c76cced (2026-08-21). Data as JSON: /api/errors/e31200f9099f3d2a. Report an issue: GitHub.