0
votes

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.

3
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.ntoskrnl
@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.Vamsi Challa
your code should work. possibly an issue in readFile(filename). does it return anything? how do you save to/read from file?Alexander Zhak

3 Answers

7
votes

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");

    }

}
2
votes

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.

0
votes

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