Link Search Menu Expand Document

C Interface

The C interface of SQLite3 Multiple Ciphers consists of the official SQLite C Interface and the following additional functions:

FunctionDescription
sqlite3_key() and sqlite3_key_v2()Set the database key to use when accessing an encrypted database
sqlite3_rekey() and sqlite3_rekey_v2()Change the database encryption key
sqlite3mc_config()Configure database encryption parameters
sqlite3mc_config_cipher()Configure cipher encryption parameters
sqlite3mc_codec_data()Configure cipher encryption parameters

A detailed description of each function and its parameters is provided in the following sections:

The functions sqlite3_key(), sqlite3_key_v2(), sqlite3_rekey(), and sqlite3_rekey_v2() belong to the C interface of the official (commercial) SQLite Add-On SQLite Encryption Extension (SEE). For compatibility with this add-on the names of these functions use the typical sqlite3_ prefix. Functions that are specific for SQLite3 Multiple Ciphers use the name prefix sqlite3mc_.


Functions sqlite3_key() and sqlite3_key_v2()

sqlite3_key() and sqlite3_key_v2() set the database key to use when accessing an encrypted database, and should usually be called immediately after sqlite3_open().

SQLITE_API int sqlite3_key(
  sqlite3* db,                   /* Database to set the key on */
  const void* pKey, int nKey     /* The key */
);

SQLITE_API int sqlite3_key_v2(
  sqlite3* db,                   /* Database to set the key on */
  const char* zDbName,           /* Database schema name */
  const void* pKey, int nKey     /* The key */
);

sqlite3_key() is used to set the key for the main database, while sqlite3_key_v2() sets the key for the database with the schema name specified by zDbName. The schema name is main for the main database, temp for the temporary database, or the schema name specified in an ATTACH statement for an attached database. If sqlite3_key() or sqlite3_key_v2() is called on an empty database, then the key will be initially set. The return value is SQLITE_OK on success, or a non-zero SQLite3 error code on failure.

Notes

  • These functions return SQLITE_OK even if the provided key isn’t correct. This is because the key isn’t actually used until a subsequent attempt to read or write the database is made. To check whether the provided key was actually correct, you must execute a simple query like e.g. SELECT * FROM sqlite_master; and check whether that succeeds.
  • When setting a new key on an empty database (that is, a database with zero bytes length), you have to make a subsequent write access so that the database will actually be encrypted. You’d usually want to write to a new database anyway, but if not, you can execute the VACUUM statement instead to force SQLite to write to the empty database.

Functions sqlite3_rekey() and sqlite3_rekey_v2()

sqlite3_rekey() and sqlite3_rekey_v2() change the database encryption key.

SQLITE_API int sqlite3_rekey(
  sqlite3* db,                   /* Database to be rekeyed */
  const void* pKey, int nKey     /* The new key */
);

SQLITE_API int sqlite3_rekey_v2(
  sqlite3* db,                   /* Database to be rekeyed */
  const char* zDbName,           /* Database schema name */
  const void* pKey, int nKey     /* The new key */
);

sqlite3_rekey() is used to change the key for the main database, while sqlite3_rekey_v2() changes the key for the database with the schema name specified by zDbName. The schema name is main for the main database, temp for the temporary database, or the schema name specified in an ATTACH statement for an attached database.

Changing the key includes encrypting the database for the first time, decrypting the database (if pKey == NULL or nKey == 0), as well as re-encrypting it with a new key. The return value is SQLITE_OK on success, or a non-zero SQLite3 error code on failure.

Notes

  • If the number of reserved bytes per database page differs between the current and the new encryption scheme, then sqlite3_rekey() performs a VACUUM statement to encrypt/decrypt all pages of the database. Thus, the total disk space requirement for re-encrypting can be up to 3 times of the database size. If possible, re-encrypting is done in-place.
  • On decrypting a database all reserved bytes per database page are released.
  • On changing the database encryption key it is not possible to change the page size of the database at the same time. This affects mainly legacy modes with a non-default page size (like legacy SQLCipher, which has a page size of 1024 bytes). In such cases it is necessary to adjust the legacy page size to the default page size or to adjust the page size in a separate step by executing the following SQL statements:
PRAGMA page_size=4096;
VACUUM;

However, please keep in mind that this works only on plain unencrypted databases.


Function sqlite3mc_config()

SQLITE_API int sqlite3mc_config(
  sqlite3*    db,                /* Database instance */
  const char* paramName,         /* Parameter name */
  int         newValue           /* New value of the parameter */
);

sqlite3mc_config() gets or sets encryption parameters which are relevant for the entire database instance. db is the database instance to operate on, or NULL to query the compile-time default value of the parameter. paramName is the name of the requested parameter. To set a parameter, pass the new parameter value as newValue. To get the current parameter value, pass -1 as newValue.

Parameter names use the following prefixes:

PrefixDescription
no prefixGet or set the transient parameter value. Transient values are only used once for the next call to sqlite3_key() or sqlite3_rekey(). Afterwards, the permanent default values will be used again (see below).
default:Get or set the permanent default parameter value. Permanent values will be used during the entire lifetime of the db database instance, unless explicitly overridden by a transient value. The initial values for the permanent default values are the compile-time default values.
min:Get the lower bound of the valid parameter value range. This is read-only.
max:Get the upper bound of the valid parameter value range. This is read-only.

The following parameter names are supported for paramName:

Parameter nameDescriptionPossible values
cipherThe cipher to be used for encrypting the database.1 .. 5
(see Cipher IDs below)
hmac_checkBoolean flag whether the HMAC should be validated on read operations for encryption schemes using HMACs0
1
mc_legacy_walBoolean flag whether the legacy mode for the WAL journal encryption should be used0
1

The following table lists the supported cipher identifiers:

Cipher IDPreprocessor SymbolCipher
1CODEC_TYPE_AES128wxSQLite3: AES 128 Bit
2CODEC_TYPE_AES256wxSQLite3: AES 256 Bit
3CODEC_TYPE_CHACHA20sqleet: ChaCha20
4CODEC_TYPE_SQLCIPHERSQLCipher: AES 256 Bit
5CODEC_TYPE_RC4System.Data.SQLite: RC4

The return value always is the current parameter value on success, or -1 on failure.

Note

  • Checking the HMAC on read operations is active by default. With the parameter hmac_check the HMAC check can be disabled in case of trying to recover a corrupted database. It is not recommended to deactivate the HMAC check for regular database operation. Therefore the default can not be changed.
  • The legacy mode for WAL journal encryption is off by default. The encryption mode used by all versions up to 1.2.5 is called legacy mode, version 1.3.0 introduced a new encryption mode that provides compatibility with legacy encryption implementations and is less vulnerable to changes in SQLite. It should only be enabled to recover WAL journal files left behind by applications using versions up to 1.2.5.

Examples

/* Use AES-256 cipher for the next call to sqlite3_key() or sqlite3_rekey() for the given db */
sqlite3mc_config(db, "cipher", CODEC_TYPE_AES256);
/* Use SQLCipher during the entire lifetime of database instance */
sqlite3mc_config(db, "default:cipher", CODEC_TYPE_SQLCIPHER);
/* Get the maximum value which can be used for the "cipher" parameter */
sqlite3mc_config(NULL, "max:cipher", -1);

Function sqlite3mc_config_cipher()

SQLITE_API int sqlite3mc_config_cipher(
  sqlite3*    db,                /* Database instance */
  const char* cipherName,        /* Cipher name */
  const char* paramName,         /* Parameter name */
  int         newValue           /* New value of the parameter */
);

sqlite3mc_config_cipher() gets or sets encryption parameters which are relevant for a specific encryption cipher only. See the sqlite3mc_config() function for details about the db, paramName and newValue parameters. See the related cipher descriptions for the parameter names supported for paramName.

The following cipher names are supported for cipherName:

Cipher nameRefers toDescription
aes128cbc1 = CODEC_TYPE_AES128AES 128 Bit CBC - No HMAC (wxSQLite3)
aes256cbc2 = CODEC_TYPE_AES256AES 256 Bit CBC - No HMAC (wxSQLite3)
chacha203 = CODEC_TYPE_CHACHA20ChaCha20 - Poly1305 HMAC (sqleet)
sqlcipher4 = CODEC_TYPE_SQLCIPHERAES 256 Bit CBC - SHA1 HMAC (SQLCipher)
rc45 = CODEC_TYPE_RC4RC4 (System.Data.SQLite)

The return value always is the current parameter value on success, or -1 on failure.

Example

/* Activate SQLCipher version 1 encryption scheme for the next key or rekey operation */
sqlite3mc_config(db, "cipher", CODEC_TYPE_SQLCIPHER);
sqlite3mc_config_cipher(db, "sqlcipher", "kdf_iter", 4000);
sqlite3mc_config_cipher(db, "sqlcipher", "fast_kdf_iter", 2);
sqlite3mc_config_cipher(db, "sqlcipher", "hmac_use", 0);
sqlite3mc_config_cipher(db, "sqlcipher", "legacy", 1);
sqlite3mc_config_cipher(db, "sqlcipher", "legacy_page_size", 1024);

Function sqlite3mc_codec_data()

SQLITE_API unsigned char* sqlite3mc_codec_data(
  sqlite3*    db,                /* Database instance */
  const char* schemaName,        /* Cipher name */
  const char* paramName          /* Parameter name */
);

sqlite3mc_codec_data() retrieves the value of encryption parameters after an encrypted database has been opened. db is the database instance to operate on. schemaName optionally specifies the schema name of an attached database; for the main database the parameter can be specified as NULL. paramName specifies the parameter to be queried.

The following parameter names are currently supported for paramName:

Cipher nameDescription
cipher_saltThe random cipher salt used for key derivation and stored in the database header (as a hexadecimal encoded string, 32 bytes)
raw:cipher_saltThe random cipher salt used for key derivation and stored in the database header (as a raw binary string, 16 bytes)

Notes

  • A NULL pointer is returned if the database is not encrypted or if the encryption scheme doesn’t use a cipher salt. If a non-NULL pointer is returned, it is the application’s responsibility to free the memory using function sqlite3_free.
  • Some cipher schemes use a random cipher salt on database creation. If the database header gets corrupted for some reason, it is almost impossible to recover the database without knowing the cipher salt. For critical applications it is therefore recommended to retrieve the cipher salt after the initial creation of a database and keep it in a safe place.

Copyright © 2020-2021 Ulrich Telle. Distributed under an MIT license.