I am by no means a security expert. Truth be told, I’m glad. I think those guys have it rough — kind of like a goalie at a hockey game. Twenty fantastic saves during the night and all everyone talks about is the one that slipped by.
In June 2011, I wrote a blog that demonstrated adding some security to your shared preferences files. The tutorial was intended for beginners, and in the spirit of trying to keep it simple, I glossed over the encryption routines. At the end of the day, the theory was sound but the actual security algorithm was a bit lacking.
Recently there has been a rash of news headlines about mobile apps and privacy concerns. I’m not arguing that some of these are justified, but for those of us who are trying to be transparent with customers and do the right thing, now more than ever is the time to go the extra mile when it comes to securing data.
With that mindset, I’ve written a quick tutorial on adding Advanced Encryption Standard (AES) level encryption to your applications. Since 2003, certain variations of AES have been approved by the National Security Agency for safeguarding top secret electronic documents.
To get started creating your own digital version of Ft. Knox, you can either download the entire project, or follow along with the walkthrough below.
1. Create a new project in Eclipse. While it is possible to implement AES with versions of Android as early as 1.0, my particular implementation is using the Base64 utility class, which was not introduced officially until Android 2.2; therefore, we will be targeting SDK 8.0 or greater. Don’t forget to rename your startup activity Main.java.
2. In the /res/layout folder, we will define our XML layout. For the purposes of this demo, we need a couple of text views and a standard linear layout.
main.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextViewandroid:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="AES Encrypt / Decrypt Demo" android:paddingBottom="12dip"/>
<TextViewandroid:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/clear_text"
android:paddingBottom="12dip"/>
<TextViewandroid:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/encrypted_text"
android:paddingBottom="12dip"/>
</LinearLayout>
3. We can move on to our /src/Main.java file. To begin with, we will import a number of standard Java security packages.
Main.java
package com.authorwjf.aes_encrypt;
import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import android.app.Activity; import android.os.Bundle; import android.util.Base64; import android.widget.TextView;
public class Main extends Activity {
}
4. We will add three utility functions to handle the encoding and decoding.
Main.java
privatebyte[] getKey() {
byte[] seed = "here_is_your_aes_key".getBytes();
KeyGenerator kg;
try {
kg = KeyGenerator.getInstance("AES");
} catch (NoSuchAlgorithmException e) {
returnnull;
}
SecureRandom sr;
try {
sr = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
return null;}
sr.setSeed(seed);
kg.init(128, sr);
SecretKey sk = kg.generateKey();
byte[] key = sk.getEncoded(); return key; }
private String encrypt(String clearText) {
byte[] encryptedText = null;
try { SecretKeySpec ks = new SecretKeySpec(getKey(), "AES");Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, ks);
encryptedText = c.doFinal(clearText.getBytes("UTF-8"));
return Base64.encodeToString(encryptedText, Base64.DEFAULT); } catch (Exception e) { return null;}}private String decrypt (String encryptedText) {byte[] clearText = null;try {SecretKeySpec ks = new SecretKeySpec(getKey(), "AES");Cipher c = Cipher.getInstance("AES");c.init(Cipher.DECRYPT_MODE, ks);clearText = c.doFinal(Base64.decode(encryptedText, Base64.DEFAULT)); return new String(clearText, "UTF-8"); } catch (Exception e) { return null;}
}5. We just need to override the on create function and utilize the encryption facilities.
Main.java@Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.main);
String s = "This is my data I want to keep safe.";
String encryptedText = encrypt(s);
String clearText = decrypt(encryptedText);
((TextView)findViewById(R.id.encrypted_text)).setText(encryptedText);
((TextView)findViewById(R.id.clear_text)).setText(clearText);
}Now you have world-class encryption at your fingertips (Figure A). I won’t even pretend to understand the complex math involved in the cipher routines of javax.crypto package; on the contrary, I appreciate the fact that I don’t have to concern myself with all the gory details of the encryption algorithm.
Figure AGoogle and the Java community have provided its developers with a plethora of tools to assist in keeping private user data private. Developers need to take a more active role in the fight for user privacy. After all, those of us who make our living developing smartphone apps have a vested interest in creating a digital ecosystem based on trust and mutual understanding.