[英]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用于密钥派生功能的问题:
SecureRandom
algorithm may (and does) differ per provider/runtime; SecureRandom
算法在每个提供者/运行时可能(并且确实)有所不同; SecureRandom
implementation may differ per provider/runtime; SecureRandom
实现可能因提供者/运行时间而异; 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
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.