[英]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.