Wenn Sie eine kryptografisch starke Zufallszahl in Java wünschen, verwenden Sie SecureRandom
. SecureRandom
Kann leider sehr langsam sein. Wenn es /dev/random
unter Linux verwendet wird, kann es das Warten auf den Aufbau einer ausreichenden Entropie blockieren. Wie vermeidet man die Leistungsstrafe?
Hat jemand Uncommon Maths als Lösung für dieses Problem verwendet?
Kann jemand bestätigen, dass dieses Leistungsproblem in JDK 6 behoben wurde?
Antworten:
Wenn Sie echte Zufallsdaten wollen, müssen Sie leider darauf warten. Dies beinhaltet den Startwert für ein
SecureRandom
PRNG. Gelegentlich kann Maths keine echten Zufallsdaten schneller erfassen alsSecureRandom
, obwohl es eine Verbindung zum Internet herstellen kann, um Startdaten von einer bestimmten Website herunterzuladen. Ich vermute, dass dies wahrscheinlich nicht schneller sein wird als/dev/random
dort, wo es verfügbar ist.Wenn Sie ein PRNG möchten, gehen Sie wie folgt vor:
Welche Zeichenfolgen unterstützt werden, hängt vom
SecureRandom
SPI-Anbieter ab. Sie können sie jedoch mitSecurity.getProviders()
und auflistenProvider.getService()
.Sun liebt SHA1PRNG und ist daher weit verbreitet. Es ist nicht besonders schnell, wie PRNGs gehen, aber PRNGs werden nur Zahlen knacken und nicht für die physikalische Messung der Entropie blockieren.
Die Ausnahme ist, dass, wenn Sie nicht anrufen,
setSeed()
bevor Sie Daten erhalten, sich der PRNG beim ersten Aufruf vonnext()
oder einmal selbst aussetztnextBytes()
. Dies geschieht normalerweise mit einer relativ kleinen Menge echter Zufallsdaten aus dem System. Dieser Aufruf kann blockieren, macht Ihre Zufallszahlenquelle jedoch weitaus sicherer als jede andere Variante von "Hash die aktuelle Zeit zusammen mit der PID, addiere 27 und hoffe auf das Beste". Wenn Sie jedoch nur Zufallszahlen für ein Spiel benötigen oder wenn Sie möchten, dass der Stream in Zukunft mit demselben Startwert zu Testzwecken wiederholt werden kann, ist ein unsicherer Startwert immer noch nützlich.quelle
Sie sollten in der Lage sein, das schnellere, aber etwas weniger sichere / dev / urandom unter Linux auszuwählen, indem Sie:
Dies funktioniert jedoch nicht mit Java 5 und höher ( Java Bug 6202721 ). Die vorgeschlagene Problemumgehung lautet wie folgt:
(Beachten Sie das Extra
/./
)quelle
/dev/urandom
, behandelt Sun dies als magische Zeichenfolge und verwendet sie/dev/random
trotzdem, sodass Sie sie vortäuschen müssen. Wann ist einefile:
URL keinefile:
URL? Wann immer Sun entscheidet, ist es nicht :-(file:/dev/urandom
in-Djava.security.egd
odersecurerandom.source
in der Datei java.security festgelegt ist,/dev/random/
immer noch gelesen wird, wenn sie aufgerufen wirdSecureRandom.getSeed()
(odersetSeed()
aufgerufen wird). Die Problemumgehungfile:/dev/./urandom
führt dazu, dass überhaupt nicht gelesen wird/dev/random
(bestätigt durch Strace)/dev/urandom
ist nicht weniger sicher als/dev/random
bei der Implementierung mit einem modernen CSPRNG: en.wikipedia.org/wiki//dev/random#FreeBSD/dev/urandom/
ist, was passiert, wenn Sie damit sofort Geheimnisse für neue Hardware generieren, die sich in einem ziemlich vorhersehbaren Zustand befinden könnten./dev/urandom/
blockiert nicht für Entropie, obwohl dies ein Fall ist, in dem Sie sollten. Die Situation ist noch schlimmer, wenn das Geheimnis bestehen bleibt, beispielsweise wenn Ihr Gerät beim ersten Start als erstes ein öffentlich-privates Schlüsselpaar generiert. Außerhalb dieser beängstigenden Situationen ist ein Gut sowieso/dev/urandom
besser als die Verwendung der üblichenSecureRandom
Algorithmen.Unter Linux
SecureRandom
lautet die Standardimplementierung fürNativePRNG
(Quellcode hier ), was in der Regel sehr langsam ist. Unter Windows ist der StandardwertSHA1PRNG
, den Sie, wie bereits erwähnt, auch unter Linux verwenden können, wenn Sie ihn explizit angeben.NativePRNG
unterscheidet sich vonSHA1PRNG
und Uncommons Maths ' AESCounterRNG darin, dass es kontinuierlich Entropie vom Betriebssystem erhält (durch Lesen von/dev/urandom
). Die anderen PRNGs erhalten nach dem Aussäen keine zusätzliche Entropie.AESCounterRNG ist ungefähr 10x schneller als
SHA1PRNG
, IIRC selbst ist zwei- oder dreimal schneller alsNativePRNG
.Wenn Sie ein schnelleres PRNG benötigen, das nach der Initialisierung Entropie erhält, prüfen Sie, ob Sie eine Java-Implementierung von Fortuna finden . Das Kern-PRNG einer Fortuna-Implementierung ist identisch mit dem von AESCounterRNG verwendeten, es gibt jedoch auch ein ausgeklügeltes System für Entropie-Pooling und automatische Neuaussaat.
quelle
Viele Linux-Distributionen (meistens auf Debian-Basis) konfigurieren OpenJDK
/dev/random
für die Entropie./dev/random
ist per definitionem langsam (und kann sogar blockieren).Von hier aus haben Sie zwei Möglichkeiten, wie Sie die Blockierung aufheben können:
Option 1, Entropie verbessern
Probieren Sie
/dev/random
den Hgedged- Daemon aus, um mehr Entropie zu erhalten . Es ist ein Daemon, der kontinuierlich die HAVEGE-Entropie sammelt und auch in einer virtualisierten Umgebung funktioniert, da keine spezielle Hardware erforderlich ist, nur die CPU selbst und eine Uhr.Unter Ubuntu / Debian:
Auf RHEL / CentOS:
Option 2. Reduzieren Sie die Zufallsanforderungen
Wenn die oben genannte Lösung aus irgendeinem Grund nicht hilft oder Sie sich nicht für kryptografisch starke Zufälligkeiten interessieren, können Sie
/dev/urandom
stattdessen zu wechseln , was garantiert nicht blockiert.Um dies global zu tun, bearbeiten Sie die zu verwendende Datei
jre/lib/security/java.security
in Ihrer Standard-Java-Installation/dev/urandom
(aufgrund eines anderen Fehlers muss sie als angegeben werden/dev/./urandom
).So was:
Dann müssen Sie es nie in der Befehlszeile angeben.
Hinweis: Wenn Sie Kryptografie betreiben, benötigen Sie eine gute Entropie. Ein typisches Beispiel: Das Problem mit Android PRNG hat die Sicherheit von Bitcoin-Geldbörsen verringert.
quelle
/dev/random
ist per Definition langsam (und kann sogar blockieren)" ist falsch. Dies hängt vollständig von der Systemkonfiguration ab. Neuere Maschinen haben möglicherweise ein schnelles RNG in der CPU, das verwendet werden kann, und BSD-Maschinen haben im Allgemeinen die gleiche Implementierung für/dev/random
und/devl/urandom
. Trotzdem sollten Sie sich wahrscheinlich nicht unbedingt darauf verlassen/dev/random
, schnell zu sein. Auf VMs möchten Sie möglicherweise das Client-Toolset auf der Client-VM installieren, damit das RNG des Host-Betriebssystems verwendet werden kann.Ich hatte ein ähnliches Problem mit
SecureRandom
Blockierungsaufrufen für jeweils etwa 25 Sekunden auf einem kopflosen Debian-Server. Ich habe denhaveged
Daemon installiert, um sicherzustellen, dass er/dev/random
immer aufgeladen ist. Auf kopflosen Servern benötigen Sie so etwas, um die erforderliche Entropie zu generieren. Meine AnrufeSecureRandom
dauern jetzt vielleicht Millisekunden.quelle
Wenn Sie eine wirklich "kryptografisch starke" Zufälligkeit wünschen, benötigen Sie eine starke Entropiequelle.
/dev/random
ist langsam, da es darauf warten muss, dass Systemereignisse Entropie erfassen (Festplattenlesevorgänge, Netzwerkpakete, Mausbewegungen, Tastendrücke usw.).Eine schnellere Lösung ist ein Hardware-Zufallszahlengenerator. Möglicherweise ist bereits eine in Ihr Motherboard integriert. In der Dokumentation zu hw_random finden Sie Anweisungen, wie Sie herausfinden können, ob Sie es haben und wie Sie es verwenden. Das rng-tools-Paket enthält einen Daemon, in den Hardware-generierte Entropie eingespeist wird
/dev/random
.Wenn auf Ihrem System kein HRNG verfügbar ist und Sie bereit sind, die Entropiestärke für die Leistung zu opfern, sollten Sie ein gutes PRNG mit Daten aus erstellen
/dev/random
und das PRNG den Großteil der Arbeit erledigen lassen. In SP800-90 sind mehrere NIST-zugelassene PRNGs aufgeführt, die einfach zu implementieren sind.quelle
Unter Verwendung von Java 8 stellte ich fest, dass
SecureRandom.getInstanceStrong()
mir unter Linux derNativePRNGBlocking
Algorithmus den Algorithmus geben würde . Dies blockierte oft für viele Sekunden, um ein paar Bytes Salz zu erzeugen.Ich habe
NativePRNGNonBlocking
stattdessen explizit nachgefragt und wie vom Namen erwartet, wurde es nicht mehr blockiert. Ich habe keine Ahnung, welche Auswirkungen dies auf die Sicherheit hat. Vermutlich kann die nicht blockierende Version nicht garantieren, wie viel Entropie verwendet wird.Update : Ok, ich habe diese hervorragende Erklärung gefunden .
Um es nicht zu blockieren, verwenden Sie es auf den Punkt gebracht
new SecureRandom()
. Dies verwendet/dev/urandom
, was nicht blockiert und im Grunde so sicher ist wie/dev/random
. Aus dem Beitrag: "Das einzige Mal, dass Sie / dev / random aufrufen möchten, ist, wenn die Maschine zum ersten Mal startet und sich noch keine Entropie angesammelt hat."SecureRandom.getInstanceStrong()
gibt Ihnen das absolut stärkste RNG, aber es ist nur in Situationen sicher, in denen eine Reihe von Blockierungen Sie nicht beeinträchtigt.quelle
getInstanceStrong()
, beispielsweise für TLS-Zertifikate. Und selbst dann würde ich liebernew SecureRandom()
einen FIPS-kompatiblen Schlüsselpaargenerator oder Zufallszahlengenerator verwenden. Ja, dies liefert eine Antwort, wenn/dev/urandom
es nicht blockiert: Am Ende hängt es immer noch von der Systementropie ab. aber es ist im Allgemeinen ein sehr guter Rat . Wenn/dev/urandom
Sie blockieren, müssen Sie möglicherweise die Ursache des Problems und nicht Ihre Java-Anwendung beheben.Es gibt ein Tool (zumindest unter Ubuntu), das künstliche Zufälligkeit in Ihr System einspeist. Der Befehl lautet einfach:
und vielleicht brauchen Sie vorne einen Sudo. Wenn Sie kein rng-tools-Paket haben, müssen Sie es installieren. Ich habe es versucht und es hat mir definitiv geholfen!
Quelle: matt vs world
quelle
sudo rngd -r /dev/urandom
mitsudo apt install rng-tools
in xenial kombinierenIch stand vor dem gleichen Problem . Nach einigem Googeln mit den richtigen Suchbegriffen bin ich auf diesen schönen Artikel über DigitalOcean gestoßen .
hasged ist eine mögliche Lösung, ohne Kompromisse bei der Sicherheit einzugehen.
Ich zitiere hier lediglich den relevanten Teil aus dem Artikel.
So installieren Sie hasged
Befolgen Sie die Schritte in diesem Artikel. https://www.digitalocean.com/community/tutorials/how-to-setup-additional-entropy-for-cloud-servers-using-haveged
Ich habe es hier gepostet
quelle
Das Problem, auf das Sie verwiesen haben,
/dev/random
liegt nicht beimSecureRandom
Algorithmus, sondern bei der verwendeten Zufallsquelle. Die beiden sind orthogonal. Sie sollten herausfinden, welcher der beiden Sie verlangsamt.Gelegentliche Mathematik-Seite, die Sie verlinkt haben, erwähnt ausdrücklich, dass sie nicht die Quelle der Zufälligkeit ansprechen.
Sie können verschiedene JCE-Anbieter wie BouncyCastle ausprobieren, um festzustellen, ob ihre Implementierung
SecureRandom
schneller ist.Eine kurze Suche zeigt auch Linux-Patches, die die Standardimplementierung durch Fortuna ersetzen. Ich weiß nicht viel mehr darüber, aber Sie können gerne nachforschen.
Ich sollte auch erwähnen, dass es zwar sehr gefährlich ist, einen schlecht implementierten
SecureRandom
Algorithmus und / oder eine Zufallsquelle zu verwenden, Sie jedoch Ihren eigenen JCE-Provider mit einer benutzerdefinierten Implementierung von rollen könnenSecureRandomSpi
. Sie müssen einen Prozess mit Sun durchlaufen, um Ihren Provider signieren zu lassen, aber das ist eigentlich ziemlich einfach. Sie müssen ihnen lediglich ein Formular faxen, aus dem hervorgeht, dass Sie die US-Exportbeschränkungen für Kryptobibliotheken kennen.quelle
Verwenden Sie den sicheren Zufall als Initialisierungsquelle für einen wiederkehrenden Algorithmus. Sie könnten dann einen Mersenne-Twister für die Massenarbeit verwenden, anstatt den in UncommonMath, der schon eine Weile existiert und sich als besser als andere Prng erwiesen hat
http://en.wikipedia.org/wiki/Mersenne_twister
Stellen Sie sicher, dass Sie ab und zu den für die Initialisierung verwendeten sicheren Zufall aktualisieren. Sie können beispielsweise einen sicheren Zufall pro Client generieren lassen, indem Sie einen Mersenne-Twister-Pseudozufallsgenerator pro Client verwenden, um einen ausreichend hohen Randomisierungsgrad zu erzielen
quelle
Random
, aber nicht fürSecureRandom
.Gemäß der Dokumentation werden die verschiedenen von SecureRandom verwendeten Algorithmen in der Reihenfolge ihrer Präferenz verwendet:
Da Sie nach Linux gefragt haben, ignoriere ich die Windows-Implementierung und auch SunPKCS11, das nur unter Solaris wirklich verfügbar ist, es sei denn, Sie haben es selbst installiert - und dann würden Sie dies nicht fragen.
Nach derselben Dokumentation werden diese Algorithmen verwendet
SHA1PRNG Das
anfängliche Seeding erfolgt derzeit über eine Kombination von Systemattributen und dem Entropiesammelgerät java.security.
NativePRNG
nextBytes()
verwendet/dev/urandom
generateSeed()
Verwendungen/dev/random
NativePRNGBlocking
nextBytes()
undgenerateSeed()
Verwendung/dev/random
NativePRNGNonBlocking
nextBytes()
undgenerateSeed()
Verwendung/dev/urandom
Das heißt, wenn Sie verwenden
SecureRandom random = new SecureRandom()
, wird diese Liste durchsucht, bis eine funktionierende gefunden wird, bei der es sich normalerweise um NativePRNG handelt. Und das bedeutet, dass es sich selbst aussät/dev/random
(oder dies verwendet, wenn Sie explizit einen/dev/urandom
Startwert generieren) und dann zum Abrufen der nächsten Bytes, Ints, Double, Booleschen Werte, What-Have-Yous verwendet.Da
/dev/random
blockiert (es blockiert, bis genügend Entropie im Entropiepool vorhanden ist), kann dies die Leistung beeinträchtigen.Eine Lösung dafür ist die Verwendung von etwas wie Hged, um genügend Entropie zu erzeugen, eine andere Lösung verwendet
/dev/urandom
stattdessen. Während Sie , dass für die gesamte Jvm, eine bessere Lösung macht es für diese bestimmte Instanz einstellen könnteSecureRandom
, unter VerwendungSecureRandom random = SecureRandom.getInstance("NativePRNGNonBlocking")
. Beachten Sie, dass diese Methode bei NativePRNGNonBlocking eine NoSuchAlgorithmException auslösen kann. Seien Sie also bereit, auf die Standardeinstellung zurückzugreifen.Beachten Sie auch, dass sich andere * nix-Systeme
/dev/urandom
möglicherweise anders verhalten .Ist
/dev/urandom
zufällig genug?Konventionelle Weisheit besagt, dass nur
/dev/random
zufällig genug ist. Einige Stimmen unterscheiden sich jedoch. In "Der richtige Weg, SecureRandom zu verwenden" und "Mythen über / dev / urandom" wird argumentiert, dass dies/dev/urandom/
genauso gut ist.Die Benutzer auf dem Informationssicherheitsstapel stimmen dem zu . Grundsätzlich
/dev/urandom
ist es für Ihren Zweck in Ordnung , wenn Sie fragen müssen .quelle
Ich bin selbst nicht auf dieses Problem gestoßen, aber ich habe beim Programmstart einen Thread erzeugt, der sofort versucht, einen Startwert zu generieren, und dann stirbt. Die Methode, die Sie für Zufälle aufrufen, wird diesem Thread hinzugefügt, wenn er aktiv ist, sodass der erste Aufruf nur blockiert wird, wenn er sehr früh in der Programmausführung auftritt.
quelle
Meine Erfahrung war nur mit der langsamen Initialisierung des PRNG, nicht mit der Erzeugung von Zufallsdaten danach. Versuchen Sie eine eifrigere Initialisierungsstrategie. Da die Erstellung teuer ist, behandeln Sie sie wie einen Singleton und verwenden Sie dieselbe Instanz erneut. Wenn für eine Instanz zu viele Thread-Konflikte auftreten, bündeln Sie sie oder machen Sie sie threadlokal.
Gehen Sie bei der Generierung von Zufallszahlen keine Kompromisse ein. Eine Schwäche dort gefährdet Ihre gesamte Sicherheit.
Ich sehe nicht viele COTS-Generatoren auf der Basis des atomaren Zerfalls, aber es gibt verschiedene Pläne für sie, wenn Sie wirklich viele zufällige Daten benötigen. Eine Seite, die immer interessante Dinge zu sehen hat, einschließlich HotBits, ist John Walkers Fourmilab.
quelle
SecureRandom
in den letzten 10 Jahren in seiner Entropie-Sammlung ein paar Mal geändert hat.SecureRandom
immer noch ein Problem ist, aber eine niedrige Entropie in einem System wird immer ein Problem sein. Wenn Sie einen Singleton verwenden, wird stark gekoppelter Code erstellt, der ein Design-Anti-Pattern ist. Es sollte daher mit äußerster Sorgfalt verwendet werden; Sie müssten vorzugsweise alle Verweise im Code umkehren, um das Problem zu beheben.Es hört sich so an, als ob Sie Ihre RNG-Anforderungen klarer definieren sollten. Die stärkste kryptografische RNG-Anforderung (so wie ich es verstehe) wäre, dass Sie, selbst wenn Sie den Algorithmus kennen, mit dem sie generiert wurden, und Sie alle zuvor generierten Zufallszahlen kennen, keine nützlichen Informationen über eine der in der generierten Zufallszahlen erhalten könnten Zukunft, ohne eine unpraktische Menge an Rechenleistung auszugeben.
Wenn Sie diese vollständige Garantie für Zufälligkeit nicht benötigen, gibt es wahrscheinlich angemessene Leistungskompromisse. Ich würde eher Dan Dyers Antwort zu AESCounterRNG von Uncommons-Maths oder Fortuna zustimmen (einer seiner Autoren ist Bruce Schneier, ein Experte für Kryptographie). Ich habe es auch nie benutzt, aber die Ideen erscheinen auf den ersten Blick seriös.
Ich würde denken , wenn Sie regelmäßig einen anfänglichen zufälligen Startwert generieren könnten (z. B. einmal pro Tag oder Stunde oder was auch immer), könnten Sie eine schnelle Stream-Verschlüsselung verwenden, um Zufallszahlen aus aufeinanderfolgenden Teilen des Streams zu generieren (wenn die Stream-Chiffre XOR verwendet, dann nur Übergeben Sie einen Strom von Nullen oder greifen Sie direkt auf die XOR-Bits zu. ECRYPTs eStreamDas Projekt enthält viele gute Informationen, einschließlich Leistungsbenchmarks. Dies würde die Entropie zwischen den Zeitpunkten, zu denen Sie sie auffüllen, nicht aufrechterhalten. Wenn also jemand eine der Zufallszahlen und den von Ihnen verwendeten Algorithmus kennt, ist es technisch möglicherweise möglich, mit viel Rechenleistung die Stream-Verschlüsselung zu brechen und Erraten Sie den internen Zustand, um zukünftige Zufallszahlen vorhersagen zu können. Sie müssten sich jedoch entscheiden, ob dieses Risiko und seine Folgen ausreichen, um die Kosten für die Aufrechterhaltung der Entropie zu rechtfertigen.
Bearbeiten: Hier sind einige kryptografische Kursnotizen zu RNG, die ich im Internet gefunden habe und die für dieses Thema sehr relevant aussehen.
quelle
Wenn Ihre Hardware dies unterstützt, verwenden Sie das Java RdRand-Dienstprogramm, dessen Autor ich bin.
Es basiert auf Intels
RDRAND
Anweisungen und ist ungefähr zehnmal schneller alsSecureRandom
und ohne Bandbreitenprobleme bei der Implementierung großer Volumes.Beachten Sie, dass diese Implementierung nur auf den CPUs funktioniert, die den Befehl bereitstellen (dh wenn das
rdrand
Prozessorflag gesetzt ist). Sie müssen es explizit über denRdRandRandom()
Konstruktor instanziieren . Es wurde kein spezifischesProvider
implementiert.quelle
RDRAND
ist eine gute Quelle, aber es ist ein bisschen nicht vertrauenswürdig. Es muss definitiv eine Eingabe von vielen in einen Sammler sein (keine Beleidigung für David Johnston).Etwas anderes zu betrachten ist die Eigenschaft securerandom.source in der Datei lib / security / java.security
Die Verwendung von / dev / urandom anstelle von / dev / random kann einen Leistungsvorteil haben. Denken Sie daran, wenn die Qualität der Zufallszahlen wichtig ist, gehen Sie keine Kompromisse ein, die die Sicherheit beeinträchtigen.
quelle