文件已加密或不是数据库:,在编译时:从sqlite_master中选择count(*);

时间:2017-04-26 09:58:28

标签: android sqlite encryption sqlcipher-android

我有一个已经投入生产多年的应用程序。它附带标准的Sqlite DB。最新版本的应用程序集成了SqlCipher 3.5.6库。

新数据库中有一些额外的表,所以我在onUpgrade方法中创建了它们。

我在我的应用程序对象中调用了以下方法。

SQLiteDatabase.loadLibs(this);

旧apk中的DB_VERSION是56,我在新的apk中将它设置为57,因此应该调用onUpgrade。

我从onUpgrade内部调用encrypt方法。

@Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

            Log.e(TAG, "++++++++++++++++++++++++++SQLiteOpenHelper onUpgrade old version = " + oldVersion + " new version = " + newVersion);

if(oldVersion == 56){

                String sqlToCreateWeeklySummary = String
                        .format("create table %s ( %s INTEGER primary key, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT, %s TEXT)",
                                TABLEWEEKLYSUMMARY, C_ID_WEEKLY_SUMMARY, C_WEEKLY_SUMMARY_STARTDATE,
                                C_WEEKLY_SUMMARY_PLANNEDCALLS, C_WEEKLY_SUMMARY_NCR, C_WEEKLY_SUMMARY_QA, C_WEEKLY_SUMMARY_PLANNEDHOURS,
                                C_WEEKLY_SUMMARY_ACTUALCALLS, C_WEEKLY_SUMMARY_ACTUALHOURS);

                db.execSQL(sqlToCreateWeeklySummary);
                Log.e(TAG, "onUpgrade " + sqlToCreateWeeklySummary);


more table upgrades................

                NfcScannerApplication.setJustUpgradedDBTrue();
                NfcScannerApplication.setDownloadingCompOptsAfterUpgradeTrue();




                try {
                    encrypt(context, "carefreemobiledb.db", "");
                }catch(Exception e){}

            }



        }//end of onUpgrade

public void encrypt(Context ctxt, String dbName, String passphrase) throws IOException {

        Log.e(TAG, "inside encrypt");

        File originalFile=ctxt.getDatabasePath(dbName);

        if (originalFile.exists()) {
            Log.e(TAG, "originalFile exists1");
            File newFile= File.createTempFile("sqlcipherutils", "tmp", ctxt.getCacheDir());
            Log.e(TAG, "created newFile2");

            SQLiteDatabase db= SQLiteDatabase.openDatabase(originalFile.getAbsolutePath(),
                    "", null, SQLiteDatabase.OPEN_READWRITE);
            Log.e(TAG, "opened DB using originalFile3");

            db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
                    newFile.getAbsolutePath(), passphrase));
            Log.e(TAG, "Attached DB4");

            db.rawExecSQL("SELECT sqlcipher_export('encrypted')");

            Log.e(TAG, "export5");

            db.rawExecSQL("DETACH DATABASE encrypted;");
            Log.e(TAG, "detached DB6");

            int version=db.getVersion();

            db.close();
            Log.e(TAG, "closed DB7");

            db= SQLiteDatabase.openDatabase(newFile.getAbsolutePath(),
                    passphrase, null,
                    SQLiteDatabase.OPEN_READWRITE);

            Log.e(TAG, "opened DB with newFile8");

            db.setVersion(version);
            Log.e(TAG, "set version for db using newFile9");
            db.close();
            Log.e(TAG, "closed db10");

            originalFile.delete();
            Log.e(TAG, "deleted orignial file11");
            newFile.renameTo(originalFile);
            Log.e(TAG, "renamed newFile to orginalFile12");
        }
    }

当我将新apk加载到安装了旧应用的设备上时,我收到以下错误。

file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master;
                                           net.sqlcipher.database.SQLiteException: file is encrypted or is not a database: , while compiling: select count(*) from sqlite_master;
                                               at net.sqlcipher.database.SQLiteCompiledSql.native_compile(Native Method)
                                               at net.sqlcipher.database.SQLiteCompiledSql.compile(Unknown Source)
                                               at net.sqlcipher.database.SQLiteCompiledSql.<init>(Unknown Source)
                                               at net.sqlcipher.database.SQLiteProgram.<init>(Unknown Source)
                                               at net.sqlcipher.database.SQLiteQuery.<init>(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDirectCursorDriver.query(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDatabase.rawQueryWithFactory(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDatabase.rawQuery(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDatabase.keyDatabase(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDatabase.openDatabaseInternal(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDatabase.openDatabase(Unknown Source)
                                               at net.sqlcipher.database.SQLiteDatabase.openOrCreateDatabase(Unknown Source)
                                               at net.sqlcipher.database.SQLiteOpenHelper.getWritableDatabase(Unknown Source)
                                               at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(Unknown Source)
                                               at net.sqlcipher.database.SQLiteOpenHelper.getReadableDatabase(Unknown Source)
                                               at com.carefreegroup.rr3.g.c(Unknown Source)
                                               at com.carefreegroup.rr3.EntryActivity.onCreate(Unknown Source)
                                               at android.app.Activity.performCreate(Activity.java:6912)
                                               at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
                                               at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2900)
                                               at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3008)
                                               at android.app.ActivityThread.-wrap14(ActivityThread.java)
                                               at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1650)
                                               at android.os.Handler.dispatchMessage(Handler.java:102)
                                               at android.os.Looper.loop(Looper.java:154)
                                               at android.app.ActivityThread.main(ActivityThread.java:6688)
                                               at java.lang.reflect.Method.invoke(Native Method)
                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
04-26 10:40:53.332 9417-9417/? E/SQLiteOpenHelper: Couldn't open carefreemobiledb.db for writing (will try read-only):

我尝试了什么:

SO上的其他帖子说加密方法上的密码必须是空字符串,以便SqlCipher可以打开未加密的数据库。

我在加密方法上将密码设置为“”,但日志显示无法打开数据库。

任何人都可以告诉我为什么数据库没有被打开?它没有达到onUpgrade方法。

NB。值得注意的是,当我清除应用程序上的数据时,它可以正常工作。

[更新1]

我已将encrypt方法移到Application类中。在Application类的onCreate中,我打电话给:

SQLiteDatabase.loadLibs(this);
        Log.e(TAG, "just called SQLiteDatabase.loadLibs(this)");


        try {
            encrypt(mContext, "carefreemobiledb.db", "");
        }catch(Exception e){}

密码短语的加密方法中仍然有一个空字符串参数,但它没有做任何事情,因为我已在下面的实际加密方法中对其进行了评论。

public static void encrypt(Context ctxt, String dbName, String passphrase) throws IOException {

        File originalFile=ctxt.getDatabasePath(dbName);

        if (originalFile.exists()) {
            Log.e(TAG, "originalFile exists1");
            File newFile= File.createTempFile("sqlcipherutils", "tmp", ctxt.getCacheDir());
            Log.e(TAG, "created newFile2");

            SQLiteDatabase db= SQLiteDatabase.openDatabase(originalFile.getAbsolutePath(),
                            "", null, SQLiteDatabase.OPEN_READWRITE);
            Log.e(TAG, "opened DB using originalFile3");

//          db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
//                  newFile.getAbsolutePath(), passphrase));
            db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
                    newFile.getAbsolutePath()));
            Log.e(TAG, "Attached DB4");

            db.rawExecSQL("SELECT sqlcipher_export('encrypted')");

            Log.e(TAG, "export5");

            db.rawExecSQL("DETACH DATABASE encrypted;");
            Log.e(TAG, "detached DB6");

            int version=db.getVersion();

            db.close();
            Log.e(TAG, "closed DB7");

            db= SQLiteDatabase.openDatabase(newFile.getAbsolutePath(),
                            passphrase, null,
                            SQLiteDatabase.OPEN_READWRITE);

            Log.e(TAG, "opened DB with newFile8");

            db.setVersion(version);
            Log.e(TAG, "set version for db using newFile9");
            db.close();
            Log.e(TAG, "closed db10");

            originalFile.delete();
            Log.e(TAG, "deleted orignial file11");
            newFile.renameTo(originalFile);
            Log.e(TAG, "renamed newFile to orginalFile12");
        }
    }

我现在收到以下错误:

04-26 13:56:02.793 15460-15460/? E/NfcScannerApplication: just called SQLiteDatabase.loadLibs(this)
04-26 13:56:02.793 15460-15460/? E/NfcScannerApplication: originalFile exists1
04-26 13:56:02.794 15460-15460/? E/NfcScannerApplication: created newFile2
04-26 13:56:02.798 15460-15460/? E/NfcScannerApplication: opened DB using originalFile3
04-26 13:56:02.806 3247-3247/? E/audit: type=1320 audit(1493211362.789:23690): 
04-26 13:56:02.817 3247-3247/? E/audit: type=1320 audit(1493211362.799:23691): 
04-26 13:56:02.828 3247-3247/? E/audit: type=1320 audit(1493211362.809:23692): 
04-26 13:56:02.886 15460-15469/? E/Database: close() was never explicitly called on database '/data/user/0/com.carefreegroup.rr3/databases/carefreemobiledb.db' 
                                             net.sqlcipher.database.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
                                                 at net.sqlcipher.database.SQLiteDatabase.<init>(Unknown Source)
                                                 at net.sqlcipher.database.SQLiteDatabase.openDatabase(Unknown Source)
                                                 at net.sqlcipher.database.SQLiteDatabase.openDatabase(Unknown Source)
                                                 at net.sqlcipher.database.SQLiteDatabase.openDatabase(Unknown Source)
                                                 at net.sqlcipher.database.SQLiteDatabase.openDatabase(Unknown Source)
                                                 at com.carefreegroup.rr3.NfcScannerApplication.a(Unknown Source)
                                                 at com.carefreegroup.rr3.NfcScannerApplication.onCreate(Unknown Source)
                                                 at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1032)
                                                 at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5881)
                                                 at android.app.ActivityThread.-wrap3(ActivityThread.java)
                                                 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1718)
                                                 at android.os.Handler.dispatchMessage(Handler.java:102)
                                                 at android.os.Looper.loop(Looper.java:154)
                                                 at android.app.ActivityThread.main(ActivityThread.java:6688)
                                                 at java.lang.reflect.Method.invoke(Native Method)
                                                 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
                                                 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)

它可以达到以下目的并崩溃:

Log.e(TAG, "opened DB using originalFile3");

[更新2]

我不确定我是否正确关闭了数据库。 LoginValidate是我的DB类,它有一个方法公开,返回DB对象。

SQLiteDatabase.loadLibs(this);
        Log.e(TAG, "just called SQLiteDatabase.loadLibs(this)");

        loginValidate.getDB().close();

        try {
            encrypt(mContext, "carefreemobiledb.db", "");
        }catch(Exception e){}

另外,我不确定加密方法中的密码。你说不要使用密码短语,但这是否意味着空字符串或根本不传入密码短语。我将给出以下示例。第一个是原始的,另外两个是我尝试过的。

Log.e(TAG, "opened DB using originalFile3");

            db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
                    newFile.getAbsolutePath(), passphrase));




Log.e(TAG, "opened DB using originalFile3");

            db.rawExecSQL(String.format("ATTACH DATABASE '%s' AS encrypted KEY '%s';",
                    newFile.getAbsolutePath(), ""));



Log.e(TAG, "opened DB using originalFile3");

            db.rawExecSQL(String.format("ATTACH DATABASE '%s';",
                    newFile.getAbsolutePath()));

2 个答案:

答案 0 :(得分:0)

  

有谁能告诉我为什么数据库没有被打开?

因为您尝试使用密码短语打开它,但这不起作用,因为数据库未加密。 SQLCipher for Android并没有神奇地决定第二次尝试打开数据库,这次没有密码,然后调用onUpgrade()

此外,你怎么去这个州?你应该从用户那里收集密码,如果你突然开始要求他们从未设置的密码短语,那么用户会看着你很有趣。相反,你需要有一个特定的用户体验,“嘿,让我们切换到加密的数据库!”,用户设置密码,然后你通过encrypt()

答案 1 :(得分:0)

您可能会收到此错误:

  

文件不是数据库:,正在编译:从中选择count()   sqlite_master; net.sqlcipher.database.SQLiteException:文件不是   数据库:,编译时:从sqlite_master中选择count();

如果您的数据库文件仅部分复制到数据库文件夹中。

转至设备浏览器,进入数据/数据/您的应用程序文件夹/数据库,请确保您有您的数据库文件的有效副本文件夹中。