DKIM may be called as PGP successor: PGP has been used by many people for signing their emails at a time when mostly technical related people had been using the internet. Today, few people still use PGP to sign their emails, but email servers took over this part using a technology called DKIM.
PGP proved that the signing person's identity, but DKIM only ensures, that the email has been send through a mailserver which is authorized for this domain, but both sign emails and both are commonly used nowadays. They're more like distant relatives than siblings and PGP isn't dead, but in the end both of them sign emails.
DKIM may be set up within a mailserver - if it's under your control - but also added by an application sending emails. Actually, it takes only 3 simple steps to sign your mails:
1. Create a pair of keys
OpenSSL is included with most default Linux installations and could be easily installed using the distributions package manager. A new private key usable for adding DKIM signatures could be easily created:
sebastian@pc:~$ openssl genrsa -out dkim.key 1024
Generating RSA private key, 1024 bit long modulus
e is 65537 (0x10001)
The new private key file dkim.key should be kept strictly secret and never published on the internet. It's required to add the signature to your mails, but the recipients (or receiving mailservers or spam filters) require a public key to validate the signature. The public key will be build out of the private key:
sebastian@pc:~$ openssl rsa -in dkim.key -out dkim.pub -pubout -outform PEM
writing RSA key
The two key files should look like this:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
Remember: Never publish your private key. I published this sample, because it has been created solely for this blog post and won't ever be used anywhere.
You might want to backup a copy of the private key file at a secret place as it's required for signing mails and can't be recovered once it's lost.
2. Create the DNS TXT records
The receiver needs your public key to verify the signature. Sending it with the email would be unsafe, because anybody would be able to send any public key and DKIM wouldn't proof anything. But there is something easily accessible for everyone which is clearly under control of the domain owner: The domain's name server.
You need to be able to add two additional entries to your domain nameserver zone:
_domainkey IN TXT "o=~;"
dkim._domainkey IN TXT "k=rsa\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSarYO5FDA1L9XUhI8XESATRXrnYbOP8wXkJ9jC+UR909UCiQd37m8Nga/fxZko6hcqIMiR41oy1ozmKLeQugwT+JeG2AgIhP8dVcf9m2MXKepoPqZ3LF+G28+tYamBYKmZOzpqgMw96/VVS9aNzhTDFYjBp59lvEPgIrzaB4ItwIDAQAB\;"
The second entry has two configurable parts: The selector which is in front of the ._domainkey suffix. I used dkim for this sample, but anything containing a-z, 0-9 and - is ok. Each domain may have an (nearly) unlimited number of different selectors and each selector may publish it's own public key.
The second part is shown between the p= and the final \;". It's the public key from the dkim.pub file created in step one without any spaces and line breaks. It's build by simply removing the header -----BEGIN PUBLIC KEY-----, footer -----END PUBLIC KEY-----, line breaks, spaces from the dkim.pub file.
Some more options are allowed by the DKIM specification, see RFC 6376 section 3.6.1 for details.
3. Sign a mail
CPAN has Mail::DKIM::Signer which does most of the work. The installation should be straightforward using any CPAN client, but many Linux distributions also have packages for the module.
First, load the module and create a signer object:
my $dkim = Mail::DKIM::Signer->new(
Algorithm => "rsa-sha1",
Method => "relaxed",
Domain => $fromdomain, # Part following the @ within the from-address sending the email
Selector => "dkim", # Selector as configured in DNS
KeyFile => "/path/to/your/private/dkim.key",
If you're sending your mails from email@example.com, set $fromdomain to domain.tld (or add a static value using single quotes if you want). The Selector needs to be exactly the same value as in step 2 and the KeyFile must contain the name of your private key file including the full path. Don't put this file into any web-accessible directory or at least deny every access to this file using a .htaccess file rule.
Next, create your email including the header lines which will not change during transmission. A good choice would be
- From (required by DKIM specification)
Do not include header files which will grow or change while the email is traveling through the internet, like Received. Including them will invalidate your signature! Now push everything into the DKIM signer:
$dkim->PRINT($header . "\r\n" . $body);
print "DKIM Signature failed: $@" if $@;
You may use as much ->PRINT calls as you like but only one ->CLOSE which tells the signer that the message is complete.
Finally get the signature header line and append it to your header:
$header .= $dkim->signature->as_string."\r\n";
Now add any more header fields that shouldn't be signed and simply send the message.
Don't forget to send a test message to yourself first. You should see your signature in the email header and there are many plugins for many email clients to validate the DKIM signature, like DKIM Verifier for Thunderbird.