当前位置: 首页 > 知识库问答 >
问题:

如何使用Java从CryptoJS解密加密的AES-256字符串?[闭门]

南宫才艺
2023-03-14

我有一个加密的AES-256字符串从CryptoJS与密码。我需要Java解密,但不知道怎么做。似乎你需要IV、key和盐来解密,就像在CryptoJS主页一样,加密数据已经包含了所有这些数据,CryptoJS可以以某种方式将它们从加密输入中解析出来。

有人知道怎么做吗?我已经看到了很多关于CryptoJS的例子——Java加密/解密,但大多数都使用硬编码的IV/密钥,或者只是从CryptoJS端向Java端发送IV/密钥。我只有一个密码,就像这个网站做的一样!

共有1个答案

司毅庵
2023-03-14

以这种方式加密邮件时:

CryptoJS.AES.encrypt("message", "passphrase")

使用基于密码的方法。对于这个问题,CryptoJS生成一个新的盐,并将这个盐与密码短语结合使用来导出密钥和IV(我已经为这个问题重新创建了一个派生函数)。
密文生成后,使用一个特殊的OpenSSL格式化程序来编码密文,包括用过的盐:

var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);

您需要解码Base64编码的字符串,以获取字节数组。然后您可以检查标头是否匹配:

byte[] ctBytes = Base64.getDecoder().decode(ciphertext.getBytes("UTF-8"));
System.out.println("Is salted: " + new String(Arrays.copyOf(ctBytes, 8)).equals("Salted__"));

之后,您可以恢复盐和密文从它:

byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);

导出密钥IV:

byte[] key = new byte[keySize/8];
byte[] iv = new byte[ivSize/8];
EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, saltBytes, key, iv);

解密密文:

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
        new IvParameterSpec(iv));
byte[] recoveredPlaintextBytes = cipher.doFinal(ciphertextBytes);
String recoveredPlaintext = new String(recoveredPlaintextBytes);

完整代码:

public static void main(String[] args) throws UnsupportedEncodingException, GeneralSecurityException {
    String ciphertext = "U2FsdGVkX1+0m/gle/XQX1shjnpveUrl1fO3oOlurPMlTks6+oQlEPfOrucihzEz";
    String plaintext = "This is some example plaintext";
    String password = "This is a very strong password";
    int keySize = 256;
    int ivSize = 128;

    // var wordArray = WordArray.create([0x53616c74, 0x65645f5f]).concat(salt).concat(ciphertext);
    byte[] ctBytes = Base64.getDecoder().decode(ciphertext.getBytes("UTF-8"));
    System.out.println("Is salted: " + Arrays.equals(Arrays.copyOf(ctBytes, 8), new byte[]{0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f}));
    System.out.println("Is salted: " + new String(Arrays.copyOf(ctBytes, 8)).equals("Salted__"));

    byte[] saltBytes = Arrays.copyOfRange(ctBytes, 8, 16);
    System.out.println("Salt matches: " + Arrays.equals(saltBytes, hexStringToByteArray("b49bf8257bf5d05f")));

    byte[] ciphertextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.length);
    System.out.println("CT matches: " + Arrays.equals(ciphertextBytes, hexStringToByteArray("5b218e7a6f794ae5d5f3b7a0e96eacf3254e4b3afa842510f7ceaee722873133")));

    byte[] key = new byte[keySize/8];
    byte[] iv = new byte[ivSize/8];
    EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, saltBytes, key, iv);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
    byte[] recoveredPlaintextBytes = cipher.doFinal(ciphertextBytes);
    String recoveredPlaintext = new String(recoveredPlaintextBytes);

    System.out.println("Recovered Plaintext: " + recoveredPlaintext);
    System.out.println("Expected Plaintext: " + plaintext);
}

public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    return EvpKDF(password, keySize, ivSize, salt, 1, "MD5", resultKey, resultIv);
}

public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    keySize = keySize / 32;
    ivSize = ivSize / 32;
    int targetKeySize = keySize + ivSize;
    byte[] derivedBytes = new byte[targetKeySize * 4];
    int numberOfDerivedWords = 0;
    byte[] block = null;
    MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
    while (numberOfDerivedWords < targetKeySize) {
        if (block != null) {
            hasher.update(block);
        }
        hasher.update(password);
        block = hasher.digest(salt);
        hasher.reset();

        // Iterations
        for (int i = 1; i < iterations; i++) {
            block = hasher.digest(block);
            hasher.reset();
        }

        System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
                Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));

        numberOfDerivedWords += block.length/4;
    }

    System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
    System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);

    return derivedBytes; // key + iv
}

/**
 * Copied from https://stackoverflow.com/a/140861
 * */
public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

JavaScript代码:

var pw = "This is a very strong password";
var pt = "This is some example plaintext";
var encrypted = CryptoJS.AES.encrypt(pt, pw);
encrypted.toString(); // U2FsdGVkX1+0m/gle/XQX1shjnpveUrl1fO3oOlurPMlTks6+oQlEPfOrucihzEz
encrypted.salt.toString(); // b49bf8257bf5d05f
encrypted.ciphertext.toString(); // 5b218e7a6f794ae5d5f3b7a0e96eacf3254e4b3afa842510f7ceaee722873133
 类似资料:
  • 问题内容: 我有一个来自CryptoJS的加密AES-256字符串,带有密码短语。我需要用Java对其解密,但无法弄清楚该怎么做。似乎需要IV,密钥和盐来解密,就像在CryptoJS主页中一样,加密的数据已经包含所有这些内容,并且CryptoJS可以某种方式从加密的输入中解析出它们。 有人知道该怎么做吗?我已经看到了很多有关CryptoJS的示例-Java加密/解密,但大多数都使用硬编码的IV /

  • 客户端: 服务器端:

  • 字符串像这里一样用php加密。可以用这个用参数解密:Rijndael-256,ECB,Base64。但是我的ActionScript代码无法解密它: 更新: “它无法解密”意味着我弄错了纯文本。 在php中,明文首先由aes-256-ecb加密。然后由Base64编码。在ActionScript中,这些步骤以相反的顺序进行。 UPD2: 编码-解码测试: 在 停止后的输出是: 更新3: 它适用于P

  • 我之所以问这个问题,是因为两天来我读了很多关于crypto AES加密的帖子,就在我以为我得到了它的时候,我意识到我根本没有得到它。 这个帖子是最接近我的问题,我有完全相同的问题,但它没有得到回答: CryptoJS AES加密与JAVA AES解密值不匹配 我得到的是已经加密的字符串(我得到的代码只是为了看看他们是怎么做的),所以修改加密方式不是一个选项。这就是为什么所有类似的问题对我来说都不是

  • 我在这个网站上用AES-256加密一个虚拟字符串: https://www.devglan.com/online-tools/aes-encryption-decryption 具有以下参数: null 当我尝试用OpenSSL从命令行解密它时: 我得到这个错误: