PHP 中的 NodeJS Crypto 等价物?
NodeJS Crypto equivalent in PHP?
几周以来我一直在寻找一种解密文件的方法。但是要在 PHP 中完整地恢复文件是不可能的,只能用 node.但我想在没有节点的情况下做到这一点。
如果有人能告诉我我哪里错了...?
我尝试使用 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;
}
}
PHP 代码中存在几个缺陷:
- while循环中的条件错误,应该是:
$progress < strlen($encryptedBuffer)
.
$encryptedChunk
被错误地确定,因为 substr()
期望第三个参数中的长度。正确的方法是:
$encryptedChunk = substr($encryptedBuffer, $progress, $chunkSize);
- 在
openssl_decrypt()
调用中,第四个参数中设置的标志太少:
除了禁用填充外,还必须使用 OPENSSL_RAW_DATA
.
禁用默认的 Base64 解码
对于小于 16 字节的密钥大小,必须使用 OPENSSL_DONT_ZERO_PAD_KEY
禁用 0x00 值到 16 字节长度的密钥填充。这是一个 PHP 错误(s. here)。修复,即标志从版本 7.1.8 开始可用。
总体:OPENSSL_DONT_ZERO_PAD_KEY | OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
.
- 使用了错误的 IV,正确的是:
hex2bin('0001020304050607')
.
进行这些更改后,使用 PHP 密码进行解密即可。
关于安全性:较短的块大小使 Blowfish 容易受到生日攻击,请参阅 here。使用静态 IV 通常是不安全的。相反,应该为每次加密生成一个随机 IV。
几周以来我一直在寻找一种解密文件的方法。但是要在 PHP 中完整地恢复文件是不可能的,只能用 node.但我想在没有节点的情况下做到这一点。 如果有人能告诉我我哪里错了...?
我尝试使用 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;
}
}
PHP 代码中存在几个缺陷:
- while循环中的条件错误,应该是:
$progress < strlen($encryptedBuffer)
. $encryptedChunk
被错误地确定,因为substr()
期望第三个参数中的长度。正确的方法是:
$encryptedChunk = substr($encryptedBuffer, $progress, $chunkSize);
- 在
openssl_decrypt()
调用中,第四个参数中设置的标志太少:
除了禁用填充外,还必须使用OPENSSL_RAW_DATA
.
禁用默认的 Base64 解码 对于小于 16 字节的密钥大小,必须使用OPENSSL_DONT_ZERO_PAD_KEY
禁用 0x00 值到 16 字节长度的密钥填充。这是一个 PHP 错误(s. here)。修复,即标志从版本 7.1.8 开始可用。
总体:OPENSSL_DONT_ZERO_PAD_KEY | OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
. - 使用了错误的 IV,正确的是:
hex2bin('0001020304050607')
.
进行这些更改后,使用 PHP 密码进行解密即可。
关于安全性:较短的块大小使 Blowfish 容易受到生日攻击,请参阅 here。使用静态 IV 通常是不安全的。相反,应该为每次加密生成一个随机 IV。