SQLCipher
We’ve seen that it doesn’t take a degree in computer science to gain access to an APK’s source code, the static information, and an app’s backup data, the dynamic information. Ideally you wouldn’t store any important customer information locally, but this isn’t always an option. But, as we’ve seen, any data that is stored in cleartext can be found easily. So if you do have to store any sensitive data, it is important to encrypt the data in either shared preferences or in a database—or store it somewhere else.
One of the more promising ways to store data securely in a database is using SQLCipher, which is an open source library used in conjunction with SQLite. SQLCipher can be downloaded from www.sqlcipher.net.
In Listing 5-3 we show how to use SQLCipher to encrypt the data in the database. First, add the sqlcipher.jar, commons-codec.jar and guava-r09.jar libraries, which can also be found on the sqlcipher.net website. Then change the import statement (line 7) to import SQLCipher, add a new loadLibs command (line 21) and, as you can see, the openOrCreateDatabase now takes a password (line 27).
Listing 5-3 Adding SQLCipher to your SQLite code
package com.riis.sqlite3; import java.io.File; import android.os.Bundle; import android.app.Activity; import net.sqlcipher.database.SQLiteDatabase; // line 7 public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); InitializeSQLite3(); } private void InitializeSQLite3() { SQLiteDatabase.loadLibs(this); // line 21 File databaseFile = getDatabasePath("names.db"); databaseFile.mkdirs(); databaseFile.delete(); SQLiteDatabase database = // line 27 SQLiteDatabase.openOrCreateDatabase(databaseFile,"pass123", null); database.execSQL("create table user(id integer primary key autoincrement, " + "first text not null, last text not null, " + "username text not null, password text not null)"); database.execSQL("insert into user(first,last,username, password) " + "values('Bertie','Ahern','bahern','celia123')"); } }
Compile and push the app to the phone. Repeat the earlier steps to back up the database onto our computer. You will probably notice that it takes noticeably longer to push the app to the phone, as well as to back it up. This is because of the size of the added libraries.
Again, try to open it in sqlitebrowser or by using the SQLite command line tool. This time the database won’t open because it’s encrypted with the key pass123.
The best way to open the database is to use the sqlite3 command line tool that comes with SQLCipher. A new step is required whereby we need to tell the database what the key is before it will allow us to do any SQL queries on the tables.
sqlite> PRAGMA key='pass123';
Figure 5-7 shows how to view the database using the new password.
Figure 5-7 Viewing an encrypted database from command line SQLite
You may also encounter databases that were created with earlier versions of the SQLCipher libraries. These can be opened using the following PRAGMA command after the PRAGMA key command.
sqlite> PRAGMA key='pass123'; sqlite> PRAGMA kdf_iter = 4000;
This tells the sqlite tool that the key definition file has a lower iteration count than the current version.
Finding the Key
Now that SQLCipher has encrypted the database, our security problem shifts to “Where can we hide the key?” If we can find the key, then we’re going to be able to open the database, just like we did in Chapter 2. We can take the following steps to pull the APK off the device.
The APK is in the /data/app folder on the phone. It will also be called the same package name we used in the adb backup command but with -1.apk appended. The complete command to get the APK off the phone is the following:
adb pull /data/app/com.riis.sqlcipher-1.apk
Convert the APK back into a jar file using the dex2jar command:
dex2jar com.riis.sqlcipher-1.apk
We can now view the source using a Java decompiler, in this case JD-GUI. Figure 5-8 shows the code for the MainActivity.java file and clearly shows that the password is pass123.
Figure 5-8 Viewing the SQLCipher key using JD-GUI
In the next section we’ll look at our options for hiding the key.