Funkcje wyprowadzania kluczy: PBKDF2, Argon2 i scrypt
Porównaj funkcje wyprowadzania kluczy dla szyfrowania hasłem. Mocne strony PBKDF2, Argon2 i scrypt.
Dla kluczy szyfrowania wyprowadzanych z hasła w 2026 roku, Argon2id to zalecany wybór (zwycięzca PHC, pierwsza propozycja OWASP, aktywnie broniony przed atakującymi GPU i ASIC), scrypt to solidna druga opcja (memory-hard, szeroko wdrożona w kryptowalutach), a PBKDF2-SHA-256 przy 600 000+ iteracjach pozostaje akceptowalny dla kompatybilności, ale oferuje minimalną odporność na GPU. Dla aplikacji transferu pliku, gdzie użytkownicy wpisują hasło do ochrony udostępnianego pliku, Argon2id z 3 iteracjami, 64 MiB pamięci i 4 równoległości to współczesna wartość bazowa. PBKDF2 przeżywa, bo jest wbudowany w Web Crypto API i nie wymaga zależności WASM. Oto czym różnią się te trzy i kiedy który ma sens.
Tabela porównawcza
| Właściwość | PBKDF2 | scrypt | Argon2id | |---|---|---|---| | Rok wprowadzenia | 2000 (RFC 2898) | 2009 (RFC 7914) | 2015 (zwycięzca PHC) | | Memory-hard | Nie | Tak | Tak | | Elastyczność parametrów | Tylko iteracje | N, r, p | czas, pamięć, równoległość | | Odporność na GPU | Słaba | Umiarkowana | Silna | | Odporność na ASIC | Bardzo słaba | Umiarkowana | Silna | | Natywna przeglądarka (Web Crypto) | Tak | Nie | Nie | | Zalecenie OWASP 2024 | Akceptowalny fallback | Akceptowalny | Preferowany | | Typowy koszt przeglądarka (nowoczesny sprzęt) | 600 000 iter = ~500 ms | N=2^17 = ~800 ms | 3 iter, 64 MiB = ~1 s |
Dlaczego memory-hard ma znaczenie
Model zagrożeń dla szyfrowania opartego na haśle to offline brute force. Atakujący przechwytuje szyfrogram wraz z solą, przechodzi przez słownik haseł i próbuje wyprowadzić klucz, który poprawnie odszyfruje. Obroną jest sprawienie, by każda próba była kosztowna.
PBKDF2 czyni każdą próbę kosztowną tylko w czasie CPU (iteracje SHA-256). Nowoczesne GPU wykonują miliardy operacji SHA-256 na sekundę; karta do gier może testować 10–100 milionów prób PBKDF2-SHA-256-600000 dziennie. Atakujący ASIC robią o rzędy wielkości więcej.
Funkcje memory-hard (scrypt, Argon2) wymagają określonej ilości pamięci na próbę. GPU i ASIC mają ograniczoną przepustowość pamięci, więc równoległość per urządzenie jest ograniczona. Wymóg 64 MiB pamięci oznacza, że GPU z 16 GB VRAM może wykonywać co najwyżej 256 równoległych prób, nie miliony. Ekonomiczny koszt brute force rośnie o 2–3 rzędy wielkości.
PBKDF2: domyślny standard dziedziczny
PBKDF2 (RFC 2898) iteruje funkcję pseudolosową, zazwyczaj HMAC-SHA-256 lub HMAC-SHA-512, nad hasłem i solą. Liczba iteracji to jedyna tunowalna wartość.
const passwordKey = await crypto.subtle.importKey(
"raw", new TextEncoder().encode(password),
"PBKDF2", false, ["deriveKey"]
);
const aesKey = await crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt, // 16 losowych bajtów
iterations: 600000,
hash: "SHA-256",
},
passwordKey,
{ name: "AES-GCM", length: 256 },
false,
["encrypt", "decrypt"]
);
OWASP 2023 zaleca minimum 600 000 iteracji PBKDF2-SHA-256. NIST SP 800-132 jest starszy i mniej szczegółowy. Niektóre specyfikacje (np. domyślna wartość LastPass 100 100 z 2018 roku) są w 2026 roku uważane za zbyt niskie.
Zalety: wbudowany w Web Crypto, brak WASM, walidowany FIPS, obsługiwany w wznowieniu sesji TLS 1.3, działa identycznie w Node i przeglądarkach.
Ograniczenia: brak memory-hardness, podatny na akcelerację GPU i ASIC. Podwojenie iteracji podwaja koszt atakującego, ale też koszt legalnego użytkownika. W pewnym momencie użytkownicy odmawiają czekania i ograniczasz iteracje.
scrypt: pierwsze powszechne wdrożenie memory-hard
scrypt (RFC 7914) został wynaleziony przez Colina Percivala w 2009 roku dla Tarsnap. Miesza materiał hasła przez duży bufor pamięci, zmuszając atakującego do przechowywania tego bufora podczas każdej próby.
Trzy parametry:
- N: czynnik kosztu (zwykle 2^14 do 2^20). Użycie pamięci to ok. 128 * N * r bajtów.
- r: rozmiar bloku (zwykle 8). Wpływa na pamięć i liczbę iteracji GHASH.
- p: równoległość (zwykle 1). Wyższe wartości przyspieszają legalną kalkulację, ale też atakujących; zazwyczaj zostaw na 1.
OWASP zaleca N=2^17, r=8, p=1 jako wartość bazową, co konsumuje ~128 MiB i działa ok. 800 ms na nowoczesnym sprzęcie.
scrypt nie jest dostępny w Web Crypto API. W JavaScript użyj scrypt-js, @noble/hashes lub libsodium.js. Litecoin i Dogecoin używają scrypt jako proof-of-work, co zachęciło do rozwoju ASIC specjalnie dla scrypt, nieco erodując jego oryginalną asymetryczną przewagę nad ASIC.
Argon2id: domyślny wybór 2026
Argon2 wygrał Password Hashing Competition w 2015 roku. Trzy warianty: Argon2d (najszybszy, zależny od danych, podatny na side-channel), Argon2i (niezależny od danych, wolniejszy), Argon2id (hybrydowy, zalecany w większości zastosowań). RFC 9106 standaryzował go w 2021 roku.
Trzy parametry:
- t (czas): iteracje przez pamięć. Typowo 2–3.
- m (pamięć): pamięć w KiB. Typowo 65536 (64 MiB) lub więcej.
- p (równoległość): stopień równoległości. Typowo 1–4.
Wartość bazowa OWASP 2024: t=2, m=19456 (19 MiB), p=1 jako minimum, i t=3, m=65536 (64 MiB), p=4 dla silniejszej ochrony.
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
});
Lub przez 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 pokonuje atakujących GPU skuteczniej niż scrypt, bo jego wzorzec dostępu do pamięci jest mniej podatny na projektowanie pamięci masowej. ASIC dla Argon2 istnieją w badaniach, ale nie są ekonomicznie wdrożone na skalę atakujących.
Dobór parametrów dla aplikacji
Metoda kalibracji: wybierz najdłuższe oczekiwanie tolerowane przez użytkowników (zazwyczaj 500 ms do 2 sekund), zmierz na najwolniejszym docelowym urządzeniu i ustaw parametry tak, by trafić w ten budżet.
Dla ochrony udostępnianych plików hasłem w stylu HexaTransfer, gdzie wyprowadzanie odbywa się raz przy przesyłaniu i raz przy pobieraniu, 1–2 sekundy są akceptowalne. Parametry:
- PBKDF2-SHA-256: 600 000–1 200 000 iteracji
- scrypt: N=2^17, r=8, p=1
- Argon2id: t=3, m=65536, p=4
Dla systemów logowania, gdzie użytkownik czeka po wpisaniu hasła, 300–500 ms to limit UX. Parametry zmniejszają się mniej więcej o połowę. Dla scenariuszy wsadowych, gdzie użytkownik nie czeka (np. ponowne szyfrowanie w tle), zwiększaj do 3–5 sekund.
Zarządzanie solą
Wszystkie trzy KDF potrzebują soli. Zasady:
- Minimum 16 losowych bajtów
- Generowane przez
crypto.getRandomValues(), nigdyMath.random() - Unikalna na hasło (jeśli Alicja i Bartek używają tego samego hasła, ich sole powinny się różnić, by wyprowadzone klucze różniły się)
- Nie jest sekretem — przechowuj ją razem z szyfrogramem
Pieprz (sekret dodawany do wszystkich wyprowadzeń) jest czasem dyskutowany. Dla transferu pliku, gdzie „serwer" to głupi magazyn blobów, pieprz nie ma wartości, bo nie ma tajemnic po stronie serwera. Dla systemów opartych na kontach, pieprz po stronie serwera przechowywany osobno od bazy haseł sprawia, że zrzuty bazy danych są mniej przydatne dla atakujących.
Migracja między KDF
Jeśli masz istniejące wdrożenie na PBKDF2 i chcesz przejść na Argon2id:
- Przechowuj identyfikator KDF w metadanych szyfrogramu (
"kdf": "pbkdf2-sha256-600000"lub"kdf": "argon2id-3-65536-4") - Dla nowych przesyłek używaj Argon2id
- Przy deszyfrowaniu odczytaj identyfikator KDF i użyj pasującej funkcji
- Nigdy nie uaktualniaj ślepo starych szyfrogramów; potrzebowałbyś hasła do ponownego wyprowadzenia
LastPass, 1Password i Bitwarden przeszły przez tę migrację. Wszystkie trzy domyślnie używają teraz PBKDF2 przy 600 000+ iteracjach, z Argon2id dostępnym w nowszych wersjach.
Co z bcrypt?
bcrypt (1999) to dobra funkcja hashowania haseł z umiarkowaną memory-hardness. Ogranicza dane wejściowe do 72 bajtów (znana pułapka — długie hasła są cicho obcinane przed rundami 2011). To historyczny standard domyślny w Ruby on Rails i wielu frameworkach PHP. Dla nowego kodu w 2026 roku preferuj Argon2id; bcrypt jest odpowiedni dla utrzymywania istniejących systemów.
Praktyczne zalecenie
Dla nowej usługi transferu pliku w 2026 roku:
- Jeśli możesz dostarczyć zależność 15–200 KB: Argon2id przez @noble/hashes lub libsodium.js
- Jeśli potrzebujesz zero zależności i minimalizacji rozmiaru pakietu za wszelką cenę: PBKDF2-SHA-256 przy 600 000 iteracjach przez Web Crypto
- Jeśli piszesz portfel kryptowalutowy lub cokolwiek dziedziczącego starszy scrypt: scrypt przy N=2^17
Dla produkcyjnych aplikacji obsługujących wrażliwe pliki, Argon2id jest wart zależności WASM. Dla prostych udziałów chronionych hasłem, gdzie użytkownicy i tak generują losowe hasło, PBKDF2 jest wystarczający, bo entropia jest w haśle, a nie w KDF.
Wypróbuj na hexatransfer.com — bezpłatnie, bez konta, do 10 GB.
Wysyłaj duże pliki bezpiecznie z szyfrowaniem end-to-end
Przesyłaj pliki do 10 GB za darmo z szyfrowaniem end-to-end. Bez rejestracji. Twoje pliki są szyfrowane w przeglądarce przed przesłaniem — nikt inny nie może ich odczytać.
Wyślij plik