用CryptoJS解密openssl AES

我试图使用CryptoJS 3.1.5解密用opensslencryption的文件。

一切工作正常,如果我使用CryptoJSencryption和解密,壳在OpenSSL一样,但是当我尝试混合CryptoJS与OpenSSL一切都出错了。

该文件是使用以下命令创build的:

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 

我错过了什么明显的?

不是绝对的答案,但太多的意见:

Commandline openssl enc默认使用带有salt的基于密码的encryption(PBE),这意味着实际的encryption密钥,以及适用于CBC的IV,可以从给定的密码和随机盐值通过基于密码的密钥推导来计算使对手更难以尝试猜测密码的function。 我不知道你的JS模块(或多lessJS),但你链接的网页列出了各种低级原语,暗示它不会自动执行PBE。 像“password”这样的文本string(可能)适用于PBE,但不能直接进行AESencryption,其中密钥必须是128,192或256位,并且应该是随机二进制数据。

如果你想openssl的半标准PBE ,在JS端匹配; evpkey项目听起来可能有帮助,因为EVP是openssl模块,我不知道其他(PB)KDFscheme将被称为EVP。 如果没有,那么默认的PBE就是密码的MD5,与salt连接,根据需要迭代多次,在这种情况下是三次。 有关(主要)perl中的示例,请参阅https://superuser.com/questions/455463/openssl-hash-function-for-generating-aes-key 。 OpenSSL将8个ASCII字符“Salted__”和8个字节的盐加到文件中,所以你需要在解密之前删除那些(和使用salt),或者在encryption之后添加它们。

如果你想要原始的encryption ,select一个更合适的密钥(在任何一边),以及一个独特和不可预知的IV,除非你总是使用一个新的密钥,在这种情况下,你可以使用一个固定的IV,并在openssl方使用-K大写)和-ivhex指定这些值。 请参阅安装了openssl的任何Unix系统上的manpage或https://www.openssl.org/docs/manmaster/apps/enc.html

另外,无论哪种情况, enc默认为“PKCS#5”(真正的PKCS#7) 填充 。 我不知道你的JS模块是不是 如果没有,你应该指定它。 除非你能保证你的明文永远是16字节的精确倍数(经过UTF8编码之后); 那么你可以在JS端指定(或者默认)没有填充,并在openssl端指定-nopad

为了logging,这是我如何解密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 }); 

这就是我如何encryption以使其与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 

希望它会帮助别人:)

这个PHP代码包含命令行OpenSSLencryption:

http://pastebin.com/sivmZvSw

…与此CryptoJS代码兼容,我通常在我的Mac上使用jsc在命令行上运行:

http://pastebin.com/LcDBG7yj

(这个代码是用CryptoJS 3.1.2编写的,虽然我不希望和3.1.5有很大的区别)。

这些技巧是:

  1. 正如另一个答案所指出的,你需要指定双方的确切的关键和IV,以使其工作。

  2. 尽pipeAES-256理论上可以处理128位密钥,但我发现只有256位密钥似乎可以工作。

  3. 在这些例子中,我避免使用盐值。 你可以说可以通过join盐来使它更安全,但是要确保你在两个地方都正确地指定了它。

  4. 另外一个能够吸引人们的是他们认为他们可以传递一个string给CryptoJS.decrypt()函数。 这是不正确的。 CryptoJS.decrypt()需要一个cipherParams对象。 (看例子)

  5. 关于填充: CryptoJSOpenSSL默认为PKCS#7,除了PKCS#7可以处理任何块大小外,其function与PKCS#5相同。 当我们谈论8字节块大小时,它们是相同的。 无论如何,你不需要在CrytoJS指定填充。

祝你好运!