使用 AES / CBC / PKCS5Padding 并使用 128位密钥创建加密字符串时遇到问题。我有解密加密字符串的代码。我有一个示例加密的字符串来自另一个成功解密的系统,但是当我尝试创建自己的加密字符串时,由于某种原因它没有正确填充。当我解密我的加密字符串时,它只显示16字节后的字符。
我找到的所有示例都假设加密首先发生,然后在加密期间设置变量之后发生解密,或者它们随机生成密钥,但在我的情况下,我想使用已知密钥。
我真的被困了所以非常感谢任何帮助,非常感谢您的时间和努力!
示例:
原文: 01234567891234565
加密: zmb16qyYrdoW6akBdcJv7DXCzlw0qU7A2ea5q4YQWUo =
密钥长度: 16
解密: 5(这是原始文字字符串中的最后一位数字)
示例代码:
package com.company.encrypt.tests;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
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 org.apache.commons.codec.binary.Base64;
public class TestEncryptDecrypt {
private static final String characterEncoding = "UTF-8";
private static final String cipherTransformation = "AES/CBC/PKCS5Padding";
private static final String aesEncryptionAlgorithm = "AES";
public static void main(String[] args) throws Exception {
String key1 = "1234567812345678";
String text = "01234567891234565";
System.out.println("Original Text: " + text);
String encrypted = encrypt(text, key1);
System.out.println("Encrypted: " + encrypted);
String decrypted = decrypt(encrypted, key1);
System.out.println("Decrypted: " + decrypted);
}
public static String decrypt(String encryptedText, String key) throws Exception {
String plainText = null;
int keyLength = key.length();
System.out.println("Key length: " + String.valueOf(keyLength));
byte[] encryptedTextBytes = Base64.decodeBase64(encryptedText.getBytes());
byte[] keyBytes = key.getBytes();
byte[] initialVector = Arrays.copyOfRange(encryptedTextBytes, 0, keyLength);
byte[] trimmedCipherText = Arrays.copyOfRange(encryptedTextBytes, keyLength, encryptedTextBytes.length);
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, aesEncryptionAlgorithm);
IvParameterSpec ivParameterSpec = new IvParameterSpec(initialVector);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] clearText;
clearText = cipher.doFinal(trimmedCipherText);
plainText = new String(clearText, characterEncoding);
} catch(NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException
| InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return plainText;
}
public static String encrypt(String plainText, String encryptionKey) throws Exception {
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), aesEncryptionAlgorithm);
Cipher cipher = Cipher.getInstance(cipherTransformation);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainTextBytes = plainText.getBytes("UTF-8");
byte[] encrypted = cipher.doFinal(plainTextBytes);
return new String(Base64.encodeBase64(encrypted));
}
}
答案 0 :(得分:2)
我注意到在decrypt()
函数中,您将加密的数组分为两部分:前16个字节,其余部分。您使用前16个字节作为解密的IV,但是,您没有在encrypt()
中将16字节IV添加到加密消息的开头。这导致明文的前16个字节丢失。我认为你假设doFinal()
会自动为你做这件事,但事实并非如此。
要解决此问题,请在返回加密邮件之前添加IV,这可以使用cipher.getIV()
进行检索。您可以使用Apache Commons Lang库中的ArrayUtils.addAll()
来完成此操作,或者只需编写您自己的函数来完成此操作。需要注意的另一点是,IV将始终是块大小,无论密钥大小如何,AES都是16字节。
希望这个答案有所帮助!