Android utilise la base de données SQLite pour stocker des données, j'ai besoin de crypter la base de données SQLite, comment procéder? Je comprends que les données d'application sont privées. Cependant, je dois crypter explicitement la base de données SQLite que mon application utilise.
SQLCipher est une extension SQLite qui fournit un cryptage AES 256 bits transparent des fichiers de base de données.
La version antérieure de sqlcipher, qui est le cryptage complet de la base de données Open Source pour SQLite, n'était pas disponible pour Android. Mais maintenant, il est disponible en version alpha pour Android. Les développeurs ont mis à jour la norme Android 'Notepadbot' pour utiliser SQLCipher).
C'est donc certainement l'option la meilleure et la plus simple pour l'instant.
Les bases de données sont cryptées afin d'empêcher INDIRECT ATTACKS
. Ce terme et les classes: KeyManager.Java, Crypto.Java sont tirés de Sheran Gunasekera livre Android Sécurité des applications . Je recommande tout ce livre à la lecture.
INDIRECT ATTACKS
Sont ainsi nommés, car le virus ne s'en prend pas directement à votre application. Au lieu de cela, il va après le système d'exploitation Android. Le but est de copier toutes les bases de données SQLite dans l'espoir que l'auteur du virus puisse copier toutes les informations sensibles qui y sont stockées. Si vous aviez ajouté une autre couche de protection, cependant, tout ce que l'auteur du virus verrait, ce sont des données brouillées. Construisons une bibliothèque cryptographique que nous pouvons réutiliser dans toutes nos applications. Commençons par créer un bref ensemble de spécifications:
Utilise des algorithmes symétriques: notre bibliothèque utilisera un algorithme symétrique ou bloc de chiffrement pour crypter et décrypter nos données. Nous nous contenterons d'AES, bien que nous devrions pouvoir le modifier ultérieurement.
Utilise une clé fixe: nous devons être en mesure d'inclure une clé que nous pouvons stocker sur l'appareil qui sera utilisée pour crypter et décrypter les données.
Clé stockée sur l'appareil: la clé réside sur l'appareil. Bien que cela représente un risque pour notre application du point de vue des attaques directes, il devrait suffire à nous protéger contre les attaques indirectes.
Commençons par notre module de gestion des clés (voir Listing 1 ). Comme nous prévoyons d'utiliser une clé fixe, nous n'aurons pas besoin d'en générer une au hasard comme nous l'avons fait dans les exemples précédents. Le KeyManager effectuera donc les tâches suivantes:
setId(byte[] data)
)setIv(byte[] data)
)getId(byte[] data)
)getIv(byte[] data)
)(Liste 1. Le module KeyManager 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());
}
}
}
Ensuite, nous faisons le module Crypto (voir Listing 2 ). Ce module s'occupe du chiffrement et du déchiffrement. Nous avons ajouté une méthode armorEncrypt()
et armorDecrypt()
au module pour faciliter la conversion des données du tableau d'octets en données imprimables Base64 et vice versa. Nous utiliserons l'algorithme AES avec mode de cryptage Cipher Block Chaining (CBC) et remplissage PKCS # 5 =.
(Listing 2. Le module cryptographique 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)));
}
}
Vous pouvez inclure ces deux fichiers dans n'importe laquelle de vos applications qui nécessitent le chiffrement du stockage de données. Tout d'abord, assurez-vous d'avoir une valeur pour votre clé et votre vecteur d'initialisation, puis appelez l'une des méthodes de chiffrement ou de déchiffrement de vos données avant de les stocker. Le listing 3 et Le listing 4 contiennent un exemple d'application simple de ces classes en utilisant. Nous créons une activité avec 3 boutons Crypter, décrypter, supprimer; 1 EditText pour la saisie de données; 1 TextView pour la sortie des données.
(Listing 3. Un exemple. 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. Un exemple. 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>
Si la base de données est petite, vous pouvez gagner une petite quantité de sécurité en déchiffrant le fichier entier vers un emplacement temporaire (pas sur la carte SD), puis en rechiffrant lorsque vous l'avez fermé. Problèmes: mort prématurée de l'application, image fantôme sur le support.
Une solution légèrement meilleure pour crypter les champs de données. Cela provoque un problème pour les clauses WHERE et ORDER BY. Si les champs chiffrés doivent être indexés pour la recherche d'équivalence, vous pouvez stocker un hachage cryptographique du champ et le rechercher. Mais cela n'aide pas avec les recherches de gamme ou les commandes.
Si vous voulez devenir plus amateur, vous pouvez vous plonger dans le NDK Android Android) et pirater du cryptage en code C pour SQLite.
Compte tenu de tous ces problèmes et solutions partielles, êtes-vous sûr d'avoir vraiment besoin d'une base de données SQL pour l'application? Vous pourriez être mieux avec quelque chose comme un fichier qui contient un objet sérialisé chiffré.
Vous pouvez certainement avoir une base de données SQLite cryptée sur Android. Cependant, vous ne pouvez pas le faire avec les cours fournis par Google.
Quelques alternatives:
http://sqlite-crypt.com/ peut vous aider à créer une base de données cryptée, même si je ne l'ai jamais utilisée sur Android semble être possible avec le code source.