-1

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");
        
        
    }
}
Muhammad
  • 2,572
  • 4
  • 24
  • 46
  • 2
    What do you expect, and what is actually happening? – tgdavies Dec 15 '20 at 09:39
  • I want to encrypt a video file `largefile.mp4` with `fileEncrypt` method, and decrypt it again with `fileDecrypt` method. I manually coded, but I dont know what is the problem as it is not working. – Muhammad Dec 15 '20 at 09:41
  • 1
    What exactly do you mean by "not working"? – tgdavies Dec 15 '20 at 09:42
  • What do you mean by it is not working? Is no encrypted file generated? Is the decrypted result wrong? – Turamarth Dec 15 '20 at 09:42
  • I dont know why some is trying to close my question while this is problem for me and asked to get help not to closed – Muhammad Dec 15 '20 at 09:43
  • @tgdavies. I mean the encryption does not work while there is no error – Muhammad Dec 15 '20 at 09:43
  • 2
    I voted to close your question because in its current state it cannot be answered, as there is not enough information about the problem you are having. If your question is closed, edit it to address the comments and it will be reopened. See [ask]. – tgdavies Dec 15 '20 at 09:44
  • file generated but the size of encrypted file is 107kb while the size of main file is 100mb – Muhammad Dec 15 '20 at 09:44
  • 2
    What *exactly* do you think this statement does: `out.write(numberOfBytedRead);`? – tgdavies Dec 15 '20 at 09:46
  • with `out.write(numberOfBytedRead)` I am trying to write the encrypted file in a new file called `newEncryptedFile ` – Muhammad Dec 15 '20 at 09:47
  • 1
    Could be a duplicate of: [Encrypting and decrypting a file using CipherInputStream and CipherOutputStream](https://stackoverflow.com/questions/41413439/encrypting-and-decrypting-a-file-using-cipherinputstream-and-cipheroutputstream) – Topaco Dec 15 '20 at 10:01

1 Answers1

1

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);
    }
}
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40
  • Thank you very much, this answer saved my time. But please I have some questions regarding your answer. as I am seeing you just called `.flush()`, Do I still need `.close()` method ? also here FileOutputSteam and FileInputStream never closed do we need to close them ? – Muhammad Dec 15 '20 at 10:23
  • 1
    The streams are opened in a "try-with-resources" mode that closes them automatically and you can't "forget" to close them. Kindly mark my answer as accepted when youre happy to use it :-) – Michael Fehr Dec 15 '20 at 10:48
  • Thank you very much, where Do we know the AES is 256, is 32 bit key means 256 AES ? – Muhammad Dec 15 '20 at 11:22
  • 1
    In **Java** the algorithm strength is defined by the length of the key. Using a 32 byte long key = 32 * 8 = 256 bit means AES 256 [a 16 byte long key = 16 * 8 = 128 bit = AES 128]. Other frameworks like PHP/OpenSSL define the algorithm strength by naming and transform a too long or too short key to a matching one. – Michael Fehr Dec 15 '20 at 11:34