如何在 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/2560x01 结尾的概率,这是正确的 PKCS 填充,有 1/(256 * 256)0x02 0x02 结尾的概率,这也是正确的填充, probability 1/(256 * 256 * 256) 它会以 0x03 0x03 0x03 结束,这也是一个正确的 padding 等。在这些极不可能的情况下不会抛出异常,但解密数据当然是不正确的。


上面的 OP 代码中有一个重要的错误:encryptFile 方法执行输入填充,尽管它不必:doFinal(...) 也添加填充。这就是为什么要添加两次填充,并且在解密后的结果数据中保留一个填充。