我正在使用 CakePHP 的
Security::rijndael()
函数来加密和解密文本和文件。 我之前直接使用 mcrypt
编写了一些代码,其工作方式相同,但后来我发现 Security::rijndael
并意识到我重新发明了轮子。 所以我遇到的问题无论如何都会发生。
如果我加密一个字符串、一个文本文件或一个 PDF 文档,下面的代码可以完美运行,并且我会得到正确的解密字符串/文件。 但是,如果我尝试加密 .doc、.docx 或图像文件,解密的文件会出现乱码。
这是执行加密/解密的代码
public static function encrypt($plainText, $key) {
$plainText = base64_encode($plainText);
//Hash key to ensure it is long enough
$hashedKey = Security::hash($key);
$cipherText = Security::rijndael($plainText, $hashedKey, 'encrypt');
return base64_encode($cipherText);
}
public static function decrypt($cipherText, $key) {
$cipherText = base64_decode($cipherText);
$hashedKey = Security::hash($key);
$plainText = Security::rijndael($cipherText, $hashedKey, 'decrypt');
return base64_decode($plainText);
}
...这段代码实际上将文件呈现给用户(我编辑了代码以使其简单):
public function download($id){
App::uses('File', 'Utility');
$key = $this->User->getDocumentKey($id);
$file = new File('my_encrypted_file.docx');
$encrypted = $file->read();
$decrypted = Encrypt::decrypt($encrypted, $key);
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Content-Disposition: attachment; filename="my_decrypted_file.docx"');
echo $decrypted;
die();
}
更新 - 看起来加密是一个转移注意力的事情,因为即使没有加密和解密,文件也是乱码! 以下生成完全相同的损坏文件:
header('Content-Disposition: attachment; filename="test.docx"');
$file = new File($this->data['Model']['file']['tmp_name']);
echo $file->read();
die();
好吧,我找错了树。
无论出于何种原因(可能是某些 PHP 文件开头的空格?),在发送标头后立即添加
ob_clean();
已经解决了问题。
我想我现在知道这个问题的原因了,它是208
行
Security.php
:
$out .= rtrim(mcrypt_decrypt($algorithm, $cryptKey, $text, $mode, $iv), "\0");
由于 PHP 的
mycrypt()
使用 ZeroBytePadding
此行随后删除了填充。
问题是
.docx
文件(据我所知)以几个 Null
字符终止。如果仅删除其中一个,Word 无法打开该文件。rtrim()
也会删除这些字节,即使它们不是填充的一部分。
要解决此问题,您可以在加密之前在文件末尾添加终止字符(例如
X
),并在解密后将其删除。这将防止从 .docx
文件中切断尾部零字节:
public static function encrypt($plainText, $key) {
$plainText = base64_encode($plainText . "X"); // `X` terminates the file
/* do encryption */
}
public static function decrypt($cipherText, $key) {
/* do decrytion */
return rtrim(base64_decode($plainText), "X"); // cut off the termination `X`
}