使用 php/mcrypt 加密文件会损坏 docx(和其他 Microsoft Office 2007)文件,但其他文件很好

Posted

技术标签:

【中文标题】使用 php/mcrypt 加密文件会损坏 docx(和其他 Microsoft Office 2007)文件,但其他文件很好【英文标题】:Encrypting files with php/mcrypt is corrupting docx (and other Microsoft Office 2007) files but others are fine 【发布时间】:2011-08-27 09:34:25 【问题描述】:

我正在使用 CodeIgniter 应用程序来加密上传的文件,然后在下载时解密它们,以便可以安全地存储它们(以及其他安全措施)。除了 docx(和其他 Microsoft Office 2007+)文件之外,这一切都很好。下载这些文件后,它们已成功解密,但 Office 检测到它们已损坏。这些可以修复,因此它们并没有完全损坏,但是文件中的某些内容与原始版本相比发生了变化,这使得 Office 将它们视为已损坏。正如我所提到的,这似乎不会发生在任何其他文件类型上(我已经注意到)。 docx 文件的大小也略有不同(仅字节问题),而其他类型则没有。

为了加密,我上传文件,使用 file_get_contents() 将内容读入字符串,然后通过 CodeIgniter 的 encode() 在加密库中运行字符串,然后将文件保存回磁盘,删除原始文件:

function mcrypt_encode($data, $key)

    $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());
    $init_vect = mcrypt_create_iv($init_size, MCRYPT_RAND);
    return $this->_add_cipher_noise($init_vect.mcrypt_encrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), $key);

并解码:

function mcrypt_decode($data, $key)

    $data = $this->_remove_cipher_noise($data, $key);
    $init_size = mcrypt_get_iv_size($this->_get_cipher(), $this->_get_mode());

    if ($init_size > strlen($data))
    
        return FALSE;
    

    $init_vect = substr($data, 0, $init_size);
    $data = substr($data, $init_size);
    return rtrim(mcrypt_decrypt($this->_get_cipher(), $key, $data, $this->_get_mode(), $init_vect), "\0");

然后通过CodeIgniter的force_download()运行解码后的字符串

默认密码为 MCRYPT_RIJNDAEL_256,模式为 MCRYPT_MODE_CBC。在我的服务器上启用了 Mcrypt 以及 MCRYPT_RIJNDAEL_256。

如果有人能指出我为什么会发生这种情况,我将不胜感激。

非常感谢

【问题讨论】:

【参考方案1】:

这是file_get_contents 和二进制数据的已知错误。 http://bugs.php.net/bug.php?id=42661

【讨论】:

感谢您指出这一点。提供的链接建议使用 readfile() 作为替代方案。我该怎么做? Readfile 似乎将文件的内容发送到输出缓冲区,而不是作为字符串返回。 由于您提到的原因,您不会使用readfile。你想要的是fread。请注意示例 #2 中关于在 Windows 中打开二进制文件的警告(不知道您的平台是什么,但以防万一......) 为了展开/解释,在没有明确 'binary' 标志的 Windows 上打开的文件将其行尾转换为 \r\n。 感谢您的建议,但问题仍然存在,并且仍然只有 docx(和 Office 2007+)文件。我确实注意到的一件事是,自从我开始使用 mcrypt 后,它才开始发生。该应用程序在 Linux 服务器上运行。还有什么想法吗? 作为一种解决方法,我设法通过首先使用 gzcompress() 压缩然后加密压缩文件来阻止 docx 损坏。这也节省了空间,这是一个好处:)【参考方案2】:

base64_encode()文件的file_get_contents(),然后加密。

base64_decode()下载前加密文件的解密file_get_contents()

【讨论】:

【参考方案3】:

我做了几乎相同的事情,并从谷歌来到这里。

我现在解决了。问题不在file_get_contents(),问题是codeigniter 中的encode 函数。该函数删除某些特殊字符,从而从文件中删除数据。有趣的是,Microsoft Office 是如何将其修复回来的。

【讨论】:

以上是关于使用 php/mcrypt 加密文件会损坏 docx(和其他 Microsoft Office 2007)文件,但其他文件很好的主要内容,如果未能解决你的问题,请参考以下文章

PHP mcrypt 使用类?

使用php mcrypt加密解密

使用php mcrypt加密解密

使用 PHP mcrypt 加密后使用 Javascript CryptoJS 解密 AES

使用 Perl CBC 加密并使用 PHP mcrypt 解密

使用 OpenSSL/C++ 和 PHP/Mcrypt 的 AES-128-CBC 加密:仅解密第一个块