Search code examples
javacryptographyjava-iojava-security

File encryption and decryption does not work in java


I want to encrypt a large video file called largefile.mp4 most efficiently and then decrypt it again, but there it is not working as expected.

actually there is not any error, and the files gets generated. but the new generated file is too small than the main file.

here largefile.mp4 is 100mb but newEncryptedFile.txt is 107kb and the newDecryptedFile.mp4 is 210 bytes

What is the problem ?

package fileenc;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

public class FileEncrypterDecrypter {
    
    SecretKey key;
    Cipher cipher;
    
    public FileEncrypterDecrypter() {
        
        try {
            
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            
            key = keygen.generateKey();
            
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            
            System.out.println(e);
        }
        
    }
    
    public boolean fileEncrypt(String plainFile) {
        
        try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(plainFile))){
                        
            
            
            cipher.init(Cipher.ENCRYPT_MODE, key);
            FileOutputStream fs = new FileOutputStream("newEncryptedFile.txt");
            CipherOutputStream out = new CipherOutputStream(fs, cipher);
            
            
            byte[] byteSize = new byte[1024];
            
            int numberOfBytedRead;
            
            while ( (numberOfBytedRead = fis.read(byteSize)) != -1 ) {
                out.write(numberOfBytedRead);
            }
            
            fis.close();
            out.flush();
            out.close();
            
            
            System.out.println("Encryption done...");
            
            return true;
            
        } catch (IOException | InvalidKeyException e) {
            
        }
        
        return false;
    }
    
    public boolean fileDecrypt(String encryptedFile) {
    
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("newDecryptedFile.mp4"))){
            
            cipher.init(Cipher.DECRYPT_MODE, key);
            FileInputStream fis = new FileInputStream(encryptedFile);
            CipherInputStream in = new CipherInputStream(fis, cipher);
            
            
            
            byte[] byteSize = new byte[1024];
            
            int numberOfBytedRead;
            
            while ( (numberOfBytedRead = in.read(byteSize)) != -1) {
                bos.write(numberOfBytedRead);
            }
            
            System.out.println("Decryption done...");
            
            
            bos.flush();
            bos.close();
            in.close();
            
            return true;
            
        } catch (IOException | InvalidKeyException e) {
            
        }
        
        return false;
    }
    
    public static void main(String[] args) throws FileNotFoundException, IOException {
            
        
        FileEncrypterDecrypter fed = new FileEncrypterDecrypter();
        
        fed.fileEncrypt("largefile.mp4"); // about 100 mb
        fed.fileDecrypt("newEncryptedFile.txt");
        
        
    }
}

Solution

  • I'm sorry that I did not inspect your code because you are using the UNSECURE mode ECB that should be no longer used in new projects.

    Below you find a sample code for file encryption & decryption with AES in CBC mode. The program generates a random key for encryption and decryption (with an out of the key in base64 encoding for better storage), generates a random initialization vector (IV) that is written at the beginning of the encrypted file.

    For decryption the first 16 bytes get read as unencrypted data, all other data go through the decryption stream.

    The encryption is done in chunks of 8192 bytes with the kindly help of a CipherOutput-/InputStream.

    Security warning: the code does not have any exception handling and is for educational purpose only. Kindly note that for better security you may change to an authenticated encryption (e.g. secured with an HMAC or using GCM mode).

    output:

    AES CBC 256 file encryption with CipherOutputStream
    encryption key in base64 encoding: vTsd0E8MX3arfLRFjxZ58FSjkKxKYe32+rT5zCnJPVY=
    result encryption: true
    result decryption: true
    

    code:

    import javax.crypto.Cipher;
    import javax.crypto.CipherInputStream;
    import javax.crypto.CipherOutputStream;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.IvParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.SecureRandom;
    import java.util.Base64;
    
    public class AesCbcEncryptionWithRandomKeyCipherOutputStreamSoExample {
        public static void main(String[] args) throws NoSuchPaddingException, NoSuchAlgorithmException, IOException,
                InvalidKeyException, InvalidAlgorithmParameterException {
            System.out.println("AES CBC 256 file encryption with CipherOutputStream");
            String uncryptedFilename = "plaintext.txt";
            String encryptedFilename = "encrypted.enc";
            String decryptedFilename = "decrypted.txt";
    
            // generate random aes 256 key
            byte[] encryptionKey = new byte[32];
            SecureRandom secureRandom = new SecureRandom();
            secureRandom.nextBytes(encryptionKey);
            System.out.println("encryption key in base64 encoding: " + base64Encoding(encryptionKey));
            boolean result;
            // encryption
            result = encryptCbcFileBufferedCipherOutputStream(uncryptedFilename, encryptedFilename, encryptionKey);
            System.out.println("result encryption: " + result);
            // decryption
            result = decryptCbcFileBufferedCipherInputStream(encryptedFilename, decryptedFilename, encryptionKey);
            System.out.println("result decryption: " + result);
        }
    
        public static boolean encryptCbcFileBufferedCipherOutputStream(String inputFilename, String outputFilename, byte[] key)
                throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
            // generate random iv
            SecureRandom secureRandom = new SecureRandom();
            byte[] iv = new byte[16];
            secureRandom.nextBytes(iv);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            try (FileInputStream in = new FileInputStream(inputFilename);
                 FileOutputStream out = new FileOutputStream(outputFilename);
                 CipherOutputStream encryptedOutputStream = new CipherOutputStream(out, cipher);) {
                out.write(iv);
                SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
                IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
                byte[] buffer = new byte[8096];
                int nread;
                while ((nread = in.read(buffer)) > 0) {
                    encryptedOutputStream.write(buffer, 0, nread);
                }
                encryptedOutputStream.flush();
            }
            if (new File(outputFilename).exists()) {
                return true;
            } else {
                return false;
            }
        }
    
        public static boolean decryptCbcFileBufferedCipherInputStream(String inputFilename, String outputFilename, byte[] key) throws
                IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
            byte[] iv = new byte[16];
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            try (FileInputStream in = new FileInputStream(inputFilename);
                 CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
                 FileOutputStream out = new FileOutputStream(outputFilename))
            {
                byte[] buffer = new byte[8192];
                in.read(iv);
                SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
                IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
                int nread;
                while ((nread = cipherInputStream.read(buffer)) > 0) {
                    out.write(buffer, 0, nread);
                }
                out.flush();
            }
            if (new File(outputFilename).exists()) {
                return true;
            } else {
                return false;
            }
        }
    
        private static String base64Encoding(byte[] input) {
            return Base64.getEncoder().encodeToString(input);
        }
    }