{"record":{"id":"a403936e20fd6772","repo":"phalcon/cphalcon","slug":"the-provided-input-is-too-short-for-the-selected-c","errorCode":null,"errorMessage":"The provided input is too short for the selected cipher.","messagePattern":"The provided input is too short for the selected cipher\\.","errorType":"exception","errorClass":"InvalidDecryptLength","httpStatus":null,"severity":"error","filePath":"phalcon/Encryption/Crypt.zep","lineNumber":239,"sourceCode":"        var blockSize, cipher, cipherText, decrypted, decryptKey, digest,\n            hashAlgorithm, hashLength, iv, ivLength, mode;\n\n        let decryptKey = this->key;\n        if true !== empty(key) {\n            let decryptKey = key;\n        }\n\n        if true === empty(decryptKey) {\n            throw new EmptyDecryptionKey();\n        }\n\n        let cipher   = this->cipher,\n            ivLength = this->ivLength;\n\n        this->checkCipherHashIsAvailable(cipher, \"cipher\");\n\n        if true !== this->isValidDecryptLength(input) {\n            throw new InvalidDecryptLength();\n        }\n\n        let mode      = this->getMode(),\n            blockSize = this->getBlockSize(mode),\n            iv        = mb_substr(input, 0, ivLength, \"8bit\");\n\n        /**\n         * Check if we have chosen signing and use the hash\n         */\n        let digest        = \"\",\n            hashAlgorithm = this->getHashAlgorithm();\n        if true === this->useSigning {\n            if !fetch hashLength, this->hashLengthCache[hashAlgorithm] {\n                let hashLength = strlen(this->phpHash(hashAlgorithm, \"\", true));\n                let this->hashLengthCache[hashAlgorithm] = hashLength;\n            }\n            let digest     = mb_substr(input, ivLength, hashLength, \"8bit\"),\n                cipherText = mb_substr(input, ivLength + hashLength, null, \"8bit\");","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Encryption/Crypt.zep#L221-L257","documentation":"Before decrypting, Crypt verifies the ciphertext is at least as long as the cipher's IV (openssl_cipher_iv_length for the configured cipher). Input shorter than that cannot possibly contain IV + data, so it throws InvalidDecryptLength without attempting decryption. This guards the mb_substr() extraction of the IV from producing garbage or an empty string.","triggerScenarios":"Calling decrypt() on: an empty string; a truncated payload; data that was never encrypted by this class (plain text, JSON); a base64 string when you meant to use decryptBase64(); or ciphertext produced with a different cipher whose IV length is larger.","commonSituations":"Passing base64-wrapped payloads (Crypt produces raw binary; encryptBase64/decryptBase64 are the matching pair) - base64 text of a short message can still be longer than the IV and instead fail later with Mismatch, but a short one fails here. Empty DB columns, truncated URL parameters (binary data mangled by GET transport), and switching ciphers between encrypt and decrypt are typical causes.","solutions":["Match the API pair: if data was produced with encryptBase64(), decrypt with decryptBase64().","Sanity-check before calling: $crypt->isValidDecryptLength($input) (public method) - it applies exactly this check.","Transport ciphertext as base64 (use encryptBase64) or raw-binary-safe (POST body, not URL params) to prevent truncation/corruption.","If input is legitimately empty (optional field), branch on empty($input) and skip decryption instead of calling decrypt('')."],"exampleFix":"// before\n$plain = $crypt->decrypt($request->getQuery('t', 'string')); // truncated by URL transport\n\n// after\n$token = $request->getQuery('t', 'string');\nif ($token === null || !$crypt->isValidDecryptLength($token)) {\n    throw new \\InvalidArgumentException('Malformed or missing token');\n}\n$plain = $crypt->decrypt($token);","handlingStrategy":"validation","validationCode":"if ('' === $payload || !$crypt->isValidDecryptLength($payload)) {\n    throw new \\InvalidArgumentException('Payload missing or shorter than the cipher IV');\n}\n$plain = $crypt->decrypt($payload);","typeGuard":"function isPlausibleCipherText(\\Phalcon\\Encryption\\Crypt $crypt, string $payload): bool\n{\n    return '' !== $payload && $crypt->isValidDecryptLength($payload);\n}","tryCatchPattern":"try {\n    $plain = $crypt->decrypt($payload);\n} catch (\\Phalcon\\Encryption\\Crypt\\Exception\\InvalidDecryptLength $e) {\n    // treat as malformed input, not a 500 - reject the request/token\n    return $response->setStatusCode(400, 'Bad Request')->setContent('Invalid token');\n}","preventionTips":["Pair encrypt/decrypt with encryptBase64/decryptBase64 and never mix raw and base64 forms.","Branch on empty input before decrypting optional fields.","Transport ciphertext via base64 in JSON/POST bodies, not raw URL parameters."],"tags":["phalcon","crypt","decryption","input-validation","payload-corruption"],"backgroundTag":"invalid-ciphertext-length","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}