我在ECB中需要一个简单的AES密码系统。我有一个工作,在某种意义上说,连续两次给出相同的密钥,它将正确地加密和解密消息。
但是,如果我使用两个不同的密钥进行加密/解密,程序会抛出javax.crypto.BadPaddingException: Given final block not properly padded
。我需要程序提供不正确的解密,大概看起来像一些加密的字符串。这是我的代码:
public static byte[] encrypt(byte[] plaintext, String key) throws Exception {
char[] password = key.toCharArray();
byte[] salt = "12345678".getBytes();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] ciphertext = cipher.doFinal(plaintext);
return ciphertext;
}
public static byte[] decrypt(byte[] ciphertext, String key) throws Exception {
char[] password = key.toCharArray();
byte[] salt = "12345678".getBytes();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret);
byte[] plaintext = cipher.doFinal(ciphertext);
return plaintext;
}
(注意:我已经意识到使用ECB的缺点,盐=" 12345678"等等,但目前我不关心它。)感谢任何人和所有帮助。
答案 0 :(得分:1)
PKCS#5填充具有非常特定的结构,因此如果您希望使用错误的密钥进行解密而无错误,则无法继续使用它。
实现目标的一个好方法可能是使用流操作模式,而不是块模式。在流模式中,输入密钥用于产生看似随机数据的永不停止的流,其与密文进行异或以产生明文(反之亦然)。如果使用了错误的密钥,则会得到与原始明文大小相同的无意义数据。
这是一个基于原始代码的简单示例。我使用全零的IV,但您可能希望在适当的时候将其改进为随机值(注意:您需要将该值与密文一起存储)。
public static void main(String[] args) throws Exception {
byte[] plaintext = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
byte[] ciphertext = encrypt(plaintext, "foo");
byte[] goodDecryption = decrypt(ciphertext, "foo");
byte[] badDecryption = decrypt(ciphertext, "bar");
System.out.println(DatatypeConverter.printHexBinary(goodDecryption));
System.out.println(DatatypeConverter.printHexBinary(badDecryption));
}
public static SecretKey makeKey(String key) throws GeneralSecurityException {
char[] password = key.toCharArray();
byte[] salt = "12345678".getBytes();
SecretKeyFactory factory =
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
return new SecretKeySpec(tmp.getEncoded(), "AES");
}
public static byte[] encrypt(byte[] plaintext, String key) throws Exception {
SecretKey secret = makeKey(key);
Cipher cipher = Cipher.getInstance("AES/OFB8/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
return cipher.doFinal(plaintext);
}
public static byte[] decrypt(byte[] ciphertext, String key) throws Exception {
SecretKey secret = makeKey(key);
Cipher cipher = Cipher.getInstance("AES/OFB8/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(new byte[16]));
return cipher.doFinal(ciphertext);
}
输出:
00010203040506070809
5F524D4A8D977593D34C