PHP 方法逐块执行 AES 加密以节省内存使用量


PHP method to perform AES encryption block-by-block to conserve memory usage

让我解释一下我的困境。在我的PHP脚本中,我需要能够加密上传到我的网站的文件。我选择使用 AES-256 加密和 CBC(密码块链接)操作模式。

最初,我发现了一个非常有前途的功能,可以做到这一点,它会像这样工作:

//Just the encryption part
$fileData = file_get_contents($serverFilePath);
$encData = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $binKey,
            $fileData,
            MCRYPT_MODE_CBC, 
            $binIV);

上面的方法运行良好,除了一个主要问题:我在共享主机帐户上托管我的网站,正如您所看到的,mcrypt_encrypt方法要求将数据作为二进制字符串一次性输入其中。如果我加密的文件足够大,这将成为一个问题。在这种情况下,mcrypt_encrypt失败,我的脚本被终止,用户看到一个空白的白页......哎呀!

之后,我在error_log中收到以下消息:

PHP 致命错误:允许的 X 字节内存大小已耗尽(尝试 分配 Y 字节)在废话中

显然,通过在共享主机上运行,我的脚本没有所有可用的 RAM,但即使它可以访问更多 RAM,仍然可能存在被加密文件的大小超过所有可用 RAM 的情况,需要将其内容加载到二进制字符串中。

(顺便说一下,当我尝试只加密一个 200 MB 的文件时,上面的方法会失败,按照今天的标准,这不是那么大。

因此,我的问题/困境:

有没有一种方法可以只对一个明文块(没有CBC或任何其他操作模式,只是普通的AES)执行AES加密,如果是这样,我可以自己做CBC?如果是,我可以通过逐块加密来编写自己的方法,从而避免mcrypt_encrypt功能的陷阱,并且不会将整个文件加载到 RAM 中。

任何建议将不胜感激?

您可以通过简单地使用 ECB 模式而不是 CBC 模式

来模拟单个 AES 块加密,只需使用 ECB mcrypt_encrypt模式而不是 CBC 模式,然后自己执行 CBC。欧洲央行模式基本上是无状态的。没有像CBC模式那样从最后一个加密块传播。它只是在每个块上分别应用 AES。

根据您执行流读取的方式,使用 CBC 加密块可能更容易或性能更高。您仍然可以对要加密的文件区块使用您的方法。然后,您将使用最后一个密文块作为下一个块的 IV。