0

I have an Android application which uses SQLCipher for database encryption. The application has gone live and has many active users. I'm looking for a solution which can remove the SQLCipher encryption from application's existing database without loosing user's data.

I tried doing the inverse of what is mentioned in this post but unable to open my encrypted database file.

public static void decrypt(Context ctxt, String dbName, String passphrase)
        throws IOException {
    try {

        File originalFile = ctxt.getDatabasePath(dbName);

        int version = 0;
        if (originalFile.exists()) {
            File newFile = File.createTempFile("sqlite", "tmp", ctxt.getCacheDir());

            net.sqlcipher.database.SQLiteDatabase dbCipher = net.sqlcipher.database.SQLiteDatabase.openDatabase(
                    originalFile.getAbsolutePath(), passphrase, null,
                    net.sqlcipher.database.SQLiteDatabase.OPEN_READWRITE);

            if (dbCipher.isOpen()) {
                dbCipher.rawExecSQL(String.format(
                        "ATTACH DATABASE '%s' AS plaintext KEY '%s';",
                        newFile.getAbsolutePath(), passphrase));
                dbCipher.rawExecSQL("SELECT sqlcipher_export('plaintext')");
                dbCipher.rawExecSQL("DETACH DATABASE plaintext;");

                version = dbCipher.getVersion();

                dbCipher.close();
            }


            SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(newFile, null);
            db.setVersion(version);
            db.close();

            originalFile.delete();
            newFile.renameTo(originalFile);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

}

And, here are the error logs I got...

06-04 11:33:54.929: E/SQLiteLog(12309): (26) file is encrypted or is not a database
06-04 11:33:54.929: E/DefaultDatabaseErrorHandler(12309): Corruption reported by sqlite on database: /data/data/ril.jio.protrak/cache/sqlite1817652413tmp
Community
  • 1
  • 1
Sonu Singh Bhati
  • 1,093
  • 10
  • 11
  • 3
    Create a regular SQLite database, open the SQLCipher database, and copy the data from the SQLCipher database to the SQLite database. It would be the inverse of the `encrypt()` method that I show [in this Stack Overflow answer](https://stackoverflow.com/a/29867682/115145). – CommonsWare Jun 03 '15 at 13:35
  • if you just want to decrypt the db, and keep using sqlcipher lib, i think you can just `rekey` the db with empty new password, but if you want to move to the android-integrated sqlite you have to take the approach of migrating data from old to new DB. – Yazan Jun 03 '15 at 13:40

1 Answers1

1

Here is sample to export SQLCipher encrypted database file into plain text database file.

Revert back to

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

Instead of

import net.sqlcipher.Cursor;
import net.sqlcipher.database.SQLiteDatabase;
import net.sqlcipher.database.SQLiteOpenHelper;

Now use this class to export encrypted database file to normal plain text

import java.io.File;
       import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.io.InputStream;
        import java.io.OutputStream;
        import android.content.Context;
        import android.os.AsyncTask;
        import android.util.Log;

    public class ExportSQLCipherEncryptedDBIntoPlainText extends
            AsyncTask<Void, Integer, Boolean> {

        private Context context;
        private String dbName, password, filePath;

        public ExportSQLCipherEncryptedDBIntoPlainText(Context context,
                String dbName, String password, String filePath) {

            this.context = context;
            this.dbName = dbName;
            this.password = password;
            this.filePath = filePath;

        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected Boolean doInBackground(Void... arg0) {

            try {

                File originalFile = context.getDatabasePath(dbName);

                int version = 0;
                if (originalFile.exists()) {

                    // create new file
                    File newFile = new File(filePath + "/plaintext.db");
                    File newAdditionalFile = new File(filePath + "/plaintext.db-journal");
                    if (!newFile.exists()) {

                        net.sqlcipher.database.SQLiteDatabase.loadLibs(context);
                        net.sqlcipher.database.SQLiteDatabase dbCipher = net.sqlcipher.database.SQLiteDatabase
                                .openDatabase(
                                        originalFile.getAbsolutePath(),
                                        password,
                                        null,
                                        net.sqlcipher.database.SQLiteDatabase.OPEN_READWRITE);

                        if (dbCipher.isOpen()) {
                            dbCipher.rawExecSQL("ATTACH DATABASE '" + filePath
                                    + "/plaintext.db' AS plaintext KEY ''");
                            dbCipher.rawExecSQL("SELECT sqlcipher_export('plaintext')");
                            dbCipher.rawExecSQL("DETACH DATABASE plaintext");
                            version = dbCipher.getVersion();
                            dbCipher.close();
                        }

                        if (newFile.exists()) {
                            android.database.sqlite.SQLiteDatabase db = android.database.sqlite.SQLiteDatabase
                                    .openOrCreateDatabase(newFile, null);
                            db.setVersion(version);
                            db.close();
                            originalFile.delete();
                            // newFile.renameTo(originalFile);
                        }

                        Log.i("AndroidLib",
                                "Copying database from external directory to application Started");
                        byte[] buffer = new byte[1024];
                        OutputStream myOutput = null;
                        int length;
                        // Open your local db as the input stream
                        InputStream myInput = null;
                        myInput = new FileInputStream(newFile);
                        // transfer bytes from the inputfile to the
                        // outputfile
                        myOutput = new FileOutputStream(originalFile);
                        while ((length = myInput.read(buffer)) > 0) {
                            myOutput.write(buffer, 0, length);
                        }

                        myOutput.flush();
                        myOutput.close();
                        myInput.close();

                        if (originalFile.exists()) {

                            android.database.sqlite.SQLiteDatabase db = android.database.sqlite.SQLiteDatabase
                                    .openOrCreateDatabase(originalFile, null);

                            newFile.delete();

                            if (newAdditionalFile.exists()) {
                                newAdditionalFile.delete();
                            }

                            Log.i("AndroidLib",
                                    "Copying database from external directory to application Completed successfully");
                        }



                    }

                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            return true;
        }

        @Override
        protected void onPostExecute(Boolean result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
        }

    }
Sonu Singh Bhati
  • 1,093
  • 10
  • 11