首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CryptoJS AES加密与Java AES解密

CryptoJS AES加密与Java AES解密
EN

Stack Overflow用户
提问于 2017-01-02 20:26:18
回答 2查看 41.6K关注 0票数 21

我之所以问这个问题,是因为我已经读了两天关于密码AES加密的文章,就在我以为我得到了它的时候,我才意识到我根本没有得到它。

这篇文章与我的问题最接近,我也有同样的问题,但它没有得到回答:

CryptoJS AES加密与JAVA AES解密值失配

我试过很多种方法,但我没有把它做好。

First Off

我得到了已经加密的字符串(我只知道代码是如何实现的),所以修改加密方式不是一种选择。这就是为什么所有类似的问题对我都没那么有用的原因。

第二

我确实可以访问秘密密钥,并且我可以修改它(因此,如果需要的话,调整长度是一个选项)。

加密是在CryptoJS上完成的,它们将加密的字符串作为GET参数发送。

代码语言:javascript
复制
GetParamsForAppUrl.prototype.generateUrlParams = function() {
const self = this;
 return new Promise((resolve, reject) => {
   const currentDateInMilliseconds = new Date().getTime();
   const secret = tokenSecret.secret;
   var encrypted = CryptoJS.AES.encrypt(self.authorization, secret);
   encrypted = encrypted.toString();
   self.urlParams = {
     token: encrypted,
     time: currentDateInMilliseconds
   };
   resolve();
 });
};

我可以使用CryptoJS轻松地在javascript上解密这一点:

代码语言:javascript
复制
var decrypted = CryptoJS.AES.decrypt(encrypted_string, secret);
    console.log(decrypted.toString(CryptoJS.enc.Utf8)); 

但出于安全考虑,我不想在Javascript上这样做,所以我试图在Java上解密:

代码语言:javascript
复制
String secret = "secret";
byte[] cipherText = encrypted_string.getBytes("UTF8");
SecretKey secKey = new SecretKeySpec(secret.getBytes(), "AES");
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, secKey);
byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
String myDecryptedText = = new String(bytePlainText);

在我不知道自己在做什么之前,我尝试了base64解码,添加了一些IV和很多我读过的东西,当然都没有用。

但是,当我开始理解我在做什么之后,我写了上面这个简单的脚本,并在文章中得到了同样的错误:无效的AES键长。

我不知道从这里往哪里走。在阅读了很多这方面的内容后,解决方案似乎是散列或填充,但我对加密方法没有控制,所以我无法真正破译这个秘密或删除它。

但是就像我说的,我可以改变密匙,这样它就能匹配特定的长度,我已经试着改变它,但是当我在黑暗中拍摄的时候,我不知道这是否是解决方案。

所以,我的问题基本上是,如果我得到了加密的字符串( javascript中的,比如第一个脚本)和秘密密钥,有没有办法解密它(Java中的)?如果是的话,怎么做?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-02 23:38:15

免责声明:除非您了解加密概念,包括链接模式、密钥派生函数、IV和块大小,否则不要使用加密。不要推出自己的安全计划,而要坚持既定的安全计划。仅仅加入加密算法并不意味着应用程序变得更加安全。

CryptoJS实现了与OpenSSL相同的密钥派生功能,并实现了将IV放入加密数据的相同格式。因此,所有处理OpenSSL编码数据的Java代码都适用。

给定以下Javascript代码:

代码语言:javascript
复制
var text = "The quick brown fox jumps over the lazy dog.  ";
var secret = "René Über";
var encrypted = CryptoJS.AES.encrypt(text, secret);
encrypted = encrypted.toString();
console.log("Cipher text: " + encrypted);

我们得到密码文本:

代码语言:javascript
复制
U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=

在Java方面,我们有

代码语言:javascript
复制
String secret = "René Über";
String cipherText = "U2FsdGVkX1+tsmZvCEFa/iGeSA0K7gvgs9KXeZKwbCDNCs2zPo+BXjvKYLrJutMK+hxTwl/hyaQLOaD7LLIRo2I5fyeRMPnroo6k8N9uwKk=";

byte[] cipherData = Base64.getDecoder().decode(cipherText);
byte[] saltData = Arrays.copyOfRange(cipherData, 8, 16);

MessageDigest md5 = MessageDigest.getInstance("MD5");
final byte[][] keyAndIV = GenerateKeyAndIV(32, 16, 1, saltData, secret.getBytes(StandardCharsets.UTF_8), md5);
SecretKeySpec key = new SecretKeySpec(keyAndIV[0], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[1]);

byte[] encrypted = Arrays.copyOfRange(cipherData, 16, cipherData.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decryptedData = aesCBC.doFinal(encrypted);
String decryptedText = new String(decryptedData, StandardCharsets.UTF_8);

System.out.println(decryptedText);

结果是:

代码语言:javascript
复制
The quick brown fox jumps over the lazy dog.  

这就是我们开始讲的课文。表情,口音和讽刺也同样有效。

GenerateKeyAndIV是一个帮助函数,它重新实现OpenSSL的密钥派生函数EVP_BytesToKey (参见key.c)。

代码语言:javascript
复制
/**
 * Generates a key and an initialization vector (IV) with the given salt and password.
 * <p>
 * This method is equivalent to OpenSSL's EVP_BytesToKey function
 * (see https://github.com/openssl/openssl/blob/master/crypto/evp/evp_key.c).
 * By default, OpenSSL uses a single iteration, MD5 as the algorithm and UTF-8 encoded password data.
 * </p>
 * @param keyLength the length of the generated key (in bytes)
 * @param ivLength the length of the generated IV (in bytes)
 * @param iterations the number of digestion rounds 
 * @param salt the salt data (8 bytes of data or <code>null</code>)
 * @param password the password data (optional)
 * @param md the message digest algorithm to use
 * @return an two-element array with the generated key and IV
 */
public static byte[][] GenerateKeyAndIV(int keyLength, int ivLength, int iterations, byte[] salt, byte[] password, MessageDigest md) {

    int digestLength = md.getDigestLength();
    int requiredLength = (keyLength + ivLength + digestLength - 1) / digestLength * digestLength;
    byte[] generatedData = new byte[requiredLength];
    int generatedLength = 0;

    try {
        md.reset();

        // Repeat process until sufficient data has been generated
        while (generatedLength < keyLength + ivLength) {

            // Digest data (last digest if available, password data, salt if available)
            if (generatedLength > 0)
                md.update(generatedData, generatedLength - digestLength, digestLength);
            md.update(password);
            if (salt != null)
                md.update(salt, 0, 8);
            md.digest(generatedData, generatedLength, digestLength);

            // additional rounds
            for (int i = 1; i < iterations; i++) {
                md.update(generatedData, generatedLength, digestLength);
                md.digest(generatedData, generatedLength, digestLength);
            }

            generatedLength += digestLength;
        }

        // Copy key and IV into separate byte arrays
        byte[][] result = new byte[2][];
        result[0] = Arrays.copyOfRange(generatedData, 0, keyLength);
        if (ivLength > 0)
            result[1] = Arrays.copyOfRange(generatedData, keyLength, keyLength + ivLength);

        return result;

    } catch (DigestException e) {
        throw new RuntimeException(e);

    } finally {
        // Clean out temporary data
        Arrays.fill(generatedData, (byte)0);
    }
}

请注意,您必须安装( 无限势力管辖权政策 )。否则,键大小为256的AES将无法工作并引发异常:

代码语言:javascript
复制
java.security.InvalidKeyException: Illegal key size

更新

我已经将我在我的答案的第一个版本中使用的Ola Bini的Java代码 of EVP_BytesToKey替换为一个更地道、更易于理解的EVP_BytesToKey代码(参见上文)。

也见如何使用AES对使用openssl命令加密的Java文件进行解密?

票数 64
EN

Stack Overflow用户

发布于 2017-01-02 21:25:11

在对一个系统进行加密和对另一个系统进行解密时,您将受到系统默认值的支配。如果任何系统默认值不匹配(而且它们通常不匹配),那么您的解密就会失败。

每件事都必须是字节的字节,在两边都是一样的。实际上,这意味着双方都要指定所有内容,而不是依赖于默认设置。只有在两端使用相同的系统时,才能使用默认值。即使如此,最好还是准确地说明。

密钥、IV、加密模式、填充和字符串到字节的转换在两端都需要相同。特别值得检查的是键字节是否相同。如果您使用密钥派生函数(KDF)来生成密钥,那么所有的参数都必须是相同的,因此需要精确地指定。

您的“无效AES密钥长度”很可能表明生成密钥时出现了问题。你使用getBytes()。这可能是个错误。您需要指定您要得到的字节类型: ANSI、UTF-8、EBCDIC等等。字符串到字节转换的默认假设可能是造成此问题的原因。指定要在两端显式使用的转换。这样你就能确定它们匹配了。

如果参数与加密和解密不完全匹配,则密码被设计为失败。例如,即使是键中的一点差异也会导致其失败。

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

https://stackoverflow.com/questions/41432896

复制
相关文章

相似问题

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