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
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);
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.