0

I am writing a simple custom encryptor/decryptor.
Basically, I just take the first 1024 bytes of a large file and encrypt it.
I used a RandomAccessFile so that I can encrypt and decrypt the first 1024bytes quickly.

Now, the problem I am facing is that even though I am using the same algorithm for encryption and decryption.
Encryption works correctly, but decryption throws a javax.crypto.BadPaddingException:Given final block not properly padded .

No matter how much I search, I can't figure out what is wrong. Some research on this tells me the padding is incorrect due to different formatting like UTF and base64. But I am unsure how padding can be incorrect if I read first 1024 bytes of such a large file & encryption threw no exceptions. Also I am making no conversions to strings.

I have provided simple commented,code below

public class Encryptor {

private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES";

public void encrypt(String key, File inputFile, File outputFile) throws CryptoException {
    doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
}

public void decrypt(String key, File inputFile, File outputFile) throws CryptoException {
    doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
}    
private void doCrypto(int cipherMode, String key, File inputFile, File outputFile) throws CryptoException {
    try {

        Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(cipherMode, secretKey);

        byte[] inputBytes = new byte[16];
        byte[] outputBytes = new byte[16];

        //Open the file in read write mode
        RandomAccessFile fileStore = new RandomAccessFile(inputFile, "rw"); 
        fileStore.seek(0); 

        //encrypt first 1024bytes
        int bytesRead = 0;
        for(int ctr=0;bytesRead!= -1 && ctr<64 ;ctr++){
            //get file pointer position
            long prevPosition = fileStore.getFilePointer();

            //read 16 bytes to array
            bytesRead = fileStore.read(inputBytes); 

            //if successful, go move back pointer and overwrite these 16 bytes with encrypted bytes
            if(bytesRead != 1){
                outputBytes = cipher.doFinal(inputBytes);
                fileStore.seek(prevPosition);
                fileStore.write(outputBytes);
            }   
        }

        fileStore.close();

    } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException
            | IllegalBlockSizeException | IOException ex) {
        throw new CryptoException(ex);
    }
}
0

1 Answer 1

3

First of all, the "AES" algorithm string is translated to "AES/ECB/PKCS5Padding" internally by the SUN provider. This means that you are using the insecure ECB mode encryption instead of the more secure CBC mode.

The reason why you get BadPaddingException is simple. As you use PKCS5Padding (or more precisely PKCS#7 padding), each 16 bytes is padded up to 32 bytes during encryption. You however only store the unpadded 16 bytes. If you try to decrypt the unpadding mechanism tries to unpad your original unpadded plaintext, which will fail.

Second, the read method may not actually read 16 bytes. It just reads up to 16 bytes. You need to create a separate method to always read precisely 16 bytes.

Calling doFinal multiple times is not a good idea. You'd better just read in 1024 bytes in one go and then call doFinal or - even better - update just once. In that case you should use e.g. "AES/CBC/NoPadding" as algorithm string.


Notes:

  • without a random IV you would still be able to distinguish files that start with the same bytes (or files that are re-encrypted in time that start with the same bytes);
  • you may want to have some kind of protocol to handle files smaller than 1024 bytes;
  • using "try-with-resources" may be an extremely good idea;
  • use memory mapping of files for a cleaner design and (possibly) faster operation.
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.