Multithread AES encryption in Java

920 Views Asked by At

As the title say i'm trying to encrypt a file using 2 thread and to decrypt using 1 thread. Since encryption isn't thread safe i use FileChannel to specify the position where to read in the second thread. I am using a 512 byte buffer so i divide the file size by 1024 thus obtaining the iteration to do in the while to reach the end of the first half of the file. The second thread start immediately after the end of the first one and iterate until the end of the file. The decryption function read only one file at time appending the second atthe end of the first.

I've tested with an image but unfortunately after the decryption only the first half of the image can be seen the rest is white. At the end of the decryption i get Error while decrypting: java.io.IOException: javax.crypto.BadPaddingException

EDIT1: I think i have made a step forward, now i am able to achieve multi thread encryption by reading the file in 2 different places but i'm still getting Error while decrypting: java.io.IOException: javax.crypto.BadPaddingException after decryption

    public void encrypt(File inputFile, File outputFile, String secret, int threadNum, long iteration) 
    {       
        try
        {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            
            FileInputStream fis = new FileInputStream(inputFile);
            FileOutputStream fos = new FileOutputStream(outputFile);
            
            byte[] buffer = new byte[512];
            long val = inputFile.length()/100, numIteration = 0;
            int count;
            if(threadNum == 1)
            {
                while(true)
                {
                    if(numIteration == iteration)
                    {
                        fis.read(buffer);
                        fos.write(cipher.doFinal(buffer));
                        System.out.println("Dofinal 1°");
                        break;
                    }
                    else {
                        fis.read(buffer);
                        fos.write(cipher.update(buffer));
                    }
                    System.out.println("Num iteration: "+numIteration);
                    numIteration++;
                }
            }
            else if(threadNum == 2)
            {
                while(numIteration <= iteration)
                {
                    if(numIteration <= iteration/2)
                    {
                        fis.skip(512);
                    }
                    else if(numIteration >= iteration/2) {
                        fis.read(buffer);
                        fos.write(cipher.update(buffer));
                        System.out.println("Iteration"+numIteration);
                    }
                    else if(numIteration == iteration)
                    {
                        fis.read(buffer);
                        fos.write(cipher.doFinal(new byte[(int) inputFile.length()%512]));
                        break;
                    }
                    System.out.println("NumIteration: "+numIteration);
                    numIteration++;
                }
            }
        }
        catch (Exception e) 
        {
            System.out.println("Error while encrypting: " + e.toString());
        }
    }

    public void decrypt(File inputFile[], File outputFile, String secret) 
    {
        System.out.println("Decryption");
        try
        {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            
            for(int i = 0; i < 2; i++)
            {
                CipherInputStream in = new CipherInputStream(new FileInputStream(inputFile[i]), cipher);
                CountingInputStream cis = new CountingInputStream(in);
                
                FileOutputStream out;
                
                if(i == 0)
                    out = new FileOutputStream(outputFile);
                else 
                    out = new FileOutputStream(outputFile, true);

                CountingOutputStream cos = new CountingOutputStream(out);

                int count;
                double val = (inputFile[i].length()/100);
                byte[] buffer = new byte[512];
                while((count = cis.read(buffer)) != -1)
                {
                    cos.write(buffer, 0, count);
                    cos.flush();
                }
                cis.close();
                cos.close();
            }
        } 
        catch (Exception e) 
        {
            System.out.println("Error while decrypting: " + e.toString());
        }
    }
1

There are 1 best solutions below

2
Marcus34 On

I managed to achieve dual-thread encryption, boosting performance of about 28% on a 48,5 mb file (from 0,57 to 0,41 s) using an i5 10210u 4c 8t. Should be possible achieve higher performance by raising the number of thread according with the number of cores of the CPU

Here is the code:

    public void encrypt(File inputFile, File outputFile, String secret, int threadNum, long iteration) 
    {       
        try
        {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            
            FileInputStream fis = new FileInputStream(inputFile);
            FileOutputStream fos = new FileOutputStream(outputFile);
            
            byte[] buffer = new byte[512];
            long numIteration = 1;
            
            if(threadNum == 1)
            {
                while(true)
                {
                    if(numIteration == iteration)
                    {
                        fis.read(buffer);
                        fos.write(cipher.doFinal(buffer));
                        break;
                    }
                    else 
                    {
                        fis.read(buffer);
                        fos.write(cipher.update(buffer));
                    }
                    numIteration++;
                }
            }
            else if(threadNum == 2)
            {
                while(numIteration <= iteration)
                {
                    if(numIteration == iteration)
                    {
                        byte[] f = new byte[(int) inputFile.length()%512];
                        fis.read(f);
                        fos.write(cipher.doFinal(f));
                        break;
                    }
                    else if(numIteration < iteration/2)
                    {
                        fis.skip(512);
                    }
                    else if(numIteration >= iteration/2 && numIteration < iteration) 
                    {
                        fis.read(buffer);
                        fos.write(cipher.update(buffer));
                    }
                    numIteration++;
                }
            }
            fis.close();
            fos.close();
        }
        catch (Exception e) 
        {
            System.out.println("Error while encrypting: " + e.toString());
        }
    }

    public void decrypt(File inputFile[], File outputFile, String secret) 
    {
        try
        {
            setKey(secret);
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            
            for(int i = 0; i < 2; i++)
            {               
                CipherInputStream in = new CipherInputStream(new FileInputStream(inputFile[i]), cipher);
                CountingInputStream cis = new CountingInputStream(in);
                
                FileOutputStream out;
                
                if(i == 0)
                    out = new FileOutputStream(outputFile);
                else 
                    out = new FileOutputStream(outputFile, true);

                CountingOutputStream cos = new CountingOutputStream(out);

                int count;
                double val = (inputFile[i].length()/100);
                byte[] buffer = new byte[512];
                
                while((count = cis.read(buffer)) != -1)
                {
                    cos.write(buffer, 0, count);
                    cos.flush();
                    System.out.println("Percentuale: "+cos.getCount()/val+"%");
                }
                cis.close();
                cos.close();
            }
        } 
        catch (Exception e) 
        {
            System.out.println("Error while decrypting: " + e.toString());
        }
    }