2015-07-20 15 views
11

Ich habe die folgende SqlCipher DB. Es funktioniert gut, wenn ich die App zum ersten Mal installiere, aber wenn ich schließe, entferne die App aus dem letzten Verlauf (aus dem Stapel) und öffne die App erneut, die mit dem folgenden Fehler abstürzt. Die db wird nicht geöffnet, sobald eine Exception auftritt, zum Beispiel setze ich eine 1/0 in eine Activity, um sie zum Absturz zu bringen und das selbe passiert darunter.CREATE TABLE android_metadata fehlgeschlagen beim erneuten Öffnen von 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 

.

Ich habe den folgenden Link gefunden, der das Problem zu beheben scheint (ich bin mir nicht sicher, ob es die Lösung ist), aber ich bin mir nicht sicher, wie ich es in meinen Code implementieren soll. Könnte jemand bitte helfen oder mir sagen, warum ich diesen Fehler bekomme?

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

Das ist mein DB-Code ist, verwende ich SqlCipher SQLiteOpenHelper die DB zu erstellen. Ich denke, dass ich diesen Code ändern muss, damit es ein DB-Objekt zurückgibt, wenn eins bereits existiert, und eines erzeugt, wenn es nicht existiert. Ich bin mir nicht sicher wie.

Vielen Dank im Voraus.

[EDIT1] Ich habe eine LoginActivity, die die Anmeldeinformationen des Benutzers überprüft. Wenn sie gültig sind, lädt sie die MenuActivity, in die ich eine 1/0 gesetzt habe, um einen Crash zu erzwingen. Nach dem Absturz, wenn ich die App wieder öffne, stürzt es in der LoginActivity in der Zeile ab, in der es die DB-Benutzertabelle abfragt.

DBModel ist eine Klasse mit den Methoden SqliteOpenHelper und CRUD.

So stürzt es bei checkUserInDB() in der DBModel-Klasse ab, die ihrerseits queryAllFromUser() aufruft.

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 

[EDIT 2]

@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

"Ich denke, ich muss diesen Code ändern, so dass es ein DB-Objekt zurückgibt, wenn eines bereits existiert und eines erstellt, wenn es nicht existiert." - 'SQLiteOpenHelper' macht das schon.Wo und wie erstellen Sie Ihre 'SQLiteOpenHelper'-Instanz und wo und wie rufen Sie' getReadableDatabase() 'oder' getWriteableDatabase() 'darauf auf, die diesen Absturz auslösen? – CommonsWare

+0

@CommonsWare Ich habe so viele Informationen wie möglich in EDIT 1 hinzugefügt. Danke – turtleboy

+0

@CommonsWare Ich dachte ich könnte hinzufügen, ich erstelle den Schlüssel zur DB in der onCreate Methode des Anwendungsobjekts, indem ich Build.SERIAL an a Methode, die den Schlüssel mit einem zufälligen Salz erzeugt. Ich überprüfe nur, dass das Anwendungsobjekt onCreate nach einem Absturz nicht erneut ausgeführt wird und einen anderen Schlüssel generiert? nur ein Gedanke. – turtleboy

Antwort

4

Das Salz muss identisch sein mit den Variablen, die Sie zum Erstellen eines Schlüssels verwenden.

Die Variablen werden vermutlich gleich bleiben, das gleiche Benutzer/Benutzer-Passwort, aber Ihr Code ist eine zufällige Salz neu generieren.

Wenn Sie die Datenbank mit einem Schlüssel verschlüsselt haben, muss der Schlüssel derselbe sein und daher muss das Salz gleich sein.

Ich hoffe, das hilft!

3

Der Fehler war ich immer waren, weil der Schlüssel, was mit einem anderen Secure regeneriert zu werden für die sa lt. Nach einem Absturz stimmten die Tasten nicht überein. Mark hat vorgeschlagen, ein ungesalzenes Benutzerpasswort zu verwenden, das der Benutzer bei der ersten Verwendung der App eingeben muss. Auch die App muss sich an das SqlOpenHelper-Objekt halten, das sich wiederum an DB und Schlüssel hält.