AES BadPaddingException

如果我使用错误的密钥或错误的盐进行解密,则抛出BadPaddingException。 我希望返回一个不正确的字符串。 doFinal()在decrypt-method中引发exception

消息: This is just an example

Unfug: 'ΩÙΩ„SåF?V®ßs.k˚·ºç€èÀHfif∫ÙÉÕ

 Exception in thread "main" 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.AESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) at casino.AES.decryptString(AES.java:130) at casino.AES.main(AES.java:172) 

  public static void main(String[] args) throws Exception { //Encryption AES encr = new AES(); encr.setKey("KEY"); encr.setSalt("SALT"); encr.setup(); String message = "This is just an example"; System.out.println("Message : " + message); byte[] code = encr.encrypt(message); System.out.println("Encrypted Strinng : "+ new String(code, "UTF-8")); //Decryption AES dec = new AES(); dec.setKey("INCORRECT"); //<--- incorrect dec.setSalt("SALT"); dec.setup(); System.out.println(dec.decryptString(code)); } public synchronized void setKey(String key) throws UnsupportedEncodingException { this.key = key.getBytes("UTF-8"); isPasswordAlreadySet = true; } public synchronized void setSalt(String salt) throws UnsupportedEncodingException { this.salt = salt.getBytes("UTF-8"); } public synchronized void setup() throws Exception { MessageDigest digest = MessageDigest.getInstance("SHA-256"); digest.update(key); digest.update(salt); byte[] raw = digest.digest(); skeySpec = new SecretKeySpec(raw, "AES"); cipher = Cipher.getInstance("AES"); } public synchronized byte[] encrypt(byte[] klartext) throws Exception { cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(klartext); return encrypted; } public synchronized byte[] encrypt(String klartext) throws Exception{ return encrypt(klartext.getBytes("UTF-8")); } public synchronized byte[] decrypt(byte[] code) throws Exception { cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] original = cipher.doFinal(code); return original; } public synchronized double decryptDouble(byte[] code) throws Exception { cipher.init(Cipher.DECRYPT_MODE, skeySpec); byte[] original = cipher.doFinal(code); return doubleFromBytes( original); } 

谢谢! 弗雷德里克

衬垫是一个很好的理智检查。 假设错误解密的数据是均匀分布的,那么对于每255个不正确的密码,它只会被正确地PKCS5 / PKCS7填充大约1次。 (1/256 + 1/256 ^ 2 + 1/256 ^ 3 …)

所以它很有用,但它不是你应该依赖的东西 – 实际上几乎是8位的消息摘要是不是对数据完整性的充分测试。

还有一件事:如果攻击者可以反复改变密文并让你解密它(例如,一个例子可能是存储在cookie中的加密数据),并且如果他们可以区分你的行为,当解密数据抛出错误填充的exception时当它只是垃圾时,他们可以通过“填充oracle攻击”来确定明文。

顺便说一句,如果你真的想要想要的行为,你可以使用“AES / CTR / NoPadding”,它不需要精确的块大小,并且无论密钥是否匹配,都将返回一个解密的byte []。

您应该使用带有隐式填充声明的AES(请参阅可用模式 )或强制加密/解密数据的长度(以字节为单位)为16的倍数。

此外,默认情况下,java使用ECB模式,根据您使用的数据类型,它可能真的不安全,您应该使用CBC模式。