Correct way of Encrypting and Decrypting an Image using AES

24,148

Solution 1

The code in the question works, but it takes around 10 seconds for getting back to the activity once the image is taken in camera. I gave up this approach and used Facebook's Conceal Library to encrypt and decrypt images. Link to Facebook's Solution : Facebook Conceal - Image Encryption and Decryption

Solution 2

Images can be easily encrypted and decrypted using Java libraries. I present to you two seperate codes using two different methods for encryption and decryption. The following codes can also be extended to use for pdf files.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;

public class ImageEncDec {

    public static byte[] getFile() {

        File f = new File("/home/bridgeit/Desktop/Olympics.jpg");
        InputStream is = null;
        try {
            is = new FileInputStream(f);
        } catch (FileNotFoundException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        byte[] content = null;
        try {
            content = new byte[is.available()];
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            is.read(content);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return content;
    }

    public static byte[] encryptPdfFile(Key key, byte[] content) {
        Cipher cipher;
        byte[] encrypted = null;
        try {
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            encrypted = cipher.doFinal(content);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return encrypted;

    }

    public static byte[] decryptPdfFile(Key key, byte[] textCryp) {
        Cipher cipher;
        byte[] decrypted = null;
        try {
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);
            decrypted = cipher.doFinal(textCryp);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return decrypted;
    }

    public static void saveFile(byte[] bytes) throws IOException {

        FileOutputStream fos = new FileOutputStream("/home/bridgeit/Desktop/Olympics-new.jpg");
        fos.write(bytes);
        fos.close();

    }

    public static void main(String args[])
            throws NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IOException {

        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        Key key = keyGenerator.generateKey();
        System.out.println(key);

        byte[] content = getFile();
        System.out.println(content);

        byte[] encrypted = encryptPdfFile(key, content);
        System.out.println(encrypted);

        byte[] decrypted = decryptPdfFile(key, encrypted);
        System.out.println(decrypted);

        saveFile(decrypted);
        System.out.println("Done");

    }

}

` this is the second code which generates the same output but with only the exception of generating the same key again and again.

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class Trial {

    public static byte[] getFile() {

        File f = new File("/home/bridgeit/Desktop/Olympics.jpg");
        InputStream is = null;
        try {
            is = new FileInputStream(f);
        } catch (FileNotFoundException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        byte[] content = null;
        try {
            content = new byte[is.available()];
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            is.read(content);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return content;
    }

    public static byte[] encryptPdfFile(SecretKey secretKey, byte[] content) {
        Cipher cipher;
        byte[] encrypted = null;
        try {
            cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

            cipher.init(Cipher.ENCRYPT_MODE, secretKey);

            encrypted = Base64.encodeBase64(cipher.doFinal(content));

        } catch (Exception e) {

            System.out.println("Error while encrypting: " + e.toString());
        }
        return encrypted;

    }

    public static byte[] decryptPdfFile(SecretKey secretKey, byte[] textCryp) {
        Cipher cipher;
        byte[] decrypted = null;
        try {
            cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");

            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            decrypted = cipher.doFinal(Base64.decodeBase64(textCryp));

        } catch (Exception e) {

            System.out.println("Error while decrypting: " + e.toString());
        }
        return decrypted;
    }

    public static void saveFile(byte[] bytes) throws IOException {

        FileOutputStream fos = new FileOutputStream("/home/bridgeit/Desktop/Olympics-new.jpg");
        fos.write(bytes);
        fos.close();

    }

    public static void main(String args[])
            throws NoSuchAlgorithmException, InstantiationException, IllegalAccessException, IOException {

        SecretKeySpec secretKey;
        byte[] key;
        String myKey = "ThisIsAStrongPasswordForEncryptionAndDecryption";

        MessageDigest sha = null;
        key = myKey.getBytes("UTF-8");
        System.out.println(key.length);
        sha = MessageDigest.getInstance("SHA-1");
        key = sha.digest(key);
        key = Arrays.copyOf(key, 16); // use only first 128 bit
        System.out.println(key.length);
        System.out.println(new String(key, "UTF-8"));
        secretKey = new SecretKeySpec(key, "AES");

        byte[] content = getFile();
        System.out.println(content);

        byte[] encrypted = encryptPdfFile(secretKey, content);
        System.out.println(encrypted);

        byte[] decrypted = decryptPdfFile(secretKey, encrypted);
        System.out.println(decrypted);

        saveFile(decrypted);
        System.out.println("Done");

    }

}

Solution 3

You are trying to do too much at once, and are getting lost in all the details.

Start by simplifying your code to the bare minimum needed for encryption and decryption:

byte[] key = { 1, 2, 3, ... 14, 15, 16 };
byte[] IV  = { 5, 5, 5, ... 5, 5, 5 };
String plaintext = "This is a secret message."

Now cut down your code to encrypt and decrypt that plaintext message back to a readable text string.

When you have that small program working correctly, add back the other complications one at a time. At each stage, check again that your code can encrypt and decrypt successfully. I suggest that you start by adding back the SecretKeyFactory part, and finish with the file reading and writing part.

By splitting your program up into smaller parts it will be easier for you to understand what each part of your program is doing, and make it easier for you to identify where you are making mistakes.

Share:
24,148
Vamsi Challa
Author by

Vamsi Challa

Updated on January 24, 2020

Comments

  • Vamsi Challa
    Vamsi Challa over 4 years

    EDIT ::: The code in the question works, but it takes around 10 seconds for getting back to the activity once the image is taken in camera. I gave up this approach and used Facebook's Conceal Library to encrypt and decrypt images. Link to Facebook's Solution : Facebook Conceal - Image Encryption and Decryption


    I have looked at lot of examples, but still couldn't figure out a way to get Encryption and Decryption right. I thought i got it correct when I used some random code on the internet, but while decoding, i get a BadPadding Exception.

    So, i am trying to work it out. I am following the below question, as suggested by most people on SO (but this code shows how to encrypt a string). Can some one help me out in encrypting and decrypting the image? Will the code in the question work for images?

    Link to the question : Java 256-bit AES Password-Based Encryption

    Here is what i have done till now:

    //Global arraylist to store iv and cipher

    static ArrayList<byte[]> ivandcipher = new ArrayList<byte[]>();
    

    //Generating Key

    public static SecretKey generateKey() throws NoSuchAlgorithmException {
    
        char[] password = { 'a', 'b', 'c', 'd', 'e' };
        byte[] salt = { 1, 2, 3, 4, 5 };
    
        SecretKeyFactory factory = SecretKeyFactory
                .getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
        SecretKey tmp = null;
        try {
            tmp = factory.generateSecret(spec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    
        yourKey = new SecretKeySpec(tmp.getEncoded(), "AES");
    
        return yourKey;
    }
    

    //Encoding File

    //byte[] fileData, contains the bitmap(image) converted to byte[]

    public static ArrayList<byte[]> encodeFile(SecretKey yourKey, byte[] fileData)
            throws Exception {
    
        byte[] encrypted = null;
    
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, yourKey);
        AlgorithmParameters params = cipher.getParameters();
        byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
        encrypted = cipher.doFinal(fileData);   
    
        ivandcipher.clear();
        ivandcipher.add(iv);
        ivandcipher.add(encrypted);
    
        return ivandcipher;
    }
    

    Why am i adding iv and encrypted byte[]s to ivandcipher. Because, as the answer in the link suggests, that i should be using the same iv while decryption.

    //Decode file

    //I call a overloaded decodeFile method inside this method.. please note

    private Bitmap decodeFile(String filename) {
    
        try {
            yourKey = generateKey();
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        }
    
        try {
            byte[] decodedData = decodeFile(yourKey, readFile(filename));
            Bitmap bitmap = bytesToBitmap(decodedData);
    
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
        }
    
        return null;
    }
    

    //overloaded decodeFile method

    public static byte[] decodeFile(SecretKey yourKey, byte[] fileData)
            throws Exception {
    
        byte[] decrypted = null;
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, yourKey, new IvParameterSpec(ivandcipher.get(0)));
        decrypted = cipher.doFinal(fileData);
        return decrypted;
    }
    

    I guess the problem is with the fileData[], that i am not able to encrypt and decrypt correctly. For Strings as shown in the answer of the above link, i.e.,

    byte[] ciphertext = cipher.doFinal("Hello, World!".getBytes("UTF-8"));

    what should be given as parameter for cipher.doFinal()?

    Let me know if you need any other piece of code.

    • ntoskrnl
      ntoskrnl over 9 years
      The reason is basically that you copied "some random code on the internet", didn't get it to work, and now we're supposed to fix it.
    • Vamsi Challa
      Vamsi Challa over 9 years
      @ntoskrnl, I am not asking anyone to fix it. I am asking your help in understanding it and making it to work. And btw, the code that i posted in the question, is not random, its from the link i posted in the question.
    • Alexander Zhak
      Alexander Zhak over 9 years
      your code should work. possibly an issue in readFile(filename). does it return anything? how do you save to/read from file?
  • Peter O.
    Peter O. over 9 years
    I believe your issue is you're trying to encrypt and decrypt in the UI thread, which may explain the 10-second delay.
  • Maarten Bodewes
    Maarten Bodewes almost 6 years
    Hey wow, bad stream handling, full buffering of the file, ECB mode encryption, single password hash for PasswordBasedEncryption. Crypto sense is zero. Find the penguin. And all that while the question started off with correct primitives such as PBKDF2 and CBC mode. And 5 upvotes. Wow. Just wow.