CREATE TABLE android_metadata falló al volver a abrir sqlcipher DB

Tengo el siguiente SqlCipher DB. Funciona bien cuando primero instale la aplicación, pero si cierro, eliminar la aplicación del historial reciente (de la pila) y volver a abrir la aplicación se bloquea con el siguiente error. El db no se abrirá una vez que se encuentre una excepción, por ejemplo puse un 1/0 en una actividad para forzarlo a chocar y lo mismo ocurrió abajo.

07-20 15:39:05.669: E/Database(21425): CREATE TABLE android_metadata failed 07-20 15:39:05.669: E/Database(21425): Failed to setLocale() when constructing, closing the database 07-20 15:39:05.669: E/Database(21425): net.sqlcipher.database.SQLiteException: file is encrypted or is not a database 

.

He encontrado el siguiente enlace que parece solucionar el problema (no estoy seguro de si es la solución), pero no estoy seguro de cómo implementarlo en mi código. ¿Podría alguien ayudar por favor o decirme por qué estoy recibiendo este error?

Http://rootslash.net/88542/sqlcipher-cant-open-database-after-apprestart

Este es mi código de DB, yo uso SqlCipher SQLiteOpenHelper para crear el DB. Creo que tengo que modificar este código por lo que devuelve un objeto DB si ya existe y crea uno si no existe. No estoy seguro de cómo.

Gracias por adelantado.

[EDIT1] Tengo una LoginActivity que verifica las credenciales del usuario. Si son válidos, cargan el MenuActivity en el que he puesto un 1/0 para forzar un accidente. Después de la caída si vuelvo a abrir la aplicación se bloquea en la LoginActivity en la línea donde consulta la tabla de usuario de la base de datos.

DBModel es una clase que tiene los métodos SqliteOpenHelper y CRUD.

Por lo tanto, se está bloqueando en checkUserInDB () en la clase DBModel, que a su vez llama a queryAllFromUser ().

 07-25 13:45:43.043 10654-10654/? E/AppObj﹕ Build.SERIAL = SH43PWM07311 07-25 13:45:43.203 10654-10654/? E/AppObj﹕ secretKey = com.android.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey@31a79cea 07-25 13:45:43.643 10654-10654/? E/Database﹕ CREATE TABLE android_metadata failed 07-25 13:45:43.643 10654-10654/? E/Database﹕ Failed to setLocale() when constructing, closing the database net.sqlcipher.database.SQLiteException: file is encrypted or is not a database at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method) at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096) at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881) at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:913) at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:132) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:197) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184) at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175) at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262) at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62) at android.app.Activity.performCreate(Activity.java:5958) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474) at android.app.ActivityThread.access$800(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:155) at android.app.ActivityThread.main(ActivityThread.java:5696) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) 07-25 13:45:43.643 10654-10654/? E/SQLiteOpenHelper﹕ Couldn't open devreach.db for writing (will try read-only): net.sqlcipher.database.SQLiteException: file is encrypted or is not a database at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method) at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096) at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881) at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(SQLiteDatabase.java:913) at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:132) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:197) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184) at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175) at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262) at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62) at android.app.Activity.performCreate(Activity.java:5958) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474) at android.app.ActivityThread.access$800(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:155) at android.app.ActivityThread.main(ActivityThread.java:5696) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) 07-25 13:45:43.983 10654-10654/? E/Database﹕ CREATE TABLE android_metadata failed 07-25 13:45:43.983 10654-10654/? E/Database﹕ Failed to setLocale() when constructing, closing the database net.sqlcipher.database.SQLiteException: file is encrypted or is not a database at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method) at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096) at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:940) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:219) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184) at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175) at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262) at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62) at android.app.Activity.performCreate(Activity.java:5958) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474) at android.app.ActivityThread.access$800(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:155) at android.app.ActivityThread.main(ActivityThread.java:5696) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) 07-25 13:45:43.983 10654-10654/? E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: devreach.co.uk.devreach, PID: 10654 java.lang.RuntimeException: Unable to start activity ComponentInfo{devreach.co.uk.devreach/devreach.co.uk.devreach.LoginActivity}: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2411) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474) at android.app.ActivityThread.access$800(ActivityThread.java:144) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:155) at android.app.ActivityThread.main(ActivityThread.java:5696) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) Caused by: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database at net.sqlcipher.database.SQLiteDatabase.native_setLocale(Native Method) at net.sqlcipher.database.SQLiteDatabase.setLocale(SQLiteDatabase.java:2096) at net.sqlcipher.database.SQLiteDatabase.<init>(SQLiteDatabase.java:1962) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:881) at net.sqlcipher.database.SQLiteDatabase.openDatabase(SQLiteDatabase.java:940) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:219) at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(SQLiteOpenHelper.java:184) at devreach.co.uk.devreach.DBModel.queryAllFromUser(DBModel.java:175) at devreach.co.uk.devreach.DBModel.checkIfUserInDB(DBModel.java:262) at devreach.co.uk.devreach.LoginActivity.onCreate(LoginActivity.java:62) at android.app.Activity.performCreate(Activity.java:5958) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1129) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2474)            at android.app.ActivityThread.access$800(ActivityThread.java:144)            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1359)            at android.os.Handler.dispatchMessage(Handler.java:102)            at android.os.Looper.loop(Looper.java:155)            at android.app.ActivityThread.main(ActivityThread.java:5696)            at java.lang.reflect.Method.invoke(Native Method)            at java.lang.reflect.Method.invoke(Method.java:372)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823) 

LoginActivity:

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); appObj = (AppObj)getApplication(); editTextFirstName = (EditText)findViewById(R.id.edittextfirstname); editTextPassword = (EditText)findViewById(R.id.editTextpassword); String firstName = appObj.dbModel.checkIfUserInDB(); if(! firstName.equalsIgnoreCase("NO_USER")){ editTextFirstName.setText(firstName); } 

DBModel:

  import net.sqlcipher.Cursor; import net.sqlcipher.database.SQLiteDatabase; import net.sqlcipher.database.SQLiteOpenHelper; import android.content.ContentValues; import android.content.Context; import android.provider.BaseColumns; import android.util.Log; import android.widget.Toast; public class DBModel { private static final String TAG = DBModel.class.getSimpleName(); // table user column names public static final String C_USER_ID_INDEX = BaseColumns._ID; public static final String C_USER_ID = "userid"; public static final String C_USER_COMP_ID = "usercompid"; public static final String C_USER_FIRSTNAME = "userfirstname"; public static final String C_USER_LASTNAME = "userlastname"; public static final String C_USER_PASSWORD = "userpassword"; public static final String C_USER_DATE_TIME = "userdatetime"; // table company column names public static final String C_COMPANY_ID_INDEX = BaseColumns._ID; public static final String C_COMPANY_ID = "companyid"; public static final String C_COMPANY_NAME = "companyname"; public static final String C_COMPANY_URL = "companyurl"; public static final String C_COMPANY_GUID = "companyguid"; Context context; DBHelper dbhelper; AppObj appObj; public DBModel(Context context) { this.context = context; dbhelper = new DBHelper(); appObj = (AppObj) context.getApplicationContext(); } /** * inner class to create/open/upgrade database * * @author matt * */ private class DBHelper extends SQLiteOpenHelper { // database name and version number public static final String DB_NAME = "devreach.db"; public static final int DB_VERSION = 1; // table names public static final String TABLEUSER = "user"; public static final String TABLECOMPANY = "company"; public DBHelper() { super(context, DB_NAME, null, DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { Log.e(TAG, "SQLiteOpenHelper oncreate "); String sqlToCreateUserTable = String .format("create table %s ( %s INTEGER primary key, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT)", TABLEUSER, C_USER_ID_INDEX, C_USER_ID, C_USER_COMP_ID, C_USER_FIRSTNAME, C_USER_LASTNAME, C_USER_PASSWORD, C_USER_DATE_TIME); db.execSQL(sqlToCreateUserTable); Log.e(TAG, "oncreate " + sqlToCreateUserTable); String sqlToCreateCompanyTable = String .format("create table %s ( %s INTEGER primary key, %s TEXT, %s TEXT, %s TEXT, %s TEXT)", TABLECOMPANY, C_COMPANY_ID_INDEX, C_COMPANY_ID, C_COMPANY_NAME, C_COMPANY_URL, C_COMPANY_GUID); db.execSQL(sqlToCreateCompanyTable); Log.e(TAG, "oncreate " + sqlToCreateCompanyTable); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }//end of onUpgrade }//end of DBHelper public void close() { dbhelper.close(); } public void deleteTableUser() { // open database SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString()); // delete contents of table db.delete(DBHelper.TABLEUSER, null, null); } public void insertIntoUser(ContentValues cv) { SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString()); db.insertWithOnConflict(DBHelper.TABLEUSER, null, cv, SQLiteDatabase.CONFLICT_REPLACE); } public Cursor queryAllFromUser() { // open database SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString()); return db.query(DBHelper.TABLEUSER, null, null, null, null, null, null); } public void deleteTableCompany() { // open database SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString()); // delete contents of table db.delete(DBHelper.TABLECOMPANY, null, null); } public void insertIntoCompany(ContentValues cv) { SQLiteDatabase db = dbhelper.getWritableDatabase(AppObj.getSecretKey().toString()); db.insertWithOnConflict(DBHelper.TABLECOMPANY, null, cv, SQLiteDatabase.CONFLICT_REPLACE); } public Cursor queryAllFromCompany() { // open database SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString()); return db.query(DBHelper.TABLECOMPANY, null, null, null, null, null, null); } public String getCompanyGuid(){ String guid = null; Cursor c = null; SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString()); c = db.query(DBHelper.TABLECOMPANY, null, null, null, null, null, null); if(c != null){ if(c.moveToLast()){ guid = c.getString(c.getColumnIndex(DBModel.C_COMPANY_GUID)); } } try{ c.close(); }catch(Exception e){} return guid; } public String getCompanyID(){ String id = null; Cursor c = null; SQLiteDatabase db = dbhelper.getReadableDatabase(AppObj.getSecretKey().toString()); c = db.query(DBHelper.TABLECOMPANY, null, null, null, null, null, null); if(c != null){ if(c.moveToLast()){ id = c.getString(c.getColumnIndex(DBModel.C_COMPANY_ID)); } } try{ c.close(); }catch(Exception e){} return id; } public String checkIfUserInDB() { String firstName = null; Cursor c = queryAllFromUser(); if(c != null && c.getCount() > 0){ if(c.moveToLast()){ Log.e(TAG,"c != null and > 0"); firstName = c.getString(c.getColumnIndex(DBModel.C_USER_FIRSTNAME)); } }else{ Log.e(TAG,"c == null"); firstName = "NO_USER"; } try{ c.close(); }catch(Exception e){} Log.e(TAG,"firstName = " + firstName); return firstName; } }//end of DBModel 

[EDIT2]

  @Override public void onCreate() { super.onCreate(); secretKey = null; Log.e(TAG, "Build.SERIAL = " + Build.SERIAL); SecureRandom secureRandom = new SecureRandom(); byte[] salt = secureRandom.generateSeed(256); try { secretKey = generateKey(Build.SERIAL.toCharArray(), salt); Log.e(TAG, "key-Base64 before in appObj = "+new String(Base64.encode(RROnCallApplication.getSecretKey().getEncoded(),0))); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvalidKeySpecException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.e(TAG, "secretKey = " + secretKey); SQLiteDatabase.loadLibs(this); dbModel = new DBModel(this); webService = new WebService(this); alertCount = 0; // Cursor checkCarerTable = dbModel.queryAllFromCarer(); // // if(checkCarerTable.getCount() == 0){ // // //runGetCarersService(); // //runGetClientsService(); // // // }else{ // // Log.e(TAG, "carer and client table is populated with some data"); // } } private static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException { // Number of PBKDF2 hardening rounds to use. Larger values increase // computation time. You should select a value that causes computation // to take >100ms. final int iterations = 1000; // Generate a 256-bit key final int outputKeyLength = 256; SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength); SecretKey secretKey = secretKeyFactory.generateSecret(keySpec); return secretKey; } 

La sal debe ser la misma, así como las variables que has hash para crear una clave.

Las variables asumiblemente seguirá siendo la misma, misma contraseña de usuario / usuario, sin embargo su código está regenerando una sal aleatoria.

Si ha cifrado la base de datos con una clave, la clave tiene que ser la misma y, por tanto, la sal debe ser la misma.

¡Espero que esto ayude!

El error que estaba recibiendo fue porque la clave de lo que se regeneró con otro SecureRandom para la sal. Así que después de un accidente las llaves no coinciden. Mark ha sugerido usar una contraseña de usuario sin saltar que el usuario debe ingresar al usar la aplicación por primera vez. También la aplicación debe mantener el objeto SqlOpenHelper que a su vez se aferra a la base de datos y la clave.

  • SQLCipher para Android: icudt46l.zip realmente necesario?
  • SQL Cursor lanza fuera de la memoria mientras llama a getString
  • Android Studio (Beta v0.8.6) e integración con SQLCipher (v3.1.0)
  • Usando SQLCipher con el archivo de base de datos SQLite enviado sqlite
  • Android SQCipher ¿Necesito cerrar la base de datos?
  • ¿Puede alguien explicarme el paso de compilación en la creación de un archivo binario sqlcipher?
  • Sqlcipher 'open' performance con cordova y Cordova-SQLitePlugin
  • ¿Existe una manera correcta de comprobar si una contraseña SQLCipher proporcionada por el usuario es válida en Android?
  • Android Proguard SqlCipher NoClassDefFoundError
  • Android No se puede cifrar la base de datos utilizando sqlcipher usando greendao
  • Integración ormlite-4.9 con sqlcipher-2.08
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.