使用 CryptoJS 解密 openssl AES
Decrypt openssl AES with CryptoJS
我正在尝试使用 CryptoJS 3.1.5.
解密使用 openssl 加密的文件
如果我使用 CryptoJS 加密和解密,一切正常,shell 中的 OpenSSL 也是如此,但是当我尝试将 CryptoJS 与 OpenSSL 混合使用时,一切都出错了。
文件是使用此命令创建的:
openssl enc -aes-256-cbc -in file.txt -out file.enc -k password
我试着这样解密:
fs.readFile('file.enc', function(err, data) {
var decrypted = CryptoJS.AES.decrypt(
data.toString(),
"password",
{ mode : CryptoJS.mode.CBC }
);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
});
// Give me this err: Uncaught Error: Malformed UTF-8 data
换句话说,我是这样的:
fs.readFile('file.txt', function(err, data) {
var encrypted = CryptoJS.AES.encrypt(
data.toString(),
"password",
{ mode : CryptoJS.mode.CBC });
fs.writeFile('file.enc', encrypted);
});
然后在Shell:
openssl enc -d -aes-256-cbc -in file.enc -out file2.txt -k password
// Give me this err: bad magic number
我是不是遗漏了什么明显的东西?
还不是绝对的答案,但评论太多了:
命令行 openssl enc
默认情况下使用带盐的基于密码的加密 (PBE),这意味着实际的加密密钥和适用于 CBC 的 IV 是根据给定密码和随机数计算得出的Password Based Key Derivation Function 的盐值,使对手更难尝试密码猜测攻击。我不知道你的 JS 模块(或根本不了解 JS),但你 link 的网页列出了各种低级原语,表明它不会自动执行 PBE。像 "password" 这样的文本字符串(可能)适用于 PBE,但不适用于直接 AES 加密,其中密钥必须正好是 128、192 或 256 位,并且应该是随机二进制数据。
如果要openssl的半标准PBE,在JS端匹配; evpkey
项听起来可能有帮助,因为 EVP
是涉及的 openssl 模块,而且我不知道其他 (PB)KDF 方案会被称为 EVP。如果不是,enc
默认 PBE 只是密码的 MD5 与 salt 连接,根据需要迭代反馈多次,在本例中为 3。请参阅 https://superuser.com/questions/455463/openssl-hash-function-for-generating-aes-key 以获取(大部分)perl 中的示例。 OpenSSL 为文件添加了 8 个 ASCII 字符 "Salted__" 和 8 个字节的加盐前缀,因此您需要在解密前删除它们(并使用加盐),或在加密后添加它们。
如果你想要原始加密,选择一个更合适的密钥(无论哪一边),以及一个独特且不可预测的IV,除非你总是使用新密钥,在这种情况下你可以使用固定 IV,并在 openssl 端使用 -K
(注意大写)和 -iv
以十六进制 指定这些值 。请参阅安装了 openssl 或 https://www.openssl.org/docs/manmaster/apps/enc.html 的任何 Unix 系统的联机帮助页。
Plus 在任何一种情况下 enc
默认为 "PKCS#5"(真正的 PKCS#7)padding。我不知道你的 JS 模块是否支持;如果不是,你应该指定它。除非你能保证你的明文总是 16 字节的精确倍数(在像 UTF8 这样的任何编码之后);那么你可以在 JS 端指定(或者默认)没有填充,并在 openssl 端指定 -nopad
。
此PHP代码,其中包括命令行OpenSSL加密:
...与此 CryptoJS 代码兼容,我通常在命令行上 运行 在我的 Mac 上使用 jsc
:
(此代码是用 CryptoJS
3.1.2 编写的,尽管我认为它与 3.1.5 之间没有重大区别。)
技巧是:
如另一个答案所示,您需要在两侧指定确切的密钥和 IV 才能正常工作。
尽管 AES-256 理论上可以处理 128 位密钥,但我发现似乎只有 256 位密钥有效。
在这些示例中,我避免使用盐值。可以说您可以通过包含盐来使其更安全,但请确保您在两个地方都正确指定了它。
另一件让人们感到困惑的事情是他们认为他们可以将字符串传递给 CryptoJS.decrypt()
函数。这是不正确的。 CryptoJS.decrypt()
需要一个 cipherParams
对象。 (参见示例。)
关于填充:CryptoJS
和OpenSSL
都默认为PKCS#7,除了PKCS#7可以处理任何块大小外,它在功能上等同于PKCS#5。当我们谈论 8 字节块大小时,它们是相同的。无论如何,您不需要在 CrytoJS
.
中指定填充
祝你好运!
郑重声明,这就是我解密 openssl 文件的方式。
//openssl enc -aes-256-cbc -in file.txt -out file.enc -k password
fs.readFile('file.enc', function(err, data) {
var salt = data.toString("hex", 8, 16),
enc = data.toString("hex", 16, data.length),
derivedParams = CryptoJS.kdf.OpenSSL.execute(
password,
256/32,
128/32,
CryptoJS.enc.Hex.parse(salt)
),
cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext : CryptoJS.enc.Hex.parse(enc)
}),
decrypted = CryptoJS.AES.decrypt(
cipherParams,
derivedParams.key,
{ iv : derivedParams.iv }
);
console.log(hex2a(decrypted.toString())); // result is in hexa
});
这就是我加密以使其与 OpenSSL 一起使用的方式
fs.readFile('file.txt', function(err, data) {
var encrypted = CryptoJS.AES.encrypt(data.toString(), password);
buff = new Buffer(encrypted.toString(), "base64");
fs.writeFile('file.enc', buff);
});
// openssl enc -d -aes-256-cbc -in file.enc -out file2.txt -k password
希望对大家有所帮助:)
您应该在 shell 命令中使用 -K 70617373776F7264
而不是 -k password
。 70617373776F7264
是密码的十六进制代码。
我正在尝试使用 CryptoJS 3.1.5.
解密使用 openssl 加密的文件如果我使用 CryptoJS 加密和解密,一切正常,shell 中的 OpenSSL 也是如此,但是当我尝试将 CryptoJS 与 OpenSSL 混合使用时,一切都出错了。
文件是使用此命令创建的:
openssl enc -aes-256-cbc -in file.txt -out file.enc -k password
我试着这样解密:
fs.readFile('file.enc', function(err, data) {
var decrypted = CryptoJS.AES.decrypt(
data.toString(),
"password",
{ mode : CryptoJS.mode.CBC }
);
console.log(decrypted.toString(CryptoJS.enc.Utf8));
});
// Give me this err: Uncaught Error: Malformed UTF-8 data
换句话说,我是这样的:
fs.readFile('file.txt', function(err, data) {
var encrypted = CryptoJS.AES.encrypt(
data.toString(),
"password",
{ mode : CryptoJS.mode.CBC });
fs.writeFile('file.enc', encrypted);
});
然后在Shell:
openssl enc -d -aes-256-cbc -in file.enc -out file2.txt -k password
// Give me this err: bad magic number
我是不是遗漏了什么明显的东西?
还不是绝对的答案,但评论太多了:
命令行 openssl enc
默认情况下使用带盐的基于密码的加密 (PBE),这意味着实际的加密密钥和适用于 CBC 的 IV 是根据给定密码和随机数计算得出的Password Based Key Derivation Function 的盐值,使对手更难尝试密码猜测攻击。我不知道你的 JS 模块(或根本不了解 JS),但你 link 的网页列出了各种低级原语,表明它不会自动执行 PBE。像 "password" 这样的文本字符串(可能)适用于 PBE,但不适用于直接 AES 加密,其中密钥必须正好是 128、192 或 256 位,并且应该是随机二进制数据。
如果要openssl的半标准PBE,在JS端匹配; evpkey
项听起来可能有帮助,因为 EVP
是涉及的 openssl 模块,而且我不知道其他 (PB)KDF 方案会被称为 EVP。如果不是,enc
默认 PBE 只是密码的 MD5 与 salt 连接,根据需要迭代反馈多次,在本例中为 3。请参阅 https://superuser.com/questions/455463/openssl-hash-function-for-generating-aes-key 以获取(大部分)perl 中的示例。 OpenSSL 为文件添加了 8 个 ASCII 字符 "Salted__" 和 8 个字节的加盐前缀,因此您需要在解密前删除它们(并使用加盐),或在加密后添加它们。
如果你想要原始加密,选择一个更合适的密钥(无论哪一边),以及一个独特且不可预测的IV,除非你总是使用新密钥,在这种情况下你可以使用固定 IV,并在 openssl 端使用 -K
(注意大写)和 -iv
以十六进制 指定这些值 。请参阅安装了 openssl 或 https://www.openssl.org/docs/manmaster/apps/enc.html 的任何 Unix 系统的联机帮助页。
Plus 在任何一种情况下 enc
默认为 "PKCS#5"(真正的 PKCS#7)padding。我不知道你的 JS 模块是否支持;如果不是,你应该指定它。除非你能保证你的明文总是 16 字节的精确倍数(在像 UTF8 这样的任何编码之后);那么你可以在 JS 端指定(或者默认)没有填充,并在 openssl 端指定 -nopad
。
此PHP代码,其中包括命令行OpenSSL加密:
...与此 CryptoJS 代码兼容,我通常在命令行上 运行 在我的 Mac 上使用 jsc
:
(此代码是用 CryptoJS
3.1.2 编写的,尽管我认为它与 3.1.5 之间没有重大区别。)
技巧是:
如另一个答案所示,您需要在两侧指定确切的密钥和 IV 才能正常工作。
尽管 AES-256 理论上可以处理 128 位密钥,但我发现似乎只有 256 位密钥有效。
在这些示例中,我避免使用盐值。可以说您可以通过包含盐来使其更安全,但请确保您在两个地方都正确指定了它。
另一件让人们感到困惑的事情是他们认为他们可以将字符串传递给
CryptoJS.decrypt()
函数。这是不正确的。CryptoJS.decrypt()
需要一个cipherParams
对象。 (参见示例。)关于填充:
CryptoJS
和OpenSSL
都默认为PKCS#7,除了PKCS#7可以处理任何块大小外,它在功能上等同于PKCS#5。当我们谈论 8 字节块大小时,它们是相同的。无论如何,您不需要在CrytoJS
. 中指定填充
祝你好运!
郑重声明,这就是我解密 openssl 文件的方式。
//openssl enc -aes-256-cbc -in file.txt -out file.enc -k password
fs.readFile('file.enc', function(err, data) {
var salt = data.toString("hex", 8, 16),
enc = data.toString("hex", 16, data.length),
derivedParams = CryptoJS.kdf.OpenSSL.execute(
password,
256/32,
128/32,
CryptoJS.enc.Hex.parse(salt)
),
cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext : CryptoJS.enc.Hex.parse(enc)
}),
decrypted = CryptoJS.AES.decrypt(
cipherParams,
derivedParams.key,
{ iv : derivedParams.iv }
);
console.log(hex2a(decrypted.toString())); // result is in hexa
});
这就是我加密以使其与 OpenSSL 一起使用的方式
fs.readFile('file.txt', function(err, data) {
var encrypted = CryptoJS.AES.encrypt(data.toString(), password);
buff = new Buffer(encrypted.toString(), "base64");
fs.writeFile('file.enc', buff);
});
// openssl enc -d -aes-256-cbc -in file.enc -out file2.txt -k password
希望对大家有所帮助:)
您应该在 shell 命令中使用 -K 70617373776F7264
而不是 -k password
。 70617373776F7264
是密码的十六进制代码。