Saturday 21 May 2016

Secure Database in Android with Sqlcipher

"How to secure the user data?" is the common question for developer, especially when our application work with user's sensitive data: Address, phone number, email, password,...

There are many useful tips for a security app in Android can be found here
https://developer.android.com/training/articles/security-tips.html
These are the technics to avoid DIRECT ATTACK (The hacker user the security holes of the app itself)

But what about INDIRECT ATTACK: The virus does not go after your application directly. Instead it goes after to Android OS. The it can copy and exploit the data of other applications.

In Android, and also other mobile platforms, OS provide an OS security level for each app that called Sandbox (Internal storage only)
It guarantees an app cannot access to the data of others. So the data in internal storage of Android application(/data/data/...) is safe with with INDIRECT ATTACK.
It's true with default user privilege. But if the phone is rooted, user can access anything in it, the Sandbox barrier is not available in this case.

An indirect attacker + root user (rooted phone) can view all data in phone.

So how to protect the data even though the attacker can get it? The answer is encryption. Encryption add an layer of protection. The virus/attacker would see the garbled data.
There two kind of stored data in Android: normal file and database file.

  • Normal file: It's easy to apply encryption. Developer just chooses an suitable encryption that provide by platform API then encrypt/decrypt easily.
    This is the good tutorial about it
    http://www.developer.com/ws/android/encrypting-with-android-cryptography-api.html
  • Database file: We cannot just encrypt/decrypt the database file as above because there are many operations on database during application life cycle. It's will be a performance disaster.
Today, I will introduce a way - a library - to do encryption on Android database file. May be you here it before: Sqlcipher.
SQLCipher is an open source library that provides transparent, secure 256-bit AES encryption of SQLite database files.
SQLCipher has been adopted as a secure database solution by many commercial and open source products, making it one of the most popular encrypted database platforms for Mobile, Embedded, and Desktop applications
https://www.zetetic.net/sqlcipher/about/ 


SQLCipher provide transparent, secure 256-bit AES encryption of SQLite database files.

An very interesting feature of it is transparent. It means, with it, developer don't need to change the original database API to make it work. In Android, the source code with Database, Cursor, DatabaseHelper is still valid.

I do not waste your time anymore. Now, I'll introduce how to integrate SQLCipher to an Android project with Android Studio.
The tutorial for Eclipse can be found here https://www.zetetic.net/sqlcipher/sqlcipher-for-android/

1. Firstly, this is the location of the library https://bintray.com/developernotes/maven/net.zetetic%3Aandroid-database-sqlcipher/view. Choose a version, the select your build configuration. I choose Gradle for this example

2. Create an simple example to apply the library.I use the Login project template of Android.

3. After create project successfully, add the following line (from step 1) to gradle file of module app
compile 'net.zetetic:android-database-sqlcipher:3.4.0'
 4. In this sample we need save/retrieve account information to database to register and login. So we need a model class. It's called Account.
public class Account {
    public long mID;    public String mName;    public String mPassword;    public double mTime;
    public Account() {
    }

    public Account(long id, String name, String password, float time) {
        mID = id;        mName = name;        mPassword = password;        mTime = time;    }
}
5. As usual, we will create a database helper class to work with sqlite in Android
mport android.content.Context;import android.util.Log;
import net.sqlcipher.database.SQLiteDatabase;import net.sqlcipher.database.SQLiteOpenHelper;
/** * Created by sumpham on 5/19/16. */public class CipherDatabaseHelper extends SQLiteOpenHelper {

    public static final String TABLE_TARGET = "table_result";    public static final String COLUMN_ID = "_id";    public static final String COLUMN_NAME = "col_name";    public static final String COLUMN_PASSWORD = "col_password";    public static final String COLUMN_TIME = "col_time";    private static final String ACCOUNT_CREATE = "create table "            + TABLE_TARGET + "(" + COLUMN_ID            + " integer primary key autoincrement, "            + COLUMN_NAME + " text, "            + COLUMN_PASSWORD + " text, "            + COLUMN_TIME + " real);";
    private static final String DATABASE_NAME = "accounts.db";
    private static final int DATABASE_VERSION = 1;
    @Override    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL(ACCOUNT_CREATE);    }

    @Override    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
        Log.v(CipherDatabaseHelper.class.getName(),                "Upgrading database from version " + i + " to "                        + i1 + ", which will destroy all old data");        sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_TARGET);        onCreate(sqLiteDatabase);    }

    public CipherDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);    }
}
Note that: we use "net.sqlcipher" instead  of "android.database.sqlite" of Android. The APIs are same between two package.

6. To easily work with database, I create a wrapper class to manipulate with Account table.
import android.content.ContentValues;import android.content.Context;import android.support.annotation.NonNull;
import net.sqlcipher.Cursor;import net.sqlcipher.SQLException;import net.sqlcipher.database.SQLiteDatabase;
import java.util.ArrayList;import java.util.List;
/** * Created by sumpham on 5/19/16. */public class AccountTable {
    private SQLiteDatabase mDatabase;    private CipherDatabaseHelper mDbHelper;
    /**     * Array of all columns in the table     */    private String[] mAllColumns = {
            CipherDatabaseHelper.COLUMN_ID,            CipherDatabaseHelper.COLUMN_NAME,            CipherDatabaseHelper.COLUMN_PASSWORD,            CipherDatabaseHelper.COLUMN_TIME    };
    public AccountTable(Context context) {
        mDbHelper = new CipherDatabaseHelper(context);    }

    /**     * Open the SQLite database     */    public void open() throws SQLException {
        mDatabase = mDbHelper.getWritableDatabase("my_secure_key");    }

    /**     * Close the SQLite database     */    public void close() {
        mDbHelper.close();    }

    public Account addAccount(@NonNull final Account result) {
        ContentValues values = new ContentValues();        values.put(CipherDatabaseHelper.COLUMN_NAME, result.mName);        values.put(CipherDatabaseHelper.COLUMN_PASSWORD, result.mPassword);        values.put(CipherDatabaseHelper.COLUMN_TIME, result.mTime);
        final long insertId = mDatabase.insert(CipherDatabaseHelper.TABLE_TARGET, null, values);
        Cursor cursor = mDatabase.query(CipherDatabaseHelper.TABLE_TARGET,                mAllColumns, CipherDatabaseHelper.COLUMN_ID + " = "                        + insertId, null, null, null, null);
        cursor.moveToFirst();
        Account resultInserted = cursorToAccount(cursor);        cursor.close();
        return resultInserted;    }

    public Account getAccountByName(String username) {
        Account rv = null;        List<Account> accounts = new ArrayList<>();        Cursor cursor = mDatabase.query(CipherDatabaseHelper.TABLE_TARGET, mAllColumns, "col_name = ?",                new String[]{username}, null, null, null, null);        if(null != cursor && cursor.getCount() > 0) {
            cursor.moveToFirst();           rv = cursorToAccount(cursor);            cursor.close();        }

        return rv;    }

    /**     * Take the cursor from a database query and create fill the result structure     *     * @param cursor Database cursor from sqlite query     * @return new result structure     */    private Account cursorToAccount(@NonNull final Cursor cursor) {
        Account result = new Account();        result.mID = cursor.getLong(0);        result.mName = cursor.getString(1);        result.mPassword = cursor.getString(2);        result.mTime = cursor.getFloat(3);        return result;    }


}
As named, The function "getAccountByName" to get and account from database by username and "addAccount" to add an account to database. And again, we use "net.sqlcipher" package.
We need password to open database: getWritableDatabase


7.   We finished with prepare helper classes for the demo. Let apply it to application work flow.

  • Go to LoginActivity.java, add following line to declare variable for AccountTable

AccountTable accountsTb; 

  •  Add a function to initialize sqlcipher database
    Please note that the call SQLiteDatabase.loadLibs(..) must be called before other actions to database.
private void initCipherDatabase() {
    SQLiteDatabase.loadLibs(this);    accountsTb = new AccountTable(this);    accountsTb.open();}

  •  Put this function to the end of onCreate function.
  • Go to UserLoginTask implementation to apply our database code. This class after done
public class UserLoginTask extends AsyncTask<Void, Void, Boolean> {

    private final String mEmail;    private final String mPassword;
    UserLoginTask(String email, String password) {
        mEmail = email;        mPassword = password;    }

    @Override    protected Boolean doInBackground(Void... params) {
        // TODO: attempt authentication against a network service.
        try {
            // Simulate network access.            Thread.sleep(2000);        } catch (InterruptedException e) {
            return false;        }

        if(null != accountsTb) {
            Account account = accountsTb.getAccountByName(this.mEmail);            if (null != account) {
                return account.mPassword == this.mPassword;            } else {
                Account newAccount = new Account();                newAccount.mPassword = mPassword;                newAccount.mName = mEmail;                return accountsTb.addAccount(newAccount) != null;            }
        } else {
            return false;        }

    }

    @Override    protected void onPostExecute(final Boolean success) {
        mAuthTask = null;        showProgress(false);
        if (success) {
            Toast.makeText(LoginActivity.this, "Login/register success", Toast.LENGTH_SHORT).show();        } else {
            mPasswordView.setError(getString(R.string.error_incorrect_password));            mPasswordView.requestFocus();        }
    }

    @Override    protected void onCancelled() {
        mAuthTask = null;        showProgress(false);    }
}
The heart of this code is
if(null != accountsTb) {
    Account account = accountsTb.getAccountByName(this.mEmail);    if (null != account) {
        return account.mPassword.contentEquals(this.mPassword);
    } else {
        Account newAccount = new Account();        newAccount.mPassword = mPassword;        newAccount.mName = mEmail;        return accountsTb.addAccount(newAccount) != null;    }
} else {
    return false;}
We just search the account in database with current username. If it's exist, compare the saved password with current. Otherwise, add a new account to database.
  • Build and run code to see how it work.

8. To view the encrypted database by SQLCipher, you can download the SQLCipher version of SQLiteBrowser here http://sqlitebrowser.org/. You need the database password to open

Complete sample source here Source code

Conclusion

It's very easy to apply SQLCipher to your project. But if you're working in a project that the performance is the most important, you should be careful. Because the encryption will take time to do.
Here is the test result to consider
https://www.zetetic.net/blog/2011/5/7/sqlcipher-performance-and-sqlcipherspeed.html

This library is also available for iOS platform

Friday 6 May 2016

Swift Tips You May Not Know But Should

Improve the Readability of Constants
A neat way to utilize structs in Swift is to make a file for all the constants in our application. This is useful because Swift allows us to nest structures like so:
import Foundation

struct Constants {

    struct FoursquareApi {
        static let BaseUrl = "https://api.foursquare.com/v2/"
    }
    
    struct TwitterApi {
        static let BaseUrl = "https://api.twitter.com/1.1/"
    }

    struct Configuration {
        static let UseWorkaround = true
    }
    
}
This nesting gives us a namespace for our constants. For example, we could useConstants.FoursquareApi.BaseUrl to access Foursquare's BaseUrl constant. This makes things more readable and provides a layer of encapsulation around related constants.
Avoid NSObject and @objc to Improve Performance
Swift allows us to extend classes from NSObject to get Objective-C runtime features for an object. It also allows us to annotate Swift methods with @objc to allow the methods to be used by the Objective-C runtime.
Supporting the Objective-C runtime means that method calls are going to be using dynamic dispatch instead of static or vtable dispatch. This end result is that methods that support the Objective-C runtime have a four times performance penalty when called. In practical usage, the performance hit may be negligible but the cool thing is that armed with this knowledge, we now know that method execution in Swift is four times faster than Objective-C.
Use Method Swizzling in Swift
Method swizzling is a technique that substitutes one method implementation for another. If you're not familiar with swizzling, check out this blog post. Swift optimizes code to call direct memory addresses instead of looking up the method location at runtime as in Objective-C. So by default swizzling doesn’t work in Swift classes unless we:
  • Disable this optimization with the dynamic keyword. This is the preferred choice, and the choice that makes the most sense if the codebase is entirely in Swift.
  • Extend NSObject. Never do this only for method swizzling (use dynamicinstead). It’s useful to know that method swizzling will work in already existing classes that have NSObject as their base class, but we're better off selectively choosing methods with dynamic .
  • Use the @objc annotation on the method being swizzled. This is appropriate if the method we would like to swizzle also needs to be exposed to Objective-C code at the same time.
Update: As requested, we've added an example of swizzling purely in Swift. It still requires the Objective-C runtime, but our class doesn’t inherit from NSObject and our methods are not marked as @objcClick here to see it in action in a playground.
import UIKit
​
class AwesomeClass {
    dynamic func originalFunction() -> String {
        return "originalFunction"
    }
    
    dynamic func swizzledFunction() -> String {
        return "swizzledFunction"
    }
}
​
let awesomeObject = AwesomeClass()
​
print(awesomeObject.originalFunction()) // prints: "originalFunction"
​
let aClass = AwesomeClass.self
let originalMethod = class_getInstanceMethod(aClass, "originalFunction")
let swizzledMethod = class_getInstanceMethod(aClass, "swizzledFunction")
method_exchangeImplementations(originalMethod, swizzledMethod)
​
print(awesomeObject.originalFunction())  // prints: "swizzledFunction"
Reference: http://savvyapps.com/blog/swift-tips-for-developers