簡體   English   中英

CryptoJs AES 加密和 Java 解密

[英]CryptoJs AES encryption and Java Decrypt

CryptoJS AES 加密和 Java AES 解密我遇到了上述解決方案。 我之前嘗試將哈希從 md5 更改為 SHA-256,但它不起作用。 給我以下錯誤:

javax.crypto.BadPaddingException:給定的最終塊未正確填充。 如果在解密過程中使用了錯誤的密鑰,則可能會出現此類問題。

在輔助函數中有什么我需要改變的嗎

我使用CryptoJS AES 加密和 Java AES 解密中的答案作為程序的基礎,該程序包括加密並將 MessageDigest 從 MD5 更改為 SHA-256。

運行這個程序,它成功地解密了加密數據(如 cipherText 中的 Base64 字符串):

Changes: added encryption and using SHA-256 as hash algorithm
cipherText: AAAAAAAAAAAUUMNwaxNxbgvkWpqE+kfq0f3K/cQ6wwwiwFFsIBa8PXsoi0Z7dRhtNVurV1MbysOzNh9R9YMltSM/6en8e9JmEingdD3Rgp8=
The quick brown fox jumps over the lazy dog. 👻 👻

運行此程序“獨立”將按預期工作,但不會像“在 CryptoJS 中加密並在 Java 中解密”所要求的那樣工作 那是因為 MD5 哈希是“內置”(或“硬編碼”)在 CryptoJS 中的,正如幾個小時前@Topaco 已經評論過的那樣(所有功勞都歸功於他)。 因此,最終沒有其他方法可以在 Java 端使用 MD5,因為 CryptoJS 將其用作 MessageDigest。 也許還有另一個可用於 JavaScript 的加密庫。

這是我的代碼:

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Arrays;
import java.util.Base64;

public class MainOrgSha256WithEncryption {
    public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        System.out.println("https://stackoverflow.com/questions/41432896/cryptojs-aes-encryption-and-java-aes-decryption");
        System.out.println("Changes: added encryption and using SHA-256 as hash algorithm");

        String secret = "René Über";
        String plainText = "The quick brown fox jumps over the lazy dog. \uD83D\uDC7B \uD83D\uDC7B";
        // generate random salt
        SecureRandom secureRandom = new SecureRandom();
        byte[] saltDataEncryption = new byte[8];
        secureRandom.nextBytes(saltDataEncryption);
        // changed MessageDigest from MD5 to SHA-256
        MessageDigest md5 = MessageDigest.getInstance("SHA-256");
        //MessageDigest md5 = MessageDigest.getInstance("MD5");
        final byte[][] keyAndIVEncryption = GenerateKeyAndIV(32, 16, 1, saltDataEncryption, secret.getBytes(StandardCharsets.UTF_8), md5);
        SecretKeySpec keyEncryption = new SecretKeySpec(keyAndIVEncryption[0], "AES");
        IvParameterSpec ivEncryption = new IvParameterSpec(keyAndIVEncryption[1]);
        // encryption
        Cipher aesCBCEncryption = Cipher.getInstance("AES/CBC/PKCS5Padding");
        aesCBCEncryption.init(Cipher.ENCRYPT_MODE, keyEncryption, ivEncryption);
        byte[] cipherTextEncryption = aesCBCEncryption.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
        // concate 8 zero bytes + salt + cipherTextEncryption
        int arrayLength = 8 + saltDataEncryption.length + cipherTextEncryption.length;
        byte[] cipherTextEncryptionComplete = new byte[arrayLength];
        System.arraycopy(saltDataEncryption, 0, cipherTextEncryptionComplete, 8, saltDataEncryption.length);
        System.arraycopy(cipherTextEncryption, 0, cipherTextEncryptionComplete, 16, cipherTextEncryption.length);
        String cipherTextBase64 = Base64.getEncoder().encodeToString(cipherTextEncryptionComplete);
        // now we are using the new cipherTextBase64 as input for the decryption
        String cipherText = cipherTextBase64;
        System.out.println("cipherText: " + cipherText);

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

        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);
    }
    /**
     * 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);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM