记一次文件编码出现的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.结论:加密过程中字节长度可能会变化,因此解密时字节长度应该和加密时字节长度存在一定的相关关系,不能随便设置。

原文地址:https://www.cnblogs.com/fiftyonesteps/p/11245517.html