Generate DKIM key pairs in Python
DKIM key pairs are simply RSA key pairs and you can easily generate them in Python.
Published: 15 Sep, 2024
DKIM key pairs are simply RSA key pairs and you can easily generate them in Python.
First, install the cryptography library. Then generate the key like so:
from cryptography.hazmat.primitives.asymmetric import rsa
p_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
I’m no cryptography expert, so I relied on experts to determine the public exponent parameter. Key size is self explanatory and recommended to be 2048 as of the year 2024 to provide adequate security against brute force attacks.
Derive the public key
A DKIM TXT record typically looks like this:
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCY8mz7LEL32wDEtrvZfLvkMM+/UNpbxF2ZUSc2WTyJGGgHHXhoZXPtQCQ9NIJ0CT0sD/fZbSCPkNEP1juwodDnXRg1mGiUNaekj6VC+v5lygDG29BvrLk16etbGkr8+D0vKCzjQzCiTSkT74zIx9ezEc1uGVSFNhheAE7EJC4kDQIDAQAB
The actual public key is after the p= part. It’s in an encoded format called DER and then encoded again as Base64 in order to make it portable.
Export the DER encoded public key like so:
import base64
from cryptography.hazmat.primitives import serialization
pub_key = p_key.public_key().public_bytes(
encoding=serialization.Encoding.DER,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
pub_key_string = base64.b64encode(pub_key).decode("utf-8")
Encode the private key
The private key itself is currently in raw bytes. You can simply write the bytes to a file and load it whenever you want. However, tools like Rspamd, which is typically used to verify DKIM keys when emails are received, expect the key to be in a format called PEM. That’s why you should store the key as PEM instead if you want the key to be useable by various third-party tools.
Export the PEM key as follows:
pem_pkey = p_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
pem_pkey_string = pem_pkey.decode("utf-8")
Then you can write it to a file:
with Path("myfile").open('w', encoding="utf-8") as fp:
fp.write(pem_pkey_string)