{"record":{"id":"419c2dd8c69821f3","repo":"PHPOffice/PhpSpreadsheet","slug":"xor-encryption-not-supported","errorCode":null,"errorMessage":"XOr encryption not supported","messagePattern":"XOr encryption not supported","errorType":"exception","errorClass":"PhpOffice\\PhpSpreadsheet\\Reader\\Exception","httpStatus":null,"severity":"error","filePath":"src/PhpSpreadsheet/Reader/Xls.php","lineNumber":373,"sourceCode":"            $this->rc4Key->RC4(str_repeat(\"\\0\", $step));\n\n            // Decrypt record data (re-keying at the end of every block)\n            while ($block != $endBlock) {\n                $step = self::REKEY_BLOCK - ($pos % self::REKEY_BLOCK);\n                $recordData .= $this->rc4Key->RC4(substr($data, 0, $step));\n                $data = substr($data, $step);\n                $pos += $step;\n                $len -= $step;\n                ++$block;\n                $this->rc4Key = $this->makeKey($block, $this->md5Ctxt);\n            }\n            $recordData .= $this->rc4Key->RC4(substr($data, 0, $len));\n\n            // Keep track of the position of this decryptor.\n            // We'll try and re-use it later if we can to speed things up\n            $this->rc4Pos = $pos + $len;\n        } elseif ($this->encryption == self::MS_BIFF_CRYPTO_XOR) {\n            throw new Exception('XOr encryption not supported');\n        }\n\n        return $recordData;\n    }\n\n    /**\n     * Use OLE reader to extract the relevant data streams from the OLE file.\n     */\n    protected function loadOLE(string $filename): void\n    {\n        // OLE reader\n        $ole = new OLERead();\n        // get excel data,\n        $ole->read($filename);\n        // Get workbook data: workbook stream + sheet streams\n        $this->data = $ole->getStream($ole->wrkbook) ?? '';\n        // Get summary information data\n        $this->summaryInformation = $ole->getStream($ole->summaryInformation);","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/PHPOffice/PhpSpreadsheet/blob/65b080eef4d9fd11a5796135ab145883e5c3d6a6/src/PhpSpreadsheet/Reader/Xls.php#L355-L391","documentation":"The Xls (BIFF) reader can decrypt workbooks using no encryption or RC4-based encryption, but deliberately refuses the legacy XOR 'weak encryption' obfuscation used by very old Excel versions and old third-party writers. When the workbook globals declare MS_BIFF_CRYPTO_XOR, record decryption throws this unsupported-feature exception mid-load.","triggerScenarios":"Loading a password-protected .xls saved with legacy XOR/weak encryption (Excel 5/95 era or old Delphi/VB/PERL tooling); corporate archives containing pre-97 protected workbooks.","commonSituations":"Legacy document migration projects; compliance extracts of decades-old spreadsheets; files generated by ancient export libraries.","solutions":["Open the file in Excel or LibreOffice and re-save it either unprotected or with modern (RC4/AES) encryption, then load the copy","Strip protection upstream where lawful: LibreOffice headless conversion of the decrypted source (soffice --headless --convert-to xlsx) then use the Xlsx reader","Pre-screen archives for encrypted workbooks and exclude them from automated ingestion with a clear report rather than a crash"],"exampleFix":"// before\n$spreadsheet = IOFactory::load('legacy-protected.xls'); // XOR-encrypted -> 'XOr encryption not supported'\n\n# after (shell): decrypt/re-save once with the password, then\nsoffice --headless --convert-to xlsx legacy-protected.xls\n// then in PHP\n$spreadsheet = IOFactory::load('legacy-protected.xlsx');","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    $spreadsheet = IOFactory::load($path);\n} catch (\\PhpOffice\\PhpSpreadsheet\\Exception $e) {\n    if (str_contains($e->getMessage(), 'XOr encryption not supported')) {\n        // legacy weak encryption: convert with the password holder once, e.g.\n        // soffice --headless --convert-to xlsx --outdir fixed \"$path\"\n        // then IOFactory::load('fixed/...xlsx')\n    }\n    throw $e;\n}","preventionTips":["Pre-screen protected .xls archives and convert unsupported-encryption files before automated ingestion","Re-save legacy protected workbooks with modern encryption (Excel 97+/RC4) or none","Treat XOR-encrypted inputs as an unsupported-format routing decision, not a retryable failure"],"tags":["xls","biff","encryption","legacy-format","unsupported-feature"],"backgroundTag":"unsupported-encryption-algorithm","analyzedSha":"65b080eef4d9fd11a5796135ab145883e5c3d6a6","analyzedAt":"2026-08-17T05:40:41.646Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}