2016-01-20 3 views
1

Я пытаюсь зашифровать данные, хранящиеся в моем поставщике контента, с обновлением приложения. Я последовал за ссылку ниже для этого
How to implement SQLCipher when using SQLiteOpenHelper
Обновление данных поставщика контента (с поддержкой SQLite) для шифрования с использованием SQLCipher -Android

Хотя это отлично работает, если новая установка не будет сделана, если я иду на обновление, приложение падает с ниже ошибками

net.sqlcipher.database.SQLiteException: file is encrypted or is not a database 
at android.app.ActivityThread.handleReceiver(ActivityThread.java:3009) 
at android.app.ActivityThread.access$1800(ActivityThread.java:177) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1526) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:145) 
at android.app.ActivityThread.main(ActivityThread.java:5951) 
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:1388) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183) 
    Caused by: net.sqlcipher.database.SQLiteException: file is encrypted or is not a database 


Я даже попытался удалить существующие таблицы и создать новую таблицу, чтобы убедиться, что это решило проблему, но это тоже не помогло. Пожалуйста, подсказывают, как это исправить, Мой класс Helper, как показано ниже,

   public class MyDBHelper extends SQLiteOpenHelper { 
       public MyDBHelper(Context context) { 
        super(context, DATABASE_NAME, null, DATABASE_VERSION); 
        SQLiteDatabase.loadLibs(context); 
       } 
       public static final String DATABASE_NAME = "mydb.db"; 

       private static final int DATABASE_VERSION = 2; // before attempting encryption it was 1 

       @Override 
       public void onCreate(SQLiteDatabase db) { 
        createTables(db); 
       } 

       @Override 
       public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
        db.execSQL("DROP TABLE IF EXISTS " + "TEST_TABLE"); 
        createTables(db); 
       } 

       private void createTables(SQLiteDatabase db){ 
        db.execSQL(MyDBQueries.CREATE_TEST_TABLE); 
       } 
      } 


Мой обновленный провайдер просто использует ключ теперь, чтобы открыть БД, как показано ниже,

   SQLiteDatabase db = databaseHelper.getWritableDatabase("encryptionKey"); 


Как я упомянутые, свежие установки работают хорошо, но обновление приводит к сбою приложения. Пожалуйста, предложите, как это исправить.

+0

Вы обновляете базу данных, которая уже зашифрована? Или вы обновляетесь из базы данных, которая еще не зашифрована? BTW, в будущем, пожалуйста, разместите всю трассировку стека. – CommonsWare

+0

База данных не зашифрована изначально, я хочу, чтобы она была зашифрована с обновлением приложения. – Kaps

ответ

4

базы данных не зашифрованы изначально, я хочу, чтобы быть зашифрованы с приложением обновления

Это не будет происходить автоматически, и это не может произойти в рамках SQLiteOpenHelper и его onUpgrade() пути (как на вызывается время onUpgrade(), SQLiteOpenHelper будет пытаться открыть незашифрованную базу данных, которая завершится неудачно, за исключением того, что вы показали).

Вам необходимо будет отдельно зашифровать эту базу данных. Этот код я использовал:

public static void encrypt(Context ctxt, String dbName, 
          String passphrase) throws IOException { 
    File originalFile=ctxt.getDatabasePath(dbName); 

    if (originalFile.exists()) { 
     File newFile= 
      File.createTempFile("sqlcipherutils", "tmp", 
           ctxt.getCacheDir()); 
     SQLiteDatabase db= 
      SQLiteDatabase.openDatabase(originalFile.getAbsolutePath(), 
             "", null, 
             SQLiteDatabase.OPEN_READWRITE); 

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

     int version=db.getVersion(); 

     db.close(); 

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

     originalFile.delete(); 
     newFile.renameTo(originalFile); 
    } 
    } 

После encrypt() возвращается, то вы можете пойти дальше и попытаться открыть базу данных.

+0

Благодарим вас за ценную информацию. Итак, где я могу назвать эту утилиту? Кроме того, как убедиться, что это не влияет на свежие установки приложения, потому что новая установка не понадобится. – Kaps

+1

@Kaps: «Итак, где я могу назвать эту утилиту?» - через некоторое время после 'loadLibs()' и раньше до 'getReadableDatabase()' или 'getWriteableDatabase()'. «Кроме того, как убедиться, что это не влияет на свежие установки приложения, потому что для новой установки это не понадобится» - посмотрите, существует ли файл базы данных. – CommonsWare

+0

@CommonsWare, разве вы не должны создавать зашифрованную базу данных в другом файле, а не переименовывать ее в исходный файл? потому что в последующих запусках 'originalFile.exists()' всегда будет 'true'. Вместо этого не лучше ли, если зашифрованный файл создается в другом файле? –