3

I'm trying to make a parallel encryption/decryption of a video file based on this topic: Encryption of video files?

I came up with this sequential version code and it works find for me

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class EncrypterSeq {
    private final static int IV_LENGTH = 16; 
    private final static int DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE = 1024;

    private final static String ALGO_RANDOM_NUM_GENERATOR = "SHA1PRNG";
    private final static String ALGO_SECRET_KEY_GENERATOR = "AES";
    private final static String ALGO_VIDEO_ENCRYPTOR = "AES/CTR/PKCS5Padding";
    static String videoPath = "";
  //-------------------------------------------------------------------------------------------------------------------------------------------------
    @SuppressWarnings("resource")
    public static void encrypt(SecretKey key, AlgorithmParameterSpec paramSpec, InputStream in, OutputStream out)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IOException {
        try {
            Cipher c = Cipher.getInstance(ALGO_VIDEO_ENCRYPTOR);
            c.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            out = new CipherOutputStream(out, c);

            int count = 0;
            byte[] buffer = new byte[DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE];
            while ((count = in.read(buffer)) >= 0) {
                out.write(buffer, 0, count);
            }
        } finally {
            out.close();
        }
    }
  //-------------------------------------------------------------------------------------------------------------------------------------------------
    @SuppressWarnings("resource")
    public static void decrypt(SecretKey key, AlgorithmParameterSpec paramSpec, InputStream in, OutputStream out)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IOException {
        try {
            Cipher c = Cipher.getInstance(ALGO_VIDEO_ENCRYPTOR);
            c.init(Cipher.DECRYPT_MODE, key, paramSpec);
            out = new CipherOutputStream(out, c);

            int count = 0;
            byte[] buffer = new byte[DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE];
            while ((count = in.read(buffer)) >= 0) {
                out.write(buffer, 0, count);
            }
        } finally {
            out.close();
        }
    }
  //-------------------------------------------------------------------------------------------------------------------------------------------------
    public static void main(String[] args) {

        System.out.print("Enter file's path(Example D:/test/copy.mp4): ");
        Scanner scanVideo = new Scanner(System.in); 
        videoPath = scanVideo.nextLine();

        File inFile = new File(videoPath);
        File outFile = new File("D:/test/enc_video.mp4");
        File outFile_dec = new File("D:/test/dec_video.mp4");

        long tStart = System.currentTimeMillis();
        try {
            SecretKey key = KeyGenerator.getInstance(ALGO_SECRET_KEY_GENERATOR).generateKey();

            byte[] keyData = key.getEncoded();
            SecretKey key2 = new SecretKeySpec(keyData, 0, keyData.length, ALGO_SECRET_KEY_GENERATOR);
            byte[] iv = new byte[IV_LENGTH];
            SecureRandom.getInstance(ALGO_RANDOM_NUM_GENERATOR).nextBytes(iv);
            AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);

            EncrypterSeq.encrypt(key, paramSpec, new FileInputStream(inFile), new FileOutputStream(outFile));
            EncrypterSeq.decrypt(key2, paramSpec, new FileInputStream(outFile), new FileOutputStream(outFile_dec));
        } catch (Exception e) {
            e.printStackTrace();
        }
        long tEnd = System.currentTimeMillis();
        long tDelta = tEnd - tStart;
        double elapsedSeconds = tDelta / 1000.0;
        System.out.println("Time is: " + elapsedSeconds + " Seconds");

    }

}

I tried to convert it to the parallel version, like this for the main class

package test1;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Scanner;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Encrypter {
    private final static int IV_LENGTH = 16;
    private final static String ALGO_RANDOM_NUM_GENERATOR = "SHA1PRNG";
    private final static String ALGO_SECRET_KEY_GENERATOR = "AES";
    private final static String ALGO_VIDEO_ENCRYPTOR = "AES/CTR/NoPadding"; //Just a string

    static String videoPath = "";

  //-------------------------------------------------------------------------------------------------------------------------------------------------

    @SuppressWarnings("resource")
    public static void encrypt(SecretKey key, AlgorithmParameterSpec paramSpec, InputStream in, OutputStream out)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IOException, Exception {
                Cipher c = Cipher.getInstance(ALGO_VIDEO_ENCRYPTOR);
                c.init(Cipher.ENCRYPT_MODE, key, paramSpec);
                EncryptTask task1 = new EncryptTask(key, paramSpec, in, out, c);
                EncryptTask task2 = new EncryptTask(key, paramSpec, in, out, c);
                EncryptTask task3 = new EncryptTask(key, paramSpec, in, out, c);
                EncryptTask task4 = new EncryptTask(key, paramSpec, in, out, c);
                Thread t1 = new Thread(task1);
                Thread t2 = new Thread(task2);
                Thread t3 = new Thread(task3);
                Thread t4 = new Thread(task4);
                t1.start();
                t2.start();
                t3.start();
                t4.start();
                t1.join();
                t2.join();
                t3.join();
                t4.join();
    }

//-------------------------------------------------------------------------------------------------------------------------------------------------

    @SuppressWarnings("resource")
    public static void decrypt(SecretKey key, AlgorithmParameterSpec paramSpec, InputStream in, OutputStream out)
            throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            InvalidAlgorithmParameterException, IOException, Exception {
                Cipher c = Cipher.getInstance(ALGO_VIDEO_ENCRYPTOR);
                c.init(Cipher.DECRYPT_MODE, key, paramSpec);
                DecryptTask task1 = new DecryptTask(key, paramSpec, in, out, c);
                DecryptTask task2 = new DecryptTask(key, paramSpec, in, out, c);
                DecryptTask task3 = new DecryptTask(key, paramSpec, in, out, c);
                DecryptTask task4 = new DecryptTask(key, paramSpec, in, out, c);
                Thread t1 = new Thread(task1);
                Thread t2 = new Thread(task2);
                Thread t3 = new Thread(task3);
                Thread t4 = new Thread(task4);
                t1.start();
                t2.start();
                t3.start();
                t4.start();
                t1.join();
                t2.join();
                t3.join();
                t4.join();
    }

  //-------------------------------------------------------------------------------------------------------------------------------------------------

    @SuppressWarnings("resource")
    public static void main(String[] args) throws Exception { //Main class

        System.out.print("Enter file's path(Example D:/test/copy.mp4): ");
        Scanner scanVideo = new Scanner(System.in); 
        videoPath = scanVideo.nextLine();

        File inFile = new File(videoPath);
        File outFile = new File("D:/test/enc_video.mp4");
        File outFile_dec = new File("D:/test/dec_video.mp4");

        long tStart = System.currentTimeMillis();

        try {
            SecretKey key = KeyGenerator.getInstance(ALGO_SECRET_KEY_GENERATOR).generateKey();

            byte[] keyData = key.getEncoded();
            SecretKey key2 = new SecretKeySpec(keyData, 0, keyData.length, ALGO_SECRET_KEY_GENERATOR);
            byte[] iv = new byte[IV_LENGTH];

            SecureRandom.getInstance(ALGO_RANDOM_NUM_GENERATOR).nextBytes(iv);

            AlgorithmParameterSpec paramSpec = new IvParameterSpec(iv);

            Encrypter.encrypt(key, paramSpec, new FileInputStream(inFile), new FileOutputStream(outFile));
            Encrypter.decrypt(key2, paramSpec, new FileInputStream(outFile), new FileOutputStream(outFile_dec));
        } catch (Exception e) {
            e.printStackTrace();
        }

        long tEnd = System.currentTimeMillis();
        long tDelta = tEnd - tStart;
        double elapsedSeconds = tDelta / 1000.0;
        System.out.println("Time is: " + elapsedSeconds + " Seconds");

    }

}

the encrypt task

package test1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

public class EncryptTask extends Encrypter implements Runnable {
    private final static int DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE = 1024;
    SecretKey key;
    AlgorithmParameterSpec paramSpec;
    private InputStream in;
    private OutputStream out;
    private Cipher c;


    public EncryptTask(SecretKey key, AlgorithmParameterSpec paramSpec, InputStream in, OutputStream out, Cipher c){
        this.key = key;
        this.paramSpec = paramSpec;
        this.in = in;
        this.out = out;

    }

    public void run() {

        byte[] buffer = new byte[DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE];
        try {
            out = new CipherOutputStream(out, c);
            int count = 0;
            while ((count = in.read(buffer)) >= 0) {
                out.write(buffer, 0, count);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}

the decrypt task

package test1;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

public class DecryptTask extends Encrypter implements Runnable {
    private final static int DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE = 1024;
    SecretKey key;
    AlgorithmParameterSpec paramSpec;
    private InputStream in;
    private OutputStream out;
    private Cipher c;


    public DecryptTask(SecretKey key, AlgorithmParameterSpec paramSpec, InputStream in, OutputStream out, Cipher c){
        this.key = key;
        this.paramSpec = paramSpec;
        this.in = in;
        this.out = out;
        this.c = c;

    }

    public void run() {

        byte[] buffer = new byte[DEFAULT_READ_WRITE_BLOCK_BUFFER_SIZE];
        try {
            out = new CipherOutputStream(out, c);
            int count = 0;
            while ((count = in.read(buffer)) >= 0) {
                out.write(buffer, 0, count);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

It ends up with these on the console

Enter file's path(Example D:/test/copy.mp4): D:/test/copy.mp4
Exception in thread "Thread-3" Exception in thread "Thread-2" Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.NullPointerException
    at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:210)
    at test1.EncryptTask.run(EncryptTask.java:46)
    at java.lang.Thread.run(Unknown Source)
java.lang.NullPointerException
    at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:210)
    at test1.EncryptTask.run(EncryptTask.java:46)
    at java.lang.Thread.run(Unknown Source)
java.lang.NullPointerException
    at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:210)
    at test1.EncryptTask.run(EncryptTask.java:46)
    at java.lang.Thread.run(Unknown Source)
java.lang.NullPointerException
    at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:210)
    at test1.EncryptTask.run(EncryptTask.java:46)
    at java.lang.Thread.run(Unknown Source)
Time is: 0.34 Seconds

Could you told me the part that I miss?

Community
  • 1
  • 1
  • 2
    I think you might have a bit of a naive idea on how to parallelize things. All the tasks seem to share the same streams for one. – Kayaman May 15 '17 at 13:19
  • I tried to split video into 4 parts and put it to each task, but it took too long time to finish the whole process. Do you have any suggestion to distribute works to each task? – AlphaCentauri May 15 '17 at 14:51
  • Keep in mind that AES-CTR encryption is stateful. You have to calculate the correct IV (actually this is called a nonce) for each thread. – Artjom B. May 15 '17 at 18:27

0 Answers0