# Upgrading to SQLCipher 4

**URL:** <https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283>\
**Category:** SQLCipher FAQ\
**Created:** [December 10, 2018, 8:16pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283 "2018-12-10T20:16:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![sjlombardo](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/sjlombardo/32/3_2.png) [@sjlombardo](https://discuss.zetetic.net/u/sjlombardo)\
**Post date:** [December 10, 2018, 8:16pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/1 "2018-12-10T20:16:07Z")

</div>

The recent release of [SQLCipher 4](https://www.zetetic.net/blog/2018/11/30/sqlcipher-400-release/) introduces many new performance and security enhancements for applications that use SQLCipher for secure local data storage. However, the introduction of new default algorithms, increased KDF iterations and a larger page size means that SQLCipher 4 will not open older databases by default.

This document provides guidance on the upgrade options available to applications that have previously integrated SQLCipher versions 1 through 3.

**Option 1: Database File Migration**

SQLCipher provides a very convenient way to perform an “in place” migration of a SQLCipher database using `PRAGMA cipher_migrate`. This does all the work of updating the database file format with a single SQL statement. After migration the database will use all of the latest default settings so an application can immediately benefit from improved performance and security.

`PRAGMA cipher_migrate` be run a single time immediately after the key is provided (i.e. via `sqlite3_key()` or `PRAGMA key` in order to upgrade the database. This would normally occur on the first run after the application is upgraded to perform a one-time conversation.

After the migration is complete the application will no longer need to call the command again on subsequent opens.

```auto
PRAGMA key = '<key material>';
PRAGMA cipher_migrate;

```

The PRAGMA will return a single row with the value `0` after successful completion of the migration process. A non-zero column value will be returned in the event of a migration failure. On success the migrated database will remain open and use the same filename.

**Important:** The `cipher_migrate` PRAGMA is potentially expensive because it needs to attempt to open the database for each version to determine the appropriate settings. Therefore an application should _NOT_ call the PRAGMA every time a database is opened. Instead, an application should use the [recommended process in the `cipher_migrate` API documentation](https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_migrate)

**Note** : SQLCipher for Android Java users: when opening a database connection to run `PRAGMA cipher_migrate`, you must include the `SQLITE_OPEN_CREATE` flag as the migration process will temporarily attach a new database during the migration process.

**Option 2: Backwards Compatibility**

The second option is to use the new SQLCipher 4 library, but use all of the SQLCipher 3 (or earlier) settings. This requires an application to execute PRAGMA statements immediately after keying the database that will match the settings originally used to create the database.

Starting with SQLCipher 4.0.1, you can use the [new `cipher_compatibility` feature](https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_compatibility). Passing values 1, 2, or 3 to the PRAGMA will cause SQLCipher to operate with default settings consistent with the respective major version number for the current connection. For example, the following will cause SQLCipher to treat the current database as a SQLCipher 3.x database:

```auto
PRAGMA cipher_compatibility = 3;

```

It is also possible to use the similar [`cipher_default compatibility` PRAGMA](https://www.zetetic.net/sqlcipher/sqlcipher-api/#cipher_default_compatibility) to set the value for the lifetime of a process before key operations are invoked.

Applications are also free to explicitly manage the low-level page size, KDF, and algorithm settings. This option is more verbose, but works effectively the same way. The appropriate settings vary by the SQLCipher version used previously:

_SQLCipher 3_

```auto
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 64000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;

```

_SQLCipher 2_

```auto
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;

```

_SQLCipher 1_

```auto
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 4000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
PRAGMA cipher_use_hmac = OFF;

```

When using legacy settings, the library will be operating in a compatibility mode with a previous release. Thus, an application will not be taking advantage of all the security improvements available in the new version. Instead the application will function with the same level of security as the original SQLCipher version.

It is important to note that since no migration is occurring, compatibility statements must be executed every time a database is opened. It is, however, possible to set process-level defaults using the `cipher_default_` versions of these PRAGMAs (e.g. `PRAGMA cipher_default_kdf_algorithm`). This will change the default settings for the lifetime of the process. Please refer to the [SQLCipher API](https://www.zetetic.net/sqlcipher/sqlcipher-api/) for a full list of available settings.

**Option 3: Custom Export Migration**

When an application uses a custom configuration or non-default settings it is possible to use the [`sqlcipher_export()` convenience function](https://www.zetetic.net/sqlcipher/sqlcipher-api/#sqlcipher_export) for fine-grained control over the migration process. The general procedure for using `sqlcipher_export()` follows.

1. Open a connection to the existing database and set the appropriate backward compatibility PRAGMAs as described in Option 2.
2. Attach a new encrypted database, which will use the new settings by default.
3. Set any custom PRAGMAs for the new attached database (optional).
4. Call `sqlcipher_export()` to “copy” the data from the main database to the new attached database.
5. After export, detach the new database, and close the main database connection.
6. Re-open the new database, optionally deleting the original database and/or renaming the new database as appropriate.

The following example demonstrates the statements required to migrate a SQLCipher 3 database using `sqlcipher_export()`. At the end of the process the migrated database will be named sqlcipher-4.db.

```auto
PRAGMA key = '<key material>';
PRAGMA cipher_page_size = 1024;
PRAGMA kdf_iter = 64000;
PRAGMA cipher_hmac_algorithm = HMAC_SHA1;
PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1;
ATTACH DATABASE 'sqlcipher-4.db' AS sqlcipher4 KEY '<key material>';
SELECT sqlcipher_export('sqlcipher4');
DETACH DATABASE sqlcipher4;

```

**Choosing the Right Approach**  
Applications are free to select an upgrade approach that most closely meets their requirements. However, the recommended approach is to use Option 1 to take advantage of new features while minimizing the complexity of the application code required for migration.

---

<div class="post-metadata">

**Author:** ![sjlombardo](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/sjlombardo/32/3_2.png) [@sjlombardo](https://discuss.zetetic.net/u/sjlombardo)\
**Post date:** [December 11, 2018, 3:22am UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/2 "2018-12-11T03:22:57Z")

</div>



---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/dan/32/906_2.png) [@Dan](https://discuss.zetetic.net/u/Dan)\
**Post date:** [December 21, 2018, 11:49pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/3 "2018-12-21T23:49:55Z")

</div>

What ciphers are supported in SQLCipher 4? 3 at some point supported aes-256-cbc, but it seems to me that 4 uses aes-256-cfb? Or am I mistaken?

If so, how does one read an old database with aes-256-cbc, since the “cipher” PRAGMA is no longer available?

---

<div class="post-metadata">

**Author:** ![mmoore](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/mmoore/32/858_2.png) [@mmoore](https://discuss.zetetic.net/u/mmoore)\
**Post date:** [December 22, 2018, 12:05am UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/4 "2018-12-22T00:05:30Z")

</div>

@Dan

Thanks for using SQLCipher.

`aes-256-cbc` is still the cipher used by SQLCipher 4, which is referenced on the [design page](https://www.zetetic.net/sqlcipher/design/) under Security Features. As you mentioned `PRAGMA cipher` is now fully deprecated and will be a no-op if you attempt to call it with a different cipher.

> but it seems to me that 4 uses aes-256-cfb?

Where are you seeing that?

---

<div class="post-metadata">

**Author:** ![Gerardo\_Robledo](https://avatars.discourse-cdn.com/v4/letter/g/edb3f5/32.png) [@Gerardo\_Robledo](https://discuss.zetetic.net/u/Gerardo_Robledo)\
**Post date:** [January 10, 2019, 12:47am UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/6 "2019-01-10T00:47:58Z")

</div>

specifically in Android, at which point do we have to call

> [@sjlombardo](#):
>
> PRAGMA key = ‘\<key material\>’; PRAGMA cipher\_migrate;

because by the moment I call getWritableDatabase(password) it crashes.

---

<div class="post-metadata">

**Author:** ![developernotes](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/developernotes/32/1309_2.png) [@developernotes](https://discuss.zetetic.net/u/developernotes)\
**Post date:** [January 10, 2019, 1:47pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/7 "2019-01-10T13:47:35Z")

</div>

Hi @Gerardo_Robledo

The `SQLiteOpenHelper` allows you to provide a `SQLiteDatabaseHook` via [this constructor](https://github.com/sqlcipher/android-database-sqlcipher/blob/master/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteOpenHelper.java#L80-L81) which will allow you to run the `PRAGMA cipher_migrate` command.

---

<div class="post-metadata">

**Author:** ![Gerardo\_Robledo](https://avatars.discourse-cdn.com/v4/letter/g/edb3f5/32.png) [@Gerardo\_Robledo](https://discuss.zetetic.net/u/Gerardo_Robledo)\
**Post date:** [January 10, 2019, 6:57pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/8 "2019-01-10T18:57:26Z")

</div>

Got it.  
I used the postKey method to call `PRAGMA cipher_migrate` command.

Thanks

---

<div class="post-metadata">

**Author:** ![ifi\_tubaf](https://avatars.discourse-cdn.com/v4/letter/i/439d5e/32.png) [@ifi\_tubaf](https://discuss.zetetic.net/u/ifi_tubaf)\
**Post date:** [January 16, 2019, 12:10pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/9 "2019-01-16T12:10:03Z")

</div>

Hey @Gerardo_Robledo

could you share your solution? My current approach looks like this:

```
super(context, DATABASE_NAME, null, DATABASE_VERSION, new SQLiteDatabaseHook() {
        @Override
        public void postKey(SQLiteDatabase database) {
            database.rawQuery("PRAGMA key = `" + THE_SECRET_PASSWORD + "`; PRAGMA cipher_migrate;", null).close();
        }

        @Override
        public void preKey(SQLiteDatabase database) {

        }
    });

```

Nevertheless I get the same error as before:

```
net.sqlcipher.database.SQLiteException: file is not a database: , while compiling: select count(*) from sqlite_master;

```

Thanks for your help!

---

<div class="post-metadata">

**Author:** ![developernotes](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/developernotes/32/1309_2.png) [@developernotes](https://discuss.zetetic.net/u/developernotes)\
**Post date:** [January 16, 2019, 2:51pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/10 "2019-01-16T14:51:57Z")

</div>

Hi @ifi_tubaf

You don’t need to execute `PRAGMA key` in the `postKey` event, the database will be keyed when you call `getWritableDatabase(...)`. Here is an [example](https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/app/src/main/java/net/zetetic/tests/CipherMigrateTest.java) of applying the `PRAGMA cipher_migrate` command and checking the result.

---

<div class="post-metadata">

**Author:** ![Gerardo\_Robledo](https://avatars.discourse-cdn.com/v4/letter/g/edb3f5/32.png) [@Gerardo\_Robledo](https://discuss.zetetic.net/u/Gerardo_Robledo)\
**Post date:** [January 16, 2019, 10:08pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/11 "2019-01-16T22:08:01Z")

</div>

Hi @ifi_tubaf  
I’m using Kotlin so it looks something like this:

```
     val hook = object: SQLiteDatabaseHook {
            override fun preKey(database: SQLiteDatabase?) {

            }

            override fun postKey(database: SQLiteDatabase?) {
                    database?.rawExecSQL("PRAGMA cipher_migrate")            
            }
        }

```

but I would recommend to check the example that @developernotes mentioned.

---

<div class="post-metadata">

**Author:** ![ifi\_tubaf](https://avatars.discourse-cdn.com/v4/letter/i/439d5e/32.png) [@ifi\_tubaf](https://discuss.zetetic.net/u/ifi_tubaf)\
**Post date:** [January 21, 2019, 9:10am UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/12 "2019-01-21T09:10:57Z")

</div>

Thanks a lot guys, got it working now! 🙂

---

<div class="post-metadata">

**Author:** ![zpapp](https://avatars.discourse-cdn.com/v4/letter/z/4491bb/32.png) [@zpapp](https://discuss.zetetic.net/u/zpapp)\
**Post date:** [February 12, 2019, 1:10am UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/13 "2019-02-12T01:10:18Z")

</div>

What’s the most elegant way to make sure in an Android app that “PRAGMA cipher\_migrate” is only executed when necessary?

I could save a flag to SharedPreferences to make sure that it’s executed exactly once, but that will do the migration even on a fresh install when it’s not necessary, and it will complicate things if we ever need to run the migration again, e.g. when we upgrade to SQLCipher 5. Neither of these are a huge deal but I’d prefer to explicitly determine whether a migration is indeed necessary…

Alternatively, what are the drawbacks of executing the migration every single time the database is opened?

---

<div class="post-metadata">

**Author:** ![anks](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anks](https://discuss.zetetic.net/u/anks)\
**Post date:** [February 12, 2019, 3:21pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/16 "2019-02-12T15:21:51Z")

</div>

I tried this on android but its not working on app upgrade, on app upgrade it’s giving “file not database” error message, any idea why I am getting this?

```auto
init {
        val hook = object : SQLiteDatabaseHook {
            override fun preKey(database: SQLiteDatabase?) {

            }

            override fun postKey(database: SQLiteDatabase?) {
                database?.rawExecSQL("PRAGMA cipher_migrate")
            }
        }
        sqliteOpenHelper = object : SQLiteOpenHelper(context, name, null, version, hook) {
            override fun onCreate(db: SQLiteDatabase) {
                this@SqliteHelperWrapper.onCreate(getDbWrapper(db))
            }

            override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
                this@SqliteHelperWrapper.onUpgrade(getDbWrapper(db), oldVersion, newVersion)
            }
        }
    }

```

---

<div class="post-metadata">

**Author:** ![sjlombardo](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/sjlombardo/32/3_2.png) [@sjlombardo](https://discuss.zetetic.net/u/sjlombardo)\
**Post date:** [February 12, 2019, 3:59pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/17 "2019-02-12T15:59:16Z")

</div>

Hello @zpapp - one fairly standard way to do this follows:

1. Attempt to open the database using standard settings (i.e. whatever the defaults are for the current version of SQLCipher for the app (in this case SQLCipher 4).

2. If the database can’t be opened using the key and the default settings, try to open it and run PRAGMA cipher\_migrate on it (e.g. with postKey in the case of android). This would then attempt to upgrade the database. If the migration succeeds, you can continue to use that connection for the remainder of the application lifecycle. If the key is incorrect here, then migration will not occur and the database will remain untouched.

3. If step 1 and step 2 fail, then the key material is incorrect or the settings of the database were not consistent with defaults for previous SQLCipher verions (i.e. custom settings were used that require manual migration)

This approach has the benefit of performing optimimally in the standard case when the database has already been migrated. It has a slowdown in the event that the key material is incorrect because the key may be derived multiple times to attempt migration, but that usally acceptable in most cases.

In the event that incorrect keys are a common situation, and thus the performance hit for rechecking in step 2 is not acceptable, then the other approaches you mentioned are more suitable, i.e. statefully tracking the current version of the database in an application preference.

---

<div class="post-metadata">

**Author:** ![zpapp](https://avatars.discourse-cdn.com/v4/letter/z/4491bb/32.png) [@zpapp](https://discuss.zetetic.net/u/zpapp)\
**Post date:** [February 14, 2019, 12:55am UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/19 "2019-02-14T00:55:39Z")

</div>

Thank you for this explanation!

I noticed that when I try to open an old database without cipher\_migrate, even if I catch the resulting SQLiteException, the Android log shows this exception along with a stack trace. The app doesn’t crash when this happens, so it’s more of a cosmetic issue, but still I wanted to check with you if this is expected. Does the library do this intentionally? Could this be changed?

And on a slightly different note: does the time it takes to execute cipher\_migrate depend on the size of the database? Is it safe to do this migration on the main thread, or am I risking an ANR?

---

<div class="post-metadata">

**Author:** ![developernotes](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/developernotes/32/1309_2.png) [@developernotes](https://discuss.zetetic.net/u/developernotes)\
**Post date:** [February 14, 2019, 1:52pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/20 "2019-02-14T13:52:41Z")

</div>

Hello @anks

It is difficult to say why it is failing given your code example. A few things to consider:

- Verify the password is correct
- Can you open it via a SQLCipher command line shell or GUI management interface?
- Check the return code from `PRAGMA cipher_migrate`, an example is [here](https://github.com/sqlcipher/sqlcipher-android-tests/blob/master/app/src/main/java/net/zetetic/tests/CipherMigrateTest.java).
- Does you application use any non-default configuration settings for SQLCipher?
- What version of SQLCipher was used to create the database file you are attempting to open?

---

<div class="post-metadata">

**Author:** ![developernotes](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/developernotes/32/1309_2.png) [@developernotes](https://discuss.zetetic.net/u/developernotes)\
**Post date:** [February 14, 2019, 2:00pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/21 "2019-02-14T14:00:24Z")

</div>

Hello @zpapp,

SQLCipher for Android will throw an exception when it is unable to access the database with the provided password material, this is by design. The migration processing time will differ depending on the size of the database itself, it would be a good idea to perform that operation on a non-UI thread to prevent any blocking that may occur.

---

<div class="post-metadata">

**Author:** ![anks](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anks](https://discuss.zetetic.net/u/anks)\
**Post date:** [February 14, 2019, 3:35pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/22 "2019-02-14T15:35:26Z")

</div>

Thanks @developernotes for your suggestion, We found an issue, It looks like somehow on app upgrade password gets changed and thats causing an issue.

---

<div class="post-metadata">

**Author:** ![zpapp](https://avatars.discourse-cdn.com/v4/letter/z/4491bb/32.png) [@zpapp](https://discuss.zetetic.net/u/zpapp)\
**Post date:** [February 14, 2019, 8:33pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/23 "2019-02-14T20:33:48Z")

</div>

> [@developernotes](#):
>
> SQLCipher for Android will throw an exception

Yes, but why is the stack trace of this exception appear in Logcat even if I catch the exception?

---

<div class="post-metadata">

**Author:** ![developernotes](https://sea2.discourse-cdn.com/flex016/user_avatar/discuss.zetetic.net/developernotes/32/1309_2.png) [@developernotes](https://discuss.zetetic.net/u/developernotes)\
**Post date:** [February 14, 2019, 9:26pm UTC](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283/24 "2019-02-14T21:26:12Z")

</div>

Hi @zpapp

SQLCipher for Android was [recently changed](https://github.com/sqlcipher/android-database-sqlcipher/blob/master/android-database-sqlcipher/src/main/java/net/sqlcipher/database/SQLiteDatabase.java#L2653-L2658) to limit logging of that exception to debug builds only. This will be included in our next public release.

[Next page](https://discuss.zetetic.net/t/upgrading-to-sqlcipher-4/3283.md?page=2)
