2015-07-20 15 views
11

Ho il seguente SqlCipher DB. Funziona perfettamente quando installo l'app, ma se chiudo, rimuovi l'app dalla cronologia recente (fuori dallo stack) e riapri l'app che si blocca con il seguente errore. Il db non si aprirà dopo che si è verificata un'eccezione, ad esempio inserisco un 1/0 in un'attività per costringerlo a bloccarsi e lo stesso è accaduto di seguito.CREATE TABLE android_metadata ha avuto esito negativo quando si riapre sqlcipher DB

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 

.

Ho trovato il seguente link che sembra risolvere il problema (non sono sicuro che sia la soluzione) ma non sono sicuro di come implementarlo nel mio codice. Qualcuno potrebbe aiutare per favore o dirmi perché sto ricevendo questo errore?

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

Questo è il mio codice DB, io uso SqlCipher SQLiteOpenHelper per creare il DB. Penso di aver bisogno di modificare questo codice in modo che restituisca un oggetto DB se ne esiste già uno e ne crea uno se non esiste. non sono sicuro di come.

Grazie in anticipo.

[EDIT1] Ho un LoginActivity che verifica le credenziali dell'utente. se sono validi carica il MenuActivity in cui ho messo un 1/0 per forzare un crash. Dopo l'arresto anomalo, se riaprio l'app si blocca in LoginActivity sulla riga in cui esegue una query sulla tabella Utente DB.

DBModel è una classe con i metodi SqliteOpenHelper e CRUD.

Quindi si blocca su checkUserInDB() nella classe DBModel, che a sua volta chiama 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.a[email protected]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; 
} 
+0

"Penso di aver bisogno di modificare questo codice in modo che restituisca un oggetto DB se ne esiste già uno e ne crea uno se non esiste." - 'SQLiteOpenHelper' lo fa già.Dove e come stai creando l'istanza di 'SQLiteOpenHelper', dove e come stai chiamando' getReadableDatabase() 'o' getWriteableDatabase() 'su di esso che sta attivando questo crash? – CommonsWare

+0

@CommonsWare Ho aggiunto più informazioni che posso in EDIT 1. Grazie – turtleboy

+0

@CommonsWare Ho pensato che potrei aggiungere, creo la chiave per il DB nel metodo onCreate dell'oggetto dell'applicazione passando il Build.SERIAL a un metodo che genera la chiave con un sale casuale. Sto solo verificando che dopo un crash l'onCreate dell'oggetto dell'applicazione non venga eseguito nuovamente e generi una chiave diversa? solo un pensiero. – turtleboy

risposta

4

Il sale deve essere uguale a quello delle variabili che si hashing per creare una chiave.

Le variabili resteranno invariate, stessa password utente/utente, tuttavia il codice sta rigenerando un salt casuale.

Se il database è stato crittografato con una chiave, la chiave deve essere la stessa, e quindi il sale deve essere lo stesso.

Spero che questo aiuti!

3

L'errore mi è stato sempre stati perché la chiave di ciò che sempre rigenerata con un altro SecureRandom per il sa lt. Quindi dopo un crash le chiavi non combaciano. Mark ha suggerito di utilizzare una password utente non salda che l'utente deve inserire quando usa l'app per la prima volta. Inoltre, l'app deve conservare l'oggetto SqlOpenHelper che a sua volta conserva il DB e la chiave.

Problemi correlati