下面的 Des 加密解密代碼,在加密時正常,但是在解密是拋出錯誤:
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.DESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..)
public class Des { static Des instance; static Key key; static Cipher encryptCipher; static Cipher decryptCipher; protected Des() { } protected Des(String strKey) { key = setKey(strKey); try { encryptCipher = Cipher.getInstance("DES"); encryptCipher.init(Cipher.ENCRYPT_MODE, key); decryptCipher = Cipher.getInstance("DES"); decryptCipher.init(Cipher.DECRYPT_MODE, key); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (NoSuchPaddingException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } } public static Des getInstance() { if (instance == null) { instance = new Des("diaxxxxoft@201Y10"); } return instance; } // 根據參數生成KEY private Key setKey(String strKey) { try { KeyGenerator _generator = KeyGenerator.getInstance("DES"); _generator.init(new SecureRandom(strKey.getBytes())); return _generator.generateKey(); } catch (Exception e) { e.printStackTrace(); } return null; } // 加密String明文輸入,String密文輸出 public String setEncString(String strMing) { BASE64Encoder base64en = new BASE64Encoder(); try { byte[] byteMing = strMing.getBytes("UTF-8"); byte[] byteMi = this.getEncCode(byteMing); return base64en.encode(byteMi); } catch (Exception e) { e.printStackTrace(); } return null; } //加密以byte[]明文輸入,byte[]密文輸出 private byte[] getEncCode(byte[] byteS) { byte[] byteFina = null; try { byteFina = encryptCipher.doFinal(byteS); } catch (Exception e) { e.printStackTrace(); } return byteFina; } // 解密:以String密文輸入,String明文輸出 public String setDesString(String strMi) { BASE64Decoder base64De = new BASE64Decoder(); try { byte[] byteMi = base64De.decodeBuffer(strMi); byte[] byteMing = this.getDesCode(byteMi); return new String(byteMing, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return null; } // 解密以byte[]密文輸入,以byte[]明文輸出 private byte[] getDesCode(byte[] byteD) { byte[] byteFina = null; try { byteFina = decryptCipher.doFinal(byteD); } catch (Exception e) { e.printStackTrace(); } return byteFina; } //多線程測試一下 public static void main(String[] args) throws InterruptedException { //沒有依賴注入的配置,所以在這裡手動生成一次 Des dtDes = Des.getInstance(); final String[] mi = new String[10]; for (int i = 0; i < 10; i++) { final Integer integer = i; Thread thread = new Thread() { public void run() { //明文加密: Des dtDes = Des.getInstance(); mi[integer] = dtDes.setEncString("ShowHistory.jsp?MenuId=345&MenuBelong=1&tableLimits=where a1450=RecordId"); //調用get函數獲取加密後密文。 } }; thread.start(); } Thread.sleep(5000); for (int i = 0; i < 10; i++) { final Integer integer = i; Thread thread2 = new Thread() { public void run() { System.out.println(String.format("mi[%s] = %s", integer, mi[integer])); //這樣來模擬另外一個頁面的獲取 Des dtDes2 = Des.getInstance(); String M = dtDes2.setDesString(mi[integer]);//調用get函數獲取解密後明文。 System.out.println(String.format("des[%s] = %s", integer, M)); } }; thread2.start(); } //等待打印完畢 Thread.sleep(5000); } }
解決方法:
將 setKey方法修改為如下:
// 根據參數生成KEY private Key setKey(String strKey) { try { SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); DESKeySpec keySpec = new DESKeySpec(strKey.getBytes("utf-8")); keyFactory.generateSecret(keySpec); return keyFactory.generateSecret(keySpec); } catch (Exception e) { e.printStackTrace(); } return null; }
不使用SecureRandom生成SecretKey,而是使用SecretKeyFactory;重新實現方法generateKey,代碼如下
問題解決。
另外如果 加密時 和解密 時使用的秘鑰 不一樣,也會報 相同的錯誤。
比如加密時使用的秘鑰:
diaxxxxoft@201xxxx10
而解密時使用的秘鑰:
addddxxxx
那麼在解密時也可能會報這個錯誤。