androiddatabaseencryptionandroid-filesqlcipher

Encrypt Existing Database with SQLCipher in Android


I have a database file in my assets that I copy in the app database folder. After the copy (it works), I want to encrypt the copied database with SQLCipher.

For some reason, I get this error:

Database: sqlite returned: error code = 26, msg = statement aborts at 5: [ATTACH DATABASE '/data/user/0/com.grandeguru.lagmeup/databases/AIRPORTS_DB.db' AS encrypted KEY 'password';] file is encrypted or is not a database

If I look the Database with a root explorer, it is still not encrypted and visible, so I suppose the error is related to the file logic inside the encrypt method.

This is the code of the DatabaseHelper class I created, that manages also the copy from assets:

public class DatabaseHelper extends SQLiteOpenHelper {

private SQLiteDatabase myDB;
private Context context;
public static String DB_NAME = "AIRPORTS_DB.db";
public static String DB_PATH = "/data/data/com.grandeguru.lagmeup/databases/";
public static final int DB_VERSION = 1;


public DatabaseHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
    myDB.loadLibs(context);
    this.context = context;
}

// THE ERROR IS SOMEWHERE INSIDE HERE
public void encryptDataBase(String passphrase) throws IOException {

    File originalFile = context.getDatabasePath(DB_NAME);

    File newFile = File.createTempFile("sqlcipherutils", "tmp", context.getCacheDir());

    openDataBase("");

    myDB.rawExecSQL("ATTACH DATABASE '" + originalFile.getPath() + "' AS encrypted KEY '" + passphrase + "';");
    myDB.rawExecSQL("SELECT sqlcipher_export('encrypted');");
    myDB.rawExecSQL("DETACH DATABASE encrypted;");
    myDB.close();
    myDB = SQLiteDatabase.openDatabase(newFile.getAbsolutePath(), passphrase, null, SQLiteDatabase.OPEN_READWRITE);
    myDB.close();
    newFile.renameTo(originalFile);
    originalFile.delete();
}

private boolean checkDataBase() {
    File databasePath = context.getDatabasePath(DB_NAME);
    return databasePath.exists();
}


public void copyDataBase() throws IOException {
    try {
        File f = context.getDatabasePath(DB_NAME);
        InputStream in = context.getAssets().open(DB_NAME);
        OutputStream out = new FileOutputStream(f.getAbsolutePath());
        byte[] buffer = new byte[1024];
        int length;
        while ((length = in.read(buffer)) > 0) {
            out.write(buffer, 0, length);
        }
        out.flush();
        out.close();
        in.close();
        Log.d("copy database", "finita copia db");

        encryptDataBase("password");
    } catch (Exception e) {
        Log.e("copy database", e.getMessage());
    }

}


public void openDataBase(String passphrase) throws SQLException {
    String myPath = DB_PATH + DB_NAME;
    myDB = SQLiteDatabase.openDatabase(myPath, passphrase, null, SQLiteDatabase.OPEN_READWRITE);
}


public void createDataBase() throws IOException {
    boolean dbExist = checkDataBase();

    if (dbExist) {
    } else {
        this.getReadableDatabase("");
        try {
            copyDataBase();
        } catch (IOException e) {
            Log.e("create database", e.getMessage());
        }
    }
}

}


Solution

  • I solved, I write my solution as future reference. I was simply getting the wrong path

    public void encryptDataBase(String passphrase) throws IOException {
    
        File originalFile = context.getDatabasePath(DB_NAME);
    
        File newFile = File.createTempFile("sqlcipherutils", "tmp", context.getCacheDir());
    
        SQLiteDatabase existing_db = SQLiteDatabase.openDatabase(DB_PATH + DB_NAME, "", null, SQLiteDatabase.OPEN_READWRITE);
    
        existing_db.rawExecSQL("ATTACH DATABASE '" + newFile.getPath() + "' AS encrypted KEY '" + passphrase + "';");
        existing_db.rawExecSQL("SELECT sqlcipher_export('encrypted');");
        existing_db.rawExecSQL("DETACH DATABASE encrypted;");
    
        existing_db.close();
    
        originalFile.delete();
    
        newFile.renameTo(originalFile);
    
    }