Version 10.0.2
Encryptors

Overview of Encryption in WiredTiger

This section explains how to configure and work with encryption in WiredTiger.

WiredTiger now provides built-in support for encryption with an extension using the open-source libsodium cryptography library. Application developers may also write their own custom encryption extensions. Three example extensions are provided for expository and testing purposes.

Warning
The encryption infrastructure included in WiredTiger, when used with an extension providing a strong encryption algorithm, is intended only to protect data stored in files (that is, it provides encryption at rest). The table content (keys, values), the metadata pertaining to data (table, index, column names, and other configuration information) as well as the database log files are encrypted on disk. However, it does not protect data in memory while the database is running. Decryption occurs when the data is read into memory; thus an attacker having the ability to directly read system memory will have access to unencrypted data. Many systems may also page memory to a backing disk under load. The security of any such paging or swap devices must be considered when planning the security of a system; in general, they should be disabled or themselves encrypted using operating system or storage system facilities.

Using an encryption extension

Enabling encryption involves two steps: first, loading the encryptor extension, and second, enabling and configuring it. Extensions must be loaded in the wiredtiger_open call. See Extending WiredTiger for details about how extensions are loaded.

Encryption must be enabled first for the overall database (the system encryption) by passing the encryption configuration (described shortly) to the wiredtiger_open call. This establishes the encryption algorithm and keys to be used for database log files and a subset of the WiredTiger metadata files. By default, this same encryption is also used for all data files.

Encryption may also be enabled separately for individual tables, column groups, and indices, by passing a different encryption configuration to the WT_SESSION::create call. This configuration overrides the system encryption for the data file so created. It may use a different encryptor and/or different key (except as noted below). It is also possible to disable encryption for individual tables; this is of course usually undesirable, but possibly a reasonable option for high-churn low-value data.

Each table, column group, and index that is to have encryption different from the system encryption must be configured explicitly; encryption configuration is not inherited by column groups or indices from the table they apply to. Such encryption must be specified when the data file is created; otherwise the system encryption is used.

It is an error to specify encryption in a WT_SESSION::create call when it was not specified in the wiredtiger_open call. This prevents accidental exposure of the file's data in log files, which would be written in the clear in such a scenario.

Warning
When using separate keys for individual data files or tables, the key used for the system encryption continues to have fundamental importance. The database log, protected by the system encryption, contains a shared stream of changes to all data files. Thus, if the system key is exposed, even when per-file keys are not exposed, an attacker can read database log files, and hence has access to data in individual files.

Note that because every encryptor providing strong encryption should also include a cryptographically strong checksum, WiredTiger's own block checksums can safely be disabled. See WT_SESSION::create.

Encryption configuration

Encryption is configured using the encryption= configuration parameter. As noted above this must be passed to wiredtiger_open and may also be passed to WT_SESSION::create. The value of encryption= is a nested configuration string with up to three parameters. The first should be name= to select the encryption extension to use. This is the name of the encryptor and should be the string the encryptor's initialization method passed to WT_CONNECTION::add_encryptor. For the built-in libsodium extension, this name is "sodium". The other parameters, keyid and secretkey, are used to specify the encryption key. To disable encryption for an individual table the reserved value name=none may be passed when creating it. (As is noted above, this is usually not desirable.)

Keys via key ID

The configuration parameter encryption=(keyid=identifier) may be used in wiredtiger_open or WT_SESSION::create calls. This is intended to reference a key stored using a Key Management Solution (KMS). The keyid given to wiredtiger_open is stored in the clear in WiredTiger configuration files; it should never contain sensitive information. Consequently, however, it need only be specified when the database is created; it is remembered thereafter. Additional keyid values may be used freely for different database files. These are stored in WiredTiger metadata using the system encryption.

As an example, with a keyid of "customerABC", the encryptor would consult the KMS to return a key previously stored for "customerABC". The encryptor would then use the returned key when encrypting.

Keys via explicit secret key

The configuration parameter encryption=(secretkey=key) is used only in the wiredtiger_open call. The value of the secret key is never stored on disk in any form, so it must always be provided when WiredTiger is reopened (again, with the wiredtiger_open call). It may not be passed to WT_SESSION::create; consequently if no KMS is available different keys cannot be used for individual tables.

If a secretkey is used, it must be provided using the -E command-line option when using the wt utility. Specifying keyid is not needed with the wt utility, as the keyid is stored in the clear on disk by WiredTiger. Note that while the wt utility takes some steps to prevent it, on most systems it is possible to see command-line arguments using operating system facilities. This creates some risk of exposure that must be considered. Using a KMS is probably preferable where possible. Alternatively, one might avoid using the wt utility entirely when using encryption, as it is not necessary.

Both keyid and secretkey values are not interpreted by the configuration framework; their exact interpretation and the sets of possible values are determined by the encryptor in use.

Custom encryption extensions

Applications may provide their own encryption extensions. Custom encryptors must be coded in the C language. Once packaged, they can be used in any language. For further information, see: general information on extending WiredTiger, and the encryptor interface WT_ENCRYPTOR.

A simple example application with its own encryptor is provided to demonstrate how this may be done. It shows both how to install a custom extension and then how to configure it. (Note, however, that it uses a trivial "encryption" that provides no security.)

Three additional encryptor extensions are included with WiredTiger. These are built as shared libraries to show how that can be done.

The libsodium encryption extension

The "sodium" encryptor uses the open source libsodium cryptography library. It currently has no support for key management and thus does not support keyid configurations, only secretkey. The secretkey is expected to be a 256-bit XChaCha20 key encoded in hex (with no leading 0x). This is not directly suitable for applications that wish to use manually-entered passwords or passphrases. Applications for which these restrictions are unsuitable can copy the extension code and extend it as needed, using additional material from libsodium or other libraries.

The sodium encryptor is intended to protect against disclosure of data, such as might otherwise happen with a database on a stolen laptop. It may provide some protection against malicious corruption of a database by an adversary with write access to the database files, but is not intended for this purpose and should not be relied upon in this context. (Note that on most operating systems, and in most situations, an adversary with write access to the database files is highly likely to also be able to read data out of memory while the database is running, and change it as well, so this limitation is not necessarily important.)

To use the encryptor, first install libsodium; then you can compile WiredTiger with the extension by passing the –enable-sodium option to configure, or the argument -DENABLE_SODIUM=1 to cmake.

If libsodium is installed in a location not normally searched by the compiler toolchain, you'll need to modify the CPPFLAGS and LDFLAGS to indicate these locations. For example, with the libsodium includes and libraries installed in /usr/local/include and /usr/local/lib, you would run configure with the following additional arguments:

--enable-sodium CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/include"

Alternatively you would run cmake with the following additional arguments:

-DENABLE_SODIUM=1 -DCMAKE_INCLUDE_PATH=/usr/local/include -DCMAKE_LIBRARY_PATH=/usr/local/lib

When opening the WiredTiger database, load the libsodium plugin library as an extension. For example, with the WiredTiger library installed in /usr/local/lib, you would use the following code:

char conf[1024];
snprintf(conf, sizeof(conf),
"create,extensions=[/usr/local/lib/libwiredtiger_sodium.so],"
"encryption=(name=sodium,secretkey=%s)",
secretkey);
error_check(wiredtiger_open(home, NULL, conf, &conn));

where secretkey comes from some suitable place. (Never compile in cryptographic keys.)

Because this encryptor includes a cryptographically strong checksum, it is safe to disable WiredTiger's own block checksums.

The nop encryption extension

The "nop" encryptor is a skeleton extension into which suitable cryptographic code may be inserted. It is provided as a framework for developers writing custom encryptors to copy as a means of getting started. It does not do anything and should obviously not be used in production.

The rotn encryption extension

The "rotn" encryptor is a test extension that performs either of two forms of trivial "encryption". It is used for testing the encryption framework. It provides no security and should never be used in production.

The ex_encrypt example

The ex_encrypt.c example (mentioned above) provides a runnable example of a simple application that loads a custom encryptor compiled into the application (rather than as a plugin library). The "encryption" it uses is trivial and should never be used in production.

Warning
Developers writing custom encryptor extensions should be sure to consult appropriate references to ensure that what they do is cryptographically sound and addresses the threat model they have in mind. Proper use of cryptographic primitives and constructions is a complex topic far beyond the scope of this documentation.
wiredtiger_open
int wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler, const char *config, WT_CONNECTION **connectionp)
Open a connection to a database.