Cryptage de firebase database Android

Android utilise la firebase database SQLite pour stocker les données, je dois chiffrer la firebase database SQLite, comment cela peut-il être fait? Je comprends que les données d’application sont privées. Cependant, je dois chiffrer explicitement la firebase database SQLite utilisée par mon application.

SQLCipher est une extension SQLite qui fournit un cryptage AES 256 bits transparent des fichiers de firebase database.

Plus tôt, sqlcipher qui est Open Source Full Database Encryption pour SQLite n’était pas disponible pour Android. Mais maintenant, il est disponible en version alpha pour la plateforme Android. Les développeurs ont mis à jour l’application Android standard ‘Notepadbot’ pour utiliser SQLCipher.

Donc, c’est certainement l’option la plus simple et la meilleure à ce jour.

Les bases de données sont cryptées afin de prévenir les INDIRECT ATTACKS . Ce terme et ces classes: KeyManager.java , Crypto.java proviennent du livre Sheran Gunasekera Android Apps Security . Je recommande tout ce livre à la lecture.

INDIRECT ATTACKS sont ainsi nommées, car le virus ne va pas directement après 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, alors tout ce que l’auteur du virus verrait, c’est 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 ensemble de spécifications:

  • Utilise des algorithmes symésortingques: Notre bibliothèque utilisera un algorithme symésortingque ou un chiffrement par blocs pour chiffrer et déchiffrer nos données. Nous allons nous arrêter sur AES, même si 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 pour chiffrer et déchiffrer les données.

  • Clé stockée sur le périphérique: la clé se trouvera sur le périphérique. Bien que cela représente un risque pour notre application du sharepoint vue des attaques directes, cela devrait suffire à nous protéger contre les attaques indirectes.

Commençons par notre module de gestion de clés (voir Listing 1 ). Comme nous prévoyons d’utiliser une clé fixe, nous n’aurons pas besoin de générer une clé aléatoire comme nous l’avons fait dans les exemples précédents. Le KeyManager effectuera donc les tâches suivantes:

  1. Accepter une clé en tant que paramètre (la setId(byte[] data) )
  2. Accepter un vecteur d’initialisation en tant que paramètre (la setIv(byte[] data) )
  3. Stocker la clé dans un fichier dans le magasin interne
  4. Récupérer la clé à partir d’un fichier dans le magasin interne (la getId(byte[] data) )
  5. Récupère le fichier IV à partir d’un fichier dans le magasin interne (la getIv(byte[] data) )

(Listing 1. Le 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 Ssortingng TAG = "KeyManager"; private static final Ssortingng file1 = "id_value"; private static final Ssortingng 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(Ssortingng 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, Ssortingng 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 prend en charge le cryptage et le décryptage. Nous avons ajouté une armorEncrypt() et armorDecrypt() au module pour faciliter la conversion des données du tableau d’octets en données Base64 imprimables et inversement. Nous utiliserons l’algorithme AES avec le mode de cryptage CBC (Cipher Block Chaining) et le 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 Ssortingng engine = "AES"; private static final Ssortingng 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 Ssortingng armorEncrypt(byte[] data) throws InvalidKeyException,NoSuchAlgorithmException, NoSuchPaddingException,IllegalBlockSizeException, BadPaddingException,InvalidAlgorithmParameterException { return Base64.encodeToSsortingng(encrypt(data), Base64.DEFAULT); } public Ssortingng armorDecrypt(Ssortingng data) throws InvalidKeyException,NoSuchAlgorithmException, NoSuchPaddingException,IllegalBlockSizeException, BadPaddingException,InvalidAlgorithmParameterException { return new Ssortingng(decrypt(Base64.decode(data, Base64.DEFAULT))); } } 

Vous pouvez inclure ces deux fichiers dans toutes vos applications nécessitant le cryptage du stockage de données. Tout d’abord, assurez-vous que vous avez une valeur pour votre clé et votre vecteur d’initialisation, puis appelez l’une des méthodes de chiffrement ou de déchiffrement sur vos données avant de les stocker. Le Listing 3 et le Listing 4 contiennent un exemple simple d’application de ces classes 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 de 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 **/ Ssortingng key = "12345678909876543212345678909876"; Ssortingng 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) { Ssortingng Data = editInputData.getText().toSsortingng(); Ssortingng 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) { Ssortingng Data = encryptedDataView.getText().toSsortingng(); Ssortingng 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)

          

Si la firebase database est petite, vous pouvez gagner un peu de sécurité en déchiffrant l’intégralité du fichier vers un emplacement temporaire (pas sur une carte SD), puis en le rechiffrant lorsque vous l’avez fermé. Problèmes: mort prématurée de l’application, image fantôme sur les médias.

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 rechercher ce dernier. Mais cela ne facilite pas les recherches sur les plages ou les commandes.

Si vous voulez devenir plus sophistiqué, vous pouvez fouiller dans le NDK Android et pirater du crypto dans du code C pour SQLite.

Compte tenu de tous ces problèmes et des solutions partielles, êtes-vous sûr d’avoir vraiment besoin d’une firebase database SQL pour l’application? Vous pourriez être mieux avec quelque chose comme un fichier qui contient un object sérialisé chiffré.

Vous pouvez certainement avoir une firebase database SQLite cryptée sur Android. Vous ne pouvez pas le faire avec les classes fournies par Google.

Quelques alternatives:

  • Comstackz votre propre SQLite via le NDK et incluez le codec de chiffrement, par exemple, wxSQLite3 (un beau codec gratuit est inclus dans le paquet)
  • SQLCipher inclut désormais le support pour Android

http://sqlite-crypt.com/ peut vous aider à créer une firebase database cryptée, même si je ne l’ai jamais utilisée sur Android semble être possible avec le code source.