How to encrypt and decrypt a file using “AES” algorithm in Android? – Google’s Advice

By | March 20, 2013

This is a simple example showing how to encrypt and decrypt a file in android.
what we will do in this post is

1. Generate a key for encrypting our data.
2. Create a file and save data using ENCRYPTION with our generated key to the SDCARD.
3. With the help of the key DECRYPT the File and show the contents.

An anti-pattern
A common (but incorrect) pattern that we’ve recently become aware of is to use SecureRandom as a means of generating deterministic key material, which would then be used to encrypt local credential caches. Examples are not hard to find, such as here, here, here, and elsewhere.

In this pattern, rather than storing an encryption key directly as a string inside an APK, the code uses a proxy string to generate the key instead — similar to a passphrase. This essentially obfuscates the key so that it’s not readily visible to attackers. However, a skilled attacker would be able to easily see around this strategy. We don’t recommend it.

This complete program does this.
Please check the Logcat for the output.

package com.coderzheaven.encryptfile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;

public class MainActivity extends Activity {

	private String encryptedFileName = "Enc_File.txt";
	private static String algorithm = "AES";
	static SecretKey yourKey = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		saveFile("Hello From CoderzHeaven asaksjalksjals");
		decodeFile();

	}
	
	public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
	    // Number of PBKDF2 hardening rounds to use. Larger values increase
	    // computation time. You should select a value that causes computation
	    // to take >100ms.
	    final int iterations = 1000; 

	    // Generate a 256-bit key
	    final int outputKeyLength = 256;

	    SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
	    KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
	    SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
	    return secretKey;
	}

	public static SecretKey generateKey() throws NoSuchAlgorithmException {
		// Generate a 256-bit key
		final int outputKeyLength = 256;
		SecureRandom secureRandom = new SecureRandom();
		// Do *not* seed secureRandom! Automatically seeded from system entropy.
		KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
		keyGenerator.init(outputKeyLength, secureRandom);
		yourKey = keyGenerator.generateKey();
		return yourKey;
	}

	public static byte[] encodeFile(SecretKey yourKey, byte[] fileData)
			throws Exception {
		byte[] encrypted = null;
		byte[] data = yourKey.getEncoded();
		SecretKeySpec skeySpec = new SecretKeySpec(data, 0, data.length,
				algorithm);
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(
				new byte[cipher.getBlockSize()]));
		encrypted = cipher.doFinal(fileData);
		return encrypted;
	}

	public static byte[] decodeFile(SecretKey yourKey, byte[] fileData)
			throws Exception {
		byte[] decrypted = null;
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.DECRYPT_MODE, yourKey, new IvParameterSpec(
				new byte[cipher.getBlockSize()]));
		decrypted = cipher.doFinal(fileData);
		return decrypted;
	}

	void saveFile(String stringToSave) {
		try {
			File file = new File(Environment.getExternalStorageDirectory()
					+ File.separator, encryptedFileName);
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(file));
			yourKey = generateKey();
			byte[] filesBytes = encodeFile(yourKey, stringToSave.getBytes());
			bos.write(filesBytes);
			bos.flush();
			bos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	void decodeFile() {

		try {
			byte[] decodedData = decodeFile(yourKey, readFile());
			String str = new String(decodedData);
			System.out.println("DECODED FILE CONTENTS : " + str);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public byte[] readFile() {
		byte[] contents = null;

		File file = new File(Environment.getExternalStorageDirectory()
				+ File.separator, encryptedFileName);
		int size = (int) file.length();
		contents = new byte[size];
		try {
			BufferedInputStream buf = new BufferedInputStream(
					new FileInputStream(file));
			try {
				buf.read(contents);
				buf.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return contents;
	}

}


IF YOU WANT MORE SUCURITY THEN USE THE BELOW CODE…

If your app needs additional encryption, a recommended approach is to require a passphase or PIN to access your application. This passphrase could be fed into PBKDF2 to generate the encryption key. (PBKDF2 is a commonly used algorithm for deriving key material from a passphrase, using a technique known as “key stretching”.) Android provides an implementation of this algorithm inside SecretKeyFactory as PBKDF2WithHmacSHA1:

package com.coderzheaven.encryptfile;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;

public class ActivityEncrypt extends Activity {

	private String encryptedFileName = "Enc_File2.txt";
	private static String algorithm = "AES";
	static SecretKey yourKey = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		saveFile("Hello From CoderzHeaven testing ");
		decodeFile();

	}

	public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt)
			throws NoSuchAlgorithmException, InvalidKeySpecException {
		// Number of PBKDF2 hardening rounds to use. Larger values increase
		// computation time. You should select a value that causes computation
		// to take >100ms.
		final int iterations = 1000;

		// Generate a 256-bit key
		final int outputKeyLength = 256;

		SecretKeyFactory secretKeyFactory = SecretKeyFactory
				.getInstance("PBKDF2WithHmacSHA1");
		KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations,
				outputKeyLength);
		yourKey = secretKeyFactory.generateSecret(keySpec);
		return yourKey;
	}

	public static SecretKey generateSalt() throws NoSuchAlgorithmException {
		// Generate a 256-bit key
		final int outputKeyLength = 256;

		SecureRandom secureRandom = new SecureRandom();
		// Do *not* seed secureRandom! Automatically seeded from system entropy.
		KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
		keyGenerator.init(outputKeyLength, secureRandom);
		SecretKey key = keyGenerator.generateKey();
		return key;
	}

	public static byte[] encodeFile(SecretKey yourKey, byte[] fileData)
			throws Exception {
		byte[] data = yourKey.getEncoded();
		SecretKeySpec skeySpec = new SecretKeySpec(data, 0, data.length,
				algorithm);
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

		byte[] encrypted = cipher.doFinal(fileData);

		return encrypted;
	}

	public static byte[] decodeFile(SecretKey yourKey, byte[] fileData)
			throws Exception {
		byte[] data = yourKey.getEncoded();
		SecretKeySpec skeySpec = new SecretKeySpec(data, 0, data.length,
				algorithm);
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.DECRYPT_MODE, skeySpec);

		byte[] decrypted = cipher.doFinal(fileData);

		return decrypted;
	}

	void saveFile(String stringToSave) {
		try {
			File file = new File(Environment.getExternalStorageDirectory()
					+ File.separator, encryptedFileName);
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(file));
			char[] p = { 'p', 'a', 's', 's' };
			SecretKey yourKey = generateKey(p, generateSalt().toString()
					.getBytes());
			byte[] filesBytes = encodeFile(yourKey, stringToSave.getBytes());
			bos.write(filesBytes);
			bos.flush();
			bos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	void decodeFile() {
		try {
			byte[] decodedData = decodeFile(yourKey, readFile());
			String str = new String(decodedData);
			System.out.println("DECODED FILE CONTENTS : " + str);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public byte[] readFile() {
		byte[] contents = null;

		File file = new File(Environment.getExternalStorageDirectory()
				+ File.separator, encryptedFileName);
		int size = (int) file.length();
		contents = new byte[size];
		try {
			BufferedInputStream buf = new BufferedInputStream(
					new FileInputStream(file));
			try {
				buf.read(contents);
				buf.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		return contents;
	}

}

Useful information collected from this link.
http://android-developers.blogspot.in/2013/02/using-cryptography-to-store-credentials.html

5 thoughts on “How to encrypt and decrypt a file using “AES” algorithm in Android? – Google’s Advice

  1. andan

    sorry my bad english.
    I am also trying to program the encryption in android ..
    may I ask for an example program file from the ..

    Reply
    1. James Post author

      You can just simply copy the code into an activity or class and it will work.

      Reply
      1. andan

        if the source code for the encryption button and text view for the password, I do not know how the implementation of the souce code for encryption and pasword button ..

        sorry I am still learning new android. so do not really understand the implementation of the button and text view for pasword ..

        please help

        Reply
  2. andan

    please help me sir …

    because I was confused for implemenasi code on the button

    Reply
  3. Jonathan

    Nice demonstrations. I have them running OK, but my question is what would be the best means of being able to reuse a key? My goal is to have encrypted files on the SD Card (which were downloaded from my server) which would be decrypted each time my app accesses them. I appreciate that I’ll need to store the within the .apk, but that’s a better option than plain files. Using the second example which has the ‘p’,’a’,’s’,’s’ token still encrypts the file differently each time. As a test (as well as looking at the file in a hex editor) I ran the app once per normal, then commented out just the “bos” variable relevant code in saveFile (as there’s a messy encodeFile call embedded in there to prime the secret key) and ran it, and it won’t decode the file even though its still using the pass token. So, please what would you suggest as the best way to be able to encrypt a file once, store that key, and use it to decrypt it at a later date?
    Again thanks for your work and post here 🙂
    Cheers
    Jonathan

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *