Sqlcipher __ CREATE TABLE android_metadata failed

╄→尐↘猪︶ㄣ 提交于 2019-12-02 01:49:16

问题


I'm trying to attach a existing sqlcipher database(encrypted) in my android application but after copying it in my directory it cannot be opened using "SQLiteDatabase.openDatabase(...)"

I tried the code in normal sqlite and it works correctly but when I used sqlcipher API i got this error message

 //CREATE TABLE android_metadata failed
 //Failed to setLocale() when constructing, closing the database
 // net.sqlcipher.database.SQLiteException: file is encrypted or is not a database

I used the following code inside SQLiteOpenHelper Class :

      if(!dbExist1)
      {

            this.getWritableDatabase(password);
            this.openDatabase();
            try
            {
                  this.close();    
                  copyDataBase();
            }
            catch (IOException e)
            {

                  throw new Error("Error copying database");
            }
      }


        public SQLiteDatabase openDatabase() throws SQLException {
    String DBPath = DATABASE_PATH + DATABASE_NAME;

    myDataBase = SQLiteDatabase.openDatabase(DBPath, password, null,
            SQLiteDatabase.NO_LOCALIZED_COLLATORS);
    return myDataBase;
}

And I used the following code inside Activity Class :

  SQLiteDatabase.loadLibs(this);
 DataBaseHelper myDbHelper ;
      myDbHelper = new DataBaseHelper(this);
  SQLiteDatabase db=myDbHelper.openDatabase();

i tried to use this solution but still same error

Blockquote


回答1:


Thanks a lot Nick Parker ,actually i used a code snippet from your sample and i created a new class representing SqlCipherAssestHelper that copy the encrypted DataBase from assets to another location in the device and read/write from the new copy using the database in the sample "1x.db" here

this is the Helper Calss:

package com.example.readdbfromas;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import net.sqlcipher.SQLException;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteDatabaseHook;
import net.sqlcipher.database.SQLiteException;
import net.sqlcipher.database.SQLiteOpenHelper;
import android.content.Context;
import android.os.Environment;
import android.util.Log;

public class DataBaseHelper extends SQLiteOpenHelper {

    private static final String DATABASE_NAME = "1x.db";// Encrypted Database
    private static final String SUB_DATABASE_FOLDER = "/DatabaseCipher/";// a sub folder for database location
    public static String DATABASE_PATH;
    public static final int DATABASE_VERSION = 1;
    private SQLiteDatabase myDataBase;
    private final Context context;
    private String password = "";
    private String FULL_DB_Path;

    public DataBaseHelper(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);

        DATABASE_PATH = Environment.getExternalStorageDirectory()
                .getAbsolutePath().toString()
                + SUB_DATABASE_FOLDER;//get the device root Directory to copy data base on it 

        this.context = context;
        SQLiteDatabase.loadLibs(context.getApplicationContext());//load SqlCipher libraries

        FULL_DB_Path = DATABASE_PATH + DATABASE_NAME;//full database path
    }

    public SQLiteDatabase open(String password) {
        this.password = password;

        if (!checkDataBase()) {// if Database Not Exist
            copyDataBase();
        }

        myDataBase = getExistDataBaseFile();

        return myDataBase;
    }

    private SQLiteDatabase getExistDataBaseFile() {// this function to open an Exist database 

        SQLiteDatabaseHook hook = new SQLiteDatabaseHook() {
            public void preKey(SQLiteDatabase database) {
            }

            public void postKey(SQLiteDatabase database) {
                database.rawExecSQL("PRAGMA cipher_migrate;");

            }
        };
        return SQLiteDatabase.openOrCreateDatabase(FULL_DB_Path, password,
                null, hook);

    }


    private boolean checkDataBase() {// Check database file is already exist or not
        boolean checkDB = false;
        try {
            File dbfile = new File(FULL_DB_Path);
            checkDB = dbfile.exists();
        } catch (SQLiteException e) {
        }
        return checkDB;
    }


    public void db_delete() {// delete database
        File file = new File(FULL_DB_Path);
        if (file.exists()) {
            file.delete();
            System.out.println("delete database file.");
        }
    }

    private void copyDataBase() {//make a sub folder for database location and copy the database
        try {
            File fofo = new File(DATABASE_PATH);
            fofo.mkdirs();
            extractAssetToDatabaseDirectory(DATABASE_NAME);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public synchronized void closeDataBase() throws SQLException {
        if (myDataBase != null)
            myDataBase.close();
        super.close();
    }

    public void extractAssetToDatabaseDirectory(String fileName)
            throws IOException {// copy the database

        int length;
        InputStream sourceDatabase = context.getAssets().open(fileName);
        File destinationPath = new File(FULL_DB_Path);
        OutputStream destination = new FileOutputStream(destinationPath);

        byte[] buffer = new byte[4096];
        while ((length = sourceDatabase.read(buffer)) > 0) {
            destination.write(buffer, 0, length);
        }
        sourceDatabase.close();
        destination.flush();
        destination.close();
    }

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

    public void onCreate(SQLiteDatabase db) {
    }

    public boolean changePassword(String newPassword) {// DataBase must be
                                                        // opened before
                                                        // changing Password

        try {
            if (myDataBase != null && myDataBase.isOpen()) {

                myDataBase.rawExecSQL("BEGIN IMMEDIATE TRANSACTION;");
                myDataBase.rawExecSQL("PRAGMA rekey = '" + newPassword + "';");

                this.close();
                myDataBase.close();

                return true;

            } else {

                Log.e("boolean changePassword()",
                        "Change Password Error : DataBase is null or not opened  !!");
                return false;
            }
        } catch (Exception e) {

            Log.e("boolean changePassword()",
                    "Change Password Error :ExecSQL Error !!");
            return false;

        }

    }

}

and this code inside activity :

     SQLiteDatabase db;
DataBaseHelper myDbHelper = new DataBaseHelper(MainActivity.this);
       db=myDbHelper.open("test");


  Cursor cursor=db.rawQuery("select * from t1", null);



回答2:


Are you certain you provided the correct passphrase to the database? Does your database have a configuration (i.e., cipher, page size, kdf iteration length, etc) that differ from the default SQLCipher distribution? I have an example of attaching another SQLCipher database here within the test suite, you might consider running the test suite locally to compare. You might also consider posting this question with your additional details on the SQLCipher mailing list.



来源:https://stackoverflow.com/questions/20373066/sqlcipher-create-table-android-metadata-failed

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!