Important Advisory: SQLCipher with Xcode 9 and new SDKs

Apple has recently released Xcode 9, along with new SDKs (e.g. iOS 11, watchOS 4, etc), with new features and enhancements. Most projects that include recent versions of SQLCipher shouldn’t have any problems upgrading. However, there are some changes in the SDKs, so we have prepared important recommendations for SQLCipher developers that run into errors after upgrading.

Note: Before proceeding, be sure that all projects implement the separately documented recommended changes related to SQLCipher link ordering, run-time checks, and testing / validation.

Changes in Xcode 9

Apple has always included a header file, sqlite3.h, in past releases of their SDKs. This header file defines the standard API interface for SQLite. Because the same interface is used with SQLCipher, it was formerly possible to use the SDK header file in place of SQLCipher’s packaged sqlite3.h. However, with the new release of Xcode 9 and the latest SDKs, the defintitions of sqlite3_key and sqlite3_rekey are missing from the Xcode 9 SDK sqlite3.h file.

This change means that if a project is not setup correctly it will be unable to locate SQLCipher’s sqlite3.h, resulting in compile time errors like these:

Implicit declaration of function ‘sqlite3_key’ is invalid in C99
Implicit declaration of function ‘sqlite3_rekey’ is invalid in C99

Note that these errors indicate a problem with the project setup, not an issue with SQLCipher itself. In other words, under earlier versions of Xcode it was possible to have an improperly configured project that would still compile anyway. Now, under Xcode 9, it is mandatory that SQLCipher’s sqlite3.h be used by the compiler via the Header Search Path in project or target Build Settings.

Recommended Resolutions

The appropriate resolution depends on how you are including SQLCipher in your Xcode project.

All Integration Methods

Before making any other changes, first, ensure that -DSQLITE_HAS_CODEC is present in the the Other C Flags property of the top level project or target Build Settings.

SQLCipher Commercial Edition / Enterprise

When using offical Zetetic package distributions, locate the Header Search Paths property in the top level project Build Settings and ensure that $(PROJECT_DIR)/sqlcipher-static-ios/include is present. If necessary, adjust according to the the path to the sqlite3.h you received as part of the package.

sqlcipher.xcodeproj

When using the sqlcipher.xcodeproj included in the SQLCipher git repository, locate the Header Search Paths property in the top level project Build Settings and ensure that $(PROJECT_DIR)/sqlcipher is present. If you have located the sqlcipher submodule elsewhere in your project structure then adjust the path as appropriate.

SQLCipher CocoaPod with use_frameworks!

When using the SQLCipher CocoaPod (or any other Pod that depends on SQLCipher, e.g. FMDB), it is necessary to make a special adjustment if the project Podfile contains the use_frameworks! directive. This appears to be the result of a CocoaPods issue that disables the creation of header links under Pods/Headers when use_framworks! is enabled. This makes it impossible for Xcode 9 to resolve the proper sqlite3.h file included with the SQLCipher Pod.

The simplest work around is to add a post_install hook in the project Podfile tha creates a link in Pods/Headers/Private. That folder is is automatically included in the Header Search Paths by CocoaPods.

post_install do | installer |
  print "SQLCipher: link Pods/Headers/sqlite3.h"
  system "mkdir -p Pods/Headers/Private && ln -s ../../SQLCipher/sqlite3.h Pods/Headers/Private"
end

SQLCipher CocoaPod without use_frameworks!

If implicit declaration warnings are present using the SQLCipher CocoaPod, but without the use_frameworks! directive, then it is possible the project Build Settings are overriding the default CocoaPod settings. In this case, inspect the project settings and each target to remove any manual Header Search Paths setting, or add $(inherited) to the setting if manual overrides are necessary. If the project is setup incorrectly running pod install will report warnings about the project HEADER_SEARCH_PATH overriding Pod settings. Change the project configuration to eliminate those warnings.

Hi there,

I am having some trouble with the following error:

Use of unresolved identifier ‘sqlite3_key’

key points:

  • I think we were guilty of incorrect installation of the software prior to migration and used the sdk’s sqlite module. that is no longer the case.
  • I have removed the sdk’s sqlite3 from the project, as well as any references to it
  • I have followed the tutorial for enterprise installation, since we acquired a license for commercial use
  • I have started a fresh project and followed the tutorial again (worked fine)
  • I have cross checked the fresh project with the existing one for both the project and target settings, they match where relevant.

I still get the following error, even though when I ‘jump to definition’ on sqlite3_key it takes me to the code, so it is finding it, yet its apparently unresolved.

Does having cocoapods installed potentially conflict with the installation?

Any ideas? Or information that would help? thanks

Hello @Steven_Warren - thanks for getting in touch about this. One possible explanation might be that there are some Target-level settings that are overriding the Project-level setting for the Header Search Path. If this were the case you might be jumping to the right locations when viewing the code or project properties in Xcode, but when the actual compiler is invoked for a given target the include paths are wrong.

One quick way to check this is to open up the target properties and see what the resolved values are for Header Search path on every target.

Alternately, if that doesn’t show anything obvious, we could take a look at the output of ls -R from the top level of your project along with the full Xcode build log. If you were to post that we can take a look.

Finally, it sounds like you have purchased SQLCipher Commercial Edition. If so and your organization has an active CipherCare support subscription you can also contact us directly for private support via email to support@zetetic.net.

Thanks!

Hi there

Thanks for taking the time to reply.

This is from the terminal. As you will see, the directories are as instructed in the installation guide.

./sqlcipher-static-ios:
LICENSE.pdf	README.txt	include		ios-libs

./sqlcipher-static-ios/include:
sqlite3.h

./sqlcipher-static-ios/ios-libs:
libsqlcipher-ios.a	sqlite3

As for the header search paths, on a project level it is again, as instructed, as you can see here:

On a target level, the header search path is $(inherited) from the project level setting, so no overriding is occurring.

Finally the build log: i cant upload it because i am a new user, so heres the bit you need anyway:

CompileSwift normal x86_64 /Users/spdspark/Desktop/ios/source/utilities/SwiftData.swift
cd /Users/spdspark/Desktop/ios
“/Applications/Xcode 9, beta 5.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift” -frontend -c -filelist /var/folders/ty/zxgf9tks7qz9z07p0yqfyy5h0000gn/T/sources-10f152 -primary-file /Users/spdspark/Desktop/ios/source/utilities/SwiftData.swift -target x86_64-apple-ios9.3 -enable-objc-interop -sdk “/Applications/Xcode 9, beta 5.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.0.sdk” -I /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Products/Debug-iphonesimulator -F /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Products/Debug-iphonesimulator -F /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Products/Debug-iphonesimulator/Alamofire -F /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Products/Debug-iphonesimulator/SwiftKeychainWrapper -F /Users/spdspark/Desktop/ios/Pods/HockeySDK/HockeySDK-iOS/HockeySDK.embeddedframework -F /Users/spdspark/Desktop/ios -F /Users/spdspark/Desktop/ios/HockeySDK.embeddedframework -F /Users/spdspark/Desktop/ios/build/Debug-iphoneos -enable-testing -g -module-cache-path /Users/spdspark/Library/Developer/Xcode/DerivedData/ModuleCache -swift-version 3 -enforce-exclusivity=checked -D PROD -serialize-debugging-options -Xcc -I/Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/swift-overrides.hmap -Xcc -iquote -Xcc /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Clearblue-generated-files.hmap -Xcc -I/Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Clearblue-own-target-headers.hmap -Xcc -I/Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Clearblue-all-non-framework-target-headers.hmap -Xcc -ivfsoverlay -Xcc /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/all-product-headers.yaml -Xcc -iquote -Xcc /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Clearblue-project-headers.hmap -Xcc -I/Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Products/Debug-iphonesimulator/include -Xcc -I/Users/spdspark/Desktop/ios/sqlcipher-static-ios/include -Xcc -I/Users/spdspark/Desktop/ios/Pods/Headers/Public -Xcc -I/Users/spdspark/Desktop/ios/Pods/Headers/Public/HockeySDK -Xcc -I/Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/DerivedSources/x86_64 -Xcc -I/Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/DerivedSources -Xcc -DPROD=1 -Xcc -working-directory/Users/spdspark/Desktop/ios -emit-module-doc-path /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Objects-normal/x86_64/SwiftData~partial.swiftdoc -serialize-diagnostics-path /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Objects-normal/x86_64/SwiftData.dia -import-objc-header /Users/spdspark/Desktop/ios/source/connect-bridging-header.h -pch-output-dir /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/PrecompiledHeaders -pch-disable-validation -Onone -module-name Clearblue -emit-module-path /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Objects-normal/x86_64/SwiftData~partial.swiftmodule -emit-dependencies-path /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Objects-normal/x86_64/SwiftData.d -emit-reference-dependencies-path /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Objects-normal/x86_64/SwiftData.swiftdeps -o /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Build/Intermediates.noindex/connect.build/Debug-iphonesimulator/connect-prod.build/Objects-normal/x86_64/SwiftData.o -index-store-path /Users/spdspark/Library/Developer/Xcode/DerivedData/connect-fdsfjbwkbmofqhdjkkxppwcpowsl/Index/DataStore -index-system-modules

/Users/spdspark/Desktop/ios/source/utilities/SwiftData.swift:811:13: error: use of unresolved identifier ‘sqlite3_key’
sqlite3_key(sqliteDB, unwrappedEncryptionKey, Int32(strlen(unwrappedEncryptionKey)))

NOTE: so in the process of compiling this response, I deleted my derived data folder for the 12th time, and now its working. Yay.

Hi @Steven_Warren - I’m glad to hear that its working for you now. I can’t tell you how many times we’ve been bitten by issues with DerivedData!

Hi, I had same problem and after adding provided lines for Pod file was able to build project.
However, I’m not able to make an encrypted DB from unencrypted. Previously this code worked perfectly.

I’m calling encryption on launching and getting log line:

[logging] no such function: sqlcipher_export

Can you advice me, how to fix it?

I’m using following methods:

// SQL Query. NOTE THAT DATABASE IS THE FULL PATH NOT ONLY THE NAME
let sqlQ = "ATTACH DATABASE '\(encryptedDatabasePath)' AS encrypted KEY '\(dbKey)';"
var unencrypted_DB: OpaquePointer? = nil

if sqlite3_open_v2(databasePath, &unencrypted_DB, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK {

    // Attach empty encrypted database to unencrypted database
    sqlite3_exec(unencrypted_DB, sqlQ, nil, nil, nil)

    // export database
    sqlite3_exec(unencrypted_DB, "SELECT sqlcipher_export('encrypted');", nil, nil, nil)

    // Detach encrypted database
    sqlite3_exec(unencrypted_DB, "DETACH DATABASE encrypted;", nil, nil, nil)

    // Close database
    sqlite3_close(unencrypted_DB)
    
    print("encrypted successfully")
    
} else {

    sqlite3_close(unencrypted_DB)
    sqlite3_errmsg(unencrypted_DB)
    //print("encryp error: \()")

}

Hello @AntonE - if you are unable to call sqlcipher_export it is likely that SQLCipher is not actually being linked into your application. I would suggest that you review this post related to link ordering, run-time checks, and testing / validation. After implementing any applicable changes, let us know if the problem is resolved.