Databases are encrypted in order to prevent `INDIRECT ATTACKS`.
This term and classes: *KeyManager.java*, *Crypto.java* are taken from *Sheran Gunasekera* book [Android Apps Security][4]. I recommend all this book to reading.
`INDIRECT ATTACKS` are so named, because the virus does not go after your application directly. Instead, it goes after the Android OS. The aim is to copy all SQLite databases in the hopes that the virus author can copy any sensitive information stored there. If you had added another layer of protection, however, then all the virus author would see is garbled data.
Let’s build a cryptographic library that we can reuse in all our applications. Let’s start by creating a brief set of specifications:
- Uses symmetric algorithms: Our library will use a symmetric algorithm,
or block cipher, to encrypt and decrypt our data. We will settle on AES,
although we should be able to modify this at a later date.
- Uses a fixed key: We need to be able to include a key that we can store on
the device that will be used to encrypt and decrypt data.
- Key stored on device: The key will reside on the device. While this is a risk
to our application from the perspective of direct attacks, it should suffice in
protecting us against indirect attacks.
Let’s start with our key management module (see **Listing 1**). Because we plan to use a fixed key, we won’t need to generate a random one as we did in the past examples. The *KeyManager* will therefore perform the following tasks:
1. Accept a key as a parameter (the `setId(byte[] data)` method)
2. Accept an initialization vector as a parameter (the `setIv(byte[] data)`
method)
3. Store the key inside a file in the internal store
4. Retrieve the key from a file in the internal store (the `getId(byte[] data)`
method)
5. Retrieve the IV from a file in the internal store (the `getIv(byte[] data)`
method)
**(Listing 1. The KeyManager Module *KeyManager.java*)**
package com.yourapp.android.crypto;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.util.Log;
public class KeyManager {
private static final String TAG = "KeyManager";
private static final String file1 = "id_value";
private static final String file2 = "iv_value";
private static Context ctx;
public KeyManager(Context cntx) {
ctx = cntx;
}
public void setId(byte[] data){
writer(data, file1);
}
public void setIv(byte[] data){
writer(data, file2);
}
public byte[] getId(){
return reader(file1);
}
public byte[] getIv(){
return reader(file2);
}
public byte[] reader(String file){
byte[] data = null;
try {
int bytesRead = 0;
FileInputStream fis = ctx.openFileInput(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while ((bytesRead = fis.read(b)) != -1){
bos.write(b, 0, bytesRead);
}
data = bos.toByteArray();
} catch (FileNotFoundException e) {
Log.e(TAG, "File not found in getId()");
} catch (IOException e) {
Log.e(TAG, "IOException in setId(): " + e.getMessage());
}
return data;
}
public void writer(byte[] data, String file) {
try {
FileOutputStream fos = ctx.openFileOutput(file,
Context.MODE_PRIVATE);
fos.write(data);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
Log.e(TAG, "File not found in setId()");
} catch (IOException e) {
Log.e(TAG, "IOException in setId(): " + e.getMessage());
}
}
}
Next, we do the *Crypto* module (see **Listing 2**). This module takes care of the encryption and decryption. We have added an `armorEncrypt()` and `armorDecrypt()` method to the module to make it easier to convert the byte array data into printable [Base64][5] data and vice versa. We will use the [AES][3] algorithm with [Cipher Block Chaining (CBC) encryption mode][1] and [PKCS#5 padding][2].
**(Listing 2. The Cryptographic Module *Crypto.java*)**
package com.yourapp.android.crypto;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import android.content.Context;
import android.util.Base64;
public class Crypto {
private static final String engine = "AES";
private static final String crypto = "AES/CBC/PKCS5Padding";
private static Context ctx;
public Crypto(Context cntx) {
ctx = cntx;
}
public byte[] cipher(byte[] data, int mode) throws NoSuchAlgorithmException,NoSuchPaddingException,InvalidKeyException,IllegalBlockSizeException,BadPaddingException,InvalidAlgorithmParameterException {
KeyManager km = new KeyManager(ctx);
SecretKeySpec sks = new SecretKeySpec(km.getId(), engine);
IvParameterSpec iv = new IvParameterSpec(km.getIv());
Cipher c = Cipher.getInstance(crypto);
c.init(mode, sks, iv);
return c.doFinal(data);
}
public byte[] encrypt(byte[] data) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException,
IllegalBlockSizeException, BadPaddingException,
InvalidAlgorithmParameterException {
return cipher(data, Cipher.ENCRYPT_MODE);
}
public byte[] decrypt(byte[] data) throws InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException,
IllegalBlockSizeException, BadPaddingException,
InvalidAlgorithmParameterException {
return cipher(data, Cipher.DECRYPT_MODE);
}
public String armorEncrypt(byte[] data) throws InvalidKeyException,NoSuchAlgorithmException,
NoSuchPaddingException,IllegalBlockSizeException,
BadPaddingException,InvalidAlgorithmParameterException {
return Base64.encodeToString(encrypt(data), Base64.DEFAULT);
}
public String armorDecrypt(String data) throws InvalidKeyException,NoSuchAlgorithmException,
NoSuchPaddingException,IllegalBlockSizeException,
BadPaddingException,InvalidAlgorithmParameterException {
return new String(decrypt(Base64.decode(data, Base64.DEFAULT)));
}
}
You can include these two files in any of your applications that require data storage to be encrypted. First, make sure that you have a value for your key and initialization vector, then call any one of the encrypt or decrypt methods on your data before you store it. **Listing 3** and **Listing 4** contain an simply App-example of these classes using. We create an Activity with 3 Buttons Encrypt, Decrypt, Delete; 1 EditText for data input; 1 TextView for data output.
**(Listing 3. An example. *MainActivity.java*)**
package com.yourapp.android.crypto;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends Activity {
TextView encryptedDataView;
EditText editInputData;
private Context cntx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.cntx = getApplicationContext();
Button btnEncrypt = (Button) findViewById(R.id.buttonEncrypt);
Button btnDecrypt = (Button) findViewById(R.id.buttonDecrypt);
Button btnDelete = (Button) findViewById(R.id.buttonDelete);
editInputData = (EditText)findViewById(R.id.editInputData) ;
encryptedDataView = (TextView) findViewById(R.id.encryptView);
/**********************************************/
/** INITIALIZE KEY AND INITIALIZATION VECTOR **/
String key = "12345678909876543212345678909876";
String iv = "1234567890987654";
KeyManager km = new KeyManager(getApplicationContext());
km.setIv(iv.getBytes());
km.setId(key.getBytes());
/**********************************************/
btnEncrypt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String Data = editInputData.getText().toString();
String Encrypted_Data = "data";
try {
Crypto crypto = new Crypto(cntx);
Encrypted_Data = crypto.armorEncrypt(Data.getBytes());
} catch (InvalidKeyException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (IllegalBlockSizeException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (BadPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (InvalidAlgorithmParameterException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
}
encryptedDataView.setText(Encrypted_Data);
}
});
btnDecrypt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String Data = encryptedDataView.getText().toString();
String Decrypted_Data = "data";
try {
Crypto crypto = new Crypto(cntx);
Decrypted_Data = crypto.armorDecrypt(Data);
} catch (InvalidKeyException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchAlgorithmException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (NoSuchPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (IllegalBlockSizeException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (BadPaddingException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
} catch (InvalidAlgorithmParameterException e) {
Log.e("SE3", "Exception in StoreData: " + e.getMessage());
}
encryptedDataView.setText(Decrypted_Data);
}
});
btnDelete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
encryptedDataView.setText(" Deleted ");
}
});
}
}
**(Listing 4. An example. activity_main.xml)**
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#363636"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<EditText
android:id="@+id/editInputData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:ems="10"
android:textColor="#FFFFFF" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/encryptView"
android:layout_width="fill_parent"
android:layout_height="100dp"
android:layout_alignLeft="@+id/editInputData"
android:layout_alignRight="@+id/editInputData"
android:layout_below="@+id/buttonEncrypt"
android:layout_marginTop="26dp"
android:background="#000008"
android:text="Encrypted/Decrypted Data View"
android:textColor="#FFFFFF"
android:textColorHint="#FFFFFF"
android:textColorLink="#FFFFFF" />
<Button
android:id="@+id/buttonEncrypt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/encryptView"
android:layout_alignRight="@+id/editInputData"
android:layout_below="@+id/editInputData"
android:layout_marginTop="26dp"
android:text="Encrypt" />
<Button
android:id="@+id/buttonDelete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/buttonDecrypt"
android:layout_alignRight="@+id/buttonDecrypt"
android:layout_below="@+id/buttonDecrypt"
android:layout_marginTop="15dp"
android:text="Delete" />
<Button
android:id="@+id/buttonDecrypt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/encryptView"
android:layout_alignRight="@+id/encryptView"
android:layout_below="@+id/encryptView"
android:layout_marginTop="21dp"
android:text="Decrypt" />
</RelativeLayout>
[1]:
[To see links please register here]
[2]:
[To see links please register here]
[3]:
[To see links please register here]
[4]:
[To see links please register here]
[5]:
[To see links please register here]