How to distinguish SQLCipher from SEE at compile- or runtime?

TL;DR: I need a way for C/C++ code to detect whether SQLite is using SQLCipher or SEE. I cannot find any explicit way to do so; I can check SQLITE_HAS_CODEC to see if encryption is enabled, but not which flavor of encryption.

I’m adding encryption support to my C++ SQLite wrapper library, sqnice. Basically I’m just adding two methods to my database class: use_password and change_password, thin wrappers around sqlite3_key() and sqlite3_rekey().

I’m presently using SQLCipher, but I have in the past used the SQLite Encryption Extension (SEE) at my day job. I’d like my library to be compatible with both. However, in looking into this I’ve found that, while the two share an API, the actual semantics of the two functions have diverged greatly:

  • In SQLCipher, the key parameter defaults to being a password string (which will be run through a KDF). To pass a raw key you have to convert it to SQL hex-literal syntax.
  • In SEE, the key defaults to being a raw key. To pass a password, you set nKey to a negative number; in that case the pKey must be a NUL-terminated C string.
  • In SQLCipher, calling sqlite3_key(db,NULL,0) is illegal and will return an error.
  • In SEE, sqlite3_key(db,NULL,0) is a useful thing to do with a new database: it doesn’t encrypt it, but reserves space in every page which makes future encryption more efficient.

I would like my library to have both key- and password-oriented methods. However, doing this requires knowing which encryption library is present, since I have to encode the password or key differently. There doesn’t seem to be any explicit way to do so: SQLCipher doesn’t define any of its own macros nor identify itself in the SQLite version string.

The only solution I’ve come up with is to call sqlite3_key(db,NULL,0) and check whether it returns SQLITE_ERROR; if so, it’s SQLCipher. But that’s a kludge, and I’d much rather do something clearer and more reliable that won’t break in the future. Ideas?

Hi @snej - Thanks for getting in touch. We’ve never seen nor worked with SEE, so I’m sure there are a bunch of operational differences.

The thought off the top of my head for a runtime check would be to execute the statement PRAGMA cipher_version on a :memory: connection. A result set will only be present if SQLCipher is the loaded SQLite library. This should be distinct to SQLCipher.

Compile time is going to be tougher. If you are directly including the sqlite3.c amalgamation you could check #ifdef CIPHER_VERSION_NUMBER, but that would be pretty unusual. We could consider adding something to the generated sqlite3.h that indicates SQLCipher is being used in a future version.

On the above, I only say “should be” because it is possible some other encrypted SQLite implementations would have copied, but I don’t think so.

Let me know what you think. I’ll give this some more thought in the mean time.

Thanks! That works fine, and I’ve updated my library to use that check.