【问题标题】:AES Encryption in Java working, but Decryption in JavaScript not working?Java中的AES加密工作,但JavaScript中的解密不起作用?
【发布时间】:2021-09-22 13:37:45
【问题描述】:

我正在尝试加密价值服务器端,然后从浏览器端解密。这是我用来加密的 Java 代码,它工作正常:

package aes;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
 
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class AesEncryption {

    private static SecretKeySpec secretKey;
    private static byte[] key;
 
    public static void setKey(String myKey) {
        MessageDigest sha = null;
        try {
            key = myKey.getBytes("UTF-8");
            sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16); 
            secretKey = new SecretKeySpec(key, "AES");
        } 
        catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } 
        catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public static String encrypt(String strToEncrypt, String secret) {
        try {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
        } 
        catch (Exception e) 
        {
            System.out.println("Error while encrypting: " + e.toString());
        }
        return null;
    }

然后我调用了一个 JavaScript 方法来解密加密值:

  aesDecrypt(encryptedValue) {
    console.log("TESTING ENCRYPTED VALUE : " , encryptedValue)
    var bytes = CryptoJS.AES.decrypt(encryptedValue, secretAesKey, {
      mode: CryptoJS.mode.ECB,
      padding: CryptoJS.pad.Pkcs7
    })
    console.log("TESTING BYTES : " , bytes)
    var originalValue = bytes.toString(CryptoJS.enc.Utf8);
    console.log("TESTING ORIGINAL VALUE : " , originalValue)
    return originalValue
  }

当记录解密的每一步时,当试图打印原始值时,它只是空白。我知道 encryptedValue 必须以与最初加密相同的方式转换回字节,然后必须用 UTF-8 编码才能返回原始字符串。我还能错过什么导致这种情况?

【问题讨论】:

  • myKey.getBytes("UTF-8"); 在 99% 的事件中都存在错误和安全问题,因为字符串从不直接用作密码学中的密钥。如果您有密码,请使用以密码为输入并以 128 位/256 位密钥为输出的密钥派生函数。
  • 在 CryptoJS 代码中,缺少通过 SHA1 派生的密钥。前 16 个字节用作密钥。请注意,通过摘要派生的密钥是不安全的(第 1 条评论)以及 ECB 模式。
  • 刚刚在网上搜索,但似乎无法找到 CryptoJS 在解密期间通过 SHA1 使用此密钥派生的示例。您知道可以在某处发布的示例吗? @user9014097 我一定会调查 myKey.getBytes("UTF-8"); 问题。我从来没有真正使用过加密,所以我只是想先让一个基本的基线代码工作。

标签: javascript java encryption aes


【解决方案1】:

使用 CryptoJS 可以通过 SHA-1 派生密钥,例如如下:

var passphrase = '<your passphrase>';
var sha1Hash = CryptoJS.SHA1(passphrase);                                           // Create SHA1 hash
var secretAesKey = CryptoJS.lib.WordArray.create(sha1Hash.words.slice(0, 16 / 4));  // Use the first 4 words (= 16 bytes) of the hash

用Java代码生成的密文进行测试:

function aesDecrypt(encryptedValue) {
    console.log("TESTING ENCRYPTED VALUE : " , encryptedValue);
    var bytes = CryptoJS.AES.decrypt(
        encryptedValue, 
        secretAesKey, 
        {
            mode: CryptoJS.mode.ECB,
            padding: CryptoJS.pad.Pkcs7
        }
    );
    console.log("TESTING BYTES : " , bytes);
    var originalValue = bytes.toString(CryptoJS.enc.Utf8);
    console.log("TESTING ORIGINAL VALUE : " , originalValue);
    return originalValue;
  }

var passphrase = 'my secret passphrase';
var sha1Hash = CryptoJS.SHA1(passphrase)
var secretAesKey = CryptoJS.lib.WordArray.create(sha1Hash.words.slice(0, 16 / 4));
var ciphertext = 'hjC0d3sEGJ/3SBTPyV5RrbiIi5jCfhj9T2ZbeWNyBHqmCrVaKLYN94ouiMOz8d4x';
aesDecrypt(ciphertext);
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"&gt;&lt;/script&gt;

将密文正确解密为原始明文。


请注意,如 cmets 中所述,ECB 模式是不安全的,而且通过摘要从密码派生的密钥也是不安全的(即使它不会被破坏)。相反,应该使用可靠的密钥派生函数,如 Argon2 或 PBKDF2。

【讨论】:

  • 这很有帮助!那么我在 sha1Hash 中使用的密码是否应该与我在 Java 端加密中使用的“秘密”相匹配?还是它们完全不同?
  • @knxwledge - 是的,没错。 Java代码中的secret,即encrypt()方法的第二个参数,对应CryptoJS代码中的passphrase。我使用您的 Java 代码和密码短语 my secret passphrase 和明文 The quick brown fox jumps over the lazy dog 创建了在我的示例中使用的密文 hjC0... 8d4x
  • 加盐如何适应这个?添加盐后如何从 ui 解密?我知道盐通常是不可预测的随机值。
  • 这无法在评论的上下文中回答。请提出一个包含所有必要信息的新问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-17
  • 2015-07-19
相关资源
最近更新 更多