Java BadPaddingException:给定的最终块未正确填充
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23070838/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
BadPaddingException: Given final block not properly padded
提问by André Perazzi
I have a private key file encripted with DES/ECB/PKCS5Padding (56 bit DES key generated by a secret phrase) and I want to decrypt it. I don't know why, but everytime I try to decript, the method doFinal of my cipher class is throwing this error:
我有一个用 DES/ECB/PKCS5Padding(由秘密短语生成的 56 位 DES 密钥)加密的私钥文件,我想解密它。我不知道为什么,但是每次我尝试解密时,我的密码类的方法 doFinal 都会抛出此错误:
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.DESCipher.engineDoFinal(DashoA13*..) at javax.crypto.Cipher.doFinal(DashoA13*..) at...
javax.crypto.BadPaddingException:在 com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) at com 中,给定最终块未正确填充.sun.crypto.provider.DESCipher.engineDoFinal(DashoA13*..) 在 javax.crypto.Cipher.doFinal(DashoA13*..) 在...
Here is my code:
这是我的代码:
public static PrivateKey readPrivateKeyFromFile(File file, String chaveSecreta) {
try {
SecureRandom r = new SecureRandom(chaveSecreta.getBytes());
KeyGenerator keyGen = KeyGenerator.getInstance("DES");
keyGen.init(56, r);
Key key = keyGen.generateKey();
byte[] privateKeyBytes = decryptPKFile(file, key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = null;
try {
privateKey = keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException e) {
JOptionPane.showMessageDialog(null, "Erro 01, tente mais tarde");
}
return privateKey;
} catch (NoSuchAlgorithmException e) {
JOptionPane.showMessageDialog(null, "Erro 02, tente mais tarde");
}
return null;
}
public static byte[] decryptPKFile(File file, Key key){
try{
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
byte[] cipherText = readBytes(file);
cipher.init(Cipher.DECRYPT_MODE, key);
System.out.println(cipher);
System.out.println(cipherText);
byte[] text = cipher.doFinal(cipherText);
return text;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
public static byte[] readBytes(File file) {
try {
FileInputStream fs = new FileInputStream(file);
byte content[] = new byte[(int) file.length()];
fs.read(content);
return content;
} catch (FileNotFoundException e) {
System.out.println("Arquivo n?o encontrado!");
e.printStackTrace();
} catch (IOException ioe) {
System.out.println("Erro ao ler arquivo!");
ioe.printStackTrace();
}
return null;
}
Any syggestions?
任何syggestions?
采纳答案by Maarten Bodewes
You're trying to decrypt ciphertext with a random number generator created using a specific seed. However, you don't specify the algorithm, and the algorithm may change internally as well. Android is even known to generate a fully random value instead for some versions.
您正在尝试使用使用特定种子创建的随机数生成器解密密文。但是,您没有指定算法,算法也可能在内部发生变化。众所周知,Android 会为某些版本生成完全随机的值。
You need to use a SecretKeyFactory
not a KeyGenerator
. And you will of course need the 8-byte key data. The only way to retrieve this in your case is to find the SecureRandom
algorithm/implementation before and re-calculate the key.
您需要使用一个SecretKeyFactory
not a KeyGenerator
。您当然需要 8 字节的密钥数据。在您的情况下检索它的唯一方法是在之前找到SecureRandom
算法/实现并重新计算密钥。
Now any ciphertext will decrypt with any key. DES ECB only provides (some sort of) confidentiality, not integrity. The problem is that it will decrypt into garbage. Now if you try to remove the padding from garbage you will likely get a padding error.
现在任何密文都可以用任何密钥解密。DES ECB 仅提供(某种)机密性,而不提供完整性。问题是它会解密成垃圾。现在,如果您尝试从垃圾中删除填充,您可能会收到填充错误。
If you're "lucky" - once in about 256 times - you will get a result. This happens when the decrypted block ends with 01
or 0202
, that's valid padding. The result will - of course - be garbage as well, but it will not end with a BadPaddingException
. In your case the SecureRandom
instance is likelyto return the same incorrect value over and over though, so this may never happen.
如果你很“幸运”——大约 256 次——你会得到一个结果。当解密块以01
or结尾时会发生这种情况0202
,这是有效的填充。结果当然也会是垃圾,但不会以BadPaddingException
. 在您的情况下,该SecureRandom
实例可能会一遍又一遍地返回相同的错误值,因此这可能永远不会发生。
In the future, please use PBKDF2 and feed it the encoded password. Clearly note the character encoding used, Java SE uses the lowest 8 bits of the char array. Never ever use String.getBytes()
as the default encoding may differ between systems.
将来,请使用 PBKDF2 并将编码的密码提供给它。清楚地注意所使用的字符编码,Java SE 使用 char 数组的最低 8 位。永远不要使用,String.getBytes()
因为默认编码可能因系统而异。