{"record":{"id":"af50043ff3575945","repo":"digininja/DVWA","slug":"iv-must-be-16-bytes-strlen-iv-passed","errorCode":null,"errorMessage":"IV must be 16 bytes, {strlen($iv)} passed","messagePattern":"IV must be 16 bytes, (.+?) passed","errorType":"exception","errorClass":"Exception","httpStatus":526,"severity":"error","filePath":"vulnerabilities/cryptography/source/token_library_high.php","lineNumber":24,"sourceCode":"\nfunction encrypt ($plaintext, $iv) {\n\t# Default padding is PKCS#7 which is interchangeable with PKCS#5\n\t# https://en.wikipedia.org/wiki/Padding_%28cryptography%29#PKCS#5_and_PKCS#7\n\n\tif (strlen ($iv) != 16) {\n\t\tthrow new Exception (\"IV must be 16 bytes, \" . strlen ($iv) . \" passed\");\n\t}\n\t$tag = \"\";\n\t$e = openssl_encrypt($plaintext, ALGO, KEY, OPENSSL_RAW_DATA, $iv, $tag);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Encryption failed\");\n\t}\n\treturn $e;\n}\n\nfunction decrypt ($ciphertext, $iv) {\n\tif (strlen ($iv) != 16) {\n\t\tthrow new Exception (\"IV must be 16 bytes, \" . strlen ($iv) . \" passed\");\n\t}\n\t$e = openssl_decrypt($ciphertext, ALGO, KEY, OPENSSL_RAW_DATA, $iv);\n\tif ($e === false) {\n\t\tthrow new Exception (\"Decryption failed\");\n\t}\n\treturn $e;\n}\n\n// Added the debug flag so that when calling from the script\n// the function can print the data used to create the token\n\nfunction create_token ($debug = false) {\n\t$token = \"userid:2\";\n\n\tif ($debug) {\n\t\tprint \"Clear text token: \" . $token . \"\\n\";\n\t\tprint \"Encryption key: \" . KEY . \"\\n\";\n\t\tprint \"IV: \" . (IV) . \"\\n\";","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/digininja/DVWA/blob/5d5c76cced604e54462b13723f5c69af58e78748/vulnerabilities/cryptography/source/token_library_high.php#L6-L42","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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()."],"exampleFix":"// before\n$iv = base64_decode($data_array['iv']);\n$d = decrypt ($ciphertext, $iv);\n// after\n$iv = base64_decode($data_array['iv'], true);\nif ($iv === false || strlen($iv) !== 16) {\n    return json_encode([\"status\" => 524, \"message\" => \"IV must be 16 bytes\"]);\n}\n$d = decrypt ($ciphertext, $iv);","handlingStrategy":"validation","validationCode":"$iv = base64_decode($data_array['iv'], true);\nif ($iv === false || strlen($iv) !== 16) {\n    // reject before decrypt() can throw\n    return json_encode(['status' => 524, 'message' => 'IV must be 16 bytes']);\n}","typeGuard":"function isValidCbcIv(string $iv): bool\n{\n    return strlen($iv) === 16;\n}","tryCatchPattern":"try {\n    $d = decrypt($ciphertext, $iv);\n} catch (Exception $e) {\n    if (str_starts_with($e->getMessage(), 'IV must be 16 bytes')) {\n        $ret = ['status' => 524, 'message' => 'Missing or malformed IV'];\n    } else {\n        $ret = ['status' => 526, 'message' => 'Unable to decrypt token'];\n    }\n}","preventionTips":["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."],"tags":["php","openssl","aes-128-cbc","iv","cryptography","dvwa"],"backgroundTag":"invalid-iv-length","analyzedSha":"5d5c76cced604e54462b13723f5c69af58e78748","analyzedAt":"2026-08-21T01:20:26.904Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}