digininja/DVWA · error · Exception
IV must be 16 bytes, {strlen($iv)} passed
Error message
IV must be 16 bytes, {strlen($iv)} passed What it means
decrypt() in the high-level token library enforces that the IV is exactly 16 bytes, the block size required by aes-128-cbc; encrypt() (line 12) carries the same guard. The token JSON's iv field is base64-decoded before the call, and any decoded length other than 16 raises this Exception with the actual length interpolated into the message.
Source
Thrown at vulnerabilities/cryptography/source/token_library_high.php:24
function encrypt ($plaintext, $iv) {
# Default padding is PKCS#7 which is interchangeable with PKCS#5
# https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS#5_and_PKCS#7
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";View on GitHub (pinned to 5d5c76cced)
Solutions
- Set the iv field to base64 of exactly 16 bytes - the original token's value base64("1234567812345678") = "MTIzNDU2NzgxMjM0NTY3OA==" works.
- When forging tokens for this level, leave the issued iv value untouched.
- Never copy nonce values produced for aes-256-gcm (12 bytes) into this CBC library.
- Pre-validate strlen($iv) === 16 before calling decrypt().
Example fix
// before
$iv = base64_decode($data_array['iv']);
$d = decrypt ($ciphertext, $iv);
// after
$iv = base64_decode($data_array['iv'], true);
if ($iv === false || strlen($iv) !== 16) {
return json_encode(["status" => 524, "message" => "IV must be 16 bytes"]);
}
$d = decrypt ($ciphertext, $iv); Defensive patterns
Strategy: validation
Validate before calling
$iv = base64_decode($data_array['iv'], true);
if ($iv === false || strlen($iv) !== 16) {
// reject before decrypt() can throw
return json_encode(['status' => 524, 'message' => 'IV must be 16 bytes']);
} Type guard
function isValidCbcIv(string $iv): bool
{
return strlen($iv) === 16;
} Try / catch
try {
$d = decrypt($ciphertext, $iv);
} catch (Exception $e) {
if (str_starts_with($e->getMessage(), 'IV must be 16 bytes')) {
$ret = ['status' => 524, 'message' => 'Missing or malformed IV'];
} else {
$ret = ['status' => 526, 'message' => 'Unable to decrypt token'];
}
} Prevention
- Always base64_decode with strict=true so damaged input is rejected instead of silently truncated.
- Generate CBC IVs with openssl_random_pseudo_bytes(16); never hard-code or reuse them (the lab's fixed IV is the demonstrated flaw).
- Keep per-cipher IV length constants next to the cipher definition to prevent CBC/GCM mixups.
When it happens
Trigger: Supplying a token JSON whose iv base64-decodes to something other than 16 bytes (e.g. "AAAA" = 4 bytes); reusing a 12-byte GCM nonce from token_library_impossible.php; hand-crafting iv strings without proper padding; base64_decode of URL-safe or whitespace-damaged input yielding a wrong-length string (strict mode is not used).
Common situations: Mixing the CBC (16-byte IV) and GCM (12-byte IV) libraries between security levels; migrating code between cipher families without updating IV length; cross-language token generation where another runtime's defaults differ; copy-paste corruption of base64.
Related errors
- Decryption failed
- IV must be 12 bytes, {strlen($iv)} passed
- Decryption failed
- Decryption failed
- Could not decode JSON object.
AI-assisted analysis of digininja/DVWA@5d5c76cced (2026-08-21).
Data as JSON: /api/errors/af50043ff3575945.
Report an issue: GitHub.