Was ist die beste Methode, um in Arduino eine echte (im Gegensatz zu einer Pseudo-Zufallszahl) zu erhalten, oder zumindest die bestmögliche Annäherung? Nach meinem Verständnis ist die Funktion randomSeed (analogRead (x)) nicht zufällig genug.
Wenn möglich, sollte die Methode das grundlegende Arduino-Setup alleine nutzen (keine zusätzlichen Sensoren). Lösungen mit externen Sensoren sind willkommen, wenn sie die Zufälligkeit gegenüber dem Grundaufbau deutlich verbessern.
programming
Rexcirus
quelle
quelle
Antworten:
Die Entropy-Bibliothek verwendet:
Diese Lösung gefällt mir, weil sie keine Pins Ihres Mikrocontrollers belegt und keine externen Schaltkreise erfordert. Dies macht es auch weniger anfällig für externe Ausfälle.
Neben einer Bibliothek wird auch eine Skizze bereitgestellt, die die Verwendung derselben Technik demonstriert, mit der ein zufälliger Startwert für den PRNG des Mikrocontrollers ohne die Bibliothek generiert wird: https://sites.google.com/site/astudyofentropy/project-definition / timer-jitter-entropiequellen / entropiebibliothek / arduino-random-seed
quelle
randomSeed(analogRead(x))
erzeugt nur 255 Folgen von Zahlen, was es trivial macht, alle Combos auszuprobieren und ein Orakel zu erzeugen, das mit Ihrem Ausgabestream gekoppelt werden kann und die gesamte Ausgabe zu 100% vorhersagt. Sie sind jedoch auf dem richtigen Weg, es ist nur ein Zahlenspiel, und Sie brauchen VIEL mehr davon. Beispiel: Nehmen Sie 100 analoge Lesevorgänge von 4 ADCs, addieren Sie diese und geben Sie sie an. DasrandomSeed
wäre viel besser. Für maximale Sicherheit benötigen Sie sowohl unvorhersehbare Eingaben als auch nicht deterministisches Mischen.Ich bin kein Kryptograf, aber ich habe Tausende von Stunden damit verbracht, nach zufälligen Generatoren für Hardware und Software zu suchen und diese zu erstellen.
Unvorhersehbare Eingabe:
Möglicherweise unvorhersehbarer Eingang:
Externer unvorhersehbarer Eingang:
RANDOM_REG32
Extrem schnell und unvorhersehbarsammeln Das letzte, was Sie tun möchten, ist Entropie auszuspucken, wie es kommt. Es ist einfacher, einen Münzwurf zu erraten als einen Eimer mit Münzen. Summieren ist gut.
unsigned long bank;
dann ist späterbank+= thisSample;
gut; es wird sich überschlagen.bank[32]
ist noch besser, lesen Sie weiter. Sie möchten für jeden Output-Block mindestens 8 Input-Samples sammeln, im Idealfall viel mehr.Schutz vor Vergiftungen Wenn das Erhitzen der Platine einen gewissen maximalen Clock-Jitter verursacht, ist dies ein Angriffsvektor. Dasselbe gilt für das Abstrahlen von RFI zu den analogen Read () - Eingängen. Ein weiterer häufiger Angriff, bei dem die Einheit einfach vom Stromnetz getrennt wird und die gesamte angesammelte Entropie verloren geht. Sie sollten erst dann Zahlen ausgeben, wenn Sie wissen, dass dies auch auf Kosten der Geschwindigkeit sicher ist.
Aus diesem Grund möchten Sie mit EEPROM, SD usw. eine gewisse Entropie auf lange Sicht erhalten. Schauen Sie sich den Fortuna PRNG an , der 32 Bänke verwendet, von denen jede halb so oft aktualisiert wird wie die vorherige. Das macht es schwierig, alle 32 Banken in angemessener Zeit anzugreifen.
Verarbeitung Sobald Sie "Entropie" gesammelt haben, müssen Sie diese bereinigen und auf eine schwer umkehrbare Weise von der Eingabe trennen. SHA / 1/256 ist dafür gut. Sie können SHA1 (oder sogar MD5) für die Geschwindigkeit verwenden, da Sie keine Sicherheitsanfälligkeit in Klartext haben. Zur Ernte, nie die volle entopy Bank verwenden und immer immer ein „Salz“ mit dem Ausgang hinzufügen , die jedes Mal anders ist , um identische Ausgänge zu verhindern gegeben keine Entropie Bankwechsel:
output = sha1( String(micros()) + String(bank[0]) + [...] );
Die sha Funktion beide kaschiert Eingänge und bleicht Ausgang, Schutz vor schwachen Samen, niedrige akkumulierte ent und andere häufige Probleme.Um Timer-Eingänge zu verwenden, müssen Sie sie unbestimmt machen. Dies ist eine einfache als
delayMicroseconds(lastSample % 255)
; Dadurch wird eine unvorhersehbare Zeitspanne angehalten, und die "aufeinanderfolgende" Uhr liest den Unterschied ungleichmäßig. Tun Sie dies regelmäßig,if(analogRead(A1)>200){...}
vorausgesetzt, A1 ist verrauscht oder mit einem dynamischen Eingang verbunden. Wenn es schwierig ist, jede Gabelung Ihres Flusses zu bestimmen, wird die Kryptoanalyse für dekompilierte / gerippte Ausgaben verhindert.Wirkliche Sicherheit besteht darin, dass der Angreifer Ihr gesamtes System kennt und es dennoch nicht überwinden kann.
Zuletzt überprüfen Sie Ihre Arbeit. Führen Sie Ihre Ausgabe über ENT.EXE aus (auch für nix / mac verfügbar) und prüfen Sie, ob sie funktioniert . Am wichtigsten ist die Chi-Quadrat-Verteilung, die normalerweise zwischen 33% und 66% liegen sollte. Wenn Sie 1,43% oder 99,999% oder so etwas bekommen, mehr als einen Test hintereinander, ist Ihr Zufall Mist. Sie möchten auch, dass die Entropie-HNO-Berichte so nahe wie möglich bei 8 Bit pro Byte liegen,> 7,9 sicher.
TLDR: Der einfachste und narrensicherste Weg ist das HWRNG des ESP8266. Es ist schnell, gleichmäßig und unvorhersehbar. Führen Sie so etwas auf einem ESP8266 mit Ardunio-Core aus und verwenden Sie die serielle Schnittstelle, um mit dem AVR zu kommunizieren:
** bearbeiten
Hier ist eine HWRNG-Skizze, die ich vor einiger Zeit geschrieben habe und die nicht nur als Sammler, sondern als ganzer CSPRNG fungiert, der aus der seriellen Schnittstelle ausspuckt. Es ist für einen Pro-Mini gebaut, sollte aber leicht an andere Boards anpassbar sein. Sie können nur schwebende analoge Pins verwenden, aber es ist besser, ihnen etwas hinzuzufügen, vorzugsweise verschiedene Dinge. Wie Mikrofone, LDRs, Thermistoren (auf maximale Temperatur eingestellt) und sogar lange Drähte. Bei HNO funktioniert es ziemlich gut, wenn Sie sogar mäßiges Rauschen haben.
Die Skizze integriert mehrere Begriffe, die ich in meiner Antwort und den nachfolgenden Kommentaren erwähnt habe: Akkumulieren der Entropie, Dehnen durch Überabtasten der weniger als idealen Entropie (von Neumann sagte, es sei cool) und Hasching zur Gleichförmigkeit. Es verzichtet auf die Schätzung der Entropiequalität zugunsten von "irgendetwas Mögliches Dynamisches" und Vermischen unter Verwendung eines kryptografischen Primitivs.
quelle
Nach meiner Erfahrung hat
analogRead()
ein Schwimmstift eine sehr niedrige Entropie. Vielleicht ein oder zwei zufällige Bits pro Anruf. Sie wollen auf jeden Fall etwas Besseres. Der in der Antwort von per1234 vorgeschlagene Jitter des Watchdog-Timers ist eine gute Alternative. Es erzeugt jedoch Entropie mit einer ziemlich langsamen Rate, was ein Problem sein kann, wenn Sie es direkt beim Start des Programms benötigen. Dandavis hat einige gute Vorschläge, aber sie erfordern im Allgemeinen entweder einen ESP8266 oder externe Hardware.Es gibt eine interessante Entropiequelle, die noch nicht erwähnt wurde: den Inhalt des nicht initialisierten RAM. Wenn die MCU eingeschaltet wird, werden einige ihrer RAM-Bits (diejenigen, die zufällig die symmetrischsten Transistoren aufweisen) in einem zufälligen Zustand gestartet. Wie in diesem Hackaday-Artikel erörtert , kann dies als Entropiequelle verwendet werden. Es ist nur bei einem Kaltstart verfügbar, sodass Sie damit einen anfänglichen Entropiepool füllen können, den Sie dann regelmäßig aus einer anderen, möglicherweise langsamen Quelle auffüllen würden. Auf diese Weise kann Ihr Programm seine Arbeit aufnehmen, ohne darauf warten zu müssen, dass sich der Pool langsam füllt.
Hier ist ein Beispiel, wie dies auf einem AVR-basierten Arduino geerntet werden könnte. Das Code-Snippet unterhalb von XOR fasst den gesamten Arbeitsspeicher zusammen, um einen Startwert zu erstellen, an den er später weitergeleitet wird
srandom()
. Der schwierige Teil ist, dass das Ernten durchgeführt werden muss, bevor die C-Laufzeit die .data- und .bss-Speicherabschnitte initialisiert, und dann muss der Startwert an einem Ort gespeichert werden, den die C-Laufzeit nicht überschreibt. Dies erfolgt unter Verwendung bestimmter Speicherbereiche .Beachten Sie, dass bei einem Warm- Reset der SRAM erhalten bleibt, sodass der gesamte Inhalt Ihres Entropie-Pools erhalten bleibt. Derselbe Code kann dann verwendet werden, um die gesammelte Entropie über einen Reset hinweg beizubehalten.
Bearbeiten : Es wurde ein Problem behoben, das in meiner ursprünglichen Version
seed_from_ram()
auf globaler Ebenerandom_seed
statt auf lokaler Ebene auftratseed
. Dies könnte dazu führen, dass der Samen mit sich selbst XOR-verknüpft wird und die gesamte Entropie zerstört wird, die bisher geerntet wurde.quelle
analogRead()
, wenn Sie wissen, was Sie tun. Sie müssen nur darauf achten, die Zufälligkeit nicht zu überschätzen, wenn Sie eine Schätzung der Entropie Ihres Pools aktualisieren. Mein Punkt überanalogRead()
ist meistens als Kritik an einem armen, aber oft wiederholten „Rezept“ gedacht :randomSeed(analogRead(0))
Einfach mal reinsetup()
und davon ausgehen, dass es reicht.analogRead(0)
1 Bit Entropie pro Aufruf vorhanden ist, ergibt ein wiederholter Aufruf 10000/8 = 1,25 KByte / s Entropie, das 150-fache der Entropiebibliothek.Wenn Sie Entropie nicht wirklich benötigen und einfach bei jedem Start eine andere Folge von Pseudozufallszahlen erhalten möchten, können Sie EEPROM verwenden, um durch aufeinanderfolgende Seeds zu iterieren. Technisch gesehen ist der Prozess vollständig deterministisch, aber in der Praxis ist er viel besser als
randomSeed(analogRead(0))
bei einem nicht verbundenen Pin, wodurch Sie häufig mit demselben Startwert von 0 oder 1023 beginnen. Das Speichern des nächsten Startwerts im EEPROM garantiert, dass Sie mit einem anderen Startwert beginnen jedes Mal säen.Wenn Sie echte Entropie benötigen, können Sie diese entweder aus der Zeitverschiebung oder durch Verstärken des externen Rauschens erfassen. Und wenn Sie viel Entropie benötigen, ist externes Rauschen die einzig gangbare Option. Zenerdiode ist eine beliebte Wahl, besonders wenn Sie eine Spannungsquelle über 5-6V haben (sie funktioniert mit einer geeigneten Zenerdiode auch mit 5V, erzeugt aber weniger Entropie):
( Quelle ).
Der Verstärkerausgang muss mit einem analogen Pin verbunden werden, der mehrere Entropiebits mit jeweils
analogRead()
bis zu zehn MHz erzeugt (schneller als Arduino abtasten kann).quelle