Link Search Menu Expand Document (external link)

Overview

The project SQLite3 Multiple Ciphers implements an encryption extension for SQLite with support for multiple ciphers.

SQLite3 Multiple Ciphers is an extension to the public domain version of SQLite that allows applications to read and write encrypted database files. Currently 6 different encryption cipher schemes are supported:

The cipher scheme ChaCha20 - Poly1305 HMAC is currently the recommended default cipher scheme, because it meets the following important criteria:

  • Encryption and tamper detection is a modern Internet Engineering Task Force standard, also used for secure web communication (TLS/SSL) - see RFC 7905.
  • A key derivation function (PBKDF2) is used to reduce vulnerability to brute force attacks.
  • Per database and per page random bytes (cryptographic nonce) are used to ensure that the same unencrypted database content does not result in the same encrypted content when the same encryption key is used.

Technically, the cipher schemes SQLCipher and Ascon are almost equivalent with respect to cryptographic security. However, SQLCipher uses AES, which has usually lower runtime performance than ChaCha20 - Poly1305 HMAC. And Ascon is a relatively new player supporting authenticated encryption schemes with associated data (AEAD), selected as new standard for lightweight cryptography in the NIST Lightweight Cryptography competition (2019–2023).

The cipher schemes AES 128/256 Bit CBC and RC4 (System.Data.SQLite) do not meet the above criteria and are included for compatibility with older existing applications only. They should not be used for new development. Developers using one of these cipher schemes should consider to update their applications to use one of the more modern and secure cipher schemes.

Technical functionality

SQLite3 Multiple Ciphers encrypts the entire database file, so that an encrypted SQLite database file appears to be white noise to an outside observer. Not only the database files themselves, but also journal files are encrypted.

Note

SQLite3 Multiple Ciphers has more or less the same limitations as the official SQLite Encryption Extension (SEE):

  1. TEMP tables are not encrypted.
  2. In-memory (":memory:") databases are not encrypted.
  3. Bytes 16 through 23 of the database file contain header information that is usually not encrypted.

To not compromise security by leaking temporary data to disk, it is very important to keep all temporary data in memory. Therefore it is strongly recommended to use the compile time option SQLITE_TEMP_STORE=2 (which is the default in the current build files) (or even SQLITE_TEMP_STORE=3, forcing temporary data to memory unconditionally). PRAGMA temp_store=MEMORY; should be used for encrypted databases, if the compile time option SQLITE_TEMP_STORE was not set to a value of 2 or 3.

In addition to reading and writing encrypted database files SQLite with the SQLite3 Multiple Ciphers extension is able to read and write ordinary database files created using a public domain version of SQLite. Applications can use the ATTACH statement of SQLite to simultaneously connect to two or more encrypted and/or unencrypted database files. For each database file a different encryption cipher scheme can be used.

Usage

The SQLite3 Multiple Ciphers encryption extension can be used via the C API as well as via SQL.

C API

Basically, the C API of the official SQLite Encryption Extension (SEE) is supported. This API consists of 4 functions:

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 */
);

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 */
);

The functions sqlite3_key() and sqlite3_key_v2() set the database key to be used when accessing an encrypted database or creating a new encrypted database, and should usually be called immediately after sqlite3_open().

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.

sqlite3_rekey() is used to change the encryption 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. These functions can also decrypt a previously encrypted database by specifying an empty key.

A more detailed description can be found here.

Note

Since SQLite3 Multiple Ciphers makes use of the automatic extension loading mechanism (via the function sqlite3_auto_extension) and dynamically allocates Virtual File System (VFS) instances, it is strongly recommended to call function sqlite3_shutdown(), right before exiting the application after all active database connections have been closed, to avoid memory leaks.

SQL API

The encryption API is also accessible via PRAGMA statements:

A more detailed description (especially, how to configure cipher schemes) can be found here.

Additionally, the SQL command ATTACH supports the KEY keyword to allow to attach an encrypted database file to the current database connection:

ATTACH [DATABASE] <db-file-expression> AS <schema-name> [KEY <passphrase>]

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