Sleutelafgeleide functies: PBKDF2, Argon2 en scrypt vergeleken
Vergelijk KDF's voor wachtwoordgebaseerde encryptie. Sterke punten van PBKDF2, Argon2 en scrypt.
Voor wachtwoordafgeleide versleutelingssleutels in 2026 is Argon2id de aanbevolen keuze (PHC-winnaar, OWASP's topkeuze, actief verdedigd tegen GPU- en ASIC-aanvallers), is scrypt een solide tweede (memory-hard, breed ingezet in cryptocurrencies) en blijft PBKDF2-SHA-256 bij 600.000+ iteraties acceptabel voor compatibiliteit maar biedt minimale GPU-weerstand. Voor bestandsoverdrachtsapps waar gebruikers een wachtwoord invoeren om een gedeeld bestand te beveiligen, is Argon2id met 3 iteraties, 64 MiB geheugen en 4 parallelisme de moderne baseline. PBKDF2 blijft omdat het is ingebouwd in de Web Crypto API en geen WASM-afhankelijkheid vereist. Hier is hoe de drie verschillen en wanneer elk zinvol is.
Vergelijkingstabel
| Eigenschap | PBKDF2 | scrypt | Argon2id | |---|---|---|---| | Jaar geïntroduceerd | 2000 (RFC 2898) | 2009 (RFC 7914) | 2015 (PHC-winnaar) | | Memory-hard | Nee | Ja | Ja | | Parameterflexibiliteit | Alleen iteraties | N, r, p | tijd, geheugen, parallelisme | | GPU-weerstand | Zwak | Matig | Sterk | | ASIC-weerstand | Zeer zwak | Matig | Sterk | | Browser-native (Web Crypto) | Ja | Nee | Nee | | OWASP 2024 aanbeveling | Acceptabele terugval | Acceptabel | Voorkeur | | Typische browserkosten (moderne hardware) | 600.000 iter = ~500 ms | N=2^17 = ~800 ms | 3 iter, 64 MiB = ~1 s |
Waarom memory-hard ertoe doet
Het bedreigingsmodel voor wachtwoordgebaseerde versleuteling is offline brute force. Een aanvaller pakt de ciphertext plus salt, doorloopt een wachtwoordwoordenboek en probeert een sleutel af te leiden die succesvol ontsleutelt. De verdediging is elke poging duur maken.
PBKDF2 maakt elke poging alleen duur in CPU-tijd (SHA-256-iteraties). Moderne GPU's voeren miljarden SHA-256-bewerkingen per seconde uit; een gaming-GPU kan 10-100 miljoen PBKDF2-SHA-256-600000-gissingen per dag testen. ASIC-aanvallers doen ordes van grootte beter.
Memory-hard functies (scrypt, Argon2) vereisen een vaste hoeveelheid geheugen per poging. GPU's en ASIC's hebben beperkte geheugenbandbreedte, waardoor parallelisme per apparaat is begrensd. Een 64 MiB geheugenvereiste betekent dat een GPU met 16 GB VRAM maximaal 256 parallelle gissingen kan uitvoeren, niet miljoenen. De economische kosten van brute force stijgen met 2-3 ordes van grootte.
PBKDF2: de legacy standaard
PBKDF2 (RFC 2898) itereert een pseudowillekeurige functie, typisch HMAC-SHA-256 of HMAC-SHA-512, over het wachtwoord en de salt. Het iteratieaantal is de enige afstelknop.
const passwordKey = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(password),
"PBKDF2", false, ["deriveKey"]
);
const aesKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt, // 16 willekeurige bytes
iterations: 600000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
OWASP 2023 beveelt minimaal 600.000 iteraties van PBKDF2-SHA-256 aan. NIST SP 800-132 is ouder en minder specifiek. Sommige specificaties (bijv. LastPass's standaard van 100.100 in 2018) worden in 2026 als te laag beschouwd.
Voordelen: ingebouwd in Web Crypto, geen WASM, FIPS-gevalideerd, ondersteund in TLS 1.3 sessiehervatting, werkt identiek in Node en browsers.
Beperkingen: geen geheugenhardheid, kwetsbaar voor GPU- en ASIC-versnelling. Verdubbeling van iteraties verdubbelt de kosten voor de aanvaller maar ook voor de legitieme gebruiker. Op een gegeven moment weigeren legitieme gebruikers te wachten en begrens je iteraties.
scrypt: de eerste memory-hard inzet
scrypt (RFC 7914) werd uitgevonden door Colin Percival in 2009 voor Tarsnap. Het mixt wachtwoordmateriaal door een groot geheugenbuffer, waardoor de aanvaller dat buffer moet vasthouden tijdens elke gissing.
Drie parameters:
- N: kostenfactor (typisch 2^14 tot 2^20). Geheugengebruik is ruwweg 128 * N * r bytes.
- r: blokgrootte (typisch 8). Beïnvloedt geheugen en GHASH-iteratieaantal.
- p: parallelisering (typisch 1). Hogere waarden versnellen legitieme berekening maar ook aanvallers; laat het gewoonlijk op 1.
OWASP beveelt N=2^17, r=8, p=1 aan als baseline, wat ~128 MiB verbruikt en op moderne hardware in ongeveer 800 ms draait.
scrypt zit niet in de Web Crypto API. Gebruik in JavaScript scrypt-js, @noble/hashes of libsodium.js. Litecoin en Dogecoin gebruiken scrypt als hun proof-of-work, wat ASIC-ontwikkeling specifiek voor scrypt heeft gestimuleerd en daarmee zijn oorspronkelijke asymmetrische voordeel tegen ASIC's enigszins heeft uitgehold.
Argon2id: de standaard voor 2026
Argon2 won de Password Hashing Competition in 2015. Drie varianten: Argon2d (snelst, data-afhankelijk, side-channel kwetsbaar), Argon2i (data-onafhankelijk, langzamer), Argon2id (hybride, aanbevolen voor de meeste toepassingen). RFC 9106 standaardiseerde het in 2021.
Drie parameters:
- t (tijd): iteraties door geheugen. Typisch 2-3.
- m (geheugen): geheugen in KiB. Typisch 65536 (64 MiB) of hoger.
- p (parallelisme): mate van parallelisme. Typisch 1-4.
OWASP 2024 baseline: t=2, m=19456 (19 MiB), p=1 voor minimum, en t=3, m=65536 (64 MiB), p=4 voor sterkere bescherming.
import { argon2id } from '@noble/hashes/argon2';
import { utf8ToBytes } from '@noble/hashes/utils';
const derivedKey = argon2id(utf8ToBytes(password), salt, {
t: 3, m: 65536, p: 4, dkLen: 32
});
Of via argon2-browser (WASM):
import argon2 from 'argon2-browser';
const hash = await argon2.hash({
pass: password, salt,
type: argon2.ArgonType.Argon2id,
time: 3, mem: 65536, parallelism: 4, hashLen: 32
});
Argon2id verslaat GPU-aanvallers effectiever dan scrypt omdat zijn geheugentoegangpatroon minder geschikt is voor bulk-geheugenontwerpen. ASIC's voor Argon2 bestaan in onderzoek maar zijn nog niet economisch ingezet op aanvallersniveau.
Parameters kiezen voor jouw app
De kalibratiemethode: kies de langste wachttijd die je gebruikers tolereren (gewoonlijk 500 ms tot 2 seconden), meet op het traagste doelapparaat en stel parameters in om dat budget te halen.
Voor HexaTransfer-stijl wachtwoordbeveiligde bestandsdelen, waarbij de afleiding één keer plaatsvindt bij upload en één keer bij download, is 1-2 seconden acceptabel. Parameters:
- PBKDF2-SHA-256: 600.000-1.200.000 iteraties
- scrypt: N=2^17, r=8, p=1
- Argon2id: t=3, m=65536, p=4
Voor aanmeldsystemen waarbij de gebruiker wacht na het invoeren van zijn wachtwoord, is 300-500 ms het UX-plafond. Parameters halveren ruwweg. Voor batchscenario's waarbij de gebruiker niet wacht (bijv. achtergrond her-versleuteling), schroef je op tot 3-5 seconden.
Saltbeheer
Alle drie de KDF's hebben een salt nodig. Regels:
- Minimaal 16 willekeurige bytes
- Gegenereerd via
crypto.getRandomValues(), nooitMath.random() - Uniek per wachtwoord (als Alice en Bob hetzelfde wachtwoord gebruiken, moeten hun salts verschillen zodat afgeleide sleutels ook verschillen)
- Niet geheim — sla op naast de ciphertext
Pepper (een geheim dat aan alle afleidingen wordt toegevoegd) wordt soms besproken. Voor bestandsoverdracht waarbij de "server" een domme blob-opslag is, voegt pepper geen waarde toe omdat er geen server-side geheim is. Voor account-gebaseerde systemen maakt een server-side pepper die apart van de wachtwoorddatabase wordt opgeslagen databasedumps minder nuttig voor aanvallers.
Migreren tussen KDF's
Als je een bestaand systeem op PBKDF2 hebt en wilt overstappen op Argon2id:
- Sla de KDF-identifier op in de ciphertext-metadata (
"kdf": "pbkdf2-sha256-600000"of"kdf": "argon2id-3-65536-4") - Gebruik bij nieuwe uploads Argon2id
- Lees bij ontsleuteling de KDF-identifier en gebruik de bijpassende functie
- Upgrade oude ciphertexts nooit blindelings; je zou het wachtwoord nodig hebben om opnieuw af te leiden
LastPass, 1Password en Bitwarden hebben deze migratie allemaal doorgemaakt. Alle drie gebruiken nu standaard PBKDF2 bij 600.000+ iteraties, met Argon2id beschikbaar in nieuwere versies. Zelfs wachtwoordmanagers waren traag met Argon2 — het rolt geleidelijk uit omdat het ecosysteemgereedschap tijd nodig had om te rijpen.
Wat met bcrypt?
bcrypt (1999) is een prima wachtwoord-hashingfunctie met bescheiden geheugenhardheid. Het begrenst invoer op 72 bytes (een beruchte valkuil — lange wachtwoorden worden stilzwijgend afgekapt voor ronde 2011). Het is de historische standaard in Ruby on Rails en veel PHP-frameworks. Voor nieuwe code in 2026 geef je de voorkeur aan Argon2id; bcrypt is prima voor het onderhouden van bestaande systemen.
De praktische aanbeveling
Voor een nieuwe bestandsoverdrachtsservice in 2026:
- Als je een afhankelijkheid van 15-200 KB kunt meesturen: Argon2id via @noble/hashes of libsodium.js
- Als je nul afhankelijkheden nodig hebt en bundelgrootte alles is: PBKDF2-SHA-256 bij 600.000 iteraties via Web Crypto
- Als je een cryptocurrency-wallet schrijft of iets met legacy scrypt erft: scrypt bij N=2^17
Voor productieapps die gevoelige bestanden verwerken, is Argon2id de WASM-afhankelijkheid waard. Voor eenvoudige wachtwoordbeveiligde delen waarbij gebruikers toch een willekeurig wachtwoord genereren, is PBKDF2 adequaat omdat de entropie in het wachtwoord zit, niet in de KDF.
Probeer het op hexatransfer.com — gratis, zonder account, tot 10 GB.
Verstuur grote bestanden veilig met end-to-end-versleuteling
Draag bestanden tot 10 GB gratis over met end-to-end-versleuteling. Geen account nodig. Uw bestanden worden in uw browser versleuteld voordat ze worden geüpload — niemand anders kan ze lezen.
Een bestand verzenden