Issue opening encrypted database in swift that was created in objective c


#1

Hello,

Today I started a new swift project, and installed SQLCipher via cocoapods (4.0 it appears). After getting it up and running I imported an existing encrypted database from an objective C project, but I cannot open it. I just receive the error file is not a database (I am using sample code from the SQLCipher tutorial for test projects)

Accessing the same database in another test project, using the equivalent objective C code works fine. The objective c project was set up with manual installation, and it is at least a year older - not sure of exact version.

As a test I created and encrypted a new database using the objective c sample code in the old project and then tried to open it with same swift equivalent code using new 4.0 and no dice. same error. My guess is 4.0 isn’t compatible with databases created using the older version? Please advise.

Objective C code - older SQLCipher version

NSString *databasePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
                              stringByAppendingPathComponent: @"test.db"];
    sqlite3 *db;
    sqlite3_stmt *stmt;
    bool sqlcipher_valid = NO;
    
    if (sqlite3_open([databasePath UTF8String], &db) == SQLITE_OK) {
        const char* key = [@"helloWorld" UTF8String];
        sqlite3_key(db, key, strlen(key));
        if (sqlite3_exec(db, (const char*) "SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) {
            if(sqlite3_prepare_v2(db, "PRAGMA cipher_version;", -1, &stmt, NULL) == SQLITE_OK) {
                if(sqlite3_step(stmt)== SQLITE_ROW) {
                    const unsigned char *ver = sqlite3_column_text(stmt, 0);
                    if(ver != NULL) {
                        sqlcipher_valid = YES;
                        
                        
                        NSString *create = @"CREATE TABLE Test (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT)";
                        
                        if(sqlite3_exec(db, [create UTF8String], NULL, NULL, NULL)==SQLITE_OK)
                        {
                            NSLog(@".. TABLE Added ..");
                        }
                        // password is correct (or database initialize), and verified to be using sqlcipher
                        
                    }
                }
                sqlite3_finalize(stmt);
            }
        }
        sqlite3_close(db);
    }

New swift code - SQLCipher 4.0 (this fails to validate key on same database created with previous code)

let path = NSSearchPathForDirectoriesInDomains(
            .documentDirectory, .userDomainMask, true
            ).first!
        
        var rc: Int32
        var db: OpaquePointer? = nil
        var stmt: OpaquePointer? = nil
        let password: String = "helloWorld"
        
        NSLog("\(SQLITE_OK)")
        
        rc = sqlite3_open("\(path)/test.db", &db)
        if (rc != SQLITE_OK) {
            let errmsg = String(cString: sqlite3_errmsg(db))
            NSLog("Error opening database: \(errmsg)")
            return
        }
        rc = sqlite3_key(db, password, Int32(password.utf8CString.count))
        if (rc != SQLITE_OK) {
            let errmsg = String(cString: sqlite3_errmsg(db))
            NSLog("Error setting key: \(errmsg)")
        }
        rc = sqlite3_prepare(db, "PRAGMA cipher_version;", -1, &stmt, nil)
        if (rc != SQLITE_OK) {
            let errmsg = String(cString: sqlite3_errmsg(db))
            NSLog("Error preparing SQL: \(errmsg)")
        }
        rc = sqlite3_step(stmt)
        if (rc == SQLITE_ROW) {
            NSLog("cipher_version: %s", sqlite3_column_text(stmt, 0))
        } else {
            let errmsg = String(cString: sqlite3_errmsg(db))
            NSLog("Error retrieiving cipher_version: \(errmsg)")
        }
        
        let create = "CREATE TABLE Test (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT)";
        if sqlite3_exec(db, create, nil, nil, nil) == SQLITE_OK {
            print(".. TABLE Added ..");
        } else {
            let errmsg = String(cString: sqlite3_errmsg(db))
            print("\(errmsg)")
        }
        
        sqlite3_finalize(stmt)
        sqlite3_close(db)

Thanks!


#2

@tcoyle

Thanks for using SQLCipher and posting to the discussion forum.

Yes, this assumption is correct. Please have a look at our blog post announcing the SQLCipher 4.0.0 release within the compatibility section it references some of the breaking changes:

Many of these changes provide a much higher level of security than previous versions of SQLCipher. However, the new page size of 4096, 256,000 KDF iterations, use of PBKDF2-HMAC-SHA512 and HMAC-SHA512 all modify important database settings. Thus, SQLCipher 4 will not open older databases by default. As always, we have updated our migration feature to streamline the upgrade process. To enable backwards-compatibility, it is possible to adjust settings at runtime or migrate older databases:

In general, major version updates typically aren’t compatible with previous major version databases – i.e. SQLCipher 2.x.x databases can’t be opened by SQLCipher 3.x.x


#3

Bingo. My apologies!


#4

No worries.

We have specific instructions regarding the steps available for upgrading to SQLCipher 4 here: