2011-04-08 34 views
2

如果我使用错误的键或错误的盐进行解密BadPaddingException被抛出。 我期望一个不正确的字符串被返回。 的doFinal()导致异常的解密法AES BadPaddingException

消息: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); 
    } 

谢谢! 弗雷德里克

回答

3

你应该或者使用AES与隐式填充声明(见the available modes)或强制的长度(以字节为单位)的加密/解密数据的,要作16

另外的倍数,在默认情况下,JAVA使用ECB模式,根据您使用的数据类型,这可能确实不安全,您应该使用CBC模式。

+0

我已经改变了密码的initline在一个提供者无关的方式的密钥:密码= Cipher.getInstance( “AES/CBC/PKCS5Padding”); 但是抛出同样的异常。 为了获得正确的长度,我使用了SHA-Hash - 我认为这应该足够了。 此外,我第一次使用setup()方法时不会引发异常 – Frederik 2011-04-08 15:28:21

+3

@Frederik:您必须了解填充的工作方式:填充模式将在加密之前将一些填充内容附加到纯文本数据。解密后,该填充再次被剥离。但要知道有多少个字节需要去除,填充的内容很重要,如果我们使用错误的密钥解密,最后一些字节不是将被填充算法添加的格式之一。如上所述,使用'NoPadding',但是您必须确保您的数据长度是块长度的倍数。 – 2011-04-08 15:49:48

+0

对于'PKCS5Padding',它与DES CBC的[RFC 1423](http://tools.ietf.org/html/rfc1423#section-1.1)中描述的相同。 – 2011-04-08 15:57:51

6

填充是一个很好的健全性检查。假设解密不正确的数据是均匀分布的,那么对于每255个不正确的密码,它将只显示为正确的PKCS5/PKCS7填充约1次。 (1/256 + 1/256^2 + 1/256^3 ...)

所以这很有帮助,但它不是你应该依赖的东西---实际上几乎是8位的消息摘要并不是对数据完整性的充分测试。还有一件事:如果攻击者可以反复更改密文并让你解密它(例如可能是存储在cookie中的加密数据),并且它们能够区分你的行为,当解密的数据抛出异常时对于不好的填充,当它只是垃圾时,他们可以通过“填充oracle攻击”来确定明文。顺便说一下,如果你真的想要想要你所期望的行为,你可以使用“AES/CTR/NoPadding”,它不需要一个确切的块大小,并且总是会返回一个解密的字节[],不管是或者不是钥匙匹配。