首页 > 解决方案 > PHP中的NodeJS Crypto等价物?

问题描述

几周以来,我一直在寻找一种解密文件的方法。但是在 PHP 中无法完整地恢复文件,只能使用 node.js。但我想在没有节点的情况下做到这一点。如果有人能告诉我我可能错在哪里......?

我尝试使用 openssl_encrypt/decrypt 然后使用 OPENSSL_NO_PADDING 和 ZERO_PADDING 选项。将结果转换为base64,但不可能有好的结果......

我先谢谢你我不知道该怎么办......

这是我的 NodeJs 加密代码:

  decrypt(encryptedBuffer) {
        const PASSPHRASE = "";

        let decryptedBuffer = Buffer.alloc(encryptedBuffer.length);
        let chunkSize = 2048;
        let progress = 0;

        while (progress < encryptedBuffer.length) {
            if ((encryptedBuffer.length - progress) < 2048) {
                chunkSize = encryptedBuffer.length - progress;
            }

            let encryptedChunk = encryptedBuffer.slice(progress, progress + chunkSize);

            // Only decrypt every third chunk and only if not at the end
            if (progress % (chunkSize * 3) === 0 && chunkSize === 2048) {
                let cipher = crypto.createDecipheriv('bf-cbc', PASSPHRASE, Buffer.from([0, 1, 2, 3, 4, 5, 6, 7]));
                cipher.setAutoPadding(false);

                encryptedChunk = Buffer.concat([cipher.update(encryptedChunk), cipher.final()]);
            }

            decryptedBuffer.write(encryptedChunk.toString('binary'), progress, encryptedChunk.length, 'binary');

            progress += chunkSize;
        }

        return decryptedBuffer;
    }

在 PHP 中

    public function decrypt($encryptedBuffer)
    {
        ini_set('memory_limit', '1G');

        $f = fopen('myfile', 'wb+');
        $chunkSize = 2048;
        $progress = 0;
        $passphrase = "h5ihb>p9`'yjmkhf";

        while ($progress > strlen($encryptedBuffer)) {
            // If the buffer is if the end calculate the valid chunksize
            if ((strlen($encryptedBuffer) - $progress) < 2048) {
                $chunkSize = strlen($encryptedBuffer) - $progress;
            }

            /** Getting the encrypted chunk part */
            $encryptedChunk = substr($encryptedBuffer, $progress, $progress + $chunkSize);

            // Only decrypt every third chunk and only if not at the end
            if ($progress % ($chunkSize * 3) === 0 && $chunkSize === 2048) {
                $encryptedChunk = openssl_decrypt($encryptedChunk, 'bf-cbc', $passphrase, OPENSSL_ZERO_PADDING, '01234567');
            }

            fwrite($f, $encryptedChunk);

            $progress += $chunkSize;
        }

    }

标签: phpnode.jscryptographybuffernode-crypto

解决方案


PHP代码有几个缺陷:

  • while 循环中的条件是错误的,应该是:
    $progress < strlen($encryptedBuffer)
  • $encryptedChunk确定不正确,因为substr()期望第三个参数中的长度。正确的方法是:
    $encryptedChunk = substr($encryptedBuffer, $progress, $chunkSize);
  • openssl_decrypt()调用中,在第四个参数中设置的标志太少:
    除了禁用填充之外,还必须使用 禁用默认的 Base64 解码OPENSSL_RAW_DATA
    对于小于 16 字节的密钥大小,使用 0x00 值填充到 16 字节长度的密钥必须使用OPENSSL_DONT_ZERO_PAD_KEY. 这是一个 PHP 错误(s. here)。从 7.1.8 版开始,该修复程序(即标志)可用。
    总体:OPENSSL_DONT_ZERO_PAD_KEY | OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
  • 使用了错误的 IV,正确的是:hex2bin('0001020304050607').

通过这些更改,可以使用 PHP 代码进行解密。

关于安全性:短块大小使 Blowfish 容易受到生日攻击,请参见此处。使用静态 IV 通常是不安全的。相反,应该为每个加密生成一个随机 IV。


推荐阅读