7.6 KiB
TREES - A NaCL-based Dovecot encryption plugin
This plugin adds individually encrypted mail storage to the Dovecot IMAP server.
This plugin is inspired by Posteo's scrambler which uses OpenSSL and RSA keypairs. TREES works in a similar way, but uses the Sodium crypto library (based on NaCL).
How it works:
-
On IMAP log in, the user's cleartext password is passed to the plugin.
-
The plugin creates an argon2 digest from the password.
-
This password digest is used as a symmetric secret to decrypt a libsodium secretbox.
-
Inside the secretbox is stored a Curve25519 private key.
-
The Curve25519 private key is used to decrypt each individual message, using lidsodium sealed boxes.
-
New mail is encrypted as it arrives using the Curve25519 public key.
Requirements
-
dovecot source (
apt install dovecot-dev
) -
libsodium (must be >= 1.0.9, which is when argon2 hashing was added) libraries and header files:
apt install -t jessie-backports libsodium18 libsodium-dev
-
libsodium authentication plugin for dovecot: not required, but there is little benefit from hashing passwords using argon2 if dovecot authentication relies on a weaker digest algorithm. https://github.com/LuckyFellow/dovecot-libsodium-plugin.git
Installation
-
Run
autogen.sh
and then./configure
. -
Type
make
to compile the plugin. -
Find the plugin at
src/.libs/lib18_trees_plugin.so
. -
Copy to
/usr/lib/dovecot/modules/
-
Enable the plugin. For example, add
mail_plugins = expire quota trees
to/etc/dovecot/conf.d/10-mail.conf
See below for how to configure the plugin.
Database
In order to run, the plugin needs the following configuration values (via the dovecot environment).
-
trees_password
The plain user password. It's used to unlock thetrees_locked_secretbox
in order to get access to the private key. -
trees_enabled
Can be either the integer1
or0
. -
trees_public_key
The public Curve25519 key of the user (hex string). -
trees_locked_secretbox
contains the Curve25519 private key of a user which is locked using the argon2 digest of the user's password (hex string). -
trees_sk_nonce
24 byte random nonce forlocked_secretbox
(hex string). -
trees_pwhash_opslimit
argon2 CPU usage parameter (3..10 int). -
trees_pwhash_memlimit
argon2 memory usage parameter (must be in range 8192 bytes to 4 TB, expressed in bytes). -
trees_pwhash_salt
16 byte random argon2 salt (hex string).
An example database scheme for this might be:
CREATE TABLE `storage_keys` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`enabled` tinyint(4) DEFAULT '1',
`public_key` text,
`pwhash_opslimit` int(11) DEFAULT NULL,
`pwhash_memlimit` int(11) DEFAULT NULL,
`pwhash_salt` varchar(255) DEFAULT NULL,
`sk_nonce` varchar(255) DEFAULT NULL,
`locked_secretbox` text,
`user_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT DEFAULT
NOTE: the database MUST NOT store the argon2 digest, since this value is the
secret key that unlocks locked_secretbox
. This is very different than how
password hashing for authentication works, where the digest and parameters are
stored.
Dovecot Configuration
-
passdb MUST be enabled.
-
prefetch MUST be enabled.
-
zlib compression must be disabled (might be compatible, need further testing).
-
indexes should be disabled (otherwise, headers of incoming email are cached in cleartext).
-
default_pass_scheme = ARGON2
recommended (Note: this will use the crypt- style argon2 digest string for authentication, which is a very different format than is used by TREES. It is out of TREES's scope how to set up Argon2 authentication with Dovecot).
SQL Configuration
/etc/dovecot/conf.d/auth-sql.conf.ext
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
userdb {
driver = prefetch
}
userdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf
}
Here is a dovecot SQL query configuration that will work with the sample
storage_keys
table.
/etc/dovecot/dovecot-sql.conf
:
##
## PASSWORD QUERY
##
## because prefetch is enabled, the userdb_x entries will be used to populate
## user object.
##
password_query = SELECT \
mailboxes.username AS username, \
mailboxes.domain AS domain, \
mailboxes.password AS password, \
8 AS userdb_uid, \
8 AS userdb_gid, \
CONCAT('/maildir/', mailboxes.maildir) AS userdb_home, \
REPLACE('%w', '%%', '%%%%') AS userdb_trees_password, \
storage_keys.enabled AS userdb_trees_enabled, \
storage_keys.public_key AS userdb_trees_public_key, \
storage_keys.locked_secretbox AS userdb_trees_locked_secretbox, \
storage_keys.sk_nonce AS userdb_trees_sk_nonce, \
storage_keys.pwhash_opslimit AS userdb_trees_pwhash_opslimit, \
storage_keys.pwhash_memlimit AS userdb_trees_pwhash_memlimit, \
storage_keys.pwhash_salt AS userdb_trees_pwhash_salt \
FROM mailboxes \
LEFT OUTER JOIN storage_keys ON mailboxes.user_id = storage_keys.user_id \
WHERE mailboxes.username = '%n' AND mailboxes.domain = '%d' \
AND mailboxes.is_active = 1
##
## USER QUERY
##
## user_query is used to return the location of the mailbox and check the quota
## because we have prefetch enabled, this query is only used for LDA.
##
user_query = SELECT \
8 AS uid, \
8 AS gid, \
CONCAT('/maildir/', mailboxes.maildir) AS home, \
storage_keys.enabled AS trees_enabled, \
storage_keys.public_key AS trees_public_key, \
CONCAT('*:bytes=', mailboxes.quota) AS quota_rule \
FROM mailboxes \
LEFT OUTER JOIN storage_keys ON mailboxes.user_id = storage_keys.user_id \
WHERE mailboxes.username = '%n' AND mailboxes.domain = '%d' \
AND mailboxes.is_active = 1
The odd line REPLACE('%w', '%%', '%%%%')
is needed to pass the cleartext
password to TREES, and allow %
as a valid password character.
Argon2 Parameters
There are three recommended levels for the Argon2 parameters, Interactive, Moderate, and Sensitive. In the case of TREES, setting the parameters at Moderate or Sensitive will make checking email very slow.
Interactive: For interactive, online operations, that need to be fast, a reasonable minimum is:
- opslimit: 4
- memlimit: 2 ** 25 (32mb)
Moderate: This requires 128 Mb of dedicated RAM, and takes about 0.7 seconds on a 2.8 Ghz Core i7 CPU.
- opslimit: 6
- memlimit: 2 ** 27 (128mb)
Sensitive: For highly sensitive data and non-interactive operations, consider these values. With these parameters, deriving a key takes about 3.5 seconds on a 2.8 Ghz Core i7 CPU and requires 512 Mb of dedicated RAM. Not practical for IMAP!
- opslimit: 8
- memlimit: 2 ** 29 (512mb)
TODOs
- Document how to migrate unencrypted mailboxes
- Fix tests