$this->validateOptions();
$this->loadEncryptionKey();
- $zw = new ZipWrapper($this->epubFile, false);
+ $zw = new ZipWrapper($this->epubFile, $this->options['stdout']);
$encryptionXml = $zw->getFromName('META-INF/encryption.xml');
if ($encryptionXml === false) {
$decryptedFiles = [];
$encInfoMap = $this->loadEncryptionInfo($zw, $sxEnc);
- foreach ($encInfoMap as $filePath => $algoUrl) {
+ foreach ($encInfoMap as $filePath => $fileData) {
$content = $zw->getFromName($filePath);
+ if ($content === false) {
+ $this->logger->error('Could not read contents of ' . $filePath);
+ continue;
+ }
+
+ $algoUrl = $fileData['algoUrl'];
if ($algoUrl == 'http://www.w3.org/2001/04/xmlenc#aes256-cbc') {
$this->logger->info('Decrypting ' . $filePath);
$decryptedContent = Crypt::decryptAES256CBC(
$content
);
+ } else if ($algoUrl == 'http://www.idpf.org/2008/embedding') {
+ //obfuscation algorithm; skip
+ continue;
+
} else {
$this->logger->error('Unsupported encryption algorithm: ' . $algoUrl);
continue;
if ($decryptedContent === null) {
$this->logger->error('Decryption failed for ' . $filePath);
- continue;
+ return;
+ }
+
+ if ($fileData['compressionMethod'] == 8) {
+ $decryptedContent = @gzinflate($decryptedContent);
+ if ($decryptedContent === false) {
+ $this->logger->error('Decompression failed for ' . $filePath);
+ return;
+ }
+ }
+ if ($fileData['originalLength'] !== null
+ && strlen($decryptedContent) != $fileData['originalLength']
+ ) {
+ $this->logger->error(
+ "Amount of decrypted data is wrong:\n"
+ . $filePath . ' should be ' . $fileData['originalLength'] . ' bytes'
+ . ' but we decrypted ' . strlen($decryptedContent),
+ 23
+ );
+ return;
+ }
+
+ if ($this->options['stdout']) {
+ echo $decryptedContent;
+ $zw->close();
+ return;
}
$decryptedFiles[] = $filePath;
}
$this->removeDecryptedFromEncryptionXml($sxEnc, $decryptedFiles);
- $zw->addFromString('META-INF/encryption.xml', $sxEnc->asXML());
+ if ($sxEnc->count() == 0) {
+ $zw->deleteName('META-INF/encryption.xml');
+ } else {
+ $zw->addFromString('META-INF/encryption.xml', $sxEnc->asXML());
+ }
if (!$zw->close()) {
$this->logger->error('Error while writing zip file contents');
}
/**
- * @return array Key is the file path, value the encryption algorithm URL.
+ * @return array Key is the file path, value an array with encryption and
+ * compression information.
*/
protected function loadEncryptionInfo(ZipWrapper $zw, \SimpleXMLElement $sxEnc): array
{
foreach ($sxEnc as $sxEncData) {
$filePath = (string) $sxEncData->CipherData->CipherReference['URI'];
$algoUrl = (string) $sxEncData->EncryptionMethod['Algorithm'];
+
+ if (isset($sxEncData->EncryptionProperties->EncryptionProperty->Compression)) {
+ $compressionMethod = (string) $sxEncData->EncryptionProperties->EncryptionProperty->Compression['Method'];
+ $originalLength = (string) $sxEncData->EncryptionProperties->EncryptionProperty->Compression['OriginalLength'];
+ } else {
+ $compressionMethod = 0;
+ $originalLength = null;
+ }
+
if ($this->options['all'] || isset($invPaths[$filePath])) {
- $encInfoMap[$filePath] = $algoUrl;
+ $encInfoMap[$filePath] = [
+ 'algoUrl' => $algoUrl,
+ 'compressionMethod' => $compressionMethod,
+ 'originalLength' => $originalLength,
+ ];
unset($invPaths[$filePath]);
}
}
);
}
+ if (!$this->options['all'] && !count($this->paths)) {
+ throw new \DomainException(
+ 'Use --all or specify at least one file to decyrpt.'
+ );
+ }
+
+ if ($this->options['all'] && $this->options['stdout']) {
+ throw new \DomainException(
+ '--all cannot be used with --stdout.'
+ );
+ }
+
if ($this->options['key'] !== null
&& $this->options['keyfile'] !== null
) {