如何在 Java 中使用 MD5 和 DES 调试 "Given final block not properly padded"?
How to debug "Given final block not properly padded" with MD5 and DES in Java?
我的计算机上有使用此代码加密的文件:
//Arbitrarily selected 8-byte salt sequence:
private static final byte[] salt = {
(byte) 0x43, (byte) 0x76, (byte) 0x95, (byte) 0xc7,
(byte) 0x5b, (byte) 0xd7, (byte) 0x45, (byte) 0x17
};
public static Cipher makeCipher(String pass, Boolean decryptMode) throws GeneralSecurityException{
//Use a KeyFactory to derive the corresponding key from the passphrase:
PBEKeySpec keySpec = new PBEKeySpec(pass.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");//PBKDF2WithHmacSHA256
SecretKey key = keyFactory.generateSecret(keySpec);
//Create parameters from the salt and an arbitrary number of iterations:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 42);
//Set up the cipher:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
//Set the cipher mode to decryption or encryption:
if(decryptMode){
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}
/**Encrypts one file to a second file using a key derived from a passphrase:**/
public static void encryptFile(String fileName, String pass){
try{
byte[] decData;
byte[] encData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = Main.makeCipher(pass, true);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
int blockSize = 8;
//Figure out how many bytes are padded
int paddedCount = blockSize - ((int)inFile.length() % blockSize );
//Figure out full size including padding
int padded = (int)inFile.length() + paddedCount;
decData = new byte[padded];
inStream.read(decData);
inStream.close();
//Write out padding bytes as per PKCS5 algorithm
for( int i = (int)inFile.length(); i < padded; ++i ) {
decData[i] = (byte)paddedCount;
}
//Encrypt the file data:
encData = cipher.doFinal(decData);
writeToFile(fileName, encData);
} catch(Exception e){
e.printStackTrace();
}
}
private static void writeToFile(String path, byte[] data) {
try {
File file = new File(path);
//Write the encrypted data to a new file:
FileOutputStream outStream = new FileOutputStream(file);
outStream.write(data);
outStream.close();
} catch(Exception e){
e.printStackTrace();
}
}
用于加密文件的密钥是:'Test'、'test' 或 'goon'。
问题在于我无法访问加密文件。我有一个应该有效的解密方法:
/**Decrypts one file to a second file using a key derived from a passphrase:**/
public static void decryptFile(String fileName, String pass, String addition)
throws GeneralSecurityException, IOException{
byte[] encData;
byte[] decData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = Main.makeCipher(pass, false);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
encData = new byte[(int)inFile.length()];
inStream.read(encData);
inStream.close();
//Decrypt the file data:
decData = cipher.doFinal(encData);
//Write the decrypted data to a new file:
FileOutputStream target = new FileOutputStream(new File(fileName + addition+ ".png"));
target.write(decData);
target.close();
}
但是在尝试解密文件时,抛出以下错误:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.PBES1Core.doFinal(PBES1Core.java:416)
at com.sun.crypto.provider.PBEWithMD5AndDESCipher.engineDoFinal(PBEWithMD5AndDESCipher.java:316)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at Main.decryptFile(Main.java:145)
at Main.main(Main.java:22)
这是哪一行:
decData = cipher.doFinal(encData);
这只是众多文件中的一个。我所有的编程项目、网站、工作、实习相关文件都是加密的。
如果有人可以帮助我重新获得对我的文件的访问权限,我将不胜感激。文件被加密的原因是因为我的用户文件夹的一些错误的权限设置,我在测试后没有改回来。现在已修复。
是否可能是我没有正确加密数据,因此无法解密?
我上传了一个加密的 word 文档,这样您就可以了解问题所在。可以在这里找到:
http://www70.zippyshare.com/v/KfY6qFGD/file.html
此文档包含 3 个 HTML/CSS 相关检查列表..
此异常消息表示密钥错误。
首先使用DES对加密数据进行解密
如果密钥错误,生成的数据将是随机的。有 1/256
以 0x01
结尾的概率,这是正确的 PKCS 填充,有 1/(256 * 256)
以 0x02 0x02
结尾的概率,这也是正确的填充, probability 1/(256 * 256 * 256)
它会以 0x03 0x03 0x03
结束,这也是一个正确的 padding 等。在这些极不可能的情况下不会抛出异常,但解密数据当然是不正确的。
上面的 OP 代码中有一个重要的错误:encryptFile
方法执行输入填充,尽管它不必:doFinal(...)
也添加填充。这就是为什么要添加两次填充,并且在解密后的结果数据中保留一个填充。
我的计算机上有使用此代码加密的文件:
//Arbitrarily selected 8-byte salt sequence:
private static final byte[] salt = {
(byte) 0x43, (byte) 0x76, (byte) 0x95, (byte) 0xc7,
(byte) 0x5b, (byte) 0xd7, (byte) 0x45, (byte) 0x17
};
public static Cipher makeCipher(String pass, Boolean decryptMode) throws GeneralSecurityException{
//Use a KeyFactory to derive the corresponding key from the passphrase:
PBEKeySpec keySpec = new PBEKeySpec(pass.toCharArray());
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");//PBKDF2WithHmacSHA256
SecretKey key = keyFactory.generateSecret(keySpec);
//Create parameters from the salt and an arbitrary number of iterations:
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 42);
//Set up the cipher:
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
//Set the cipher mode to decryption or encryption:
if(decryptMode){
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec);
} else {
cipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec);
}
return cipher;
}
/**Encrypts one file to a second file using a key derived from a passphrase:**/
public static void encryptFile(String fileName, String pass){
try{
byte[] decData;
byte[] encData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = Main.makeCipher(pass, true);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
int blockSize = 8;
//Figure out how many bytes are padded
int paddedCount = blockSize - ((int)inFile.length() % blockSize );
//Figure out full size including padding
int padded = (int)inFile.length() + paddedCount;
decData = new byte[padded];
inStream.read(decData);
inStream.close();
//Write out padding bytes as per PKCS5 algorithm
for( int i = (int)inFile.length(); i < padded; ++i ) {
decData[i] = (byte)paddedCount;
}
//Encrypt the file data:
encData = cipher.doFinal(decData);
writeToFile(fileName, encData);
} catch(Exception e){
e.printStackTrace();
}
}
private static void writeToFile(String path, byte[] data) {
try {
File file = new File(path);
//Write the encrypted data to a new file:
FileOutputStream outStream = new FileOutputStream(file);
outStream.write(data);
outStream.close();
} catch(Exception e){
e.printStackTrace();
}
}
用于加密文件的密钥是:'Test'、'test' 或 'goon'。
问题在于我无法访问加密文件。我有一个应该有效的解密方法:
/**Decrypts one file to a second file using a key derived from a passphrase:**/
public static void decryptFile(String fileName, String pass, String addition)
throws GeneralSecurityException, IOException{
byte[] encData;
byte[] decData;
File inFile = new File(fileName);
//Generate the cipher using pass:
Cipher cipher = Main.makeCipher(pass, false);
//Read in the file:
FileInputStream inStream = new FileInputStream(inFile);
encData = new byte[(int)inFile.length()];
inStream.read(encData);
inStream.close();
//Decrypt the file data:
decData = cipher.doFinal(encData);
//Write the decrypted data to a new file:
FileOutputStream target = new FileOutputStream(new File(fileName + addition+ ".png"));
target.write(decData);
target.close();
}
但是在尝试解密文件时,抛出以下错误:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
at com.sun.crypto.provider.PBES1Core.doFinal(PBES1Core.java:416)
at com.sun.crypto.provider.PBEWithMD5AndDESCipher.engineDoFinal(PBEWithMD5AndDESCipher.java:316)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at Main.decryptFile(Main.java:145)
at Main.main(Main.java:22)
这是哪一行:
decData = cipher.doFinal(encData);
这只是众多文件中的一个。我所有的编程项目、网站、工作、实习相关文件都是加密的。
如果有人可以帮助我重新获得对我的文件的访问权限,我将不胜感激。文件被加密的原因是因为我的用户文件夹的一些错误的权限设置,我在测试后没有改回来。现在已修复。
是否可能是我没有正确加密数据,因此无法解密?
我上传了一个加密的 word 文档,这样您就可以了解问题所在。可以在这里找到:
http://www70.zippyshare.com/v/KfY6qFGD/file.html
此文档包含 3 个 HTML/CSS 相关检查列表..
此异常消息表示密钥错误。
首先使用DES对加密数据进行解密
如果密钥错误,生成的数据将是随机的。有 1/256
以 0x01
结尾的概率,这是正确的 PKCS 填充,有 1/(256 * 256)
以 0x02 0x02
结尾的概率,这也是正确的填充, probability 1/(256 * 256 * 256)
它会以 0x03 0x03 0x03
结束,这也是一个正确的 padding 等。在这些极不可能的情况下不会抛出异常,但解密数据当然是不正确的。
上面的 OP 代码中有一个重要的错误:encryptFile
方法执行输入填充,尽管它不必:doFinal(...)
也添加填充。这就是为什么要添加两次填充,并且在解密后的结果数据中保留一个填充。