我在java类中遇到了解密错误:
javax.crypto.IllegalBlockSizeException :
Input length must be multiple of 16 when decrypting with padded cipher.
我该怎么做才能解决这个问题?
更新:
我忘了提到它工作一次,第二次我试图再次执行它时抛出上述错误。
package com.tb.module.service;
import java.security.Key;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;
/**
* This class is used for encrypt and decrypt the password field.
*
*/
public class PswdEnc {
private static final String ALGO = "AES";
private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };
public static String encrypt(String Data) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public static String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGO);
return key;
}
}
答案 0 :(得分:71)
您使用的算法“AES”是“AES / ECB / NoPadding”的简写。这意味着您使用的是具有128位密钥大小的AES algorithm和block size,ECB mode of operation和no padding。
换句话说:您只能以128位或16字节的块加密数据。这就是你得到IllegalBlockSizeException
例外的原因。
如果要加密大小不是16字节倍数的数据,则要么必须使用某种填充,要么使用密码流。例如,您可以通过指定“AES / CBC / NoPadding”作为算法,使用CBC mode(一种有效地将块密码转换为stream cipher的操作模式),或通过指定“AES”来使用PKCS5填充/ ECB / PKCS5“,它将以非常特定的格式自动在数据末尾添加一些字节,以使密文的大小为16个字节的倍数,并且解密算法将理解它必须忽略一些数据。
无论如何,我强烈建议您立即停止正在做的事情,并研究一些关于密码学的介绍性材料。例如,选中Crypto I on Coursera。你应该非常清楚选择一种或另一种模式的含义,它们的优点是什么,最重要的是它们的弱点。没有这方面的知识,很容易构建非常容易破解的系统。
更新:根据您对该问题的评论,在将密码存储到数据库时不要对密码进行加密 !!!!!你永远不应该这样做。您必须 HASH 密码,正确加密,这与加密完全不同。真的,拜托,不要做你想做的事情......通过加密密码,可以解密它们。这意味着您作为数据库管理员和谁知道密钥,您将能够读取存储在数据库中的每个密码。要么你知道这一点,要么做得非常非常糟糕,或者你不知道这一点,应该感到震惊并阻止它。
答案 1 :(得分:3)
一些评论:
import sun.misc.*;
不要这样做。它是非标准的,并不保证在实现之间是相同的。还有其他库可以使用Base64转换。
byte[] encVal = c.doFinal(Data.getBytes());
您依赖于此处的默认字符编码。始终指定您正在使用的字符编码:byte[] encVal = c.doFinal(Data.getBytes("UTF-8"));
默认值可能在不同的地方有所不同。
正如@thegrinner指出的那样,你需要明确地检查你的字节数组的长度。如果存在差异,则逐字节比较它们以查看差异在哪里蔓延。
答案 2 :(得分:0)
那是因为
您只能以128位或16字节的块加密数据。这就是你得到IllegalBlockSizeException异常的原因。 一种方法是直接将数据加密到字符串中。
看看这个。尝试,你将能够解决这个问题public static String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
System.out.println("This is Data to be Decrypted" + decordedValue);
return decordedValue;
}
希望这会有所帮助。