11

I have the following SqlCipher DB. It works fine when i first install the app, but if i close, remove the app from recent history(off the stack) and re-open the app it crashes with the following error. The db will not open once an exception is encountered, for example i put a 1/0 in an Activity to force it to crash and the same happened below.

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

.

I've found the following link that seems to fix the problem (i'm not sure if it is the solution) but i'm not sure how to implement it into my code. Could anyone help please or tell me why i'm getting this error?

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

This is my DB code, i use SqlCipher SQLiteOpenHelper to create the DB. I think i need to modify this code so it returns a DB object if one already exists and creates one if it doesn't exist. i'm just not sure how.

Thanks in advance.

[EDIT1] I have a LoginActivity that verifies the user's credentials. if they are valid it loads the MenuActivity in which i have put a 1/0 to force a crash. After the crash if i re-open the app it crashes in the LoginActivity at the line where it queries the DB User table.

DBModel is a class that has the SqliteOpenHelper and CRUD methods.

So it is crashing at checkUserInDB() in the DBModel class, which in turn calls 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;
}
turtleboy
  • 8,210
  • 27
  • 100
  • 199
  • "I think i need to modify this code so it returns a DB object if one already exists and creates one if it doesn't exist." -- `SQLiteOpenHelper` already does that. Where and how are you creating your `SQLiteOpenHelper` instance, and where and how are you calling `getReadableDatabase()` or `getWriteableDatabase()` on it that is triggering this crash? – CommonsWare Jul 25 '15 at 10:39
  • @CommonsWare I've added as much info as i can in EDIT 1. Thanks – turtleboy Jul 25 '15 at 12:47
  • @CommonsWare I thought i might add, i create the key to the DB in the onCreate method of the application object by passing the Build.SERIAL to a method that generates the key with a random salt. I'm just checking that after a crash the application object's onCreate doesn't run again and generate a different key? just a thought. – turtleboy Jul 25 '15 at 13:10
  • Well, your code has a variety of issues (e.g., disk I/O on the main application thread). I don't know where you are creating `dbModel`, but since you are holding onto it in `static` scope, the `Context` that it holds onto needs to be the `Application` instance (`AppObj` instance in your case). Anything else would not only result in a memory leak but could cause problems when you try using a defunct `Context` later on. Using SQLCipher here is a waste of time, as your key generation is trivially reverse-engineered, so you might consider rolling back to plain SQLite. – CommonsWare Jul 25 '15 at 15:31
  • Beyond that, confirm that `getSecretKey()` is returning the right value in the post-exception case, try switching from `getReadableDatabase()` to `getWriteableDatabase()`, and see if the database file exists before your crash. – CommonsWare Jul 25 '15 at 15:33
  • @CommonsWare I think what seems to be happening is when the app crashes my Appliction Object is generating a new SecretKey. i checked the value on install and re-opening app after a crash; They were different. Where is the best place to store the Secret Key, in SharedPreferences? – turtleboy Jul 27 '15 at 09:12
  • @CommonsWare To answer the questions above, i'm creating the dbModel class in the AppObj. I followed the Marakana video from about 5 yrs ago. Marko suggested 'hanging the DB off the Appliction Object'. So i've designed all my apps this way. i hope i'm correct in doing so? with regards to disk I/O on the UIthread, do you mean the lack of ContentProvider/CursorLoader? I've just started this project and haven't got around to designing these yet :) – turtleboy Jul 27 '15 at 09:21
  • @CommonsWare i have found a post from last year where you state that the user should keep the password in their head. The password on the DB would be derived from the login password. in Edit2 i have posted the appObj and how i generate the password. If i were to use the login password, i use a SecureRandom when generating the salt. would this not generate a different key each time? – turtleboy Jul 27 '15 at 10:51
  • "Where is the best place to store the Secret Key" -- in the user's head. SQLCipher is not a DRM solution. "i hope i'm correct in doing so?" -- there is nothing intrinsically wrong with it; just make sure you are using `Application` as your `Context`. "do you mean the lack of ContentProvider/CursorLoader?" -- whether you use that or some other solution is up to you, but you need to get the disk I/O off the main application thread. – CommonsWare Jul 27 '15 at 11:13
  • "If i were to use the login password, i use a SecureRandom when generating the salt. would this not generate a different key each time?" -- yes. You do not need to randomly generate a salt here. – CommonsWare Jul 27 '15 at 11:15
  • @CommonsWare ok thanks Mark, it is becoming a little clearer now. The last thing i'm unsure of is if i don't store the password in memory and only in the user's head, how can subsequent calls to the DB be made when the password is needed. Surely the login password needs to be store somewhere in memory then cleared down when the app is exited? – turtleboy Jul 27 '15 at 13:23
  • "Surely the login password needs to be store somewhere in memory then cleared down when the app is exited?" -- no. Just hold onto your `SQLiteOpenHelper`. It, in turn, holds onto the `SQLiteDatabase`. Only when you `close()` the `SQLiteOpenHelper` (or your process terminates) do you have to worry about supplying a passphrase to SQLCipher again, when your process starts up again. And, at that point, you ask the user for the passphrase again. – CommonsWare Jul 27 '15 at 13:40
  • @CommonsWare great thanks a lot for your help. If you would like to make an answer as it was the passwords that didn't match, i'll accept your answer. – turtleboy Jul 27 '15 at 13:45
  • I would recommend that you post your own answer, explaining where things went wrong in your secret key generation. That would be more useful that simply my rehash of this comment thread. – CommonsWare Jul 27 '15 at 13:50

2 Answers2

4

The salt must be the same as well as the variables that you are hashing to create a key.

The variables assumably will remain the same, same user/user password, however your code is regenerating a random salt.

If you have encrypted the database with a key, the key has to be the same, and therefore the salt must be the same.

I hope this helps!

3

The error i was getting were because the key what getting regenerated with another SecureRandom for the salt. So after a crash the keys did not match. Mark has suggested using an unsalted user password which the user must enter when first using the app. Also the app must hold on to the SqlOpenHelper object which in turn holds on to the DB and key.

turtleboy
  • 8,210
  • 27
  • 100
  • 199