0

I'm trying to create AES encryption/decryption methods, but I cant seem to get my original input without using AES/ECB/NoPadding. Now I am trying to use AES/CBC/PKCS7Padding. I have confirmed that reading and writing the byte to/from the file works fine. With PKCS7 padding I get a BadPaddingException from

cipher.doFinal(encrypted)

in the decrypt method. Without padding, no exceptions - however the output is scrambled. I've spent time going through other posts about this exact same issue but I cant seem to find a solution that fits my problem.

How do I unscramble that output?

protected boolean encrypt(String place, String encrypt) {
    try {

        // encrypt the text
        cipher.init(Cipher.ENCRYPT_MODE, aesKey);
        byte[] encrypted = cipher.doFinal(encrypt.getBytes());

        Context context = HomeViewActivity.hva.getApplicationContext();
        FileOutputStream writer = context.openFileOutput(file_name.get(place.toUpperCase()), Context.MODE_PRIVATE);
        writer.write(encrypted);
        writer.close();
        return true; //successfully wrote encrypted string to file
    }catch(Exception e) {
        e.printStackTrace();
    }
    return false;
}
protected String decrypt(String place){
    String decrypted = null;
    try{
        Context context = HomeViewActivity.hva.getApplicationContext();
        // decrypt the text
        cipher.init(Cipher.DECRYPT_MODE, aesKey);
        FileInputStream reader = context.openFileInput(file_name.get(place.toUpperCase()));
        byte[] encrypted = new byte[reader.available()];
        reader.read(encrypted);
        reader.close();
        decrypted= new String(cipher.doFinal(encrypted));
    }catch(FileNotFoundException e){return null;}
    catch(IllegalBlockSizeException |
            BadPaddingException |
            InvalidKeyException |
            NoSuchAlgorithmException |
            IOException |
            NoSuchPaddingException e){e.printStackTrace();}
    return decrypted;
}

Edit 1: Made the encrypted array read in from file the appropriate size

Edit 2: initialized key and cipher in constructor instead of each method

Zach
  • 447
  • 6
  • 16
  • 1
    Why don't you use the same algorithm to decrypt than the one used to encrypt? Why do you only decrypt 16 bytes, and not the complete output of the encryption? – JB Nizet Feb 24 '15 at 21:01
  • Like i said, i get an exception if I use padding in the decryption method. Also the array is 16 bytes because it is encrypted with a 128 bit key – Zach Feb 24 '15 at 22:34
  • 1
    To clarify: key size and block size are different. AES uses 128-bit blocks, and 128-, 192- or 256-bit keys. Padding ensures that the text is a multiple of the block size. Using `NoPadding` means that you are responsible for ensuring the input is the right size. In any case, it needs to be consistent on encrypt and decrypt (which isn't clear from the code posted). And, to @JBNizet's point, you should expect the cipher text (i.e., `encrypted`) to be more than 1 block. By only taking 16 bytes, you may be truncating the data. – bimsapi Feb 25 '15 at 04:31
  • 2
    You seem to be using a key that is transported as a string. If the string is binary you may lose data. Loosing data means a different key. A different key means that you get garbage plaintext (as AES CBC is not integrity protected). Garbage plaintext means that the padding is random as well, meaning that it will fail with `BadPaddingException`. – Maarten Bodewes Feb 25 '15 at 10:05
  • @zach832 Please provide us enough information to reproduce your issue. I'm pretty sure Maarten is going to be correct, but if you can provide a sample key that we can test with, we can answer you for sure. – Duncan Jones Feb 25 '15 at 11:00
  • @Duncan a sample key would be String key = "abcdefghijklmnop"; I just made a key 128 bits long – Zach Feb 25 '15 at 15:25
  • @bimsapi edited to make the array the appropriate size each time – Zach Feb 25 '15 at 15:46
  • 1
    Reading this again I don't see any handling of the IV value. The IV value should be random and prefixed to the ciphertext, then removed and reused for decryption. ECB does not use an IV value. – Maarten Bodewes Feb 28 '15 at 02:17
  • @MaartenBodewes That was exactly my problem! I didn't know CBC requires an iv. If youll post that as an answer, ill go ahead and accept the solution – Zach Mar 01 '15 at 00:40

1 Answers1

1

The problem is that ECB doesn't use an IV and that CBC - and most other modes of operation do use an IV value. Java randomizes the IV value when it is not explicitly given, which means that the plaintext after decryption is not correct.

For AES CBC mode this means that the first 16 bytes of the plaintext - the initial block - contains random characters. As the blocks after the initial block contain the normal plaintext you won't get a BadPaddingException in the code.

The normal solution to this problem is to prefix the IV value to the ciphertext or write it to the underlying stream first. Needless to say you have to retrieve the IV during decryption and skip the IV value during decryption by altering the offset in a buffer or by advancing a stream (for files you may not want to copy the entire ciphertext).

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263