NodeJS Crypto TripleDes解密(mcrypt端口)
NodeJS Crypto TripleDes decryption (mcrypt port)
我正在努力处理一些用 PHP 5.5 和 mcrypt 编写的遗留代码。
我想在 Node.js 中创建一个向后兼容的功能,所以结果我必须将下面的代码移植到更新的标准。
public function decr($hash) {
$decoded = base64_decode($hash);
$decodedShorter = substr($decoded, 0, -8);
$iv = substr($decoded, -8);
$decr = rtrim(@mcrypt_decrypt(MCRYPT_3DES, file_get_contents('some.key'), $decodedShorter, MCRYPT_MODE_CFB, $iv));
return $decr;
}
我一直在试验 crypto-js 和节点引擎外的原生 crypto 多种策略。
我最近遇到的问题:
ERR_CRYPTO_INVALID_IV
const decrypt = (text, secretKey, iv = null) => {
const decipher = crypto.createDecipheriv('des-ede3-cfb8', secretKey, iv);
let decrypted = decipher.update(text, 'utf8');
decrypted += decipher.final();
return decrypted;
};
async function main() {
const decoded = atob(name);
const key = await readFile(
path.resolve(`some.key`)
)
const decodedShorter = decoded.substr(0, decoded.length - 8)
const iv = decoded.substr(-8)
return decrypt(decodedShorter, key, Buffer.from(iv))
}
有什么想法吗?新的 openSSL 实现是否与 mcrypt 不同以至于不兼容?或者也许我搞砸了什么?我很确定参数类型是正确的,因为我指的是@types/node/crypto,但是 content/logic 本身有些不正确...
PHP代码中的decr()
方法首先对加密后的数据进行Base64解码,然后分离出密文和IV。这里的 8 字节 IV 应该附加到密文中。
之后执行 CFB 模式下的 AES 解密。有不同段大小的不同 CFB 变体,这里使用 8 位的段大小。 CFB是流密码模式,所以没有填充是needed/applied.
发布的 NodeJS 代码中的错误是密文和 IV 使用 UTF-8 编码作为字符串处理。这通常会破坏任意字节序列(例如密文或 IV)。
关于密文,损坏发生在decipher.update(text, 'utf8')
。这里在第二个参数中明确指定了 UTF-8 作为输入编码。
关于 IV,在将 IV 读入缓冲区时发生损坏:Buffer.from(iv)
。由于在第二个参数中未指定编码,因此隐式使用 UTF-8。这两个问题都可以通过使用 latin1
作为编码来解决。
一个更健壮的解决方案是在整个过程中使用缓冲区,这样就不需要编码了:
var crypto = require('crypto')
const decrypt = (text, secretKey, iv = null) => {
const decipher = crypto.createDecipheriv('des-ede3-cfb8', secretKey, iv);
let decrypted = decipher.update(text, '', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const name = "OrjgCsq9EkT2TkCZzDOfW492nXQCNIC0BtVJy1FaaTXv2jXAPqx75kaUJVSG/5MCFXXq"
const decoded = Buffer.from(name, 'base64')
const decodedShorter = decoded.slice(0, decoded.length - 8)
const iv = decoded.slice(decoded.length - 8)
const key = Buffer.from('ffa3b5205582d6ea7de6439ec2bafef46a80810003158922', 'hex');
console.log(decrypt(decodedShorter, key, iv))
测试: 两种代码都用密钥$key
将以下密文$ciphertext
解密为给定的明文:
$ciphertext = 'OrjgCsq9EkT2TkCZzDOfW492nXQCNIC0BtVJy1FaaTXv2jXAPqx75kaUJVSG/5MCFXXq';
$key = hex2bin('ffa3b5205582d6ea7de6439ec2bafef46a80810003158922');
// Plaintext: The quick brown fox jumps over the lazy dog
我正在努力处理一些用 PHP 5.5 和 mcrypt 编写的遗留代码。 我想在 Node.js 中创建一个向后兼容的功能,所以结果我必须将下面的代码移植到更新的标准。
public function decr($hash) {
$decoded = base64_decode($hash);
$decodedShorter = substr($decoded, 0, -8);
$iv = substr($decoded, -8);
$decr = rtrim(@mcrypt_decrypt(MCRYPT_3DES, file_get_contents('some.key'), $decodedShorter, MCRYPT_MODE_CFB, $iv));
return $decr;
}
我一直在试验 crypto-js 和节点引擎外的原生 crypto 多种策略。
我最近遇到的问题:
ERR_CRYPTO_INVALID_IV
const decrypt = (text, secretKey, iv = null) => {
const decipher = crypto.createDecipheriv('des-ede3-cfb8', secretKey, iv);
let decrypted = decipher.update(text, 'utf8');
decrypted += decipher.final();
return decrypted;
};
async function main() {
const decoded = atob(name);
const key = await readFile(
path.resolve(`some.key`)
)
const decodedShorter = decoded.substr(0, decoded.length - 8)
const iv = decoded.substr(-8)
return decrypt(decodedShorter, key, Buffer.from(iv))
}
有什么想法吗?新的 openSSL 实现是否与 mcrypt 不同以至于不兼容?或者也许我搞砸了什么?我很确定参数类型是正确的,因为我指的是@types/node/crypto,但是 content/logic 本身有些不正确...
PHP代码中的decr()
方法首先对加密后的数据进行Base64解码,然后分离出密文和IV。这里的 8 字节 IV 应该附加到密文中。
之后执行 CFB 模式下的 AES 解密。有不同段大小的不同 CFB 变体,这里使用 8 位的段大小。 CFB是流密码模式,所以没有填充是needed/applied.
发布的 NodeJS 代码中的错误是密文和 IV 使用 UTF-8 编码作为字符串处理。这通常会破坏任意字节序列(例如密文或 IV)。
关于密文,损坏发生在decipher.update(text, 'utf8')
。这里在第二个参数中明确指定了 UTF-8 作为输入编码。
关于 IV,在将 IV 读入缓冲区时发生损坏:Buffer.from(iv)
。由于在第二个参数中未指定编码,因此隐式使用 UTF-8。这两个问题都可以通过使用 latin1
作为编码来解决。
一个更健壮的解决方案是在整个过程中使用缓冲区,这样就不需要编码了:
var crypto = require('crypto')
const decrypt = (text, secretKey, iv = null) => {
const decipher = crypto.createDecipheriv('des-ede3-cfb8', secretKey, iv);
let decrypted = decipher.update(text, '', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
const name = "OrjgCsq9EkT2TkCZzDOfW492nXQCNIC0BtVJy1FaaTXv2jXAPqx75kaUJVSG/5MCFXXq"
const decoded = Buffer.from(name, 'base64')
const decodedShorter = decoded.slice(0, decoded.length - 8)
const iv = decoded.slice(decoded.length - 8)
const key = Buffer.from('ffa3b5205582d6ea7de6439ec2bafef46a80810003158922', 'hex');
console.log(decrypt(decodedShorter, key, iv))
测试: 两种代码都用密钥$key
将以下密文$ciphertext
解密为给定的明文:
$ciphertext = 'OrjgCsq9EkT2TkCZzDOfW492nXQCNIC0BtVJy1FaaTXv2jXAPqx75kaUJVSG/5MCFXXq';
$key = hex2bin('ffa3b5205582d6ea7de6439ec2bafef46a80810003158922');
// Plaintext: The quick brown fox jumps over the lazy dog