我正在用Java加密文件,需要在客户端解密它。 这是服务器端代码:
Key secretKey = new SecretKeySpec("mysecretmysecret".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] outputBytes = cipher.doFinal(read(sampleFile));
return outputBytes;
在客户端,我使用Ajax请求来获取文件并使用CryptoJS AES:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'file', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function (e) {
var encryptedData = this.response;
var decrypted = CryptoJS.AES.decrypt(encryptedData, "mysecretmysecret");
console.log(decrypted);
};
xhr.send();
但是这不会解密文件。我在打印机中将其打印为解密值:
W…y.init {words: Array[0], sigBytes: 0}
我也尝试将arraybuffer转换为建议here的WordArray,但结果仍然相同。 如果有人能指出我正确的方向并告诉我我做错了什么,我会非常高兴。
编辑1: 我已经解决了这个问题。我使用的代码是作为答案发布的。
答案 0 :(得分:1)
让我们回顾一下,在Java中你正在使用
如果密钥作为字符串传递给CryptoJS,则必须使用OpenSSL的EVP_BytesToKey
和单轮MD5从假定密码派生密钥。由于您的密文未以OpenSSL兼容格式编码,因此它将失败。问题是,你不需要那样。
以下代码会正确解密来自Java的密文,但它不是很安全:
var passwordWords = CryptoJS.enc.Utf8.parse("mysecretmysecret");
var decrypted = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.lib.WordArray.create(encryptedData) // or use some encoding
}, passwordWords, {
mode: CryptoJS.mode.ECB
});
console.log(decrypted.toString(CryptoJS.enc.Utf8)); // in case the plaintext is text
ECB模式不包含在基本汇总中,因此您必须在主CryptoJS文件之后的页面中包含JavaScript file。
此外,CryptoJS默认情况下不处理ArrayBuffer。您需要包含shim(来源:this answer)。
这个问题是它的不安全感。 ECB模式非常不安全。
绝不使用ECB mode 。它是确定性的,因此在语义上不安全。您应该至少使用CBC或CTR等随机模式。 IV / nonce不是秘密,因此您可以将其与密文一起发送。一种常见的方法是将它放在密文的前面。
最好对您的密文进行身份验证,以便像padding oracle attack这样的攻击是不可能的。这可以使用经过验证的模式(如GCM或EAX)或encrypt-then-MAC方案来完成。
密钥可以从密码派生,但应使用适当的方案,如PBKDF2。 Java和CryptoJS都支持这些。
答案 1 :(得分:0)
所以我终于解决了这个问题。感谢Artjom指向正确的方向。 我已将Java代码更改为使用带有PKCS5Padding的CBC。
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec("mysecretmysecret".getBytes(), "AES");
IvParameterSpec IVKey = new IvParameterSpec("mysecretmysecret".getBytes());
cipher.init(Cipher.ENCRYPT_MODE, myKey, IVKey);
byte[] outputBytes = cipher.doFinal(read(sampleFile));
return outputBytes;
我的javascript就是这样:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'file', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
var encryptedData = this.response;
var passwordWords = CryptoJS.enc.Utf8.parse("mysecretmysecret"); //yes I know, not a big secret!
var wordArray = CryptoJS.lib.WordArray.create(encryptedData);
var decrypted = CryptoJS.AES.decrypt({
ciphertext: wordArray
}, passwordWords, {
iv: passwordWords, //yes I used password as iv too. Dont mind.
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
console.log(decrypted); //Eureka!!
};
xhr.send();
decrypted
是WordArray。