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?
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.
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 /./
)
Unter Linux ist die Standardimplementierung für SecureRandom
NativePRNG
(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.
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:
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.
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.
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.
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.
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
Ich stand gleich vor Problem . Nach einigem googeln mit den richtigen Suchbegriffen bin ich auf diesen netten Artikel auf DigitalOcean gestoßen.
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
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
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.
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
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.
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.
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.
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.
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.
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.