首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CryptoJS解密(AES)来自Java的文件字节数组

CryptoJS解密(AES)来自Java的文件字节数组
EN

Stack Overflow用户
提问于 2016-04-25 11:27:53
回答 2查看 4K关注 0票数 3

我正在用Java加密一个文件,需要在客户端解密它。这是服务器端的代码:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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();

但这并不能解密文件。我在控制台中将此打印为解密值:

代码语言:javascript
复制
W…y.init {words: Array[0], sigBytes: 0}

我还尝试将arraybuffer转换为WordArray,建议使用这里,但结果仍然相同。如果有人能指出我的正确方向,告诉我我做错了什么,我会非常高兴的。

编辑1:我已经解决了这个问题。我使用的代码是作为答案发布的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-04-25 15:13:53

让我们回顾一下,在Java中,您正在使用

  • AES,
  • 欧洲央行(没有指定,但大多数情况下是默认的;它是不安全的!),
  • PKCS#7填充(没有指定,但通常是默认的;它与PKCS#5填充相同),以及
  • 16个字符的密码,作为16个字节的键(取决于默认的系统编码)。

如果密钥作为字符串传递给CryptoJS,则必须使用OpenSSL的EVP_BytesToKey和一轮MD5从假定的密码中派生密钥。因为您的密文不是用OpenSSL兼容的格式编码的,所以它将失败。问题是你不需要那个。

下面的代码将正确地解密来自Java的密文,但并不十分安全:

代码语言:javascript
复制
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

欧洲央行模式不包括在基本汇总中,因此您必须在主JavaScript文件文件之后的页面中包含该CryptoJS。

而且,默认情况下,CryptoJS不处理ArrayBuffer。为此您需要包含希姆 (源:这个答案)。

这方面的问题在于其不安全。欧洲央行的模式非常不安全。

  • 从不使用 欧洲央行模式。它是确定性的,因此在语义上不安全。您至少应该使用像CBCCTR这样的随机模式。IV/nonce不是秘密的,所以你可以把它和密文一起发送。一个常见的方法是把它放在密文前面。
  • 最好对密文进行身份验证,这样就不可能发生像填充甲骨文攻击这样的攻击。这可以通过GCM或EAX等经过身份验证的模式完成,也可以使用加密-然后-MAC方案来完成。
  • 密钥可以从密码中派生出来,但是应该使用适当的方案,如PBKDF2。Java和CryptoJS都支持这些。
票数 1
EN

Stack Overflow用户

发布于 2016-04-26 09:22:17

所以我终于解决了这个问题。感谢Artjom指出了正确的方向。我已经将我的Java代码更改为在PKCS5Padding中使用CBC。

代码语言:javascript
复制
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是这样的:

代码语言: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。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36839254

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档