Open database from v1.x with v3.x on iOS

I’ve updated SQLCipher in my app to v3.x from 1.x. I’d like to keep backward compatibility so I’m trying to open DB like this:
if (sqlite3_open([dbFilePath UTF8String], &database) != SQLITE_OK){
NSLog(@“Failed to open database!”);
return;
}
if (sqlite3_exec(database, “PRAGMA cipher_use_hmac = off; PRAGMA cipher_page_size = 1024; PRAGMA kdf_iter = 4000;”, NULL, NULL, NULL) != SQLITE_OK)
NSLog(@“error”);

sqlite3_key(database, [[Utils dbPW] UTF8String], (int)strlen([[Utils dbPW] UTF8String]));
if (sqlite3_exec(database, “SELECT count(*) FROM sqlite_master;”, NULL, NULL, NULL) != SQLITE_OK)
NSLog(@“DB LOCKED/BUSY OR KEY INCORRECT”);

It works fine on iPad mini and simulators, but doesn’t work on iPad Air 2 (I get ‘DB LOCKED/BUSY OR KEY INCORRECT’).
Any suggestions? Thanks

Hello @axkazek - You should switch the order of execution around, such that sqlite3_key is executed prior to the PRAGMAs that adjust SQLCipher’s behavior. Alternately, if you would prefer to make changes to the default behavior for the database library at runtime before calling sqlite3_key, you must use cipher_default_use_hmac, cipher_default_page_size, and cipher_default_kdf_iter respectively.

sqlite3_open([dbFilePath UTF8String], &database);
sqlite3_key(database, [[Utils dbPW] UTF8String], (int)strlen([[Utils dbPW] UTF8String]));
sqlite3_exec(database, “PRAGMA cipher_use_hmac = off; PRAGMA cipher_page_size = 1024; PRAGMA kdf_iter = 4000”, NULL, NULL, NULL);
if (sqlite3_exec(database, “SELECT count(*) FROM sqlite_master;”, NULL, NULL, NULL) != SQLITE_OK)
NSLog(@“DB LOCKED/BUSY OR KEY INCORRECT”);

does not work, and this one does not work too:

sqlite3_open([dbFilePath UTF8String], &database);
sqlite3_exec(database, “PRAGMA cipher_default_use_hmac = off; PRAGMA cipher_default_page_size = 1024; PRAGMA cipher_default_kdf_iter = 4000”, NULL, NULL, NULL);
sqlite3_key(database, [[Utils dbPW] UTF8String], (int)strlen([[Utils dbPW] UTF8String]));
if (sqlite3_exec(database, “SELECT count(*) FROM sqlite_master;”, NULL, NULL, NULL) != SQLITE_OK)
NSLog(@“DB LOCKED/BUSY OR KEY INCORRECT”);

@sjlombardo any other hints?

Hello @axkazek. The sqlcipher repository contains a sample 1.x database called sqlcipher-1.1.8-testkey.db for testing purposes. I have verified that the following simple program, executing the same steps as defined above, is able to open the database without a problem:

int main(int argc, char **argv) {
  char* infile = "sqlcipher-1.1.8-testkey.db";
  char *pass= "testkey";
  sqlite3 *db;

  sqlite3_open(infile, &db);
  sqlite3_key(db, pass, strlen(pass));
  sqlite3_exec(db, "PRAGMA cipher_use_hmac = off; PRAGMA cipher_page_size = 1024; PRAGMA kdf_iter = 4000", NULL, NULL, NULL);
  if (sqlite3_exec(db, "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) != SQLITE_OK)
    printf("DB LOCKED/BUSY OR KEY INCORRECT");
  else
    printf("ok");
  sqlite3_close(db);
}

From this, we can determine that SQLCipher is able to open a 1.x database in compatibility mode as described. Thus, it would seem most likely that there is some problem with your implementation, e.g.:

  1. The key material you are using doesn’t match the database.

  2. The database being opened is not actually a 1.x database. Perhaps it was not created with a different version, e.g. a very early prerelease version of SQLCipher (< 1.0), or more likely SQLCipher 2.x?

  3. The application is not properly linking the new version of SQLCipher, and as such, is not actually using the library, instead using they system provided SQLite library.

I would suggest verifying each of these independently. It would also make sense to extract the database and try opening it with the command line version of SQLCipher, at least to further rule out a problem with your app.

Alternately, if you can provide a sample 1.x database for reference that can’t be opened with the new version of SQLCipher using the documented PRAGMA statements we’d be happy to look into it in more detail.