记一次文件编码出现的BUG javax.crypto.BadPaddingException: Given final block not properly padded
1.前景:工作中需要实现一个功能,导出的数据需要加密,不能被明文看到,使用DES加密,对byte数组加密解密操作代码如下
public class DESTool { static String transformation = "DESede/ECB/PKCS5Padding"; static String algorithm = "DESede"; public byte[] decode(byte[] srcByte, byte[] keyByte, int offset, int length) throws Exception, NoSuchAlgorithmException { // DESKeySpec spec = new DESKeySpec(keyByte); // SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm); // SecretKey secretKey = keyFactory.generateSecret(spec); SecretKey secretKey = new SecretKeySpec(keyByte, algorithm); // KeySpec spec = new SecretKeySpec(keyByte, algorithm); // SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm); // SecretKey secretKey = keyFactory.generateSecret(spec); Cipher cipher = Cipher.getInstance(transformation); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] b = cipher.doFinal(srcByte, offset, length); return b; } public byte[] encode(byte[] srcByte, byte[] keyByte, int offset, int length) throws Exception, NoSuchAlgorithmException { // DESKeySpec spec = new DESKeySpec(keyByte); // SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm); // SecretKey secretKey = keyFactory.generateSecret(spec); SecretKey secretKey = new SecretKeySpec(keyByte, algorithm); // KeySpec spec = new SecretKeySpec(keyByte, algorithm); // SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm); // SecretKey secretKey = keyFactory.generateSecret(spec); Cipher cipher = Cipher.getInstance(transformation); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] b = cipher.doFinal(srcByte, offset, length); return b; } }
2.在使用如上方法进行加解密时,由于文件大小是不确定的,所以使用分批次加解密,一次加解密50*1024个byte
3.自主测试没有问题,但是测试环境上出现问题,堆栈信息如下
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.DESedeCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..)
4.网上搜索答案都是说一些linux上SecretKey获取的问题,但是和本人工作中的状况不符,本人工作中windows开发环境上加密导出的文件去测试环境导入是可以正常导入的,并且本人写了测试类,编译成class文件后去测试环境执行class文件,加解密没有问题,所以这个可能性排除
5.于是我要来了测试环境的数据库连接信息,本地连接测试数据库,同时导出未加密的明文文件和加密的密文文件,之后对明文文件加密之后和密文文件逐字节进行对比,对比结果完全一样
6.最后想到加密解密是按自己进行的,会不会是加解密的字节长度导致的,于是我把测试类中加密明文文件时使用的字节数组长度设置为5*1024,而不是50*1024,之后加密,再和密文文件逐字节对比,果然出现了不同,
7.最后经测试,需加密的字节长度和加密结果的字节长度存在以下关系:加密结果字节长度 = (需加密字节长度/8)* 8 + 8;于是我把解密时字节长度改为了50*1024+8,问题解决
8.结论:加密过程中字节长度可能会变化,因此解密时字节长度应该和加密时字节长度存在一定的相关关系,不能随便设置。