phoenix
phoenix

Reputation: 995

Unable to get decrypted file as String in AES Encryption/Decryption

I am trying to encrypt a file which consists of some sample data like

company=abc-company

I have written the following code to encrypt the file using AES-128 bit key using password and salt. I am able to encrypt the file successfully to a file and write the decrypted data from the file to another file successfully. But, I want to store the decrypted data in a string. So, after roaming here on SO, I used ByteArrayOutputStream. But with that I am not able to get the complete plaintext in to the string. I am getting partial data (only first 16 characters i.e. excluding 'any') from the file. How to get the complete text from the file into the string?

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestAES {

    private static final Logger logger = LoggerFactory.getLogger(TestAES.class);
    private char[] password = "1111111111111111".toCharArray();
    private byte[] salt = "SampleSalt".getBytes();
    private byte[] initializationVector;

    public static void main(String[] args) {
        TestAES aes = new TestAES();

        aes.encrypt(new File("D:\\plainText.licence"), new File("D:\\sample.licence"));
        aes.decrypt(new File("D:\\sample.licence"));
    }

    public void encrypt(File plainTextFile, File encryptedLicenceFile) {

        if (plainTextFile.exists() == false) {
            try {
                throw new FileNotFoundException("The plainTextFile was not found");
            } catch (FileNotFoundException e) {
                logger.error("The plainTextFile was not found", e);
                e.printStackTrace();
            }
        }

        if (encryptedLicenceFile.exists() == false) {
            try {
                encryptedLicenceFile.createNewFile();
            } catch (IOException e) {
                logger.error("IOException while creating encryptedLicenceFile", e);
                e.printStackTrace();
            }
        }

        logger.info("plainTextFile.exists() = " + plainTextFile.exists());

        // To read the file to be encrypted
        FileInputStream fileInputStream = null;

        // To write the encrypted file
        FileOutputStream fileOutputStream = null;

        // To read the file information and to encrypt
        CipherInputStream cipherInputStream = null;
        try {
            fileInputStream = new FileInputStream(plainTextFile);
            fileOutputStream = new FileOutputStream(encryptedLicenceFile);

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec keySpec = new PBEKeySpec(password, salt, 65536, 128);
            logger.info("Generating KeySpec with password, salt.");

            SecretKey secretKey = factory.generateSecret(keySpec);
            SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            logger.debug("Obtaining AES cipher in encryption mode with secret key.");
            cipher.init(Cipher.ENCRYPT_MODE, secret);
            AlgorithmParameters parameters = cipher.getParameters();
            this.initializationVector = parameters.getParameterSpec(IvParameterSpec.class).getIV();
            logger.info("Initialization Vector length = " + initializationVector.length);

            cipherInputStream = new CipherInputStream(fileInputStream, cipher);

            int read = 0;
            while ((read = cipherInputStream.read()) != -1) {
                fileOutputStream.write((char) read);
                fileOutputStream.flush();
            }

            logger.info("Successfully written the sample.licence file.");

        } catch (NoSuchAlgorithmException e) {
            logger.error("NoSuchAlgorithmException: Check alogrithm.", e);
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            logger.error("NoSuchPaddingException: Check padding.", e);
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            logger.error("InvalidKeySpecException: Check keySpec.", e);
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            logger.error("InvalidKeyException: Check keySize.", e);
            e.printStackTrace();
        } catch (InvalidParameterSpecException e) {
            logger.error("InvalidParameterSpecException: Check parameters.", e);
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            logger.error("FileNotFoundException: Check fileToBeEncrypted.", e);
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("IOException occured.", e);
            e.printStackTrace();
        } finally {
            try {
                if (cipherInputStream != null) {
                    cipherInputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
            } catch (IOException e) {
                logger.error("Exception while closing stream.", e);
                e.printStackTrace();
            }
        }

    }

    public void decrypt(File sampleLicence) {

        if (sampleLicence.exists() == false) {
            try {
                throw new FileNotFoundException("The sampleLicence was not found");
            } catch (FileNotFoundException e) {
                logger.error("The sampleLicence was not found", e);
                e.printStackTrace();
            }
        }

        // To read the sample.licence
        FileInputStream fileInputStream = null;

        // To write decrypted licence file
        FileOutputStream fileOutputStream = null;

        // To read encrypted licence file and decrypt it
        CipherOutputStream cipherOutputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        try {
            fileInputStream = new FileInputStream(sampleLicence);
            byteArrayOutputStream = new ByteArrayOutputStream();

            SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
            KeySpec keySpec = new PBEKeySpec(password, salt, 65536, 128);
            logger.info("Generating KeySpec with password, salt during decryption.");

            SecretKey secretKey = factory.generateSecret(keySpec);
            SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");

            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            logger.debug("Obtaining AES cipher in decryption mode with secret key.");
            cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(initializationVector));

            cipherOutputStream = new CipherOutputStream(byteArrayOutputStream, cipher);
            byte[] data = new byte[4096];
            int read;
            while ((read = fileInputStream.read(data)) != -1) {
                cipherOutputStream.write(data, 0, read);
            }
            cipherOutputStream.flush();

            byte[] plainText = byteArrayOutputStream.toByteArray();
            System.out.println(new String(plainText, "UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            logger.error("NoSuchAlgorithmException: Check alogrithm.", e);
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            logger.error("NoSuchPaddingException: Check padding.", e);
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            logger.error("InvalidKeySpecException: Check keySpec.", e);
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            logger.error("InvalidKeyException: Check keySize.", e);
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            logger.error("FileNotFoundException: Check fileToBeEncrypted.", e);
            e.printStackTrace();
        } catch (IOException e) {
            logger.error("IOException occured.", e);
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            logger.error("InvalidAlgorithmParameterException", e);
            e.printStackTrace();
        } finally {
            try {
                if (cipherOutputStream != null) {
                    cipherOutputStream.close();
                }
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (byteArrayOutputStream != null) {
                    byteArrayOutputStream.close();
                }
            } catch (IOException e) {
                logger.error("Exception while closing stream.", e);
                e.printStackTrace();
            }
        }

    }
}

Upvotes: 1

Views: 1841

Answers (1)

Henry
Henry

Reputation: 43788

I did not try that, but it looks like you need to close the cipherOutputStream:

cipherOutputStream.close();

instead of the flush you have currently.

The reason is that flush can be called several times so the decryption will not be finished until close is called.

Upvotes: 1

Related Questions