简体   繁体   English

函数解密引发javax.crypto.BadPaddingException:android中的类SimpleCrypto中的填充块已损坏

[英]function decrypt throws javax.crypto.BadPaddingException: pad block corrupted in class SimpleCrypto in android

I am writing an android app that decrypts some text stored in a file. 我正在编写一个可解密文件中存储的某些文本的android应用。 I used the following code - 我使用了以下代码-

public class SimpleCrypto {
    public static String encrypt(String seed, String cleartext)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] result = encrypt(rawKey, cleartext.getBytes());
        return toHex(result);
    }

    public static String decrypt(String seed, String encrypted)
            throws Exception {
        byte[] rawKey = getRawKey(seed.getBytes());
        byte[] enc = toByte(encrypted);
        byte[] result = decrypt(rawKey, enc);
        return new String(result);
    }

    private static byte[] getRawKey(byte[] seed) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
        sr.setSeed(seed);
        kgen.init(128, sr); // 192 and 256 bits may not be available
        SecretKey skey = kgen.generateKey();
        byte[] raw = skey.getEncoded();
        return raw;
    }

    private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
        byte[] encrypted = cipher.doFinal(clear);
        return encrypted;
    }

    private static byte[] decrypt(byte[] raw, byte[] encrypted)
            throws Exception {
        SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        byte[] decrypted = cipher.doFinal(encrypted);//this is the line that throws error
        return decrypted;
    }

    public static String toHex(String txt) {
        return toHex(txt.getBytes());
    }

    public static String fromHex(String hex) {
        return new String(toByte(hex));
    }

    public static byte[] toByte(String hexString) {
        int len = hexString.length() / 2;
        byte[] result = new byte[len];
        for (int i = 0; i < len; i++)
            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),
                    16).byteValue();
        return result;
    }

    public static String toHex(byte[] buf) {
        if (buf == null)
            return "";
        StringBuffer result = new StringBuffer(2 * buf.length);
        for (int i = 0; i < buf.length; i++) {
            appendHex(result, buf[i]);
        }
        return result.toString();
    }

    private final static String HEX = "0123456789ABCDEF";

    private static void appendHex(StringBuffer sb, byte b) {
        sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
    }

}

EDIT: This is the text that I am trying to decrypt - 编辑:这是我要解密的文字-

39D4CA73AAF2D42C32659FDC5D1848EA

with this key - 用这个键-

thebestsecret153

if that helps. 如果有帮助。 it should show in153 . 它应该显示在in153

EDIT: The line that throws the error in android. 编辑:在Android中引发错误的行。 - --

byte[] decrypted = cipher.doFinal(encrypted);

I also created a project in swing to read from a file and got the following error - 我还摆动创建了一个项目以从文件中读取,并收到以下错误-

javax.crypto.BadPaddingException: Given final block not properly padded
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
    at javax.crypto.Cipher.doFinal(Cipher.java:2087)
    at decrypt.Decrypt.decrypt(Decrypt.java:43)
    at decrypt.MainForm.jButton1MouseClicked(MainForm.java:91)
    at decrypt.MainForm.access$000(MainForm.java:20)
    at decrypt.MainForm$1.mouseClicked(MainForm.java:46)
    at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:270)
    at java.awt.Component.processMouseEvent(Component.java:6508)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3320)
    at java.awt.Component.processEvent(Component.java:6270)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4861)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4501)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
    at java.awt.Container.dispatchEventImpl(Container.java:2273)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:708)
    at java.awt.EventQueue$4.run(EventQueue.java:706)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
    at java.lang.String.<init>(String.java:556)
    at decrypt.MainForm.jButton1MouseClicked(MainForm.java:91)
    at decrypt.MainForm.access$000(MainForm.java:20)
    at decrypt.MainForm$1.mouseClicked(MainForm.java:46)
    at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:270)
    at java.awt.Component.processMouseEvent(Component.java:6508)
    at javax.swing.JComponent.processMouseEvent(JComponent.java:3320)
    at java.awt.Component.processEvent(Component.java:6270)
    at java.awt.Container.processEvent(Container.java:2229)
    at java.awt.Component.dispatchEventImpl(Component.java:4861)
    at java.awt.Container.dispatchEventImpl(Container.java:2287)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
    at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4501)
    at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
    at java.awt.Container.dispatchEventImpl(Container.java:2273)
    at java.awt.Window.dispatchEventImpl(Window.java:2719)
    at java.awt.Component.dispatchEvent(Component.java:4687)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
    at java.awt.EventQueue$4.run(EventQueue.java:708)
    at java.awt.EventQueue$4.run(EventQueue.java:706)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

It works perfectly if encryption and decryption is done in same program. 如果在同一程序中完成加密和解密,则可以完美地工作。

Any help is appreciated. 任何帮助表示赞赏。 Thanks in advance. 提前致谢。

TL;DR: SecureRandom.getInstance("SHA1PRNG") may not always return the same results even when seeded with the same seed. TL; DR: 即使使用相同的种子进行播种, SecureRandom.getInstance("SHA1PRNG")也不总是返回相同的结果。


You have walked in the trap set up by some person that thought a Pseudo Random Number Generator (PRNG) is the same thing as a Key Derivation Function (KDF). 您走进了一个人的陷阱,他认为伪随机数生成器(PRNG)与密钥派生函数(KDF)是同一回事。 And in general, they are pretty close in operation. 通常,它们在运行中非常接近。 The only problem is that with (some implementations of) Android's crypto provider implementation, the setSeed method adds the seed to the random, even when it is the first call. 唯一的问题是,使用Android的加密提供程序实现(的某些实现),即使是第一次调用, setSeed方法也种子添加到随机数中。 So you will generate a different key each time. 因此,您每次都会生成一个不同的密钥。 Different keys mean random ciphertext that may never be decrypted. 不同的密钥意味着可能永远不会被解密的随机密文。

Random ciphertext means that the padding is very likely to be incorrect as ECB or CBC decryption with the wrong key still returns plaintext - it's just random just like the ciphertext. 随机密文意味着填充很可能是不正确的,因为使用错误密钥的ECB或CBC解密仍会返回纯文本-它就像密文一样是随机的。 The unpadding routine is likely to fail on randomized plaintext, so the decryption will fail with a padding exception. 取消填充例程可能会在随机化的纯文本上失败,因此解密将失败,并出现填充异常。 Note that authenticated ciphers such as GCM mode encryption will on the other hand always fail if the wrong key is used. 请注意,如果使用了错误的密钥,则诸如GCM模式加密之类的经过身份验证的密码总是会失败。

The solution: use a true random AES key, or use the build-in PBKDF2 functionality to derive a key from a password (and salt). 解决方案:使用真正的随机AES密钥,或使用内置的PBKDF2功能从密码(和密码)派生密钥。 You can view an examples of how to do this here . 您可以在此处查看如何执行此操作的示例。


Issues with using SecureRandom for key derivation functions: 将SecureRandom用于密钥派生功能的问题:

  • the SecureRandom algorithm may (and does) differ per provider/runtime; SecureRandom算法在每个提供者/运行时可能(并且确实)有所不同;
  • the SecureRandom implementation may differ per provider/runtime; SecureRandom实现可能因提供者/运行时间而异;
  • the SecureRandom implementation may either add or replace the seed during the first call of SecureRandom ; SecureRandom实现可以在第一次调用SecureRandom期间添加或替换种子;

Finally some providers return a completely different random number generator when "SHA1PRNG" is used as many people seem to do this by default. 最终,当使用"SHA1PRNG"时,某些提供程序会返回完全不同的随机数生成器,因为许多人似乎默认情况下会这样做。 When creating a random number generator simply use new SecureRandom instead and remember that "SHA1PRNG" does not denote a specific algorithm. 创建随机数生成器时,只需使用new SecureRandom代替,并记住"SHA1PRNG"并不表示特定的算法。

With provider I mean a cryptographic service provider as explained in the Java Cryptography Architecture, JCA; 提供程序是指Java密码体系结构JCA中解释的加密服务提供程序; ie a java.security.Provider . java.security.Provider

I had written a sample blog , to help understand Using Cipher to implement Cryptography in Android. 我写了一个示例博客 ,以帮助理解使用密码在Android中实现密码术。

You can also reference a sample project I created on github for the same. 您也可以引用我在github上创建的示例项目。

Hope this helps too. 希望这也会有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 javax.crypto.BadPaddingException:pad块损坏 - javax.crypto.BadPaddingException: pad block corrupted Android javax.crypto.BadPaddingException:填充块已损坏 - Android javax.crypto.BadPaddingException: pad block corrupted 文件解密失败:javax.crypto.BadPaddingException:填充块已损坏 - Decryption of file fails: javax.crypto.BadPaddingException: pad block corrupted javax.crypto.BadPaddingException:填充块损坏的异常 - javax.crypto.BadPaddingException: pad block corrupted exception javax.crypto.BadPaddingException:填充块有时损坏 - javax.crypto.BadPaddingException: pad block corrupted sometimes 错误:javax.crypto.BadPaddingException:解密时填充块损坏 - Error : javax.crypto.BadPaddingException: pad block corrupted while Decryption 解密图像时,给出javax.crypto.BadPaddingException:填充块损坏的Android - When Decrypting Image, gives javax.crypto.BadPaddingException: pad block corrupted Android Java Blowfish CBC 解密 javax.crypto.BadPaddingException:填充块已损坏 - Java Blowfish CBC Decryption javax.crypto.BadPaddingException: pad block corrupted AES128解密:javax.crypto.badpaddingexception pad块损坏 - AES128 Decryption :javax.crypto.badpaddingexception pad block corrupted javax.crypto.BadPaddingException:未知的块类型 - javax.crypto.BadPaddingException: unknown block type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM