71 votos

Cifrado de la base de datos Android

Android utiliza base de datos SQLite para almacenar datos, necesito para cifrar la base de datos SQLite, ¿cómo se puede hacer? Entiendo que los datos de la aplicación están privados. Sin embargo yo necesito a exiger cifrar la base de datos SQLite que está usando mi aplicación.

64voto

vaichidrewar Puntos 2154

SQLCipher es una SQLite extensión que proporciona transparente de 256-bit AES de cifrado de archivos de base de datos.

Antes sqlcipher que es Open Source Cifrado de Base de datos SQLite no estaba disponible para android. Pero ahora disponible como versión alpha para la plataforma android. Los desarrolladores han actualizado el estándar de la aplicación de android'Notepadbot " para uso SQLCipher.

Así que es definitivamente la mejor y más sencilla opción como la de ahora.

25voto

Plo_Koon Puntos 614

Las bases de datos están cifrados con el fin de prevenir INDIRECT ATTACKS. Este término y clases: KeyManager.java, Crypto.java se toman de Sheran Gunasekera libro de Android las Aplicaciones de Seguridad. Recomiendo a todos este libro a la lectura.

INDIRECT ATTACKS son llamados así, porque el virus no ir después de su aplicación directamente. En su lugar, se va después de que el sistema operativo Android. El objetivo es copiar todas las bases de datos SQLite en la esperanza de que el virus de autor puede copiar cualquier información sensible almacenada allí. Si había añadido otra capa de protección, sin embargo, todos los virus de autor sería ver es distorsionado de datos. Vamos a construir una biblioteca de cifrado que se pueden reutilizar en todas nuestras aplicaciones. Vamos a empezar por la creación de un breve conjunto de especificaciones:

  • Utiliza los algoritmos simétricos: Nuestra biblioteca que va a utilizar un algoritmo simétrico, o bloque de cifrado para cifrar y descifrar los datos. Vamos a resolver en AES, aunque debemos ser capaces de modificar esto en una fecha posterior.

  • Utiliza una clave fija: Tenemos que ser capaces de incluir una clave que nos puede almacenar en el dispositivo que se utiliza para cifrar y descifrar los datos.

  • Clave almacenada en el dispositivo: La clave residirá en el dispositivo. Mientras que esto es un riesgo para nuestra aplicación desde la perspectiva de los ataques directos, deben ser suficientes nos protege contra ataques indirectos.

Vamos a empezar con la llave de nuestro módulo de gestión (ver Listado 1). Porque tenemos la intención de utilizar una clave fija, no necesitamos generar una al azar, como hicimos en el pasado ejemplos. El KeyManager será, por tanto, realizar las siguientes tareas:

  1. Aceptar una clave como parámetro ( setId(byte[] data) método)
  2. Aceptar un vector de inicialización como un parámetro ( setIv(byte[] data) el método)
  3. Almacenar la clave dentro de un archivo en el almacén interno
  4. Recuperar la clave de un archivo en el almacén interno ( getId(byte[] data) el método)
  5. Recuperar el IV a partir de un archivo en el almacén interno ( getIv(byte[] data) el método)

(Listado 1. El Módulo 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());
         }
     }
}

A continuación, vamos a hacer el Crypto módulo (ver Listado 2). Este módulo se ocupa del cifrado y el descifrado. Hemos añadido un armorEncrypt() y armorDecrypt() método para el módulo para hacer más fácil para convertir la matriz de bytes de datos en imprimible Base64 de datos y viceversa. Vamos a utilizar la AES algoritmo con Cipher Block Chaining (CBC) el modo de encriptación y PKCS#5 relleno.

(Listado 2. El Módulo Criptográfico 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)));
               }
}

Usted puede incluir estos dos archivos en cualquiera de sus aplicaciones que requieren el almacenamiento de datos a cifrar. En primer lugar, asegúrese de que tiene un valor para la clave y el vector de inicialización, a continuación, llamar a cualquiera de los cifrar o descifrar los métodos en los datos antes de almacenarlos. El listado 3 y 4 Listado de contener una simplemente de la Aplicación-ejemplo de estas clases. Vamos a crear una Actividad con 3 Botones de Cifrar, Descifrar, Eliminar; 1 EditText para la entrada de datos; 1 TextView para la salida de datos.

(Listado 3. Un ejemplo de ello. 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 ");
            }
        });

    }

}

(Listado 4. Un ejemplo de ello. 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>

13voto

Mark Borgerding Puntos 2259

Si la base de datos será pequeño, entonces usted podría tener una pequeña cantidad de seguridad por descifrar todo el archivo a una ubicación temporal (no en la tarjeta sd), luego volver a cifrar cuando se ha cerrado. Problemas: prematuro de la aplicación de la muerte, el fantasma de la imagen en los medios de comunicación.

Un poco mejor solución para cifrar los datos de los campos. Esto provoca un problema para las cláusulas where y ORDER BY. Si el cifrado de los campos deben ser indexados para la equivalencia de búsqueda, entonces usted puede almacenar un hash criptográfico del campo y la búsqueda de ese. Pero eso no ayuda con las búsquedas por rango o un orden.

Si desea obtener más elegante, se podría profundizar en el Android NDK y hack algunos criptografía en código C para SQLite.

Teniendo en cuenta todos estos problemas y soluciones parciales, está seguro de que usted realmente necesita una base de datos SQL para la aplicación? Usted puede ser mejor con algo como un archivo que contiene un cifrado objeto serializado.

3voto

NuSkooler Puntos 2679

Sin duda puede tener una base de datos SQLite cifrada en Android. No puedes hacerlo con la salida de la caja de acceso de Java, sin embargo. En cambio, compilar SQLite vía el NDK con un códec de cifrado como que ya vinculados o de wxSQLite (un buen codec libre es incluido en el paquete).

Entonces podrías escribir tu propio contenedor Java alrededor de todo el asunto.

Esperemos que Google añade soporte para cifrado en el futuro.

2voto

Ryan Puntos 543

¿Por qué no solo encriptar datos en la base de datos y solamente almacenar la clave 14,640 cantidad de tiempo antes de que el usuario vuelva a escribirla?

Echale un vistazo http://www.androidsnippets.org/snippets/39/

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X