Link Search Menu Expand Document (external link)

C Interface

The C interface of SQLite3 Multiple Ciphers consists of the official SQLite C Interface and several additional functions described in the following sections. Please click on the function name in below tables to jump to a detailed description of the respective function.

Passphrase 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

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_.

Configuration functions

FunctionDescription
sqlite3mc_config()Configure database encryption parameters
sqlite3mc_config_cipher()Configure cipher encryption parameters
sqlite3mc_codec_data()Retrieve cipher scheme data

Registration functions

FunctionDescription
sqlite3mc_register_cipher()Register a cipher scheme
sqlite3mc_cipher_count()Retrieve number of registered cipher schemes
sqlite3mc_cipher_index()Retrieve index of a cipher scheme
sqlite3mc_cipher_name()Retrieve name of cipher at a given index

Description of passphrase functions

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,              /* The key */
  int nKey                       /* Number of bytes in 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,              /* The key */
  int nKey                       /* Number of bytes in 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

  • For plaintext passphrases (keys) it is strongly recommended to use UTF-8 encoding.
  • 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,              /* The new key */
  int nKey                       /* Number of bytes in the new key  */
);

SQLITE_API int sqlite3_rekey_v2(
  sqlite3* db,                   /* Database to be rekeyed */
  const char* zDbName,           /* Database schema name */
  const void* pKey,              /* The new key */
  int nKey                       /* Number of bytes in 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

  • For plaintext passphrases (keys) it is strongly recommended to use UTF-8 encoding.
  • 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.


Description of configuration functions

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 .. n
(where n is the number of
registered cipher schemes;
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 builtin cipher schemes:

Cipher NamePreprocessor SymbolCipher
aes128cbcCODEC_TYPE_AES128wxSQLite3: AES 128 Bit
aes256cbcCODEC_TYPE_AES256wxSQLite3: AES 256 Bit
chacha20CODEC_TYPE_CHACHA20sqleet: ChaCha20
sqlcipherCODEC_TYPE_SQLCIPHERSQLCipher: AES 256 Bit
rc4CODEC_TYPE_RC4System.Data.SQLite: RC4
ascon128CODEC_TYPE_ASCON128Ascon: Ascon-128 v1.2

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

Notes

  • When configuring the cipher scheme with function sqlite3mc_config(), the cipher ID has to be used. However, the cipher IDs depend on the order of cipher scheme registrations. Therefore it is strongly recommended to use function sqlite3mc_cipher_index() to retrieve the cipher ID of the requested cipher scheme via the cipher name, instead of using fixed cipher IDs.
  • Checking the HMAC on read operations is enabled 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", sqlite3mc_cipher_index("aes256cbc"));
/* Use SQLCipher during the entire lifetime of database instance */
sqlite3mc_config(db, "default:cipher", sqlite3mc_cipher_index("sqlcipher"));

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 used as the cipherName for the supported builtin cipher schemes:

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", sqlite3mc_cipher_index("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.

Description of cipher registration functions

Function sqlite3mc_cipher_count()

SQLITE_API int sqlite3mc_cipher_count();

sqlite3mc_cipher_count() retrieves the number of currently registered cipher schemes.

Function sqlite3mc_cipher_index()

SQLITE_API int sqlite3mc_cipher_index(
  const char* cipherName  /* Name of the cipher scheme */
);

sqlite3mc_cipher_index() retrieves the relative 1-based index of the named cipher scheme in the list of registered cipher schemes. This index can be used in function sqlite3mc_config_cipher().

Note

  • The value -1 is returned, if the given cipher scheme name could not be found.

Function sqlite3mc_cipher_name()

SQLITE_API const char* sqlite3mc_cipher_name(
  int cipherIndex   /* Index of cipher scheme */
);

sqlite3mc_cipher_name() retrieves the name of the cipher scheme for the given relative 1-based index in the list of registered cipher schemes. This index can be used in function sqlite3mc_config().

Notes

  • An empty string is returned if an invalid index was given.
  • The returned string is valid until the next call to this function. That is, the string will be overwritten by the next call to this function.

Function sqlite3mc_register_cipher()

SQLITE_API int sqlite3mc_register_cipher(
  const CipherDescriptor* desc, /* Cipher descriptor */
  const CipherParams* params,   /* List of cipher configuration parameters */
  int makeDefault               /* Flag, whether this cipher scheme should be made the default */
);

sqlite3mc_register_cipher allows to register cipher schemes dynamically. Further information can be found in the section about Dynamic cipher schemes.


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