我正在使用这种AES加密和解密方法来加密我的数据。 udp没有问题但是当我使用tcp时我得到了这个错误" javax.crypto.IllegalBlockSizeException:当使用填充密码进行解密时输入长度必须是16的倍数"
AES加密/解密代码:
public class AESEncDec {
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);
System.err.println("encVal: "+encryptedValue.length());
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);
//byte[] decValue = c.doFinal(encryptedData.getBytes());
String decryptedValue = new String(decValue);
System.err.println("decVal: "+decryptedValue.length());
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGO);
return key;
}
}
TCP服务器代码:
class TCPServer
{
public static void main(String argv[]) throws Exception
{
AESEncDec edData= new AESEncDec();
// AES edData= new AES();
String msg="Message_";
String clientSentence="";
String capitalizedSentence;
ServerSocket welcomeSocket = new ServerSocket(6789);
Socket connectionSocket = welcomeSocket.accept();
for (int i = 0; i < 10; i++)
{
clientSentence=edData.encrypt(msg+i)+"\n";
DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());
outToClient.writeBytes(clientSentence);
Thread.sleep(100);
}
}
}
TCP客户端代码:
class TCPClient {
public static void main(String argv[]) throws Exception {
AESEncDec edData= new AESEncDec();
String modifiedSentence;
String DecData="";
Socket clientSocket = new Socket("localhost", 6789);
while(true){
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
modifiedSentence = inFromServer.readLine();
DecData=edData.decrypt(modifiedSentence);
System.out.println("FROM SERVER: " + DecData);
}
//clientSocket.close();
}
}
对于相同的代码,当消息很小时,它会被正确解密。但是当消息很长时,我得到了illegalBlocksize异常。 我尝试使用AES / CBC / PKCS5Padding以便消息被填充并且blocksize以16的倍数出现。但是我仍然得到相同的错误或BadPaddingException。如果我指定PKCS5Padding作为填充技术,那么消息应该正确填充,不应该给出这个错误。为什么这不起作用。我该怎么做才能正确解密数据。请帮忙..
答案 0 :(得分:1)
问题是TCP为您提供了一个流。如果您读取一个块并尝试解密它,它可能会失败,因为块的大小可能不是16(或128)的倍数。 AES适用于16字节或128字节数据块。因此,您可能需要等待一段时间才能在解密之前收集大量数据。
由于UDP是面向消息的,因此不会遇到这样的问题。
@Kiara,请使用Java8的内置编码,看看它是如何工作的。有关文档,请参阅here。示例:
String asB64 = Base64.getEncoder().encodeToString(data.getBytes("utf-8"));
对于长度高达7兆字节的消息进行了测试。它没有在编码消息中引入换行符。
答案 1 :(得分:1)
AES是块密码,只能将16个字节加密到16个字节。如果要加密任意输入,则需要一种操作模式和填充方案。默认模式通常是ECB,默认填充方案是PKCS#5填充(实际上是PKCS#7填充)。
这意味着单个加密也必须以完全相同的方式解密,因为在解密期间必须删除填充。重要的是,多个密文不会重叠并且不会被分解(分块/包裹) 这就是你的换行字符在加密多个消息时应该做的事情,因为你在接收端按行读取密文。
问题是默认的sun.misc.BASE64Encoder#encode
方法实际上自己引入了换行符。每76个字符都插入一个换行符,但是接收者无法知道哪个换行符实际上将消息密文分开,哪个换行符将单个消息密文中的换行分开。
最简单的解决方法是在Base64编码后删除换行符:
String encryptedValue = new BASE64Encoder().encode(encVal).replaceAll("\\s", "");
这将替换单个消息密文中的所有空格。
由于您正在使用私有sun.misc.*
类,因此最好转移到另一个Base64实现,因为这些类不必在每个JVM中都可用。您应该使用一些已知的库,例如Apache的commons-codec,它提供implementation,您可以在其中禁用包装/分块:
String encryptedValue = Base64.encodeBase64(encVal, false);
相当于
String encryptedValue = Base64.encodeBase64(encVal);