Aplikacje Java mogą i powinny używać klasy java.security.SecureRandom do tworzenia kryptograficznie silnych losowych wartości za pomocą silnie kryptograficznie generatora liczb pseudolosowych ( CSPRNG ). Standardowe implementacje JDK klasy java.util.Random nie są uważane za kryptograficznie silne.
Uniksowe systemy operacyjne mają /dev/random
specjalny plik, który obsługuje pseudolosowe liczby uzyskujące dostęp do szumu otoczenia zebranego ze sterowników urządzeń i innych źródeł. Jednak blokuje się, jeśli dostępna jest mniejsza entropia niż wymagana ; /dev/urandom
zazwyczaj nigdy nie blokuje, nawet jeśli ziarno generatora liczb pseudolosowych nie zostało w pełni zainicjowane entropią od momentu rozruchu. Nadal istnieje trzeci plik specjalny, /dev/arandom
który blokuje się po uruchomieniu, dopóki ziarno nie zostanie bezpiecznie zainicjowane z wystarczającą ilością entropii, a następnie nigdy więcej nie blokuje.
Domyślnie JVM wykorzystuje klasę SecureRandom/dev/random
, dlatego kod Java może zostać nieoczekiwanie zablokowany . Opcja -Djava.security.egd=file:/dev/./urandom
w wywołaniu wiersza poleceń używana do uruchomienia procesu Java mówi JVM, aby /dev/urandom
zamiast tego użyła .
Dodatkowa /./
wydaje się zmusić JVM do korzystania z algorytmu SHA1PRNG, który wykorzystuje SHA-1 jako podstawę PRNG (Pseudo Random Number Generator). Jest silniejszy niż algorytm NativePRNG używany, gdy /dev/urandom
jest określony.
Wreszcie istnieje mit, który /dev/urandom
jest pseudolosowym generatorem liczb losowych, PRNG, podczas gdy /dev/random
jest „prawdziwym” generatorem liczb losowych . To po prostu nie jest prawdą, zarówno /dev/random
i /dev/urandom
są karmione przez samego CSPRNG (kryptograficznie bezpieczny generator liczb pseudolosowych). Tylko zachowanie, gdy w ich puli zabraknie entropii, według niektórych szacunków, różni się: /dev/random
blokuje, podczas gdy /dev/urandom
nie.
Co powiesz na niski poziom entropii? To nie ma znaczenia
Okazuje się, że „wyglądanie losowo” jest podstawowym wymogiem dla wielu naszych kryptograficznych elementów składowych. A jeśli weźmiesz wynik szyfrowania kryptograficznego, musi on być nie do odróżnienia od losowego ciągu, aby szyfry go zaakceptowały. To jest powód zastosowania algorytmu SHA1PRNG, ponieważ wykorzystuje on funkcję skrótu i licznik wraz z ziarnem.
Kiedy należy zastosować?
Zawsze tak mówię.
Źródła:
https://gist.github.com/svrc/5a8accc57219b9548fe1
https://www.2uo.de/myths-about-urandom
EDYCJA 04/2020:
Komentarz wspomina o zmianie zachowania klasy SecureRandom w Javie 8.
Naprawiono SHA1PRNG i NativePRNG, aby odpowiednio przestrzegać właściwości źródła inicjującego SecureRandom w pliku java.security. (Niejasne obejście przy użyciu file: /// dev / urandom i file: / dev /./ urandom nie jest już wymagane).
Zostało to już wskazane w testach wymienionych w sekcji Źródła powyżej. Dodatkowa /./
jest wymagana do zmiany algorytmu używanego przez SecureRanom w Javie 8 z NativePRNG na SHA1PRNG.
Mam jednak kilka wiadomości, którymi chciałbym się podzielić. Zgodnie z JEP-273 , od Java 9 klasa SecureRandom implementuje trzy mechanizmy deterministycznego generatora bitów losowych (DRBG) opisane w NIST 800-90Ar1 . Mechanizmy te implementują nowoczesne algorytmy tak silne, jak SHA-512 i AES-256.
JDK miał dwa rodzaje implementacji SecureRandom :
- Jeden jest zależny od platformy i oparty na natywnych połączeniach lub urządzeniach z systemem operacyjnym, takich jak czytanie
/dev/{u}random
w systemie Unix lub używanie CryptoAPI w systemie Windows. Najnowsze wersje systemów Linux i Windows obsługują już DRBG, ale starsze wersje i systemy wbudowane mogą nie .
- Drugi rodzaj to czysta implementacja Java, która wykorzystuje starszą implementację RNG opartą na SHA1, która nie jest tak silna jak algorytmy stosowane przez zatwierdzone mechanizmy DRBG.
Tymczasem Java 13 Security Developer's Guide wciąż czyta
W systemach Linux i macOS, jeśli urządzenie do gromadzenia entropii w java.security jest ustawione na file:/dev/urandom
lub file:/dev/random
, wówczas NativePRNG jest lepszy niż SHA1PRNG. W przeciwnym razie preferowany jest SHA1PRNG.
Aby wyjaśnić, w jaki sposób nowe mechanizmy DRBG działają razem z poprzednimi PRNG, uruchamiam kilka testów na macOS (Darwin) z AdoptOpenJDK (kompilacja 13.0.2 + 8). Oto wyniki:
plik: / dev / random
Kolejność preferencji dla dostawców:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
plik: / dev / urandom
Kolejność preferencji dla dostawców:
SecureRandom.NativePRNG
SecureRandom.DRBG
SecureRandom.SHA1PRNG
plik: / dev /./ urandom
Kolejność preferencji dla dostawców:
SecureRandom.DRBG
SecureRandom.SHA1PRNG
SecureRandom.NativePRNG
Wniosek:
Polecam użyć, -Djava.security.egd=file:/dev/./urandom
aby upewnić się, że wykorzystasz najsilniejszą dostępną implementację SecureRandom, niezależnie od używanej platformy, unikając nieoczekiwanego zablokowania kodu.