javax.crypto.BadPaddingException: Given final block not properly padded

时间:2021-06-07 18:32:02

在项目中运用到了Java的AES加密,本地Windows调试一切正常,部署到Linux服务器后一直报空指针异常。

经过一番调试,找到真正原因:javax.crypto.BadPaddingException: Given final block not properly padded

 1 package com.daredo.utils;
 2 
 3 import javax.crypto.Cipher;
 4 import javax.crypto.KeyGenerator;
 5 import javax.crypto.SecretKey;
 6 import javax.crypto.spec.SecretKeySpec;
 7 import java.security.SecureRandom;
 8 
 9 /**
10  * Created by IntelliJ IDEA
11  * Author: d-arlin@qq.com
12  * Date: 2018/3/14
13  * Time: 15:38
14  */
15 public class SecurityUtils {
16 
17     /**
18      * 编码格式
19      */
20     private static String ENCODING = "UTF-8";
21     /**
22      * 加密算法
23      */
24     public static final String KEY_ALGORITHM = "AES";
25 
26     /**
27      * 加密
28      *
29      * @param content 待加密内容
30      * @param key     加密的密钥
31      * @return
32      */
33     public static String encrypt(String content, String key) {
34         try {
35             KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
36             kgen.init(128, new SecureRandom(key.getBytes(ENCODING)));
37             SecretKey secretKey = kgen.generateKey();
38             byte[] enCodeFormat = secretKey.getEncoded();
39             SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, KEY_ALGORITHM);
40             Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
41             byte[] byteContent = content.getBytes(ENCODING);
42             cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
43             byte[] byteRresult = cipher.doFinal(byteContent);
44             StringBuffer sb = new StringBuffer();
45             for (int i = 0; i < byteRresult.length; i++) {
46                 String hex = Integer.toHexString(byteRresult[i] & 0xFF);
47                 if (hex.length() == 1) hex = '0' + hex;
48                 sb.append(hex.toUpperCase());
49             }
50             return sb.toString();
51         } catch (Exception e) {
52             e.toString();
53         }
54         return null;
55     }
56 
57     /**
58      * 解密
59      *
60      * @param content 待解密内容
61      * @param key     解密的密钥
62      * @return
63      */
64     public static String decrypt(String content, String key) {
65         if (content.length() < 1) return null;
66         byte[] byteRresult = new byte[content.length() / 2];
67         for (int i = 0; i < content.length() / 2; i++) {
68             int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
69             int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
70             byteRresult[i] = (byte) (high * 16 + low);
71         }
72         try {
73             KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
74             kgen.init(128, new SecureRandom(key.getBytes(ENCODING)));
75             SecretKey secretKey = kgen.generateKey();
76             byte[] enCodeFormat = secretKey.getEncoded();
77             SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, KEY_ALGORITHM);
78             Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
79             cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
80             byte[] result = cipher.doFinal(byteRresult);
81             return new String(result, ENCODING);
82         } catch (Exception e) {
83             e.toString();
84         }
85         return null;
86     }
87 
88 }

 

那么为什么在Windows正常,在Linux就出现异常呢?

原因分析
SecureRandom 实现完全随操作系统本身的內部状态,除非调用方在调用 getInstance 方法之后又调用了 setSeed 方法;

该实现在 windows 上每次生成的 key 都相同,但是在 solaris 或部分 linux 系统上则不同。

解决方法

 1 package com.daredo.utils;
 2 
 3 import javax.crypto.Cipher;
 4 import javax.crypto.KeyGenerator;
 5 import javax.crypto.SecretKey;
 6 import javax.crypto.spec.SecretKeySpec;
 7 import java.security.SecureRandom;
 8 
 9 /**
10  * Created by IntelliJ IDEA
11  * Author: d-arlin@qq.com
12  * Date: 2018/3/14
13  * Time: 15:38
14  */
15 public class SecurityUtils {
16 
17     /**
18      * 编码格式
19      */
20     private static final String ENCODING = "UTF-8";
21     /**
22      * 加密算法
23      */
24     public static final String KEY_ALGORITHM = "AES";
25     /**
26      * 签名算法
27      */
28     public static final String SIGN_ALGORITHMS = "SHA1PRNG";
29 
30     /**
31      * 加密
32      *
33      * @param content 待加密内容
34      * @param key     加密的密钥
35      * @return
36      */
37     public static String encrypt(String content, String key) {
38         try {
39             KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
40             SecureRandom random = SecureRandom.getInstance(SIGN_ALGORITHMS);
41             random.setSeed(key.getBytes(ENCODING));
42             kgen.init(128, random);
43             SecretKey secretKey = kgen.generateKey();
44             byte[] enCodeFormat = secretKey.getEncoded();
45             SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, KEY_ALGORITHM);
46             Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
47             byte[] byteContent = content.getBytes(ENCODING);
48             cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
49             byte[] byteRresult = cipher.doFinal(byteContent);
50             StringBuffer sb = new StringBuffer();
51             for (int i = 0; i < byteRresult.length; i++) {
52                 String hex = Integer.toHexString(byteRresult[i] & 0xFF);
53                 if (hex.length() == 1) hex = '0' + hex;
54                 sb.append(hex.toUpperCase());
55             }
56             return sb.toString();
57         } catch (Exception e) {
58             e.toString();
59         }
60         return null;
61     }
62 
63     /**
64      * 解密
65      *
66      * @param content 待解密内容
67      * @param key     解密的密钥
68      * @return
69      */
70     public static String decrypt(String content, String key) {
71         if (content.length() < 1) return null;
72         byte[] byteRresult = new byte[content.length() / 2];
73         for (int i = 0; i < content.length() / 2; i++) {
74             int high = Integer.parseInt(content.substring(i * 2, i * 2 + 1), 16);
75             int low = Integer.parseInt(content.substring(i * 2 + 1, i * 2 + 2), 16);
76             byteRresult[i] = (byte) (high * 16 + low);
77         }
78         try {
79             KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
80             SecureRandom random = SecureRandom.getInstance(SIGN_ALGORITHMS);
81             random.setSeed(key.getBytes(ENCODING));
82             kgen.init(128, random);
83             SecretKey secretKey = kgen.generateKey();
84             byte[] enCodeFormat = secretKey.getEncoded();
85             SecretKeySpec secretKeySpec = new SecretKeySpec(enCodeFormat, KEY_ALGORITHM);
86             Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
87             cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
88             byte[] result = cipher.doFinal(byteRresult);
89             return new String(result, ENCODING);
90         } catch (Exception e) {
91             e.toString();
92         }
93         return null;
94     }
95 
96 }

改动的地方如代码中已标红。