AES对称加密:客户端发加密数据至服务器解密时出现BadPaddingException
解决AES解密时的BadPaddingException问题
看起来你遇到的这个BadPaddingException主要是两个小细节处理错误导致的,咱们一步步梳理和修正:
问题1:服务器错误处理了接收到的加密数据长度
你在服务器里直接用packet.getData()获取数据,但这个方法返回的是你初始化的1024字节数组——而客户端实际发送的加密数据长度远小于这个值,数组里多余的部分都是默认填充的0字节。当你把包含这些无效字节的数组传给cipher.doFinal()时,AES的PKCS5填充验证就会失败,因为这些额外的0不符合填充规则。
正确的做法是获取数据包的有效长度,然后截取对应长度的字节数组来解密:
byte[] EncryptedData = Arrays.copyOfRange(packet.getData(), 0, packet.getLength());
问题2:解密时Cipher初始化参数错误
在解密模式初始化Cipher时,你写了:
cipher.init(Cipher.DECRYPT_MODE,secretKey, cipher.getParameters());
但此时cipher刚被实例化,还没有任何有效参数,传递cipher.getParameters()完全没必要(而且在ECB模式下,AES本来就不需要额外的算法参数)。直接使用两个参数的init方法即可:
cipher.init(Cipher.DECRYPT_MODE, secretKey);
另外,服务器里打印解密后的数据时,直接输出plainBytesDecrypted只会显示字节数组的内存地址,应该转成字符串才能看到明文:
System.out.println("Decrypted data: " + new String(plainBytesDecrypted));
修正后的完整服务器代码
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.util.Arrays; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; public class Server { public static void main(String[] args) throws IOException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException { int port = 56321; byte[] keySymme = { 0x74, 0x68, 0x69, 0x73, 0x49, 0x73, 0x41, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79 };//"thisIsASecretKey"; SecretKeySpec secretKey = new SecretKeySpec(keySymme, "AES"); DatagramSocket socket = new DatagramSocket(port); DatagramPacket packet = null; byte[] data = null; while(true){ data = new byte[1024]; packet = new DatagramPacket(data, data.length); socket.receive(packet); int port2 = packet.getPort(); InetAddress address = packet.getAddress(); // 修正:获取有效加密数据 byte[] EncryptedData = Arrays.copyOfRange(packet.getData(), 0, packet.getLength()); System.out.println("Address " + address + " Port " + port2 + " Encrypted data length: " + EncryptedData.length); System.out.println("Listening..."); try { Cipher cipher = Cipher.getInstance("AES"); // 修正:解密模式初始化,不需要额外参数 cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] plainBytesDecrypted = cipher.doFinal(EncryptedData); // 修正:转成字符串输出明文 System.out.println("Decrypted data: " + new String(plainBytesDecrypted)); } catch(Exception e) { e.printStackTrace(); } } } }
额外提示
虽然你的代码现在能正常工作,但ECB模式是不安全的(它不对数据做混淆,相同的明文块会得到相同的密文块),实际生产环境建议使用更安全的模式,比如AES/CBC/PKCS5Padding或者AES/GCM/NoPadding,不过这需要额外处理IV(初始化向量)的传递,感兴趣的话可以深入了解下。
内容的提问来源于stack exchange,提问作者Nfernandez
相关产品推荐
相关产品推荐

