Sqlcipher __ CREATE TABLE android_metadata失败

时间:2013-12-04 10:40:10

标签: android sqlite sqlcipher

我正在尝试在我的Android应用程序中附加一个现有的sqlcipher数据库(加密),但在我的目录中复制后,无法使用“SQLiteDatabase.openDatabase(...)”打开它

我在普通sqlite中尝试了代码并且它正常工作但是当我使用sqlcipher API时我收到了此错误消息

 //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

我在SQLiteOpenHelper类中使用了以下代码:

      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;
}

我在Activity Class中使用了以下代码:

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

我尝试使用this solution,但仍然是同样的错误

  

块引用

2 个答案:

答案 0 :(得分:7)

非常感谢Nick Parker,实际上我使用了样本中的代码片段,我创建了一个代表SqlCipherAssestHelper的新类,它将加密的DataBase从资产复制到设备中的另一个位置,并使用数据库从新副本读取/写入在示例“1x.db”here

这是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;

        }

    }

}

此活动中的代码:

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


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

答案 1 :(得分:1)

您确定为数据库提供了正确的密码吗?您的数据库是否具有与默认SQLCipher分发不同的配置(即密码,页面大小,kdf迭代长度等)?我有一个在测试套件中附加另一个SQLCipher数据库here的示例,您可以考虑在本地运行测试套件进行比较。您也可以考虑将此问题与SQLCipher mailing list上的其他详细信息一起发布。