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
2
  • 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. Commented Jun 3, 2015 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. Commented Jun 3, 2015 at 13:40

1 Answer 1

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

    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.