Error: No such function: sqlcipher_export iOS

I have installed SQLCipher via pod. but I am getting this error saying No such function: sqlcipher_export. I was using FMDB and for SQLCipher I am using the subspec of it i.e. FMDB/sqlcipher. I have added #import <SQLCipher/sqlite3.h> on top
below is my code:

NSString *docsDir;
NSArray *dirPaths; 
dirPaths = NSSearchPathForDirectoriesInDomains
(NSApplicationSupportDirectory, NSUserDomainMask, YES);
docsDir = dirPaths[0];

databasePath = [[NSString alloc] initWithString:[docsDir stringByAppendingPathComponent: @"MyDB.db"]];

NSString *encryptDB = [docsDir stringByAppendingPathComponent:@"MyDB_enc.db"];

const char* sqlQ = [[NSString stringWithFormat:@"ATTACH DATABASE '%@' AS MyDB_enc KEY 'test123';",encryptDB] UTF8String];

//sqlite3 *unencrypted_DB;

if (sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
    
    // Attach empty encrypted database to unencrypted database
    sqlite3_exec(database, sqlQ, NULL, NULL, NULL);

    // export database
    sqlite3_exec(database, "SELECT sqlcipher_export('MyDB_enc');", NULL, NULL, NULL); //gives error
    
    // Detach encrypted database
    sqlite3_exec(database, "DETACH DATABASE MyDB_enc;", NULL, NULL, NULL);
    
    sqlite3_close(database);
}
else {
    sqlite3_close(database);
    NSAssert1(NO, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
}

databasePath = [docsDir stringByAppendingPathComponent:@"MyDB_enc.db"];

can anyone guide me on how to fix this issue

Hello @Ajeet_Maurya

It sounds as if your project is not correctly including SQLCipher, or that you may have another dependency that is overriding SQLCipher, causing your application to link against another version of SQLite. You can check if your application is linking against SQLCipher by querying the library for the cipher version, this will only be reported by SQLCipher. Please execute the following command and share the results:

PRAGMA cipher_version;

Hey @developernotes

I removed the pods and used the sqlite3.h from the binary and its working fine.
Thanks.

Hello @Ajeet_Maurya

We are happy to hear everything is working properly for you now.

I am trying to export the database using the extension FMDB/SQLCipher.

I am running the following code:

func exportDatabase() {
        if database.open() {
            database.setKey(password)
            let attach = "ATTACH DATABASE ? AS decrypted KEY ''"
            
            do {
                let cursor = try database.executeQuery("PRAGMA cipher_version", values: nil)
                if cursor.next() {
                    print(cursor.string(forColumnIndex: 0)) // 4.4.3 community
                }
                try database.executeQuery(attach, values: [dbPath])
                let export = "SELECT sqlcipher_export('decrypted')"
                try database.executeQuery(export, values: nil)
                try database.executeQuery("DETACH DATABASE 'decrypted'", values: nil)
            } catch {
                print(error)
            }
            database.close()
        }                
    }

The version of sql_cipher is 4.4.3 community.
No issues arises from the code above, however, my database with no password is not created.

Any thoughts?

Hey @rmorbach

Check the result of sqlcipher_export:

Error calling sqlite3_step (1: unknown database decrypted) rs

The attach statement is never actually executing.

You could adjust this line:

try database.executeQuery(attach, values: [dbPath])

to this:

try database.executeUpdate(attach, values: [decryptedDbPath])

Alternatively you can re-work the attach to just drop in the path inline so you can call executeStatement instead:

let attach = "ATTACH DATABASE '\(decryptedDbPath)' AS decrypted KEY ''"

...

let success = database.executeStatements(attach)
print("success of attach: \(success)")
1 Like

@Ajeet_Maurya
I am facing the same issue if anyone can help me out. I am using same Objective C.
SQLCipher Version : 4.5.2
FMDB : 2.7.5
I do have previous database I want to encrypt previous as well as new data.
Thank you

@Manish_Chauhan you should check the runtime version to make sure the library is properly linked.

When I execute this from the .sqlite file its says 4.4.3 community


But in the code &stmt is NULL

+ (BOOL)isDatabaseEncrypted:(NSString *)encryptedDatabasePath {
    sqlite3 *db;
    sqlite3_stmt *stmt;
    bool sqlcipher_valid = NO;
    int databaseVersion;

    if (sqlite3_open([encryptedDatabasePath UTF8String], &db) == SQLITE_OK) {
        const char* key = [[self databaseEncryptionKey] UTF8String];
        sqlite3_key(db, key, (int)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) {
                databaseVersion = sqlite3_column_int(stmt, 0);
                NSLog(@"%s: version %d", __FUNCTION__, databaseVersion);
                **if(sqlite3_step(stmt)== SQLITE_ROW) {**
**                    const unsigned char *ver = sqlite3_column_text(stmt, 0);**
**                    if(ver != NULL) {**
**                        sqlcipher_valid = YES;**
**                        // password is correct (or database initialize), and verified to be using sqlcipher**
**                    }**
**                }**
                sqlite3_finalize(stmt);
            }
        }
        sqlite3_close(db);
    }
    return sqlcipher_valid;
}

@developernotes

Also I have installed with CocoaPods So, how can I check from my Build Setting is correctly installed because I can’t see anything on Other Linker Flags or Other CFlags.

Assist me here as well please !!

@Manish_Chauhan

The result from PRAGMA cipher_version in DB Browser for SQLite confirms that SQLCipher is properly linked within that program, but is completely unrelated to whether it is properly linked in your own program.

Because the sample code to check the cipher_version in your own program isn’t returning any results, this indicates the SQLCipher isn’t properly linked.

Also I have installed with CocoaPods So, how can I check from my Build Setting is correctly installed because I can’t see anything on Other Linker Flags or Other CFlags.

When installed via CocoaPods the appropriate Other C Flags and Other Linker Flags should be set automatically for you (on the target not on the project). You should double check that the Other C Flags and Other Linkers flags on your target to confirm that they are indeed properly automatically set.

If they are set but you’re still not getting a value from PRAGMA cipher_version then it’s possible you may have another dependency on sqlite within your project which is causing a conflict.

To determine this, I’d recommend reviewing all of your dependencies/pods (you can see what libraries are linked using the Podspec of each dependency) and determine where the other dependency on SQLite could be coming from. Another option is to create a new project, add the FMDB/SQLCipher pod, run the test code to confirm a correct cipher_version is produced, then add each of your additional dependencies in one by one until you run into a situation where PRAGMA cipher_version no longer produces a value which should narrow down where the additional SQLite dependency is coming from.

Thank you for the explanation

Yes You are right Firebase/Messaging cause this issue but for me both are important how can I solve this conflict ?
@mmoore

@Manish_Chauhan This contains guidance on linker settings: Important Advisory: SQLCipher with Xcode 8 and new SDKs - SQLCipher / SQLCipher FAQ - Zetetic Community Discussion