I am working on a class to encrypt/decrypt large files so I am trying to use the streams instead of byte arrays to avoid OutOfMemory exceptions.
In the encryption method I add random salt and iv to the beginning of the encrypted file and it works fine, and here is the code:
public File encryptFile(File inputFile, File outPutFile, String password, ProgressBar progressBar, Label progressPercentage){ //Create IV byte[] ivBytes = new byte[16]; SecureRandom random1 = new SecureRandom(); random1.nextBytes(ivBytes); IvParameterSpec iv = new IvParameterSpec(ivBytes); //Create the key with the salt SecureRandom random = new SecureRandom(); byte[] salt = new byte[SALT_SIZE]; random.nextBytes(salt); SecretKeySpec keySpec = generateAesKey(password, salt); //Create and Init the cipher Cipher c = Cipher.getInstance("AES/CBC/"+padding); c.init(Cipher.ENCRYPT_MODE, keySpec, iv); byte[] buf = new byte[8192]; FileInputStream in = new FileInputStream(inputFile); FileOutputStream out = new FileOutputStream(outPutFile); int nread; int progress = 0; byte[] ivAndSalt = new byte[ivBytes.length + salt.length]; System.arraycopy(ivBytes,0, ivAndSalt,0, ivBytes.length ); System.arraycopy(salt, 0, ivAndSalt, ivBytes.length, salt.length); out.write(ivAndSalt); while((nread = in.read(buf)) != -1) { byte[] enc = c.update(buf, 0, nread); out.write(enc); progress++; }
Then I try to get the iv and salt in decryption method and then decrypt the rest of the file into an output one with FileInputStream.getChannel.position()
:
public File decryptFile(File inputFile, File outPutFile, String password, ProgressBar progressBar, Label progressPercentage) { //Create and Init Cipher Cipher c = Cipher.getInstance("AES/CBC/" + padding); FileInputStream in = new FileInputStream(inputFile); FileOutputStream out = new FileOutputStream(outPutFile); //Getting the iv and salt byte[] ivBytes = new byte[16]; byte[] salt = new byte[SALT_SIZE]; byte[] ivAndSalt = new byte[ivBytes.length+SALT_SIZE]; in.read(ivAndSalt, 0, ivBytes.length+SALT_SIZE); System.arraycopy(ivAndSalt, 0, ivBytes, 0, ivBytes.length); System.arraycopy(ivAndSalt, ivBytes.length, salt, 0, SALT_SIZE); IvParameterSpec iv =new IvParameterSpec(ivBytes); SecretKeySpec keySpec = generateAesKey(password, salt); c.init(Cipher.DECRYPT_MODE, keySpec, iv); in.getChannel().position(ivAndSalt.length); int nread; int progress = 0; byte[] buf = new byte[8192]; while((nread = in.read(buf)) != -1) { byte[] enc = c.update(buf, 0, nread); out.write(enc); progress++; /*if (enc.length / 8192 != 0) System.out.println((nread*progress) + "%");*/ } System.out.println("Size of out before doFinal(): " + out.getChannel().size()); byte[] enc = c.doFinal(); out.write(enc); System.out.println("Size of out after doFinal(): " + out.getChannel().size()); return outPutFile; }
I didn't get an error on calling decryptFile() but the produced file is corrupted and this means that there is an issue somewhere in the decrypting.
stream.read(buf) != -1
does not guarantee you read 8192 bytes. – Oleg Sklyarin.getChannel().position(ivAndSalt.length);
though otherwise nothing obvious.. If the decryption woudn't be ok, you'd get an exception.. – gusto2