Files
exim-encrypt-dlfunc/README.md
2021-09-13 16:47:56 +02:00

199 lines
7.7 KiB
Markdown

# exim-encrypt-dlfunc
This library injects functions for string encryption and decryption into [exim4](https://www.exim.org/). It is basically
glue code that exports certain parts of the [libsodium library](https://github.com/jedisct1/libsodium) to exim at runtime.
[[_TOC_]]
## Installation
These instructions are currently only tested on [Debian](https://www.debian.org) and
[Ubuntu](https://ubuntu.com).
1. Install development tools and libsodium development files:
```shell
apt-get install -y build-essential exim4-dev libsodium-dev meson pkg-config openssl exim4-daemon-heavy
```
This project uses [meson](https://mesonbuild.com/) (and [ninja](https://ninja-build.org/)) as build system. To ensure
all features are present (which are lacking in the packaged versions of older distributions)
you are strongly advised to install from [pypi](https://pypi.org/) via [pip](https://pypi.org/project/pip/):
```shell
apt-get install -y python3-pip
pip3 install -U meson ninja
```
You may alternatively try to use your distribution packages:
```shell
apt-get install -y meson
```
2. Clone this repository:
```shell
git clone https://git.scc.kit.edu/mail/exim-encrypt-dlfunc.git
cd exim-encrypt-dlfunc
```
3. Build and test everything:
```shell
meson build # run only once
meson compile -C build
meson test -C build
```
The `ci_container` directory contains a [script](ci_container/build.sh) (and a [short README](ci_container/README.md))
which creates the container images used in continuous integration for this project.
5. Install library and tools (defaults to `/usr/local/bin` and `/usr/local/lib/x86_64-linux-gnu`):
```shell
meson install -C build
```
6. Ensure you have the correct exim build:
Not every build of exim is able to load libraries at runtime. Please refer to the
[documentation](https://www.exim.org/exim-html-current/doc/html/spec_html/ch-string_expansions.html)
of the `${dlfunc{…}}` function for details. The Debian
package [`exim4-daemon-heavy`](https://packages.debian.org/exim4-daemon-heavy)
meets these requirements.
Try
```shell
exim4 --version | egrep -i --color 'Expand_dlfunc|Content_Scanning'
```
for a preliminary test.
7. Configure exim to use the new functionality
This highly depends on your use case. See [the example below](#xoip-example) and
[`src/test_libexim-encrypt-dlfunc.sh`](src/test_libexim-encrypt-dlfunc.sh).
## Usage
There are currently two sets of complementary function pairs:
### Symmetric encryption that derives the key from an ASCII string (aka a “password”)
* `sodium_crypto_secretbox_encrypt_password(password, cleartext) → ciphertext`
* `sodium_crypto_secretbox_decrypt_password(password, ciphertext) → cleartext`
The generated key is only as strong as the provided password. Use `openssl rand --base64 48 | tr -d =`
to get a passable password.
### Public key encryption that uses a key pair which needs to be created beforehand
* `sodium_crypto_box_seal(public key, cleartext) → ciphertext`
* `sodium_crypto_box_seal_open(private key, public key, ciphertext) → cleartext`
The second pair needs a matching key pair in the correct format. This is what the
`libexim-encrypt-dlfunc-genkeys` utility is for. Simply run it once to generate a pair in the current directory. Be
aware that every invocation will overwrite the previous key pair file without confirmation! Make sure to store your
production keys in a safe place!
```shell
$ libexim-encrypt-dlfunc-genkeys
=== Creating cryptobox key pair ===
Wrote »cryptobox_recipient_pk_exim.conf«
Wrote »cryptobox_recipient_pk.raw«
Wrote »cryptobox_recipient_sk_exim.conf«
Wrote »cryptobox_recipient_sk.raw
```
The `*_exim.conf` files contain the keys in a format that can simply be used in
`exim.conf` (the first line contains the key as a C code comment and can usually be ignored or discarded):
```shell
$ cat cryptobox_recipient_pk_exim.conf
# const unsigned char cryptobox_recipient_pk[32] = { 0xda, 0x46, 0xc8, 0x75, 0x2b, 0x31, 0xd9, 0x0c, 0x83, 0x54, 0x2d,
# 0x18, 0xda, 0xdc, 0xe5, 0x2d, 0x0e, 0x10, 0xe8, 0x0c, 0x39, 0xde, 0xaf, 0x30, 0x7e, 0xab, 0xca, 0x4d, 0xed, 0x26,
# 0x4d, 0x6e }; const unsigned int cryptobox_recipient_pk_length = 32;
CRYPTOBOX_RECIPIENT_PK=2kbIdSsx2QyDVC0Y2tzlLQ4Q6Aw53q8wfqvKTe0mTW4=
```
The `*.raw` files contain the same key without any formatting; these files are not needed for usage with exim but are
generated as convenience when writing your own tools.
### Example: remove `X-Originating-IP:` header
<a name="xoip-example"></a>
This task was the initial reason to develop this library: remove the X-Originating-IP header to preserve our user's
privacy but also keep the information in the final e-mail to enable response to complaints and abuse (the original
header is usually provided in these cases). Add this snippet to your DATA ACL section in exim:
```
warn log_message = Removing X-Originating-IP: header
condition = ${if def:h_X-originating-IP: {1}{0}}
add_header = X-Orig-IP-PKK: ${dlfunc{/usr/lib/x86_64-linux-gnu/libexim-encrypt-dlfunc.so} \
{sodium_crypto_box_seal} \
{ktp1OEEItrgvSfpVTtu+ybyNjzuuN8OzCdfrGAJt4j8=} \
{$h_X-originating-IP:}}
add_header = X-Orig-IP-Pass: ${dlfunc{/usr/lib/x86_64-linux-gnu/libexim-encrypt-dlfunc.so} \
{sodium_crypto_secretbox_encrypt_password} \
{Insert your password here} \
{$h_X-originating-IP:}}
remove_header = X-Originating-IP
```
Pick one of the `add_header` lines depending on which kind of encryption you want.
### Decryption Tools
Two additional programs are included:
* `libexim-encrypt-dlfunc-decrypt-secretbox`
* `libexim-encrypt-dlfunc-decrypt-sealedbox`
They can decrypt strings that were encrypted by the two respective functions. Please refer to their `--help` message
(reproduced below) for usage information and to both [test](src/test_libexim-encrypt-dlfunc-decrypt-secretbox.sh)
[scripts](src/test_libexim-encrypt-dlfunc-decrypt-sealedbox.sh) for usage examples.
```shell
$ libexim-encrypt-dlfunc-decrypt-secretbox -h
Usage: libexim-encrypt-dlfunc-decrypt-secretbox [OPTIONS] [CIPHERTEXT]
Password:
-p, --password PASSWORD Decrypt using PASSWORD
If the environment variable LIBEXIM_PASSWORD is set the password is read from there.
Setting a password with -p/--password overwrites this mechanism.
Select input:
-f, --infile FILE Decrypt contents of the first line of file FILE (use - for stdin)
Output:
-n, --no-newline Do not append a newline to the output
Password and ciphertext are expected to be base64-encoded (as produced by the library).
```
```shell
$ libexim-encrypt-dlfunc-decrypt-sealedbox -h
Usage: libexim-encrypt-dlfunc-decrypt-sealedbox [OPTIONS] [CIPHERTEXT]
Secret and public key:
-s, --secret-key SECRETKEY Secret key (base64-encoded)
-p, --public-key PUBLICKEY Public key (base64-encoded)
-S, --secret-key-file FILE Read secret key (raw) from file FILE (use - for stdin)
-P, --public-key-file FILE Read public key (raw) from file FILE (use - for stdin)
The environment variables LIBEXIM_SECRETKEY and LIBEXIM_PUBLICKEY may contain base64-encoded secret/public keys.
Select input:
-f, --infile FILE Decrypt contents of the first line of file FILE (use - for stdin)
Output:
-n, --no-newline Do not append a newline to the output
Keys in arguments and environment variables are expected to be base64 encoded (as produced by the library).
Keys in files need to be raw bytes with no encoding, ciphertext should always be base64-encoded.
```