【问题标题】:function decrypt throws javax.crypto.BadPaddingException: pad block corrupted in class SimpleCrypto in android函数解密抛出 javax.crypto.BadPaddingException:在 android 中的类 SimpleCrypto 中损坏的垫块
【发布时间】:2013-11-19 04:30:02
【问题描述】:

我正在编写一个 android 应用程序来解密存储在文件中的一些文本。我使用了以下代码 -

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));
    }

}

编辑:这是我要解密的文本 -

39D4CA73AAF2D42C32659FDC5D1848EA

用这个键-

thebestsecret153

如果有帮助的话。它应该显示in153

编辑:在 android 中引发错误的行。 -

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

我还在 swing 中创建了一个项目来读取文件并得到以下错误 -

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)

如果加密和解密在同一个程序中完成,它可以完美地工作。

感谢任何帮助。提前致谢。

【问题讨论】:

    标签: java android encryption


    【解决方案1】:

    TL;DR:SecureRandom.getInstance("SHA1PRNG") 可能并不总是返回相同的结果即使使用相同的种子播种。


    您已经走入了某个人设下的陷阱,他们认为伪随机数生成器 (PRNG) 与密钥推导函数 (KDF) 是一回事。总的来说,它们的运行非常接近。唯一的问题是,对于 Android 的加密提供程序实现(某些实现),setSeed 方法 种子添加到随机数中,即使它是第一次调用也是如此。因此,您每次都会生成不同的密钥。不同的密钥意味着可能永远无法解密的随机密文。

    随机密文意味着填充很可能是不正确的,因为使用错误密钥的 ECB 或 CBC 解密仍然返回明文 - 它就像密文一样是随机的。未填充例程可能在随机明文上失败,因此解密将失败并出现填充异常。请注意,另一方面,如果使用了错误的密钥,经过身份验证的密码(例如 GCM 模式加密)总是会失败。

    解决方案:使用真正的随机 AES 密钥,或使用内置 PBKDF2 功能从密码(和盐)派生密钥。您可以查看如何执行此操作的示例here


    将 SecureRandom 用于密钥派生函数的问题:

    • SecureRandom 算法可能(并且确实)因提供程序/运行时而异;
    • SecureRandom 实现可能因提供程序/运行时而异;
    • SecureRandom 实现可以在第一次调用SecureRandom 期间添加或替换种子;

    最后,一些提供者在使用"SHA1PRNG" 时返回一个完全不同的随机数生成器,因为许多人似乎默认这样做。创建随机数生成器时,只需改用new SecureRandom,并记住"SHA1PRNG" 并不表示特定的算法。

    对于提供者,我指的是 Java 密码体系结构 JCA 中解释的加密服务提供者;即java.security.Provider

    【讨论】:

    • 你能给我指出一个好的起点吗?碰巧的是,我读得越多,我就越困惑。
    • 好吧,关于字符串加密,你可以从我的代码here开始
    • 还有什么遗漏的吗,pankaj?不要忘记点击接受或指出为什么答案缺少有关您的问题的重要信息..
    • 很高兴听到这个消息,我希望你没有用那种奇怪的密钥派生机制加密太多数据。
    【解决方案2】:

    我编写了一个示例 blog,以帮助理解使用 Cipher 在 Android 中实现密码学。

    您也可以参考我在github 创建的示例项目。

    希望这也有帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-17
      • 2015-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多