8

Here is what I am doing which can look a bit clumsy but any help is appreciated regarding the problem. I'm getting a BadPaddingException. Read almost all related topics but didn't find the appropriate solution. I am new to encryption decryption programming and need to implement it in one of my Java application.

Thank You.. this is how the code looks....

public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
    // TODO Auto-generated method stub
            String FileName="encryptedtext.txt";
            String FileName2="decryptedtext.txt";
            String pad="0"; 

            KeyGenerator KeyGen=KeyGenerator.getInstance("AES");
            KeyGen.init(128);

            SecretKey SecKey=KeyGen.generateKey();

            Cipher AesCipher=Cipher.getInstance("AES");
            AesCipher.init(Cipher.ENCRYPT_MODE,SecKey);

            byte[] byteText="My name is yogesh".getBytes();
            byte[] byteCipherText=AesCipher.doFinal(byteText);
            String cipherText = null;

            try {
                FileWriter fw=new FileWriter(FileName);
                BufferedWriter bw=new BufferedWriter(fw);
                bw.write(byteCipherText.toString());
                bw.close();
            }catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            try {
                FileReader fr=new FileReader(FileName);
                BufferedReader br=new BufferedReader(fr);
                cipherText=br.readLine();
                br.close();
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            AesCipher.init(Cipher.DECRYPT_MODE,SecKey);
            while(((cipherText.getBytes().length)%16)!=0)
            {
                cipherText=cipherText+pad;


            }

            byte[] bytePlainText=AesCipher.doFinal(cipherText.getBytes());
            FileWriter fw1;
            try {
                fw1 = new FileWriter(FileName2);
                BufferedWriter bw1=new BufferedWriter(fw1);
                bw1.write(bytePlainText.toString());
                bw1.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }






}
LarsH
  • 27,481
  • 8
  • 94
  • 152
Yogesh D
  • 1,663
  • 2
  • 23
  • 38

2 Answers2

22

You need to define what padding algorithm you use when you create instance of Cipher. Personally I use PKCS5.

So you should change:

Cipher AesCipher=Cipher.getInstance("AES");

to:

Cipher AesCipher=Cipher.getInstance("AES/CBC/PKCS5Padding");

CBC stands for Cipher-block chaining.

CBC requires IV to be passed. So you want to generate random IV and pass it in init method:

byte[] iv = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
AesCipher.init(Cipher.ENCRYPT_MODE, SecKey, ivParameterSpec);

Note: it's a good practice to avoid magical numbers/strings in your code. I'd suggest to extract argument passes in Cipher#getInstance to a constant.

Leri
  • 12,367
  • 7
  • 43
  • 60
  • Did the above mentioned changes but now i am getting Exception in thread "main" java.security.InvalidKeyException: Parameters missing....exception – Yogesh D Dec 27 '13 at 07:12
  • I don't think the problem is with padding scheme. It is due to some minor misunderstanding of Text files vs Binary files and toString() method of java arrays. – Buddhima Gamlath Dec 27 '13 at 07:12
  • @user3117915 More likely `IV` is missing. – Leri Dec 27 '13 at 07:16
  • 1
    @bgamlath More likely, you are right. However, I always prefer to pad before encrypting/decrypting so in most cases I can avoid bad padding. – Leri Dec 27 '13 at 07:17
  • @Leri - yup.. there is no doubt that padding is important. :-) – Buddhima Gamlath Dec 27 '13 at 07:25
11

Here, what you have to understand is that cipher text may contain non-printable characters. So, when you use readLine(), it will likely not give you all of the bytes in the file.

Also, byteCipherText.toString() does not give you what you thought you would get. In java, the toString() method does not give the string representation of the contents of the array.

There is no need to add padding to encrypted text. It is already padded.

import java.nio.file.Files;
import java.nio.file.Paths;
import javax.crypto.*;

public class Main {

    public static void main(String[] args) throws Exception {
        String fileName = "encryptedtext.txt";
        String fileName2 = "decryptedtext.txt";

        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(128);

        SecretKey secKey = keyGen.generateKey();

        Cipher aesCipher = Cipher.getInstance("AES");


        byte[] byteText = "Your Plain Text Here".getBytes();

        aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
        byte[] byteCipherText = aesCipher.doFinal(byteText);
        Files.write(Paths.get(fileName), byteCipherText);


        byte[] cipherText = Files.readAllBytes(Paths.get(fileName));

        aesCipher.init(Cipher.DECRYPT_MODE, secKey);
        byte[] bytePlainText = aesCipher.doFinal(cipherText);
        Files.write(Paths.get(fileName2), bytePlainText);
    }
}
Max
  • 2,036
  • 2
  • 18
  • 27
Buddhima Gamlath
  • 2,318
  • 1
  • 16
  • 26
  • 13
    Be aware that encryption like this is not secure as it does not use an IV. Using this code in a production environment would be **very stupid**. – Luke Joshua Park Jan 05 '16 at 04:28
  • 1
    @LukePark would this be a bad idea if the key file changed for every input to be encrypted? Is an IV required if the key will only be used once? – Allan5 Sep 19 '16 at 20:08
  • 2
    @Allan5 There are very specific situations where an IV is not required. For example, if the key is constantly changing and you are encrypting less than the block size (128 bits for AES). Otherwise use an IV. Or just always use one. – Luke Joshua Park Sep 19 '16 at 20:30