Een cryptografische signature is een van de weinige dingen online die nog precies betekent wat er staat. Is de key van jou en verifieert de signature, dan komt de inhoud van jou. Punt. Geen vendor heeft je deze identiteit gegeven, geen CA kan hem intrekken, geen platform kan hem schorsen. Hij bestaat omdat jij de key hebt gegenereerd, en hij blijft van jou precies zolang jij de private helft in handen houdt. Het meeste wat we losjes “online identiteit” noemen is geleend: een handle die iemand kan bannen, een blauw vinkje dat iemand kan weghalen, een e-mailadres dat een domein-eigenaar terugeist op de dag dat het hem uitkomt. Een GPG-signature staat daar volledig buiten. De key die deze alinea heeft ondertekend is van jou of van iemand anders, en niemand krijgt daar een stem in.
Jarenlang was die eigenschap iets waar crypto-nerds om gaven en bijna niemand anders. Dat verandert nu, en snel. We konden vroeger aannemen dat de mens achter een mail of een commit of een voice-note ook echt een mens was, en waarschijnlijk de persoon die de headers beweerden. Die aanname valt uit elkaar. AI-gegenereerde tekst, stem en video worden alsmaar goedkoper en overtuigender, en het mentale default-model schuift op naar “kan iedereen zijn, kan niemand zijn.” De ruis zit al in mijn inbox: overtuigende PR-berichten die de stijl van een maintainer naapen, synthetische voice-calls die zich voordoen als een collega die om een gunst vraagt, complete sites vol plausibel proza in minuten opgehoest. Bewijzen dat jij die post schreef of die commit pushte houdt op gratis te zijn. Een signature is het ene ding in die stapel dat AI niet kan namaken zonder eerst jouw key te stelen.
Er zit een tweede druk op dezelfde setup, trager en veel verder weg. Als er ooit een grote genoeg quantumcomputer opduikt, wordt alles wat je ooit met klassieke public-key cryptografie versleutelde met terugwerkende kracht leesbaar. De naam hiervoor is harvest-now-decrypt-later, en van statelijke actoren wordt aangenomen dat ze het al doen. Ze pikken je versleutelde verkeer vandaag op en gaan erop zitten, met het plan om het over tien of twintig jaar te kraken zodra de hardware bestaat. De ciphertext die je al lekte krijg je niet terug, maar je kunt stoppen met de stapel groter maken, en dat betekent nu naar post-quantum encryptie grijpen, terwijl de tooling nog wat ruw is.
Dus dit is de vraag waar het mij echt om gaat: houdt de GPG-setup die je nu hebt over tien jaar nog stand? Attributie bijt al. Confidentialiteit op lange termijn bijt later. Een key die je vandaag genereert moet allebei overleven.
Deze post is de setup waar ik op uitkwam nadat ik op die vraag had zitten kauwen. Eén offline masterkey, drie identiteitsaliassen eraan gekoppeld, post-quantum encryptie via ML-KEM (Kyber), en drie onafhankelijke backup-lagen. Hij loopt lang, want elke keuze hier is een afweging en die redenering is het deel dat de moeite waard is. Nieuw met GPG? Lees dan eerst GPG uitgelegd. Vanaf hier ga ik ervanuit dat je ooit minstens één key hebt gegenereerd.
Wat we gaan bouwen
[Masterkey - Ed25519 - Certify only] ← offline, in een kluis, op papier
│
├── UID 1: Tom Herder <tom@byteherder.com>
├── UID 2: kapott <kapott@pm.me>
├── UID 3: Tom Meurs <tom.meurs@gmail.com>
│
├── [Sub 1 - Ed25519] [S] Sign → e-mail en git
├── [Sub 2 - ML-KEM+X448] [E] Encrypt → quantum-safe
└── [Sub 3 - Ed25519] [A] Auth → SSH login
Eén root, drie identiteiten, drie subkeys. Waarom het zo opdelen?
| Keuze | Reden |
|---|---|
| Masterkey = certify-only | De master ondertekent alleen andere keys en identiteiten. Nooit voor e-mail, nooit voor git. Houd hem offline en je identiteit overleeft elke laptop-diefstal. |
| Aparte subkeys voor Sign / Encrypt / Auth | Je kunt elke subkey los roteren of intrekken. Laptop gestolen? Subkeys revoken, identiteit behouden. |
| Meerdere UIDs op één key | Alle drie de aliassen zijn cryptografisch gebonden aan dezelfde master - bewijs dat ze van dezelfde persoon komen. |
| ML-KEM (Kyber) voor encryptie | Beschermt tegen harvest-now-decrypt-later. Wie jouw ciphertext vandaag opneemt kan die in 2046 niet ontsleutelen met een quantumcomputer. |
| Ed25519 voor signing en auth | Signatures hebben geen harvest-probleem - die worden op het moment van ondertekenen geverifieerd. Volledig post-quantum signing (ML-DSA) staat in RFC 9580, maar tooling-support is in 2026 nog dun (Thunderbird, GitHub, SSH-servers). Ed25519 is de pragmatische keuze. |
Eén afweging wil ik vooraf benoemen, voordat je een commando kopieert. Door kapott@pm.me en tom.meurs@gmail.com op dezelfde key te zetten maak je publiek aantoonbaar dat “kapott” en “Tom Meurs” dezelfde mens zijn. Prima als je attribution wilt over je aliassen heen. Echt gevaarlijk als kapott een pseudoniem moet blijven, want zodra die publieke key op een keyserver staat is de link permanent. Keyservers vergeten niet, en je kunt ze er niet om vragen. Heb je een echt pseudoniem nodig, geef het dan een eigen aparte key (scenario B verderop).
Prerequisites
Je hebt GnuPG 2.5 of later nodig. ML-KEM subkey-generatie bestaat niet in 2.4.
# Arch
sudo pacman -S gnupg paperkey qrencode zbar diceware pwgen veracrypt
# Debian/Ubuntu - activeer de officiële GnuPG-repo voor 2.5.x
curl -fsSL https://repos.gnupg.com/GPG-KEY-gnupg.asc \
| sudo tee /etc/apt/keyrings/gnupg.asc > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/gnupg.asc] https://repos.gnupg.com/debian bookworm main" \
| sudo tee /etc/apt/sources.list.d/gnupg.list
sudo apt update && sudo apt install -y gnupg2 paperkey qrencode zbar-tools veracrypt diceware pwgen
Verifieer:
gpg --version | head -2 # moet 2.5.x of later zijn
Genereer de keys op een schoon OS. Een Ubuntu live-USB of Tails is de paranoïde optie, en paranoia is hier de juiste stand: niets wat je dagelijkse laptop misschien stilletjes draait komt ooit in de buurt van de master. Werk in een aparte GNUPGHOME zodat hier niets van naar je bestaande keyring lekt:
mkdir -p ~/gpg-build && chmod 700 ~/gpg-build
export GNUPGHOME=~/gpg-build
GnuPG hardenen
Plaats een hardened config in $GNUPGHOME/gpg.conf vóór je iets genereert. Dit schakelt zwakke algoritmen uit en kiest moderne defaults:
cat > "$GNUPGHOME/gpg.conf" <<'EOF'
keyid-format 0xlong
with-fingerprint
with-subkey-fingerprint
list-options show-uid-validity
no-emit-version
no-comments
no-greeting
export-options export-minimal
personal-cipher-preferences AES256 AES192 AES
personal-digest-preferences SHA512 SHA384 SHA256
default-preference-list SHA512 SHA384 SHA256 AES256 AES192 AES ZLIB BZIP2 ZIP Uncompressed
weak-digest SHA1
disable-cipher-algo 3DES
disable-cipher-algo CAST5
disable-pubkey-algo RSA1024
require-cross-certification
no-symkey-cache
throw-keyids
keyserver hkps://keys.openpgp.org
EOF
chmod 600 "$GNUPGHOME"/gpg.conf
gpgconf --kill gpg-agent && gpgconf --launch gpg-agent
Een passphrase die je écht onthoudt
De passphrase is het laatste wat tussen een aanvaller en je master staat zodra hij een kopie van het encrypted bestand heeft. Hij moet offline bruteforce overleven door iemand met hardware die je niet kunt voorspellen. Gebruik Diceware: een willekeurige rij van zeven of meer woorden uit een grote lijst. Makkelijker in je hoofd te houden dan %Xh9$!Lq, en tegelijk sterker.
diceware -n 8 -d ' ' --no-caps
# schemerig koning fiets bramboes tunnel ijverig mosterd kraaier
Schrijf hem op papier en leg dat papier ergens fysiek op slot. Raak je de passphrase kwijt, dan verandert elke backup uit deze post in stortplaats-materiaal, geen uitzonderingen.
Masterkey aanmaken
We willen Ed25519, certify-only, tien jaar.
gpg --expert --full-generate-key
Antwoorden: 11 (ECC met eigen capabilities) → s toggle om Sign uit te zetten (alleen Certify blijft over) → q → 1 (Curve 25519) → 10y → je primaire UID (ik gebruik mijn echte naam + echte adres). GPG vraagt twee keer om de passphrase en dan is hij klaar.
Leg de fingerprint meteen vast zodat de rest van de post $KEYID kan gebruiken:
export KEYID=$(gpg --list-secret-keys --with-colons | awk -F: '/^fpr/ {print $10; exit}')
echo "$KEYID" > ~/gpg-build/KEY_INFO.txt
UIDs toevoegen voor elk alias
gpg --expert --edit-key "$KEYID"
In de editor:
gpg> adduid # Tom Herder <tom@byteherder.com>
gpg> adduid # kapott <kapott@pm.me>
gpg> uid 1 # kies je primaire
gpg> primary
gpg> save
Elke UID is nu getekend door dezelfde master, en dat is het cryptografische bewijs dat ze bij één persoon horen.
Subkeys toevoegen
Nog steeds in --edit-key:
Signing-subkey (Ed25519): addkey → 10 (ECC sign only) → 1 → 2y.
Encryption-subkey - de post-quantum variant: addkey → 16 (ECC and Kyber) → 4 (Kyber 1024 + X448) → 2y.
Dit is het hybride stuk, en meteen de hele reden voor GnuPG 2.5. De subkey last ML-KEM-1024 (NIST FIPS 203, quantum-safe) aan X448 (klassiek ECC) vast. Om je ciphertext te lezen moet een aanvaller beide breken. Dus je blijft gedekt wat er ook eerst valt: klassieke crypto die bezwijkt voor een quantumcomputer, of een nare verrassing die opduikt in ML-KEM zelf. Met opzet dubbel beveiligd.
Authentication-subkey (Ed25519): addkey → 11 (ECC custom) → s uit en a aan → q → 1 → 2y → save.
Verifieer met gpg --list-secret-keys --with-subkey-fingerprint. Je zou [C], [S], [E], [A] markers moeten zien bij respectievelijk master, sign, encrypt, auth.
Genereer meteen, nu je hier toch bent, een revocation certificate. Zie het als de nucleaire knop voor de dag dat de masterkey compromised raakt:
gpg --output "$GNUPGHOME/revocation-$KEYID.asc" --gen-revoke "$KEYID"
De master offline halen
Hier komt de stap die de rest van dit verhaal de moeite waard maakt. Exporteer alles, wis het master-secret uit de werkkeyring, en importeer dan alleen de subkey-secrets terug.
cd "$GNUPGHOME"
gpg --export-secret-keys --armor --output MASTER-FULL.asc "$KEYID"
gpg --export-secret-subkeys --armor --output SUBKEYS-ONLY.asc "$KEYID"
gpg --export --armor --output PUBLIC.asc "$KEYID"
gpg --export-ownertrust > OWNERTRUST.txt
gpg --delete-secret-keys "$KEYID"
gpg --import SUBKEYS-ONLY.asc
gpg --import-ownertrust OWNERTRUST.txt
Controleer het resultaat:
gpg --list-secret-keys --with-subkey-fingerprint
# sec# ed25519/0x... [C] ← de # betekent "master-secret niet aanwezig"
# ssb ed25519/... [S]
# ssb ky1024_cv448/.. [E]
# ssb ed25519/... [A]
Die # is waar we voor kwamen. Je dagelijkse laptop draagt nu niets meer dan vervangbare subkeys, dus ze revoken na een diefstal kost je een paar minuten in plaats van je identiteit.
Drie backup-lagen
Eén backup is geen backup. Dus draai ik drie onafhankelijke paden, en elk gaat ervanuit dat de andere twee al gefaald zijn op het moment dat ik ernaar grijp.
Hot - VeraCrypt-volume bij meerdere clouds. Altijd bereikbaar, overleeft een verloren laptop.
veracrypt --text --create cloud-backup/gpg-vault.vc \
--volume-type=normal --size=128M \
--encryption=AES-Twofish-Serpent --hash=Whirlpool \
--filesystem=FAT --pim=0 --keyfiles="" \
--random-source=/dev/urandom
sudo veracrypt --text --mount cloud-backup/gpg-vault.vc /tmp/vault --pim=0 --keyfiles=""
sudo cp MASTER-FULL.asc SUBKEYS-ONLY.asc PUBLIC.asc OWNERTRUST.txt \
revocation-$KEYID.asc KEY_INFO.txt /tmp/vault/
sync && sudo veracrypt --text --dismount /tmp/vault
rclone copy cloud-backup/gpg-vault.vc gdrive:SecureBackups/
rclone copy cloud-backup/gpg-vault.vc proton:SecureBackups/
Geef het VeraCrypt-volume een andere passphrase dan je GPG-key, zodat één lek niet de ander omver trekt. De AES-Twofish-Serpent cascade met een Argon2-afgeleide key is ruim post-quantum prima: Grover halveert de effectieve symmetrische sleutellengte, en je loopt nog steeds weg met zo’n 128 bits marge.
Cold - paperkey + QR-codes. Overleeft cloud-uitval en account-bans.
Paperkey haalt de redundante structuur uit een secret key en houdt alleen de bytes over die er echt toe doen, precies wat je op archiefpapier wilt. Ed25519 kan het netjes aan. Kyber nog niet, want dat is te nieuw en er is nog geen compacte encoding voor, dus de master gaat via paperkey terwijl de volledige armored export via QR-codes gaat, verdeeld over meerdere PNG’s met hoge foutcorrectie.
# Paperkey voor de master
paperkey --secret-key <(gpg --export-secret-keys "$KEYID") \
--output master.paperkey.txt
# QR-stapel voor de volledige bundle
split -b 1500 -d -a 2 MASTER-FULL.asc part_
i=1; total=$(ls part_* | wc -l)
for f in part_*; do
qrencode -l H -s 10 -m 4 \
-o "qr-$(printf '%02d' $i)-of-$(printf '%02d' $total).png" < "$f"
i=$((i+1))
done
Test je restore voordat je erop vertrouwt:
for f in qr-*.png; do zbarimg --raw --quiet "$f" >> combined.asc; done
diff combined.asc MASTER-FULL.asc && echo "restore werkt"
Print op archiefpapier met een laserprinter, want inkjet-inkt vervaagt binnen een decennium en het hele punt is om dat te overleven. Leg de stapel in een brandwerende kluis, of verdeel ze over twee locaties als je grondig wilt zijn.
Hardware - YubiKey (optioneel). Dit dekt het vervelende scenario waarin je backups lekken maar de fysieke token nog in je broekzak zit. In 2026 doet YubiKey-firmware nog geen PQC-subkeys, dus alleen de Ed25519 sign- en auth-subkeys gaan op de token terwijl de Kyber-encrypt-subkey in software blijft. Yubico’s roadmap zet PQC voorzichtig op firmware 6 in 2027, dus dit gat zou moeten dichten.
Per-werkgever-identiteiten
Klant- en werkgeverwerk geeft je twee scenario’s, en die keuze maak je beter bewust dan per ongeluk.
Scenario A - UID toevoegen aan bestaande masterkey. Eenvoudig, en het bewijst cryptografisch dat dezelfde persoon achter al je identiteiten staat. De adder onder het gras is dat elke collega die je werkgever-publickey importeert meteen een volledige lijst van je privé-aliassen krijgt. Prima voor tom@byteherder.com, dat toch al mijn publieke identiteit is. Een echt probleem voor kapott@pm.me.
Scenario B - aparte key per werkgever. Eén key extra om op te passen, maar de scheiding is schoon. Je kunt hem alsnog cross-signen met je hoofdmaster wanneer je de attribution wilt, en doe je dat niet, dan blijven de identiteiten cryptografisch niet-verbonden. Dit is mijn default zodra privacy-per-context echt telt.
export GNUPGHOME=~/gpg-dsm
mkdir -p "$GNUPGHOME" && chmod 700 "$GNUPGHOME"
gpg --expert --full-generate-key # herhaal de §6–§8 flow
Houd per identiteit een eigen VeraCrypt-volume aan (dsm-vault.vc, klantX-vault.vc). Dezelfde drie-lagen-backup als eerder, alleen met de blast radius per klant afgeschermd.
Dagelijks gebruik
Publiceer de publieke sleutel. Keys.openpgp.org laat je elke UID per e-mail verifiëren voordat het iets publiceert, wat meteen een prettige sanity-check is dat je de adressen goed hebt getypt:
gpg --keyserver hkps://keys.openpgp.org --send-keys "$KEYID"
Git signing. Pin je commits op de signing-subkey. Die ! op het eind is wat GnuPG dwingt om déze specifieke subkey te gebruiken in plaats van er zelf een te kiezen:
SIGNKEY=$(gpg --list-secret-keys --with-colons "$KEYID" \
| awk -F: '/^ssb/ && $12~/s/ {print $5; exit}')
git config --global user.signingkey "$SIGNKEY!"
git config --global commit.gpgsign true
git config --global tag.gpgsign true
Per-repo overrides laten je werkgever-commits met de werkgever-key signen:
git config user.email tom.meurs@dsm.com
git config user.signingkey "DSM_SIGNKEY!"
SSH via gpg-agent. Je auth-subkey wordt je SSH-key:
gpg --list-secret-keys --with-keygrip "$KEYID" # noteer de keygrip van de A-subkey
echo "<KEYGRIP>" >> ~/.gnupg/sshcontrol
# In je shell rc
export GPG_TTY=$(tty)
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent
ssh-add -L # plak deze regel in GitHub → SSH keys
E-mail. Zodra alle drie de adressen naar dezelfde master key wijzen, matcht Thunderbird de UID vanzelf op je From:-header. Mutt doet hetzelfde zodra je pgp_default_key = $KEYID zet.
Rotatie
Elke achttien maanden, ruim voordat de twee-jaars-expiry van de subkeys toeslaat, haal ik de master een paar minuten terug en schuif ik de expiry weer naar voren. Het is dezelfde VeraCrypt-mount-dans als bij de backups:
sudo veracrypt --text --mount ~/gpg-build/cloud-backup/gpg-vault.vc /tmp/vault
export GNUPGHOME=$(mktemp -d) && chmod 700 "$GNUPGHOME"
gpg --import /tmp/vault/MASTER-FULL.asc
gpg --expert --edit-key "$KEYID"
# key 1, key 2, key 3 → expire → 2y → save
gpg --export-secret-subkeys --armor "$KEYID" > ~/SUBKEYS-NEW.asc
rm -rf "$GNUPGHOME" && unset GNUPGHOME
sudo veracrypt --text --dismount /tmp/vault
GNUPGHOME=~/.gnupg gpg --import ~/SUBKEYS-NEW.asc
gpg --keyserver hkps://keys.openpgp.org --send-keys "$KEYID"
Lekt een subkey ooit, dan is het dezelfde flow met één stap extra: revkey op de gecompromitteerde subkey, exporteer, publiceer. De master is nooit verplaatst, dus je identiteit blijft intact. Dit is de uitbetaling voor al dat ritueel.
Het bredere principe
Niks aan dit alles is minimaal, en ik ga niet doen alsof. Zeven Diceware-woorden, drie backup-lagen, een terugkerend ritueel, een paar USB-sticks die in verschillende laden wonen. Je zou het hele ding kunnen overslaan, je commits signen met de eerste de beste SaaS “identity service,” en nooit meer een woord over keyservers hoeven lezen.
De adder is dat een SaaS-identiteit van de provider is, niet van jou. Die kan hem intrekken, kwijtraken bij een incident, gedwongen worden hem af te staan na een bevel, en op de dag dat ze hun businessmodel omgooien migreer je op hun klok in plaats van die van jou. Ik ben deze hele controle-versus-gemak-vraag in Sovereign Infrastructure ingedoken. De root bezitten gaat niet om een paar euro per maand uitsparen. Het gaat om weigeren afhankelijk te zijn van een systeem dat ik niet kan openmaken en inspecteren.
Attributie is datzelfde argument, alleen bijt het nu al. Wanneer tekst en stem en video allemaal overtuigend te faken zijn op hardware die iedereen kan kopen, wordt de eerlijke default voor elk bericht “kan iedereen zijn.” Je commits signen weerhoudt niemand ervan rotzooi in jouw naam uit te poepen. Wat het wél doet, is iedereen die het wil weten een manier geven om het verschil te checken, en die check houdt stand ook als de vervalsing verder perfect is. Het mooie is dat dat anker alleen werkt als het er al staat, dus de zet is om nu te beginnen met signen en het klaar te hebben liggen.
Quantum-safety is datzelfde argument, uitgerekt over decennia. Waar ik me tegen verdedig is niet een quantumcomputer die volgende dinsdag mijn RSA kraakt. Het is een geduldige tegenstander die vandaag stilletjes mijn encrypted verkeer opneemt en gokt dat de hardware later opduikt. De enige tegenzet is stoppen met ze ciphertext voeren die straks goedkoop te kraken is, en dat betekent nu naar post-quantum encryptie grijpen, ruwe tooling en al.
Een key die ik vandaag genereer moet over twintig jaar nog standhouden. Dat is de lat die ik leg, en alles hierboven is wat nodig was om daar overheen te komen met commodity tools, in de openbaarheid, zonder mijn vertrouwen aan iemand anders dan mezelf te geven.
