4.12

Dovecot Server Encrypted Storage

Image
Using server-side email messages encryption with Dovecot IMAP4 server

How to setup encrypted storage for Dovecot IMAP4 server

This article presents a working scenario tested under several production servers. It has been tested and works out-of-the-box.


Using the Mail crypt plugin to secure email messages stored in a Dovecot mailstore.

In order to protect users privacy and security it is good idea to encrypt the local mailstore of Dovecot IMAP4 server using the Dovecot's built-in mail-crypt plugin.
This article covers the setup of Dovecot IMAP4 server for Linux and OpenBSD operating systems.
All the below setup and operations must use the root system account.

The first step is to create a keypair (private and public) to be used by the encryption.
In this sample the prime256v1 ECC prime is used. It is a reasonable choice as security vs speed.
There are other primes that can be chosen here such as: brainpoolP512r1, secp224r1, secp160r2.
$ openssl ecparam -name prime256v1 -genkey | openssl pkey -out enc.key
$ openssl pkey -in enc.key -pubout -out enc.pub
$ ls
enc.key enc.pub
The private key used for decrypting the stored email messages. The public key used for encrypting the stored email messages.
Move the both keys to this directory /etc/dovecot/keys/. If the directory does not exists, create it. Be sure to chown/chmod the key pair files to be readable just by dovecot. It is a good idea to make them read-only 0440 or even more ... as immutable by changing chflags to uchg.

(c) 2022 w3soft.org, license: GPLv3 learning resources for software development and operating systems administration configuration Dovecot IMAP4 Server dovecot conf
The second step is to add the configuration to the dovecot.conf usually found in the /etc/dovecot/ directory
Edit the /etc/dovecot/dovecot.conf file and add the mail_crypt to the list of plugins and after add some settings at the end of the plugin area (as below):

## previous settings ; example
#mail_plugins = quota
## new settings (add `mail_crypt`) ; example
mail_plugins = quota mail_crypt


plugin {

	## ... existing previous settings above ...

	## the settings required by the mail crypt plugin
	mail_crypt_curve = prime256v1
	mail_crypt_global_private_key = </etc/dovecot/keys/enc.key
	mail_crypt_global_public_key  = </etc/dovecot/keys/enc.pub
	mail_crypt_save_version = 2

}


The third (final) step is to restart Dovecot server and check status
Linux: systemd
$ sudo service dovecot restart
$ sudo service dovecot status
● dovecot.service - Dovecot IMAP4 server
     Loaded: loaded (/lib/systemd/system/dovecot.service; enabled; vendor preset: enabled)
     Active: active (running)
OpenBSD: rc.d
$ doas rcctl restart dovecot
dovecot(ok)
dovecot(ok)
$ doas rcctl ls started | grep dovecot
dovecot

Final considerations: Important

DISCLAIMER for this article

  • the method in this article was tested to work with Dovecot 2.3 ; it may not work as expected with other Dovecot versions
  • the w3soft.org is not responsible for any data loss or other issues (includding security) regarding the usage of the encrypted storage with Dovecot like explained in this article
  • as found in the Dovecot's 2.3 documentation the default encrypt/decrypt algo aes-256-gcm-sha256 has been used in this article, below

The existing email messages already stored by Dovecot server (if any) will not be encrypted automatically after using the above setup and restart.
All the existing email messages stored before restarting Dovecot at the third step have to be manually encrypted or can leave as unencrypted. See below a sample script how to encrypt them.

The encrypted storage of Dovecot can be reverted by rolling back the above settings and decrypting all the messages back to the plain format.
To decrypt existing encrypted messages you can use by running in a shell (example):
doveadm fs get crypt algo=aes-256-gcm-sha256:private_key_path=/etc/dovecot/keys/enc.key:public_key_path=/etc/dovecot/keys/enc.pub:posix:prefix=/tmp/messages/encrypted/ /tmp/messages/encrypted/cur/test-message.email > /tmp/messages/plain/cur/test-message.email

(c) 2022 w3soft.org, license: BSD learning resources for software development and operating systems administration configuration Unix / Linux Shell: Bash, Ksh shell script
Sample shell script to manually encrypt existing email messages if any.
Before running this script the Dovecot server needs to be stopped.
This script is optional as Dovecot can still read existing plain messages and only new created messages will be encrypted.
If you wish to have also the existing Dovecot's messages encrypted you can use the following script (read carefully all the instructions in the script header below).
#!/bin/sh

#######
# (c) 2022 w3soft.org
# License: BSD
#
# Purpose of this script: Encrypt and Check the encrypted email messages with Dovecot's mail-crypt plugin
# This sample script is not intended to encrypt email messages in-place in order to prevent data loss
# This sample script is intended to be run over a fresh copy of the Dovecot's plain maildir storage folder and write them to a new destination (a new empty created folder)
#
# Before runnig this script read carefully the Dovecot Documentation available at:
#	https://doc.dovecot.org/developer_manual/design/dcrypt/
#	https://doc.dovecot.org/configuration_manual/mail_crypt_plugin/
#
# BE SURE TO ARCHIVE ALL DOVECOT'S DATA BEFORE RUNNING THIS SCRIPT TO BE ABLE TO RESTORE IF ANYTHING GOES WRONG
#
# !!! IMPORTANT to avoid loose of data !!!
# Use below your own keys pair (as generated above): THE_ENC_PRIV_KEY ; THE_ENC_PUBL_KEY
# Adjust all the bellow settings to match your system !
#
# This script have to be run once for each email account and for each Dovecot folder under each account.
# Example (Inbox), for user 1:
# THE_USER="myuser1@mydomain.ext" : THE_DIR="cur" ; THE_DIR="new" ; THE_DIR="tmp"
# Example (Sent), for user 2:
# THE_USER="myuser2@mydomain.ext" , THE_DIR=".Sent/cur" ; THE_DIR=".Sent/new" ; THE_DIR=".Sent/tmp"
#
# Before running this script first time you need to backup all Dovecot's data and adjust:
# THE_PATH : absolute full path to an existing copy/mirror of the original Dovecot's folder containing all the Dovecot's existing plain messages
# do not use the original Dovecot folder ; make a copy of it and also an archive of it prior to run this script to prevent data loss !
# THE_MAILDIR : absolute full path to an existing empty folder where to store the encrypted messages after procesing
# do not use the original Dovecot folder ; use another one for safety !
#
# Before running this script each time, for each combination of THE_USER / THE_DIR as found in THE_PATH, you need to adjust:
# THE_USER : email account such as "myuser@mydomain.ext" or "myuser" ... it depends how Dovecot storage was set ... look at that folder
# THE_DIR : reative path of the maildir (existing) folder under the Dovecot storage folder
#
# At the final after running this script over all existing email accounts and sub-folders:
# 1. keep the archive with the original Dovecot's plain messages for a while until you ensure everything was converted successfuly to the encrypted format
# 2. do a directory compare to ensure that all the plain files from THE_PATH were encrypted and they are present in THE_MAILDIR
# 3. replace the content of the original Dovecot's maildir with the new encrypted content from the THE_MAILDIR
# 4. Fix the chown recursive as _dovecot:_dovecot or dovecot:dovecot (depends on the system) over the Dovecot's maildir
# 5. Restart Dovecot
# 6. Test if you can read existing messages and everything works as expected ; check dovecot's log files
# 7. If anything works unexpected or there are errors when running this script or other errors after restarting Dovecot:
# 	* TRY TO ADJUST IT TO MATCH YOUR SYSTEM AND RUN AGAIN
# 	OR
# 	* ROLL-BACK ALL CONFIGURATIONS CHANGED AS ABOVE AND ROLL-BACK ALL YOUR DOVECOT DATA FROM THE ARCHIVE
#######

THE_PATH="/tmp/dovecot-old-plain-dir-copy"
THE_MAILDIR="/tmp/dovecot-new-encrypted-dir/"

THE_USER="myuser@mydomain.ext"

#THE_DIR=".Sent/cur"
#THE_DIR=".Trash/cur"
THE_DIR="cur"

THE_ENC_PRIV_KEY=/etc/dovecot/keys/enc.key
THE_ENC_PUBL_KEY=/etc/dovecot/keys/enc.pub

###

THE_SOURCE_PATH="${THE_PATH}/${THE_USER}/${THE_DIR}"
THE_DEST_PATH="${THE_MAILDIR}${THE_USER}/${THE_DIR}"

if [ ! -d ${THE_SOURCE_PATH} ]; then
    echo "ERR: Source Dir not found: ${THE_SOURCE_PATH}"
    exit 1
fi

if [ ! -d ${THE_DEST_PATH} ]; then
    echo "ERR: Dest Dir not found: ${THE_DEST_PATH}"
    exit 2
fi

echo "Processing: ${THE_SOURCE_PATH}/"
THE_FILES=`ls -A "${THE_SOURCE_PATH}"`
for mailmessage in $THE_FILES; do
    if [ -f "${THE_DEST_PATH}/${mailmessage}" ]; then
        echo "Encrypting Message: ${THE_DEST_PATH}/${mailmessage}"
    doveadm fs put crypt algo=aes-256-gcm-sha256:private_key_path=${THE_ENC_PRIV_KEY}:public_key_path=${THE_ENC_PUBL_KEY}:posix:prefix=${THE_DEST_PATH}/ ${THE_SOURCE_PATH}/${mailmessage} ${mailmessage}
    else
        echo "ERR: Failed to Encrypt Message: ${mailmessage}"
        exit 3
    fi
done

echo "[ Done: ${THE_SOURCE_PATH}/ ]"

# END