Jeśli chcesz mieć silne kryptograficznie liczby losowe w Javie, użyj SecureRandom
. Niestety SecureRandom
może to być bardzo powolne. Jeśli używa /dev/random
w systemie Linux, może blokować oczekiwanie na zbudowanie wystarczającej entropii. Jak uniknąć spadku wydajności?
Czy ktoś użył Uncommon Maths jako rozwiązania tego problemu?
Czy ktoś może potwierdzić, że ten problem z wydajnością został rozwiązany w JDK 6?
Odpowiedzi:
Jeśli chcesz prawdziwych losowych danych, niestety musisz na to poczekać. Obejmuje to ziarno
SecureRandom
PRNG. Uncommon Maths nie może gromadzić prawdziwie losowych danych szybciej niżSecureRandom
, chociaż może łączyć się z Internetem w celu pobrania danych początkowych z określonej witryny. Domyślam się, że prawdopodobnie nie będzie to szybsze niż/dev/random
tam, gdzie jest to dostępne.Jeśli chcesz PRNG, zrób coś takiego:
Obsługiwane ciągi zależą od
SecureRandom
dostawcy SPI, ale można je wyliczyć za pomocąSecurity.getProviders()
iProvider.getService()
.Sun lubi SHA1PRNG, więc jest szeroko dostępny. Nie jest szczególnie szybki jak PRNG, ale PRNG będą po prostu przetwarzać liczby, a nie blokować fizycznego pomiaru entropii.
Wyjątkiem jest to, że jeśli nie zadzwonisz
setSeed()
przed pobraniem danych, PRNG uruchomi się po pierwszym wywołaniunext()
lubnextBytes()
. Zwykle robi to przy użyciu dość małej ilości prawdziwie losowych danych z systemu. To wywołanie może blokować, ale sprawi, że twoje źródło liczb losowych będzie o wiele bezpieczniejsze niż jakikolwiek wariant "mieszaj aktualny czas razem z PID, dodaj 27 i miej nadzieję na najlepsze". Jeśli jednak potrzebujesz tylko liczb losowych do gry lub jeśli chcesz, aby strumień był powtarzalny w przyszłości przy użyciu tego samego ziarna do celów testowych, niezabezpieczone ziarno jest nadal przydatne.źródło
Powinieneś być w stanie wybrać szybszy, ale nieco mniej bezpieczny / dev / urandom w systemie Linux za pomocą:
Jednak to nie działa z Javą 5 i nowszymi wersjami ( błąd Java 6202721 ). Sugerowanym obejściem jest użycie:
(uwaga na dodatek
/./
)źródło
/dev/urandom
, Sun traktuje to jako magiczny ciąg i/dev/random
tak czy inaczej używa , więc musisz go sfałszować. Kiedyfile:
adres URL nie jestfile:
adresem URL? Kiedy Sun zdecyduje, że nie jest :-(file:/dev/urandom
ustawione w-Djava.security.egd
lub wsecurerandom.source
pliku java.security,/dev/random/
jest nadal odczytywaneSecureRandom.getSeed()
(lubsetSeed()
jest wywoływane). Obejście problemu zfile:/dev/./urandom
wynikiem w ogóle nie czytającym/dev/random
(potwierdzonym strace)/dev/urandom
nie jest mniej bezpieczny niż/dev/random
po wdrożeniu za pomocą nowoczesnego CSPRNG: en.wikipedia.org/wiki//dev/random#FreeBSD/dev/urandom/
jest to, co się stanie, jeśli użyjesz go do wygenerowania sekretów na nowym sprzęcie po wyjęciu z pudełka, który może być w dość przewidywalnym stanie./dev/urandom/
nie blokuje entropii, mimo że jest to jeden przypadek, w którym powinieneś. Sytuacja jest jeszcze gorsza, jeśli sekret jest trwały, na przykład jeśli pierwszą rzeczą, którą urządzenie robi przy pierwszym uruchomieniu, jest wygenerowanie pary kluczy publiczny-prywatny. Poza tymi przerażającymi sytuacjami, i tak dobre/dev/urandom
jest lepsze niż używanie zwykłychSecureRandom
algorytmów.W Linuksie domyślna implementacja dla
SecureRandom
toNativePRNG
( tutaj kod źródłowy ), która zwykle działa bardzo wolno. W systemie Windows wartość domyślna toSHA1PRNG
, której, jak wskazywali inni, można również używać w systemie Linux, jeśli wyraźnie to określisz.NativePRNG
różni się odSHA1PRNG
i Uncommons Maths AESCounterRNG tym, że stale otrzymuje entropię z systemu operacyjnego (czytając z/dev/urandom
). Pozostałe PRNG nie uzyskują żadnej dodatkowej entropii po zaszczepieniu.AESCounterRNG jest około 10x szybszy niż
SHA1PRNG
IIRC, który sam jest dwa lub trzy razy szybszy niżNativePRNG
.Jeśli potrzebujesz szybszego PRNG, który uzyskuje entropię po inicjalizacji, sprawdź, czy możesz znaleźć implementację Fortuny w Javie . Podstawowy PRNG implementacji Fortuny jest identyczny z tym używanym przez AESCounterRNG, ale istnieje również wyrafinowany system pulowania entropii i automatycznego ponownego zasiewu.
źródło
Wiele dystrybucji Linuksa (głównie opartych na Debianie) konfiguruje OpenJDK do wykorzystania
/dev/random
w entropii./dev/random
jest z definicji powolny (a nawet może blokować).Tutaj masz dwie opcje odblokowania:
Opcja 1, Popraw entropię
Aby uzyskać więcej entropii
/dev/random
, wypróbuj zniszczonego demona. Jest to demon, który w sposób ciągły zbiera entropię HAVEGE i działa również w środowisku zwirtualizowanym, ponieważ nie wymaga żadnego specjalnego sprzętu, a jedynie sam procesor i zegar.W systemie Ubuntu / Debian:
Na RHEL / CentOS:
Opcja 2. Zmniejsz wymagania dotyczące losowości
Jeśli z jakiegoś powodu powyższe rozwiązanie nie pomoże lub nie zależy Ci na silnej kryptograficznie losowości, możesz
/dev/urandom
zamiast tego przełączyć się na , co gwarantuje, że nie zostanie zablokowany.Aby to zrobić globalnie, edytuj plik
jre/lib/security/java.security
w domyślnej instalacji Java do użycia/dev/urandom
(z powodu innego błędu należy go określić jako/dev/./urandom
).Lubię to:
Wtedy nigdy nie będziesz musiał podawać tego w wierszu poleceń.
Uwaga: jeśli zajmujesz się kryptografią, potrzebujesz dobrej entropii. Sprawa w punkcie - android problem PRNG zmniejszone bezpieczeństwo portfele Bitcoin.
źródło
/dev/random
z definicji jest powolny (i może nawet blokować)” jest błędny; zależy to całkowicie od konfiguracji systemu. Nowsze maszyny mogą mieć np. Szybki RNG w CPU, który może być używany, a maszyny BSD mają generalnie tę samą implementację dla/dev/random
i/devl/urandom
. Mimo to prawdopodobnie nie powinieneś polegać na/dev/random
szybkości. W przypadku maszyn wirtualnych możesz chcieć zainstalować zestaw narzędzi klienta na maszynie wirtualnej klienta, aby można było używać RNG systemu operacyjnego hosta.Miałem podobny problem z wezwaniami do
SecureRandom
blokowania przez około 25 sekund na raz na bezgłowym serwerze Debiana. Zainstalowałemhaveged
demona, aby mieć pewność, że/dev/random
jest doładowany, na serwerach bezgłowych potrzebujesz czegoś takiego, aby wygenerować wymaganą entropię. Moje telefony doSecureRandom
tej pory mogą zająć milisekundy.źródło
Jeśli chcesz naprawdę „kryptograficznie silnej” losowości, potrzebujesz silnego źródła entropii.
/dev/random
jest powolny, ponieważ musi czekać, aż zdarzenia systemowe zgromadzą entropię (odczyty dysku, pakiety sieciowe, ruchy myszy, naciśnięcia klawiszy itp.).Szybszym rozwiązaniem jest sprzętowy generator liczb losowych. Być może masz już jeden wbudowany w płytę główną; zapoznaj się z dokumentacją hw_random, aby dowiedzieć się, czy go masz i jak go używać. Pakiet rng-tools zawiera demona, który będzie dostarczał wygenerowaną sprzętowo entropię do
/dev/random
.Jeśli HRNG nie jest dostępny w twoim systemie i jesteś gotów poświęcić siłę entropii na rzecz wydajności, będziesz chciał obsiać dobry PRNG danymi z
/dev/random
i pozwolić PRNG wykonać większość pracy. Istnieje kilka zatwierdzonych przez NIST PRNG wymienionych w SP800-90, które są łatwe do wdrożenia.źródło
Używając Java 8, odkryłem, że w Linuksie wywołanie
SecureRandom.getInstanceStrong()
daje miNativePRNGBlocking
algorytm. Często blokowałoby się to na wiele sekund, aby wygenerować kilka bajtów soli.NativePRNGNonBlocking
Zamiast tego przełączyłem się na wyraźne pytanie i zgodnie z oczekiwaniami po nazwie nie było już blokowane. Nie mam pojęcia, jakie są tego konsekwencje dla bezpieczeństwa. Prawdopodobnie wersja nieblokująca nie może zagwarantować ilości użytej entropii.Aktualizacja : Ok, znalazłem to doskonałe wyjaśnienie .
Krótko mówiąc, aby uniknąć blokowania, użyj
new SecureRandom()
. To używa/dev/urandom
, które nie blokuje i jest w zasadzie tak bezpieczne jak/dev/random
. Z posta: „Jedyny przypadek, w którym chciałbyś wywołać / dev / random, to pierwszy rozruch maszyny, a entropia jeszcze się nie nagromadziła”.SecureRandom.getInstanceStrong()
daje absolutnie najsilniejszy RNG, ale można go bezpiecznie używać tylko w sytuacjach, w których kilka bloków nie wpłynie na ciebie.źródło
getInstanceStrong()
na długie klucze terminowych, takich jak te, dla certyfikatów TLS. I nawet wtedy wolałbym używaćnew SecureRandom()
generatora par kluczy lub generatora liczb losowych zgodnego z FIPS. Więc tak, to daje odpowiedź, jeśli/dev/urandom
nie blokuje: w końcu nadal opiera się na entropii systemu; ale ogólnie jest to bardzo dobra rada . Jeśli/dev/urandom
blokuje, może być konieczne naprawienie źródła problemu, a nie aplikacji Java.Istnieje narzędzie (przynajmniej na Ubuntu), które wprowadzi sztuczną losowość do twojego systemu. Polecenie to po prostu:
i możesz potrzebować sudo z przodu. Jeśli nie masz pakietu rng-tools, musisz go zainstalować. Próbowałem tego i zdecydowanie mi pomogło!
Źródło: Matt vs World
źródło
sudo rngd -r /dev/urandom
zsudo apt install rng-tools
xenialemNapotkałem ten sam problem . Po pewnym googlowaniu z odpowiednimi wyszukiwanymi hasłami natknąłem się na ten fajny artykuł na DigitalOcean .
Haveged to potencjalne rozwiązanie bez narażania bezpieczeństwa.
Cytuję tylko odpowiednią część z tego artykułu.
Jak zainstalować haveged
Wykonaj czynności opisane w tym artykule. https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged
Opublikowałem to tutaj
źródło
Problem, o którym się odwołujesz,
/dev/random
nie dotyczySecureRandom
algorytmu, ale źródła losowości, którego używa. Te dwa są ortogonalne. Powinieneś dowiedzieć się, który z nich spowalnia cię.Niezbyt często strona Matematyka, do której odsyłasz, wyraźnie wspomina, że nie dotyczą one źródła losowości.
Możesz wypróbować różnych dostawców JCE, takich jak BouncyCastle, aby sprawdzić, czy ich implementacja
SecureRandom
jest szybsza.Krótkie wyszukiwanie ujawnia również łatki Linuksa, które zastępują domyślną implementację Fortuną. Nie wiem nic więcej na ten temat, ale zapraszam do zbadania.
Powinienem również wspomnieć, że chociaż bardzo niebezpieczne jest użycie źle zaimplementowanego
SecureRandom
algorytmu i / lub źródła losowości, możesz utworzyć własnego dostawcę JCE z niestandardową implementacjąSecureRandomSpi
. Będziesz musiał przejść przez proces w firmie Sun, aby podpisać umowę z dostawcą, ale w rzeczywistości jest to całkiem proste; Wystarczy, że prześlesz im faksem formularz stwierdzający, że znasz amerykańskie ograniczenia eksportowe dotyczące bibliotek kryptograficznych.źródło
Użyj bezpiecznego losowego jako źródła inicjalizacji dla powtarzającego się algorytmu; możesz wtedy użyć twistera Mersenne do pracy masowej zamiast tego w UncommonMath, który istnieje od jakiegoś czasu i okazał się lepszy niż inne prng
http://en.wikipedia.org/wiki/Mersenne_twister
Pamiętaj, aby od czasu do czasu odświeżyć bezpieczny losowy używany do inicjalizacji, na przykład możesz mieć jeden bezpieczny generowany losowo na klienta, używając jednego pseudo-losowego generatora twister mersenne na klienta, uzyskując wystarczająco wysoki stopień randomizacji
źródło
Random
, ale nie dlaSecureRandom
.Zgodnie z dokumentacją różne algorytmy używane przez SecureRandom to, w kolejności preferencji:
Ponieważ pytałeś o Linuksa, ignoruję implementację Windows, a także SunPKCS11, który jest naprawdę dostępny tylko w Solarisie, chyba że sam go zainstalowałeś - a wtedy nie pytałbyś o to.
Według tej samej dokumentacji, czego używają te algorytmy
SHA1PRNG
Wstępne udostępnianie jest obecnie wykonywane za pomocą kombinacji atrybutów systemowych i urządzenia gromadzącego entropię java.security.
NativePRNG
nextBytes()
wykorzystuje/dev/urandom
generateSeed()
zastosowań/dev/random
NativePRNGBlocking
nextBytes()
igenerateSeed()
używanie/dev/random
NativePRNGNonBlocking
nextBytes()
igenerateSeed()
używanie/dev/urandom
Oznacza to, że jeśli używasz
SecureRandom random = new SecureRandom()
, przegląda tę listę, dopóki nie znajdzie takiego, który działa, którym zazwyczaj będzie NativePRNG. A to oznacza, że wysiewa się z/dev/random
(lub używa tego, jeśli jawnie generujesz ziarno), a następnie używa/dev/urandom
do pobrania kolejnych bajtów, ints, double, booleans, what-have-you.Ponieważ
/dev/random
blokuje (blokuje, dopóki nie ma wystarczającej entropii w puli entropii), może to utrudnić działanie.Jednym z rozwiązań jest użycie czegoś takiego jak haveged do wygenerowania wystarczającej entropii, a innym rozwiązaniem jest użycie
/dev/urandom
zamiast tego. Chociaż można to ustawić dla całej jvm, lepszym rozwiązaniem jest zrobienie tego dla tego konkretnego wystąpieniaSecureRandom
, używającSecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking")
. Należy pamiętać, że ta metoda może zgłosić NoSuchAlgorithmException, jeśli NativePRNGNonBlocking, więc przygotuj się na powrót do wartości domyślnej.Zauważ również, że w innych systemach * nix
/dev/urandom
może zachowywać się inaczej .Czy jest
/dev/urandom
wystarczająco losowy?Konwencjonalna mądrość mówi, że tylko
/dev/random
jest wystarczająco przypadkowa. Jednak niektóre głosy się różnią. W „Właściwy sposób korzystania z SecureRandom” i „Mity o / dev / urandom” argumentowano, że/dev/urandom/
jest to równie dobre.Zgadzają się z tym użytkownicy na stosie bezpieczeństwa informacji . Zasadniczo, jeśli musisz o to zapytać,
/dev/urandom
jest w porządku.źródło
Sam nie napotkałem tego problemu, ale przy starcie programu tworzyłem wątek, który natychmiast próbuje wygenerować ziarno, a następnie umiera. Metoda, którą wywołujesz dla randoms, dołączy do tego wątku, jeśli jest aktywny, więc pierwsze wywołanie blokuje się tylko wtedy, gdy występuje na bardzo wczesnym etapie wykonywania programu.
źródło
Moje doświadczenie dotyczyło tylko powolnej inicjalizacji PRNG, a nie późniejszego generowania losowych danych. Wypróbuj bardziej chętną strategię inicjalizacji. Ponieważ są drogie w tworzeniu, traktuj je jak pojedyncze egzemplarze i używaj ponownie tej samej instancji. Jeśli w jednym wystąpieniu występuje zbyt duża rywalizacja o wątki, połącz je lub ustaw jako lokalne wątki.
Nie idź na kompromis przy generowaniu liczb losowych. Słabość w tym miejscu naraża całe twoje bezpieczeństwo.
Nie widzę wielu generatorów COTS opartych na rozpadzie atomowym, ale istnieje kilka planów dla nich, jeśli naprawdę potrzebujesz wielu losowych danych. Jedną z witryn, które zawsze zawierają interesujące rzeczy do obejrzenia, w tym HotBits, jest Fourmilab Johna Walkera.
źródło
SecureRandom
zmienił się kilka razy w ciągu ostatnich 10 lat w gromadzeniu entropii.SecureRandom
jest nadal problemem, ale niska entropia w systemie zawsze będzie problemem. Użycie singletona spowoduje utworzenie silnie sprzężonego kodu, który jest wzorcem projektowym. Dlatego należy go używać z najwyższą ostrożnością; najlepiej byłoby odwrócić wszystkie odwołania w kodzie, jeśli chcesz rozwiązać problem.Wygląda na to, że powinieneś jaśniej określić swoje wymagania dotyczące RNG. Najsilniejszym wymaganiem kryptograficznym RNG (jak rozumiem) byłoby to, że nawet jeśli znasz algorytm używany do ich generowania i znasz wszystkie wcześniej wygenerowane liczby losowe, nie możesz uzyskać żadnych przydatnych informacji o żadnej z liczb losowych wygenerowanych w przyszłości, bez wydawania niepraktycznej ilości mocy obliczeniowej.
Jeśli nie potrzebujesz tej pełnej gwarancji losowości, prawdopodobnie istnieją odpowiednie kompromisy dotyczące wydajności. Zgodziłbym się z odpowiedzią Dana Dyera na temat AESCounterRNG z Uncommons-Maths lub Fortuna (jednym z jej autorów jest Bruce Schneier, ekspert w dziedzinie kryptografii). Ja też nigdy nie korzystałem, ale na pierwszy rzut oka pomysły wydają się godne zaufania.
Pomyślałbym , że gdybyś mógł okresowo generować początkowe losowe ziarno (np. Raz dziennie, godzinę lub cokolwiek innego), mógłbyś użyć szybkiego szyfru strumieniowego do generowania liczb losowych z kolejnych fragmentów strumienia (jeśli szyfr strumieniowy używa XOR, to po prostu przekazać strumień wartości null lub bezpośrednio pobrać bity XOR). EStream firmy ECRYPTProjekt zawiera wiele dobrych informacji, w tym testy wydajności. Nie utrzymałoby to entropii między punktami w czasie, w których ją uzupełniasz, więc gdyby ktoś znał jedną z liczb losowych i algorytm, którego użyłeś, technicznie byłoby możliwe, z dużą mocą obliczeniową, złamać szyfr strumieniowy i zgadnij jego stan wewnętrzny, aby móc przewidzieć przyszłe liczby losowe. Ale musiałbyś zdecydować, czy to ryzyko i jego konsekwencje są wystarczające, aby uzasadnić koszt utrzymania entropii.
Edycja: oto kilka notatek z kursu kryptograficznego na temat RNG , które znalazłem w sieci, które wyglądają bardzo na ten temat.
źródło
Jeśli twój sprzęt to obsługuje, spróbuj użyć narzędzia Java RdRand, którego jestem autorem.
Jest oparty na
RDRAND
instrukcjach Intela i jest około 10 razy szybszy niżSecureRandom
i nie ma problemów z przepustowością w przypadku implementacji dużej objętości.Zauważ, że ta implementacja działa tylko na tych procesorach, które dostarczają instrukcje (tj. Gdy
rdrand
flaga procesora jest ustawiona). Musisz jawnie utworzyć instancję za pomocąRdRandRandom()
konstruktora; żaden konkretnyProvider
nie został wdrożony.źródło
RDRAND
to dobre źródło, ale trochę niegodne zaufania. Zdecydowanie musi to być jeden z wielu wkładów do kolekcjonera (bez obrazy Davida Johnstona).Inną kwestią, na którą należy zwrócić uwagę, jest właściwość securerandom.source w pliku lib / security / java.security
Używanie / dev / urandom zamiast / dev / random może przynieść korzyści w zakresie wydajności. Pamiętaj, że jeśli jakość liczb losowych jest ważna, nie idź na kompromis, który łamie zabezpieczenia.
źródło