5
votes

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:

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...

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?

1
I'm guessing the input that you read from file is not a valid encrypted text. With DES being block algorithm, you should check whether length of file is multiplication of 64. If not, it would mean, that file is corrupted.markubik
You mean multiple of 8? It is, the file is not corrupted, I've checked.André Perazzi
@markubik It's a random key :PMaarten Bodewes

1 Answers

8
votes

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.

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.

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.

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 likely to return the same incorrect value over and over though, so this may never happen.

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.