Een cryptografische signature is een van de weinige dingen online die precies betekent wat er staat. Is de key van jou en verifieert de signature, dan komt de inhoud van jou. Geen vendor geeft deze identiteit uit, geen CA kan hem intrekken, geen platform kan hem schorsen. Hij bestaat omdat jij de key hebt gegenereerd, en hij blijft van jou zolang jij de private helft beheert. Het meeste wat we “online identiteit” noemen is geleend van iemand anders: een handle die gebanned kan worden, een blauw vinkje dat weggehaald kan worden, een e-mailadres dat een domein-eigenaar kan terugeisen. Een GPG-signature staat daarbuiten. Óf de key die deze alinea heeft ondertekend is van jou, óf niet, en niemand anders mag daarover beslissen.
Die eigenschap was ooit een niche-zorg. Hij wordt een dagelijkse. Het was ooit redelijk om aan te nemen dat de persoon achter een mail, een commit of een voice-note daadwerkelijk een mens was, en waarschijnlijk ook de persoon die de headers beweerden. Die aanname valt uit elkaar. AI-gegenereerde tekst, stem en video worden alsmaar goedkoper, beter en minder te onderscheiden van het echte werk. De default schuift op naar “dit zou iedereen kunnen zijn, of niemand.” De ruis is er al: nep-PR berichten in de stijl van een maintainer, synthetische voice-calls die zich voordoen als een collega, complete sites vol geloofwaardig proza geschreven in minuten. Bewijzen dat jij die post schreef, die commit pushte of die woorden uitsprak houdt op vanzelfsprekend te zijn. Een cryptografische signature is het anker dat AI niet kan vervalsen zonder de key.
Een tweede, langzamere druk zit op dezelfde setup, op een veel langere tijdlijn. Als er ooit een voldoende grote quantumcomputer opduikt, dan wordt elk bericht dat je ooit met klassieke public-key cryptografie hebt versleuteld met terugwerkende kracht leesbaar. Dit heeft een naam: harvest-now-decrypt-later. Van statelijke actoren wordt aangenomen dat ze het nu al doen. Versleuteld verkeer dat ze vandaag oppikken willen ze over tien of twintig jaar ontcijferen. De verdediging is om ze geen klassieke ciphertext meer te geven, wat betekent: post-quantum encryptie nu, terwijl de tooling nog volwassen-aan-het-worden is.
De echte vraag is of jouw huidige GPG-setup over tien jaar nog verdedigbaar is: voor dagelijkse attributie, die nu al bijt, en voor confidentialiteit op lange termijn, die dat nog gaat doen.
Deze post loopt door een setup die beide probeert te doen. Eén offline masterkey, drie identiteitsaliassen eraan gekoppeld, post-quantum encryptie via ML-KEM (Kyber), en drie onafhankelijke backup-lagen. Lang verhaal, omdat elke keuze een afweging is en de redenering net zo belangrijk is als de commando’s. Ben je nieuw met GPG? Begin dan eerst met GPG uitgelegd. Deze post gaat ervanuit dat je minstens één key hebt aangemaakt.
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 deze vorm?
| 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. Door kapott@pm.me en tom.meurs@gmail.com op dezelfde key te zetten maak je publiek aantoonbaar dat “kapott” en “Tom Meurs” dezelfde persoon zijn. Dat is een feature als je attribution wilt. Het is een serieuze bug als kapott een pseudoniem moet blijven. Zodra de publieke sleutel op een keyserver staat, krijg je de link niet meer ongedaan - keyservers vergeten niet. Heb je een echt pseudoniem nodig, gebruik dan een volledig aparte sleutel (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 keys op een schoon OS. Ubuntu live-USB of Tails is de paranoïde default - geen malware van je dagelijkse systeem bij je master. Werk in een aparte GNUPGHOME zodat er niets lekt naar je bestaande keyring:
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 je laatste linie wanneer iemand een kopie van je encrypted master heeft. Hij moet offline bruteforce overleven, inclusief aanvallers met toekomstige hardware. Gebruik Diceware - een willekeurige rij van zeven of meer woorden uit een grote lijst. Makkelijker te onthouden dan %Xh9$!Lq, en sterker.
diceware -n 8 -d ' ' --no-caps
# schemerig koning fiets bramboes tunnel ijverig mosterd kraaier
Schrijf hem op papier. Leg het papier ergens fysiek veilig. Ben je de passphrase kwijt, dan is elke backup uit deze post stortplaats-materiaal.
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. Cryptografisch bewijs dat ze bij elkaar 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. De subkey combineert ML-KEM-1024 (NIST FIPS 203, quantum-safe) met X448 (klassiek ECC). Een aanvaller moet beide breken om je ciphertext te lezen. Je zit goed als één van de twee faalt - klassieke crypto die valt voor een quantumcomputer, of een onverwachte zwakte in ML-KEM zelf.
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 een revocation certificate. Dit is de nucleaire knop als de masterkey ooit compromised raakt:
gpg --output "$GNUPGHOME/revocation-$KEYID.asc" --gen-revoke "$KEYID"
De master offline halen
Dit is de stap die het hele verhaal de moeite waard maakt. We exporteren alles, wissen het master-secret uit de werkkeyring, en importeren 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 het hele punt. Je dagelijkse laptop heeft nu alleen nog vervangbare subkeys. Ze revoken kost je geen identiteit meer.
Drie backup-lagen
Eén backup is geen backup. Drie onafhankelijke paden, elk ervan uitgaand dat de andere twee zijn gefaald:
Hot - VeraCrypt-volume bij meerdere clouds. Altijd bereikbaar, overleeft laptop-verlies.
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/
Gebruik een andere passphrase voor het VeraCrypt-volume dan voor je GPG-key. Falen mag niet cascaderen. De AES-Twofish-Serpent cascade met een Argon2-afgeleide key is post-quantum prima - Grover halveert effectieve symmetrische sleutellengte en je houdt dan nog ~128 bits marge over.
Cold - paperkey + QR-codes. Overleeft cloud-uitval en account-bans.
Paperkey haalt de redundante structuur uit een secret key en houdt alleen de echte geheime bytes over - perfect voor print op archiefpapier. Het kan Ed25519 netjes aan, maar geen Kyber (te nieuw, nog geen compacte encoding). De master gaat dus via paperkey, en de volledige armored export gaat via QR-codes 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 (inkjet vervaagt in een decennium). Leg de stapel in een brandwerende kluis, of verdeel ze over twee locaties.
Hardware - YubiKey (optioneel). Dekt het scenario waar je backups lekken maar de hardware heel is. In 2026 ondersteunt YubiKey-firmware nog geen PQC-subkeys, dus alleen de Ed25519 sign- en auth-subkeys gaan op de token en de Kyber-encrypt-subkey blijft in software. Yubico’s roadmap heeft PQC gepland voor firmware 6 in 2027.
Per-werkgever-identiteiten
Voor klant- of werkgevercontexten zijn er twee scenario’s. Kies bewust.
Scenario A - UID toevoegen aan bestaande masterkey. Eenvoudig, en cryptografisch bewijsbaar dat het dezelfde persoon is. Nadeel: elke collega die je werkgever-publickey importeert ziet ook je privé-aliassen. Dat is prima voor tom@byteherder.com (mijn publieke identiteit), en een probleem voor kapott@pm.me.
Scenario B - aparte key per werkgever. Een extra key om te beheren, maar schone scheiding. Je kunt hem alsnog cross-signen met je hoofdmaster als je attribution wil; anders blijven de identiteiten cryptografisch niet-verbonden. Dit is de default als privacy-per-context ertoe doet.
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 (dsm-vault.vc, klantX-vault.vc). Dezelfde drie-lagen-backup, geïsoleerde blast radius.
Dagelijks gebruik
Publiceer de publieke sleutel. Keys.openpgp.org verifieert elke UID per e-mail voor publicatie - een prettige sanity-check:
gpg --keyserver hkps://keys.openpgp.org --send-keys "$KEYID"
Git signing. Pin commits op je signing-subkey (de ! forceert déze subkey):
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. Thunderbird matcht UID automatisch op From: zodra alle drie de adressen naar dezelfde master key wijzen. Mutt pakt pgp_default_key = $KEYID op dezelfde manier op.
Rotatie
Elke achttien maanden, vóór de twee-jaars-expiry van de subkeys toeslaat, haal je de master tijdelijk terug en schuif je de expiry op. Zelfde VeraCrypt-mount-dans:
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: dezelfde flow, maar revkey op de gecompromitteerde subkey, exporteer, publiceer. Je identiteit blijft intact. Precies daarvoor deden we dit hele circus.
Het bredere principe
Deze setup is niet minimalistisch. Zeven Diceware-woorden, drie backup-lagen, een ritueel elke achttien maanden, twee USB-sticks. Je zou je git-commits kunnen signen met een SaaS “identity service” en van dit alles nooit iets hoeven aanraken.
Maar een SaaS-identiteit is niet van jou. De provider is de eigenaar. Die kan hem intrekken, kwijtraken, of gedwongen worden hem af te staan, en als het businessmodel verandert migreer je op hun tijdlijn. Zoals ik in Sovereign Infrastructure uitwerk: de root bezitten gaat niet om geld besparen - het gaat om het weigeren afhankelijk te zijn van systemen die je niet kunt inspecteren of controleren.
Attributie is datzelfde argument, en het is het argument dat nu al bijt. In een wereld waarin tekst, stem en video overtuigend gesynthetiseerd kunnen worden op commodity-hardware, schuift de default-aanname over elk bericht op naar “kan iedereen zijn, kan niemand zijn.” Je commits en je woorden ondertekenen weerhoudt niemand ervan om content in jouw naam te verzinnen, maar het geeft iedereen die het wil weten een cryptografische manier om het verschil te zien. De signature is het anker dat AI niet kan vervalsen zonder de key. Begin nu met signen en het anker staat er al zodra je het nodig hebt.
Quantum-safety is datzelfde argument, uitgerekt over decennia. Het dreigingsmodel is niet “een quantumcomputer breekt mijn RSA morgen.” Het is “een geduldige actor neemt vandaag mijn encrypted verkeer op en wacht.” De enige verdediging is om ze de ciphertext niet meer te geven die straks goedkoop te kraken is. Dat betekent post-quantum encryptie nu, ook al is de tooling nog volwassen-aan-het-worden, ook al kost het meer werk.
De identiteit die je vandaag genereert, moet over twintig jaar nog verdedigbaar zijn. Dat is de lat. Alles in deze post is wat nodig is om daar overheen te komen met commodity tools, in de openbaarheid, zonder iemand te hoeven vertrouwen behalve jezelf.
