digininja/DVWA · error · Exception

Decryption failed

Error message

Decryption failed

What it means

decrypt() wraps openssl_decrypt with cipher aes-128-ecb, the hard-coded key "ik ben een aardbei" and OPENSSL_PKCS1_PADDING, and throws this Exception whenever openssl returns false. ECB has no IV, so a false result means one of: the raw bytes (after hex2bin) were not produced with the same key, the ciphertext length is not a multiple of the 16-byte AES block, or the decrypted PKCS padding did not validate (corrupted or spliced ciphertext).

Source

Thrown at vulnerabilities/cryptography/source/medium.php:5

<?php
function decrypt ($ciphertext, $key) {
	$e = openssl_decrypt($ciphertext, 'aes-128-ecb', $key, OPENSSL_PKCS1_PADDING);
	if ($e === false) {
		throw new Exception ("Decryption failed");
	}
	return $e;
}

$key = "ik ben een aardbei";

$errors = "";
$success = "";
$messages = "";

if ($_SERVER['REQUEST_METHOD'] == "POST") {
	try {
		if (!array_key_exists ('token', $_POST)) {
			throw new Exception ("No token passed");
		} else {
			$token = $_POST['token'];
			if (strlen($token) % 32 != 0) {
				throw new Exception ("Token is in wrong format");

View on GitHub (pinned to 5d5c76cced)

Solutions

  1. Resubmit one of the three provided sample tokens unchanged to confirm the happy path decrypts.
  2. Verify the token is pure hex, even-length, and a multiple of 32 characters before submitting.
  3. When crafting your own token, encrypt with aes-128-ecb using the exact key "ik ben een aardbei" (PHP zero-pads it), then bin2hex() the raw ciphertext.
  4. Confirm the openssl extension is loaded and check the PHP error log for openssl warnings.
  5. Remember the decrypted plaintext must then be valid JSON or you hit the next exception.

Example fix

// before
$decrypted = decrypt(hex2bin ($token), $key);
// after
$raw = hex2bin($token);
if ($raw === false || strlen($raw) === 0 || strlen($raw) % 16 !== 0) {
    throw new Exception("Token is in wrong format");
}
$decrypted = decrypt($raw, $key);
Defensive patterns

Strategy: try-catch

Validate before calling

$token = trim($_POST['token'] ?? '');
if ($token === '' || !ctype_xdigit($token) || strlen($token) % 32 !== 0) {
    $errors = 'Token is in wrong format';
} else {
    $raw = hex2bin($token);
    if ($raw === false || strlen($raw) % 16 !== 0) {
        $errors = 'Token is in wrong format';
    }
}

Type guard

function isHexEncryptedToken(string $token): bool
{
    return $token !== ''
        && ctype_xdigit($token)
        && strlen($token) % 32 === 0;
}

Try / catch

try {
    $decrypted = decrypt(hex2bin($token), $key);
} catch (Exception $e) {
    // Distinguish crypto failure from transport/shape failures for actionable messages
    error_log('Token decrypt failed: ' . $e->getMessage());
    $errors = 'Token could not be decrypted with the expected key and mode.';
}

Prevention

When it happens

Trigger: POSTing a hex token encrypted with a different key or mode (for example re-using the high-level key 'rainbowclimbinghigh'); submitting an empty token, which passes the % 32 length gate (0 % 32 == 0) and makes openssl_decrypt fail on empty input; hex containing non-hex characters so hex2bin yields garbage; block-splicing ECB blocks so the final block's padding no longer validates; raw ciphertext not a multiple of 16 bytes.

Common situations: Copy/paste truncation of the sample tokens; re-encrypting tokens externally (other languages reject or pad the 18-byte key differently from PHP's zero-padding, so cross-stack tokens fail); editing hex in editors that introduce smart quotes or whitespace; OpenSSL configuration differences between environments.

Related errors


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