Skip to content

Commit

Permalink
Improve documentation, add FAQ section
Browse files Browse the repository at this point in the history
  • Loading branch information
utelle committed Jun 15, 2024
1 parent a711594 commit 50282be
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 20 deletions.
1 change: 1 addition & 0 deletions docs/ciphers/cipher_aes128cbc.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ The following table lists all parameters related to this cipher that can be set
**Note**
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- It is not recommended to use [_legacy_ mode]({{ site.baseurl }}{% link docs/ciphers/cipher_legacy_mode.md %}) for encrypting new databases. It is supported for compatibility reasons only, so that databases that were encrypted in _legacy_ mode can be accessed.
- Only _page size_ values corresponding to a power of 2 (i.e. 0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) are allowed.
1 change: 1 addition & 0 deletions docs/ciphers/cipher_aes256cbc.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ The following table lists all parameters related to this cipher that can be set
**Note**
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- It is not recommended to use [_legacy_ mode]({{ site.baseurl }}{% link docs/ciphers/cipher_legacy_mode.md %}) for encrypting new databases. It is supported for compatibility reasons only, so that databases that were encrypted in _legacy_ mode can be accessed.
- Only _page size_ values corresponding to a power of 2 (i.e. 0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) are allowed.
1 change: 1 addition & 0 deletions docs/ciphers/cipher_chacha20.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ The following table lists all parameters related to this cipher that can be set
**Note**
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- It is not recommended to use [_legacy_ mode]({{ site.baseurl }}{% link docs/ciphers/cipher_legacy_mode.md %}) for encrypting new databases. It is supported for compatibility reasons only, so that databases that were encrypted in _legacy_ mode can be accessed.
- Only _page size_ values corresponding to a power of 2 (i.e. 0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) are allowed.
1 change: 1 addition & 0 deletions docs/ciphers/cipher_sds_rc4.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ The following table lists all parameters related to this cipher that can be set
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- Currently only the [_legacy_ mode]({{ site.baseurl }}{% link docs/ciphers/cipher_legacy_mode.md %}) is implemented; it is not intended to implement a _non-legacy_ mode in the future, because RC4 encryption has known weaknesses (for example, the use of RC4 in TLS was prohibited by RFC 7465 published in February 2015).
- **The use of this cipher scheme for new applications is strongly discouraged.**
- Only _page size_ values corresponding to a power of 2 (i.e. 0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) are allowed.
3 changes: 2 additions & 1 deletion docs/ciphers/cipher_sqlcipher.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The following table lists all parameters related to this cipher that can be set
| `legacy_page_size` | 4096 | 0 | 65536 | Page size to use in legacy mode, 0 = default SQLite page size |
| `kdf_algorithm` | 2 | 0 | 2 | Hash algoritm for key derivation function<br/>0 = SHA1, 1 = SHA256, 2 = SHA512 |
| `hmac_algorithm` | 2 | 0 | 2 | Hash algoritm for HMAC calculation<br/>0 = SHA1, 1 = SHA256, 2 = SHA512 |
| `plaintext_header_size` | 0 | 0 | 100 | Size of plaintext database header<br/>must be multiple of 16, i.e. 32 |
| `plaintext_header_size` | 0 | 0 | 100 | Size of plaintext database header<br/>must be a multiple of 16, i.e. 32 |

The following table shows the parameter settings for the various _legacy_ versions of SQLCipher. The columns labelled **v4**, **v3**, **v2**, and **v1** correspond to legacy SQLCipher versions **4**, **3**, **2**, and **1** respectively. To access databases encrypted with a certain SQLCipher version the listed parameters have to be set explicitly. However, the default _legacy_ mode for the various SQLCipher versions can be easily set using just the parameter `legacy` set to the requested version number. That is, all other parameters have to be specified only, if their requested value deviates from the default value of the respective SQLCipher version.

Expand All @@ -52,3 +52,4 @@ The following table shows the parameter settings for the various _legacy_ versio
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- It is not recommended to use [_legacy_ mode]({{ site.baseurl }}{% link docs/ciphers/cipher_legacy_mode.md %}) for encrypting new databases. It is supported for compatibility reasons only, so that databases that were encrypted in _legacy_ mode can be accessed.
- Version 4 of SQLCipher introduced a new parameter `plain_text_header_size` to overcome an issue with shared encrypted databases under **iOS**. If this parameter is set to a non-zero value (like 16 or 32), the corresponding number of bytes at the beginning of the database header are not encrypted allowing **iOS** to identify the file as a SQLite database file. The drawback of this approach is that the cipher salt used for the key derivation can't be stored in the database header any longer. Therefore it is necessary to retrieve the cipher salt on creating a new database, and to specify the salt on opening an existing database. In **SQLite3 Multiple Ciphers** the cipher salt can be retrieved with the function `sqlite3mc_codec_data` using parameter `cipher_salt`, and has to be supplied on opening a database via the database URI parameter `cipher_salt`.
- Only _page size_ values corresponding to a power of 2 (i.e. 0, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) are allowed.
39 changes: 23 additions & 16 deletions docs/configuration/config_capi.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,25 +40,28 @@ The functions `sqlite3_key()`, `sqlite3_key_v2()`, `sqlite3_rekey()`, and `sqlit

## <a name="config_key" />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()`.
`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()`.

```c
SQLITE_API int sqlite3_key(
sqlite3* db, /* Database to set the key on */
const void* pKey, int nKey /* The key */
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, int nKey /* The key */
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](https://www.sqlite.org/lang_attach.html) 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
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- 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](https://www.sqlite.org/lang_vacuum.html) statement instead to force SQLite to write to the empty database.

Expand All @@ -71,13 +74,15 @@ Notes
```c
SQLITE_API int sqlite3_rekey(
sqlite3* db, /* Database to be rekeyed */
const void* pKey, int nKey /* The new key */
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, int nKey /* The new key */
const void* pKey, /* The new key */
int nKey /* Number of bytes in the new key */
);
```

Expand All @@ -87,9 +92,10 @@ Changing the key includes encrypting the database for the first time, decrypting

Notes
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- 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](https://www.sqlite.org/lang_vacuum.html) 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:
- 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:

```sql
PRAGMA page_size=4096;
Expand Down Expand Up @@ -133,21 +139,21 @@ The following parameter names are supported for `paramName`:

The following table lists the builtin cipher schemes:

| Cipher Name | Cipher ID | Preprocessor Symbol | Cipher |
| Cipher Name | Preprocessor Symbol | Cipher |
| :--- | :---: | :--- | :--- |
| `aes128cbc` | 1 | `CODEC_TYPE_AES128` | [wxSQLite3: AES 128 Bit]({{ site.baseurl }}{% link docs/ciphers/cipher_aes128cbc.md %}) |
| `aes256cbc` | 2 | `CODEC_TYPE_AES256` | [wxSQLite3: AES 256 Bit]({{ site.baseurl }}{% link docs/ciphers/cipher_aes256cbc.md %}) |
| `chacha20` | 3 | `CODEC_TYPE_CHACHA20` | [sqleet: ChaCha20]({{ site.baseurl }}{% link docs/ciphers/cipher_chacha20.md %}) |
| `sqlcipher` | 4 | `CODEC_TYPE_SQLCIPHER` | [SQLCipher: AES 256 Bit]({{ site.baseurl }}{% link docs/ciphers/cipher_sqlcipher.md %}) |
| `rc4` | 5 | `CODEC_TYPE_RC4` | [System.Data.SQLite: RC4]({{ site.baseurl }}{% link docs/ciphers/cipher_sds_rc4.md %}) |
| `ascon128` | 6 | `CODEC_TYPE_ASCON128` | [Ascon: Ascon-128 v1.2]({{ site.baseurl }}{% link docs/ciphers/cipher_ascon.md %}) |
| `aes128cbc` | `CODEC_TYPE_AES128` | [wxSQLite3: AES 128 Bit]({{ site.baseurl }}{% link docs/ciphers/cipher_aes128cbc.md %}) |
| `aes256cbc` | `CODEC_TYPE_AES256` | [wxSQLite3: AES 256 Bit]({{ site.baseurl }}{% link docs/ciphers/cipher_aes256cbc.md %}) |
| `chacha20` | `CODEC_TYPE_CHACHA20` | [sqleet: ChaCha20]({{ site.baseurl }}{% link docs/ciphers/cipher_chacha20.md %}) |
| `sqlcipher` | `CODEC_TYPE_SQLCIPHER` | [SQLCipher: AES 256 Bit]({{ site.baseurl }}{% link docs/ciphers/cipher_sqlcipher.md %}) |
| `rc4` | `CODEC_TYPE_RC4` | [System.Data.SQLite: RC4]({{ site.baseurl }}{% link docs/ciphers/cipher_sds_rc4.md %}) |
| `ascon128` | `CODEC_TYPE_ASCON128` | [Ascon: Ascon-128 v1.2]({{ site.baseurl }}{% link docs/ciphers/cipher_ascon.md %}) |

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

Notes
{: .label .label-red .ml-0 .mb-1 .mt-2 }
- 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()`](#cipher_index) to determine the _cipher ID_ of the requested cipher scheme via the _cipher name_.
- 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.
- 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()`](#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.

<span class="label label-green">Examples</span>
Expand Down Expand Up @@ -262,7 +268,7 @@ SQLITE_API const char* sqlite3mc_cipher_name(
);
```

`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_cipher()`](#config_general).
`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()`](#config_general).

Notes
{: .label .label-red .ml-0 .mb-1 .mt-2 }
Expand All @@ -279,3 +285,4 @@ SQLITE_API int sqlite3mc_register_cipher(
);
```

`sqlite3mc_register_cipher` allows to register cipher schemes dynamically. Further information can be found in the section about [Dynamic cipher schemes]({{ site.baseurl }}{% link docs/ciphers/cipher_dynamic.md %}).
4 changes: 2 additions & 2 deletions docs/configuration/config_sql_pragmas.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ PRAGMA hexkey = { hex-passphrase | 'hex-passphrase' };
```
Note
{: .label .label-red .ml-0 .mb-1 .mt-2 }
The unquoted variant for the _passphrase_ is only valid, if the passphrase does not contain any whitespace characters. The _key_ pragma only works with string keys. If you use a binary key, use the _hexkey_ pragma instead.
The unquoted variant for the _passphrase_ is only valid, if the passphrase does not contain any whitespace characters. The _key_ pragma only works with string keys. The encoding of the passphrase should be UTF-8, unless a wrapper is used that implicitly performs conversion to UTF-8 internally. If you use a binary key, use the _hexkey_ pragma instead.

Notes
{: .label .label-red .ml-0 .mb-1 .mt-2 }
Expand Down Expand Up @@ -128,7 +128,7 @@ PRAGMA hexrekey = { hex-passphrase | 'hex-passphrase' };
```
Note
{: .label .label-red .ml-0 .mb-1 .mt-2 }
The unquoted variant for the _passphrase_ is only valid, if the passphrase does not contain any whitespace characters. The _rekey_ pragma only works with string keys. If you use a binary key, use the _hexrekey_ pragma instead.
The unquoted variant for the _passphrase_ is only valid, if the passphrase does not contain any whitespace characters. The _rekey_ pragma only works with string keys. The encoding of the passphrase should be UTF-8, unless a wrapper is used that implicitly performs conversion to UTF-8 internally. If you use a binary key, use the _hexrekey_ pragma instead.

<span class="label label-green">Example 1:</span> _Change passphrase_

Expand Down
4 changes: 3 additions & 1 deletion docs/external/external_links.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
layout: default
title: External Links
nav_order: 6
nav_order: 7
has_children: false
---
# External Links
Expand All @@ -13,13 +13,15 @@ Several tools, wrappers, and applications are using **SQLite3 Multiple Ciphers**
- [SQLiteStudio](https://sqlitestudio.pl), ([GitHub](https://github.com/pawelsalawa/sqlitestudio))
- [sqlite-gui](https://github.com/little-brother/sqlite-gui)
- [SQLMaestro](https://www.sqlmaestro.com), (commercial)
- [HeidiSQL](https://www.heidisql.com), ([GitHub](https://github.com/HeidiSQL/HeidiSQL)); it is expected that version 12.8 will have support for SQLite encryption officially (see [HeidiSQL issue 1248](https://github.com/HeidiSQL/HeidiSQL/issues/1284)).

## SQLite Wrapper

- **Node.js.** wrapper [better-sqlite3-multiple-ciphers](https://www.npmjs.com/package/better-sqlite3-multiple-ciphers), ([GitHub](https://github.com/m4heshd/better-sqlite3-multiple-ciphers))
- [SQLite JDBC Driver](https://github.com/Willena/sqlite-jdbc-crypt)
- [SQLDelight driver](https://github.com/toxicity-io/sqlite-mc)
- **.NET NuGet** package [SQLitePCLRaw.bundle_e_sqlite3mc](https://www.nuget.org/packages/SQLitePCLRaw.bundle_e_sqlite3mc)
- **Python3** package [APSW-sqlite3mc](), ([GitHub](https://github.com/utelle/apsw-sqlite3mc)); not yet officially released

## Applications

Expand Down
72 changes: 72 additions & 0 deletions docs/faq/faq_overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
layout: default
title: Frequently Asked Questions
nav_order: 6
has_children: false
---
# Frequently Asked Questions

<details>

<summary>How can I enable encryption for a non-default SQLite VFS?</summary>

On initialization of the SQLite library encryption is automatically enabled for the default VFS by registering a new VFS combining the _SQLite3 Multiple Ciphers_ VFS shim with SQLite's default VFS for the current platform (for example, on _Windows_ this would result in the (new) VFS `multipleciphers-win32`) and making it the new default VFS.

On most platforms SQLite offers additional VFS implementations. For example, on _Windows_ there is the VFS `win32-longpath` which supports very long file path specifications for database files, while the default VFS `win32` supports only file paths of at most 1040 characters.

A non-default VFS is chosen for a SQLite database connection by specifying the name of the requested VFS on opening the database connection. Encryption support can be enabled for such a non-default VFS by simply prefixing the VFS name with the string `multipleciphers-`. For example, for using the VFS `win32-longpath` with encryption support specify the VFS name `multipleciphers-win32-longpath`. _SQLite3 Multiple Ciphers_ will create and register this new VFS automatically. However, the new VFS will not be made the default.

</details>


<details>

<summary>How can I change the page size of an encrypted database?</summary>

Usually SQLite allows to change the page size of a database by requesting the new page size via a `PRAGMA page_size` SQL statement and actually changing the page size when a `VACUUM` statement is executed.

Unfortunately, this method does not work for encrypted databases. If you need to change the page size of an encrypted database, apply the following procedure:

```SQL
-- Decrypt database
PRAGMA rekey='';
-- Set requested page size
PRAGMA page_size=32768;
-- Vacuun database
VACUUM;
-- Encrypt database again
PRAGMA rekey='passphrase';
```

An alternative would be to create a copy of the database with the new page size:

```SQL
PRAGMA page_size=32768;
VACUUM INTO 'file:databasefile?key=passphrase'
```

> [!IMPORTANT]
> The database must not be in WAL journal mode.
</details>

<!--
<details>
<summary></summary>
</details>
<details>
<summary></summary>
</details>
<details>
<summary></summary>
</details>
-->

0 comments on commit 50282be

Please sign in to comment.