web-dev-qa-db-de.com

Wie löst man langsam Java `SecureRandom`?

Wenn Sie in Java eine kryptografisch starke Zufallszahl wünschen, verwenden Sie SecureRandom. Leider kann SecureRandom sehr langsam sein. Wenn es unter Linux /dev/random Verwendet, kann es das Warten auf ausreichende Entropie zum Aufbau blockieren. Wie vermeidest du die Leistungsminderung?

Hat jemand ncommon Maths als Lösung für dieses Problem verwendet?

Kann jemand bestätigen, dass dieses Leistungsproblem in JDK 6 behoben wurde?

152
David G

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 als SecureRandom, obwohl es eine Verbindung zum Internet herstellen kann, um Startdaten von einer bestimmten Website herunterzuladen. Ich vermute, dass dies wahrscheinlich nicht schneller ist als /dev/random, Wo dies verfügbar ist.

Wenn Sie ein PRNG möchten, gehen Sie folgendermaßen vor:

SecureRandom.getInstance("SHA1PRNG");

Welche Zeichenfolgen unterstützt werden, hängt vom Anbieter SecureRandom SPI=) ab. Sie können sie jedoch mit Security.getProviders() und Provider.getService() auflisten.

Sun mag SHA1PRNG sehr, daher ist es weit verbreitet. Es ist nicht besonders schnell, wie PRNGs gehen, aber PRNGs werden nur Zahlen knacken, nicht für die physikalische Messung der Entropie blockieren.

Die Ausnahme ist, dass, wenn Sie setSeed() nicht aufrufen, bevor Sie Daten abrufen, sich das PRNG beim ersten Aufrufen von next() oder nextBytes(). In der Regel wird hierfür eine relativ kleine Menge echter Zufallsdaten aus dem System verwendet. Dieser Aufruf kann blockieren, macht Ihre Quelle für Zufallszahlen jedoch weitaus sicherer als jede Variante von "Hash the Current" Mal zusammen mit der PID 27 addieren und auf das Beste hoffen ". Wenn Sie jedoch nur Zufallszahlen für ein Spiel benötigen oder wenn Sie möchten, dass der Stream in Zukunft wiederholt werden kann, indem Sie denselben Startwert für Testzwecke verwenden, ein unsicherer Saatgut ist immer noch nützlich.

72
Steve Jessop

Sie sollten in der Lage sein, das schnellere, aber etwas weniger sichere/dev/urandom unter Linux auszuwählen, indem Sie Folgendes verwenden:

-Djava.security.egd=file:/dev/urandom

Dies funktioniert jedoch nicht mit Java 5 und höher ( Java Bug 6202721 ). Die vorgeschlagene Lösung ist:

-Djava.security.egd=file:/dev/./urandom

(Beachten Sie die zusätzlichen /./)

171
Thomas Leonard

Unter Linux ist die Standardimplementierung für SecureRandomNativePRNG (Quellcode hier ), was in der Regel sehr langsam ist. Unter Windows ist der Standardwert SHA1PRNG, auf das Sie, wie andere bereits hingewiesen haben, auch unter Linux zurückgreifen können, wenn Sie es explizit angeben.

NativePRNG unterscheidet sich von SHA1PRNG und Uncommons Maths ' AESCounterRNG , indem es kontinuierlich Entropie vom Betriebssystem empfängt (durch Lesen von /dev/urandom). Die anderen PRNGs erhalten nach dem Säen keine zusätzliche Entropie.

AESCounterRNG ist ungefähr 10x schneller als SHA1PRNG, welches IIRC selbst zwei- oder dreimal schneller ist als NativePRNG.

Wenn Sie eine schnellere PRNG, die nach der Initialisierung Entropie erhält, suchen Sie nach einer Java Implementierung von Fortuna . Der Kern PRNG einer Fortuna-Implementierung ist mit der von AESCounterRNG verwendeten identisch, es gibt jedoch auch ein ausgeklügeltes System für Entropie-Pooling und automatisches Reseeding.

34
Dan Dyer

Viele Linux-Distributionen (hauptsächlich Debian-basierte) konfigurieren OpenJDK so, dass /dev/random Für die Entropie verwendet wird.

/dev/random Ist per definitionem langsam (und kann sogar blocken).

Von hier aus haben Sie zwei Möglichkeiten, wie Sie die Sperre aufheben können:

  1. Entropie verbessern oder
  2. Reduzieren Sie die Zufallsanforderungen.

Option 1, Entropie verbessern

Um mehr Entropie in /dev/random Zu erhalten, versuchen Sie es mit dem Daemon . Es ist ein Daemon, der kontinuierlich 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:

apt-get install haveged
update-rc.d haveged defaults
service haveged start

Auf RHEL/CentOS:

yum install haveged
systemctl enable haveged
systemctl start haveged

Option 2. Zufallsanforderungen reduzieren

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 stattdessen zu /dev/urandom Wechseln, das garantiert nicht blockiert.

Bearbeiten Sie dazu die Datei jre/lib/security/Java.security In Ihrer Java Standardinstallation, um /dev/urandom Zu verwenden (aufgrund eines anderen Fehlers es muss angegeben werden als /dev/./urandom).

So was:

#securerandom.source=file:/dev/random
securerandom.source=file:/dev/./urandom

Dann müssen Sie es niemals in der Befehlszeile angeben.


Hinweis: Wenn Sie kryptografieren, benötigen Sie eine gute Entropie. Beispiel - Das Problem mit Android PRNG verringerte die Sicherheit von Bitcoin-Brieftaschen.

22
rustyx

Ich hatte ein ähnliches Problem mit Aufrufen von SecureRandom, die ungefähr 25 Sekunden lang auf einem kopflosen Debian-Server blockierten. Ich habe den Daemon haveged installiert, um sicherzustellen, dass /dev/random wird nachgefüllt, auf Headless-Servern benötigen Sie so etwas, um die erforderliche Entropie zu erzeugen. Meine Aufrufe von SecureRandom dauern jetzt vielleicht Millisekunden.

16
thunder

Wenn Sie wirklich "kryptografisch starke" Zufälligkeit wollen, dann brauchen Sie eine starke Entropiequelle. /dev/random Ist langsam, da es auf Systemereignisse warten muss, um Entropie zu sammeln (Festplattenlesevorgänge, Netzwerkpakete, Mausbewegungen, Tastendrücke usw.).

Eine schnellere Lösung ist ein Hardware-Zufallszahlengenerator. Möglicherweise ist bereits eine in Ihr Motherboard integriert. Lesen Sie die hw_random-Dokumentation , um herauszufinden, ob und wie Sie es verwenden. Das Paket rng-tools enthält einen Daemon, der die von der Hardware erzeugte Entropie in /dev/random Einspeist.

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 /dev/random Setzen und lassen Die PRNG erledigen den Großteil der Arbeit. In SP800-9 sind mehrere NIST-genehmigte PRNGs aufgeführt, deren Implementierung einfach ist.

11
Chris Kite

Das von Ihnen angesprochene Problem mit /dev/random bezieht sich nicht auf den Algorithmus SecureRandom, sondern auf die verwendete Zufallsquelle. Die beiden sind orthogonal. Sie sollten herausfinden, welcher der beiden Sie verlangsamt.

Auf der von Ihnen verlinkten ungewöhnlichen Mathematik-Seite wird ausdrücklich darauf hingewiesen, dass sie sich nicht mit der Quelle der Zufälligkeit befasst.

Sie können verschiedene JCE-Anbieter wie BouncyCastle ausprobieren, um festzustellen, ob ihre Implementierung von SecureRandom schneller ist.

Eine kurze Suche enthüllt auch Linux-Patches, die die Standardimplementierung mit 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 schlecht implementierte Zufallsquelle zu verwenden, Sie aber Ihren eigenen JCE-Provider mit einer benutzerdefinierten Implementierung von SecureRandomSpi erstellen können. Sie müssen einen Prozess mit Sun durchlaufen, um Ihren Provider zu signieren, aber es ist eigentlich ziemlich einfach. Sie müssen ihnen lediglich ein Formular faxen, in dem angegeben wird, dass Sie die US-Exportbeschränkungen für Kryptobibliotheken kennen.

5
ykaganovich

Es gibt ein Tool (zumindest auf Ubuntu), das künstliche Zufälligkeit in Ihr System einbringt. Der Befehl lautet einfach:

rngd -r /dev/urandom

und vielleicht brauchen Sie einen Sudo an der Front. Wenn Sie kein rng-tools-Paket haben, müssen Sie es installieren. Ich habe es versucht und es hat mir definitiv geholfen!

Quelle: matt gegen Welt

5
David K

Ich stand gleich vor Problem . Nach einigem googeln mit den richtigen Suchbegriffen bin ich auf diesen netten Artikel auf DigitalOcean gestoßen.

haveged ist eine potenzielle Lösung ohne Kompromisse bei der Sicherheit.

Ich zitiere hier nur den relevanten Teil des Artikels.

Basierend auf dem HAVEGE-Prinzip und zuvor basierend auf der zugehörigen Bibliothek ermöglicht haveged das Erzeugen von Zufälligkeiten basierend auf Variationen der Code-Ausführungszeit auf einem Prozessor. Da es selbst in derselben Umgebung auf derselben Hardware nahezu unmöglich ist, dass ein Codeteil exakt dieselbe Ausführungszeit benötigt, sollte der Zeitpunkt für die Ausführung eines einzelnen oder mehrerer Programme geeignet sein, um eine zufällige Quelle zu erzeugen. Bei der Implementierung mit Haveged wird die Zufallsquelle Ihres Systems (normalerweise/dev/random) unter Verwendung von Unterschieden im Zeitstempelzähler (TSC) Ihres Prozessors nach wiederholter Ausführung einer Schleife aussortiert

Wie installiere ich Haveged

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 gepostet hier

5
so-random-dude

Unter Verwendung von Java 8) stellte ich fest, dass der Aufruf von SecureRandom.getInstanceStrong() unter Linux den Algorithmus NativePRNGBlocking liefert, der häufig für viele Sekunden blockiert, um ein paar Bytes zu generieren aus Salz.

Ich habe stattdessen explizit nach NativePRNGNonBlocking gefragt und es wurde, wie vom Namen erwartet, nicht mehr blockiert. Ich habe keine Ahnung, welche Auswirkungen dies auf die Sicherheit hat. Vermutlich kann die nicht blockierende Version die Menge der verwendeten Entropie nicht garantieren.

Update : Ok, ich fand diese ausgezeichnete Erklärung .

Kurz gesagt, verwenden Sie new SecureRandom(), um Blockierungen zu vermeiden. Dies verwendet /dev/urandom, Das nicht blockiert und im Grunde genommen 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 hochfährt 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 Sie durch eine Reihe von Blockierungen nicht beeinträchtigt werden.

4
Lachlan

Verwenden Sie den sicheren Zufall als Initialisierungsquelle für einen wiederkehrenden Algorithmus. Sie könnten dann einen Mersenne-Twister für die Massenarbeit anstelle desjenigen in UncommonMath verwenden, das es schon eine Weile gibt und das 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 Zufallsgenerator aktualisieren. Sie können beispielsweise einen sicheren Zufallsgenerator pro Client generieren lassen, indem Sie einen Mersenne-Twister-Pseudozufallsgenerator pro Client verwenden, um einen ausreichend hohen Grad an Zufallsgenerierung zu erzielen

4

Ich habe dieses Problem nicht selbst angegriffen, aber ich habe beim Programmstart einen Thread erzeugt, der sofort versucht, einen Startwert zu generieren, und dann stirbt. Die Methode, die Sie für Randoms aufrufen, verbindet sich mit diesem Thread, wenn er aktiv ist, sodass der erste Aufruf nur blockiert, wenn er sehr früh in der Programmausführung auftritt.

2
Nick

Wenn Ihre Hardware dies unterstützt, versuchen Sie es mit mit Java RdRand Utility , dessen Autor ich bin.

Es basiert auf Intels RDRAND -Anweisung und ist ungefähr 10-mal schneller als SecureRandom und es gibt keine Bandbreitenprobleme für die Implementierung großer Volumes.


Beachten Sie, dass diese Implementierung nur auf den CPUs funktioniert, die den Befehl bereitstellen (d. H. Wenn das Prozessor-Flag rdrand gesetzt ist). Sie müssen es explizit über den Konstruktor RdRandRandom() instanziieren. Es wurde kein spezifisches Provider implementiert.

2
user2781824

Es hört sich so an, als ob Sie klarer über Ihre RNG-Anforderungen sein sollten. Die stärkste kryptografische RNG-Anforderung (so wie ich es verstehe) wäre, dass selbst wenn Sie den Algorithmus kennen, mit dem sie generiert wurden, und Sie alle zuvor generierten Zufallszahlen kennen, Sie keine nützlichen Informationen über eine der in generierten Zufallszahlen erhalten könnten Zukunft, ohne eine unpraktische Menge an Rechenleistung auszugeben.

Wenn Sie diese vollständige Zufallsgarantie nicht benötigen, gibt es wahrscheinlich geeignete Leistungskompromisse. Ich würde eher zustimmen Dan Dyers Antwort über AESCounterRNG von Uncommons-Maths oder Fortuna (einer seiner Autoren ist Bruce Schneier, ein Experte für Kryptographie). Ich habe auch nie verwendet, aber die Ideen scheinen auf den ersten Blick seriös zu sein.

Ich würde denken , dass, wenn Sie einen anfänglichen zufälligen Startwert periodisch erzeugen könnten (z. B. einmal pro Tag oder Stunde oder was auch immer), Sie eine schnelle Stream-Verschlüsselung verwenden könnten, um Generieren Sie Zufallszahlen aus aufeinanderfolgenden Teilen des Streams (wenn die Stream-Verschlüsselung XOR verwendet, übergeben Sie einfach einen Stream mit Nullen oder greifen Sie direkt auf die XOR Bits) zu). Das eStream -Projekt von ECRYPT enthält viele gute Informationen, einschließlich Leistungsbenchmarks. Dies würde die Entropie zwischen den Zeitpunkten, zu denen Sie es auffüllen, nicht aufrechterhalten. Wenn also jemand eine der Zufallszahlen und den von Ihnen verwendeten Algorithmus kennt, Technisch gesehen könnte es mit viel Rechenleistung möglich sein, die Stream-Chiffre zu knacken und ihren internen Zustand zu erraten, um zukünftige Zufallszahlen vorhersagen zu können. Sie müssten sich jedoch entscheiden, ob dieses Risiko und seine Konsequenzen ausreichen, um das zu rechtfertigen Kosten für die Aufrechterhaltung der Entropie.

Bearbeiten: hier sind einige kryptografische Kursnotizen zu RNG Ich habe im Internet festgestellt, dass sie für dieses Thema sehr relevant aussehen.

2
Jason S

Meine Erfahrung war nur mit der langsamen Initialisierung des PRNG, nicht mit der Erzeugung von Zufallsdaten danach. Versuchen Sie eine eifrigere Initialisierungsstrategie. Da ihre Erstellung teuer ist, sollten Sie sie wie einen Singleton behandeln und dieselbe Instanz wiederverwenden. Wenn es für eine Instanz zu viele Thread-Konflikte gibt, bündeln Sie sie oder machen Sie sie thread-lokal.

Gehen Sie keine Kompromisse bei der Generierung von Zufallszahlen ein. Eine Schwäche dort beeinträchtigt Ihre gesamte Sicherheit.

Ich sehe nicht viele COTS-Atomic-Decay-basierte Generatoren, 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.

2
erickson

Zu beachten ist außerdem 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, machen Sie keinen Kompromiss, der die Sicherheit verletzt.

1
Diastrophism

Sie können das Apache-Commons-Math-Projekt ausprobieren, das einige Implementierungen bekannter Algorithmen enthält:

https://commons.Apache.org/proper/commons-math/userguide/random.html

Seien Sie jedoch vorsichtig mit der Leistung. Der Standardkonstruktor von RandomDataGenerator erstellt eine dedizierte Instanz von Well19937c, das ist ein sehr teurer Vorgang.

Gemäß der Dokumentation ist diese Klasse nicht threadsicher . Wenn Sie jedoch sicherstellen können, dass nur ein Thread auf diese Klasse zugreift, können Sie nur eine Instanz initialisieren pro Thread.

0
jfcorugedo