【问题标题】:AES BadPaddingExceptionAES BadPaddingException
【发布时间】:2014-03-19 15:46:46
【问题描述】:

如果我使用错误的密钥或错误的盐进行解密,则会引发 BadPaddingException。 我希望返回一个不正确的字符串。 doFinal() 导致解密方法中的异常

留言: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);
    }

谢谢! 弗雷德里克

【问题讨论】:

    标签: java aes


    【解决方案1】:

    填充是一个很好的完整性检查。假设错误解密的数据是均匀分布的,每 255 个错误密码,它只会出现大约 1 次正确的 PKCS5/PKCS7 填充。 (1/256 + 1/256^2 + 1/256^3 ...)

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

    还有一件事:如果攻击者可以反复更改密文并让您解密它(例如存储在 cookie 中的加密数据),并且当解密的数据引发异常时,他们是否可以区分您的行为错误的填充,当它只是垃圾时,他们可以通过“填充预言攻击”来确定明文。

    顺便说一句,如果你真的想要你所期望的行为,你可以使用“AES/CTR/NoPadding”,它不需要确切的块大小并且总是返回一个解密的字节[ ],无论键是否匹配。

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 我已将密码的 initline 更改为:cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");但是抛出了同样的异常......为了获得正确的长度,我使用了 SHA-Hash - 我认为这应该足够了。此外,我第一次使用 setup() 方法时没有抛出异常
      • @Frederik:您必须了解填充的工作原理:填充模式会在加密之前将一些填充内容附加到纯文本数据中。解密后,此填充将再次被剥离。但是要知道要删除多少字节,填充的内容很重要,如果我们用错误的密钥解密,最后一些字节不是填充算法会添加的格式之一。如前所述,使用NoPadding,但是你必须确保你的数据长度是块长度的倍数。
      • PKCS5PaddingRFC 1423 DES CBC 中描述的相同。
      • 对不起,我还是没明白这个问题。我的加密数据的长度是 32。块长度是 16 不是吗?如果我继续让密码在长度无效的情况下抛出异常,这是一个安全漏洞吗?
      【解决方案3】:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-22
        • 2021-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多