 für den Originalton. Die Vortragen heute sind Felix Dörre, ein Student am Karlsruhe Institute of Technology und im Wesentlichen ist das seine Bachelorarbeit und dafür hat er eine Auszeichnung bekommen, den International Student Award für Undergraduate Forschung und daneben ist noch Vladimir Klebanov, der die Bachelorarbeit betreut hat und Feedback gegeben hat und er hat auch ein Automatistool entwickelt, das dieses Framework benutzt. Vielen Dank und bitte einen Applaus. Vielen Dank. Diese Arbeit wurde von der Karlsruhe Institute of Technology unterstützt und auch vom Deutschen Nationalen Forschungsrat unter dem Vorrangprogramm Reliably Secure Software Systems und vor einiger Zeit haben wir angefangen zu uns zu fragen, woher wissen wir, dass unsere PRNGs eigentlich richtig funktionieren und kurz danach haben wir festgestellt, dass die Antwort ist, wir hoffen, dass sie richtig funktionieren und das ist eine wichtige Frage und hat jemand eine Ahnung, was in dieser Liste steht? Die jüngere Generation kennt das vielleicht nicht, aber die sind alle Dienste, die betroffen waren, als OpenSSL in der Debian-Distribution nicht richtig funktioniert hat und es ist ein wunderbares Beispiel für ein Single-Point-of-Failure. Und dies war wirklich ein entscheidender Moment in der Geschichte von den Säule-Zufallszahlen-Generatoren und es ist wirklich eine tolle Geschichte und wir gehen etwas in technisches Detail später im Vortrag, aber ich möchte euch ermutigen, das zu googeln und wirklich die Geschichte zu lesen, was passiert ist, das ist wirklich eine fantastische Geschichte, eine technischen menschlichen und Organisationsfaktoren, die diesen perfekten Sturm erzeugt haben. Und zwei Jahre lang gab es eine Hintertür in allen diesen Diensten und irgendwann wurde es dann festgestellt und es gab auf dem 25C3 einen Vortrag darüber und dann könnte man sich, könnten wir uns fragen, was ist denn danach passiert? Was waren die technischen Maßnahmen, die getroffen wurden, um zu verhindern, dass das nochmal passiert? Ja, und die technische Konsequenz war, diese beiden Kommentare einzufügen, die man hier sieht. Also was passiert war, war, dass der Debian-Maintenor irgendwie diese Codezeile entfernt hat und irgendjemand hat die Zeile wieder eingefügt und einen Kommentar eingefügt, diese Zeile bitte nicht entfernen. Das ist sehr spezifisch und das war auch schon alles. Und am Ende werden wir sehen, dass man bessere Sachen machen kann, um sicher zu sein, dass die Generatoren gut funktionieren und es gibt auch gute technische Gründe, warum Qualitätssicherung schwer ist. Und während wir schon dabei sind und über Kommentare sprechen, würde ich euch gerne ein paar mehr Kommentare zeigen aus anderen Implementationen, von anderen Zufallszahlen-Generatoren, um euch zu zeigen, was Zustand der Implementationen gerade ist. Und die sind keine obskuren Implementationen. Das sind wirklich Sachen, die wahrscheinlich auf euren Geräten sind, was ihr jeden Tag benutzt. Und vielleicht sagt ihr, das ist aber unfair, das ist aus dem Kontext gerissen. Ja, das stimmt, aber ich kann auch sagen, es ist nur ein bisschen unfair und da gibt es einfach nicht sehr viel Kontext dafür. Und das ist wirklich das Gefühl, was ich bekommen habe, wenn ich diesen Code gesehen habe. Zum Beispiel in einer Implementation lesen wir hashbytes to use defines, number of bytes returned by compute hash to use to form. Was, was bedeutet das? Es ist wirklich schwer zu verstehen, was hier passiert. Und ich bin immer noch nicht ganz sicher, was er damit sagen will. Ich glaube, der Autor wollte einfach nur sagen, wir definieren, dass wir 20 bytes zurückgeben mit dem hash und ja, aber was er damit sagen will, ist völlig unklar. Und es gibt noch was, put the data into the entropy, add some data from the unknown state, we see it. Ja, und die Terminologie ist auch schwierig in diesem Fall. Ja, so ist das, aber man muss sich schon anstrengen. Take some random data and make some random looking data from it. Ich weiß auch nicht, was das bedeuten soll, das ist schon seltsam. Das ist nur an einer Stelle im Code. Das ist wirklich der Code, der möglicherweise eine Hintertür in all deine Anwendung macht. Und ja, und hier ist noch einer. Das ist von der Benutzerdokumentation. Und da steht, es gibt immerhin Benutzerdokumentation. Das ist wirklich toll. Aber niemand ist perfekt und diese Funktion, da steht einfach nur, sei sehr vorsichtig, sonst passieren schlimme Dinge. Da steht nicht, warum oder wie man vorsichtig sein soll und was passiert hier überhaupt. Und um etwas präziser zu werden, ich zeige das natürlich zur Unterhaltung, aber wir wollen hier nicht einfach nur dem Entwickler die Schuld geben und während es ein besserer Entwickler gewesen wäre, dann wäre das nicht passiert. Und ich werde natürlich diese Fehler nie machen. Und wenn du das denkst, dann wird dir das auch passieren. Und der Punkt ist einfach, es gibt einen Prozess und es gibt natürliche Kräfte, die das führen. Das ist so, wie es heute ist. Und üblicherweise geht es einfach um persönliche Projekte oder Forschungsprojekte. Manchmal gibt es Clean Room Implementation und irgendwann veröffentlicht zu deinen Code und Leute bemerken das und dann wird es in einem großen Projekt verwendet. Das ist eine große Organisation, zum Beispiel die Apache Foundation. Und dann plötzlich am Ende gibt es irgendwie ein Händler, der so einen Zuvorzeigengenerator braucht und sagt, oh, ich habe hier diesen Code gefunden. Und der sieht wunderbar aus. Und wir bauen ihn einfach in unser Produkt ein und wir untersuchen das nicht mehr genau, sondern wir bauen es einfach ein und verkaufen das. Und ich glaube, Leute wie diese sind verantwortlich für viele der Probleme, die wir haben. Die Händler nehmen einfach den Open Source Code, gucken den nicht mehr genau an, sondern tun den einfach in ihr Produkt und verkaufen das. Also wir müssen wirklich auf den Prozess achten, wie wir unsere Software behandeln. Ich habe wirklich da keine bessere Empfehlung als das. Aber noch ein weiteres Beispiel. Das ist hier der einzige Kommentar in einer kritischen Funktion. Und wenn du weißt, was hier passiert, wenn ihr wisst, was passiert, dann macht es Sinn. Aber wenn du nicht weißt, was hier passiert, dann hast du einfach überhaupt keine Chance, das nicht zu verstehen. Wir brauchen Dokumentationen. Und wir müssen auch Dokumentationen, die für Leute geschrieben wird, die nicht wissen, was hier passiert, sonst ist es sinnlos. Was wir herausgefunden haben ist, was am besten funktioniert ist, wenn man ein Design-Dokument hat, wo man einen Abstrakt erklärt. Das Design von dem zuverzahlen Generator. Und dann kann man daraus die Dokumentation schreiben. Und nur Kommentare in den Funktionen im Source Code sind nicht genug. Und ich solle vielleicht dazu sagen, es ist gut, dass es diesen Kommentar gibt. Man hat eine Abstraktion von dem Code, aber man muss es anders ausdrücken. Und für ein anderes Publikum auch. Und bei diesem Generator war ein Link zu einem wissenschaftlichen Paper, was die Inspiration für diese Art von Schema, diese Art von Technik gemacht hat. Und das war schon mal ganz gut. Und ich hoffe, ihr bekommt jetzt, habt eine Idee davon, Eindruck davon, dass Sachen verbessert werden müssen und dass wir Qualitätskontrolle brauchen. Und was kann man machen für Qualitätskontrolle? Und hier gibt es eine Top-5-Liste, die man machen soll. Das Erste ist, man sollte System-Level-Tests machen, was auch immer für eine Software ist. Vielleicht formale Methoden und Verifikation, dass die Software wirklich das tut, was sie tun sollte. Aber in diesem Fall ist es einfach sehr schwer zu machen. Das ist vielleicht sogar unmöglich. Wir müssen sagen, dass die Spezifikation eines PNGs, ja gut, es ist eine Stück Software, was ein bisschen zufällig Daten nimmt, von außerhalb des Systems und dann erzeugt ein System anderer Daten, die ununterscheidbar von echten Zufallsdaten sind. Und es gibt nicht nur die Eigenschaften von einem Output-Stream, und man kann nicht nur einen Ausgabestream testen und dann kann man nicht sagen, ob das wirklich gut ist, sondern es ist eine Eigenschaft von allen Ausgabeströmen zusammen. Und das ist wirklich schwer. Was man zum Beispiel machen könnte, man macht erst mal Unit-Testing und die einzelnen Units, die ganz genau spezifiziertes Verhalten haben. Wir wissen zum Beispiel von einigen Implementationen, dass es schwierig ist, einen Ringpuffer zu implementieren. Und kein C-Programmierer will sagen, ich implementiere die Datenstruktur, dann baue ich Tests für diese Datenstruktur und dann benutze ich diese Datenstruktur in meinem Code. Und nein, natürlich baut man ein riesen, monolithisches Ding. Und das ist das, was man in C macht, weil Performance. Aber es macht nicht wirklich Sinn. Und die Empfehlung ist wirklich hier, macht euren Code modular, lässt den Compiler. Der Compiler wird schon gut performanten Code machen. Nur einem ganz kleinen Overhead. Aber wenn du Unit-Tests macht und das Einzelntestet, dann seid ihr auf der sicheren Seite und geht kein unnötiges Risiko ein. Und eine andere Testmöglichkeit, die man noch sieht, und das ist auch ab und zu empfehlenswert, sind statistische Teste. Es gibt hier einige Beispiele dafür. Und wenn man sich einzelne Ausgabeströme anguckt und man guckt, ob es irgendwie verdächtig aussieht, wenn es sehr viel mehr Nullen als 1 hat, dann ist es schon mal verdächtig. Das kann man machen, aber es ist nicht sehr hilfreich aus einem Grund. Denn die meisten PNGs sind kryptografische PNGs. Und das heißt, auf der einen Seite wird es für Verschlüsselung benutzt und auf der anderen Seite haben sie kryptografische Bausteine. Und die haben die Eigenschaft, dass wenn man einmal etwas da durchschickt, dann ist die Ausgabe auf jeden Fall diesen statistischen Test bestehen. Das heißt, es kann völlig kaputt sein. Und es ist trotzdem kaputt, obwohl es diesen Test bestimmt. Das ist manchmal ein vorgeschriebener Test. Und manchmal wird die Ausgabe von PNGs benutzt, die gar nicht für Kryptografie geeignet waren. Und auf der anderen Seite, was auch nützlich ist, aber auch nicht genug gemacht. Wir sind Regression-Tests. Und das sind Referenz-Eingaben und Ausgaben. Und wenn man die Eingabe und die Ausgabe vergleicht mit den Referenzwerten, dann weiß man, ob es so gut oder so schlecht ist, wie das was andere gemacht haben. Insbesondere, wenn man diesen ganz bestimmten PNG-Standard implementiert, aber das nicht alle machen, aber manche, und dann gibt es diese Referenz-Werte. Und dann kann man so gut oder so schlecht sein, wie der Standard. Und dann kann man sicher sein, dass mehrere Leute den Standard angeguckt haben. Und wenn man etwas verändert, wenn man den Code wartet, dann sollte sich die Ausgabe nicht ändern. Und wenn sich die Ausgabe nicht ändert, dann kann man einigermaßen sicher sein, dass man nichts Wichtiges verändert hat, also macht Regression-Tests. Und das ist auch wichtig, das zu tun. Und das Einzige, was oft gemacht wird, ist oft, das Einzige ist Manual Code Review. Die Leute gucken einfach den Code an und sagen, oh, sieht okay aus. Und würdest du sowas akzeptieren für andere Software, egal wie unwichtig das ist? Wäre das okay für dich, dass wenn dieses Stück Software nie getestet wurde, wir haben es angeguckt und wir finden, das sieht okay aus. Es gibt keine technische Qualitätskontrolle, würdest du dir das akzeptieren? Und Code, der nur so behandelt wurde, ist im Zentrum der Sicherheitsinfrastruktur. Wir haben nicht nur schlechte Nachrichten, wir haben Sachen versucht, etwas zu verbessern. Und hier haben wir zwei Sachen gemacht. Wir haben sehr viele Vorfälle angeschaut, die zuversahlenen Generatoren aufgetragen. Darüber hinaus haben wir ein Werkzeug entwickelt, eine Methode, eine statische Analyse, die diese Verletzungen dieser Eigenschaft finden kann. Zum Beispiel OpenSSL und so weiter. Und in diesem Vortrag möchten wir vorstellen, was die Eigenschaften sind, was das Werkzeug tut. Aber zuerst möchte ich erklären, wie ein PNG funktioniert. Das ist ein sehr vereinfachtes Modell. In der Praxis ist das natürlich viel kompliziert, aber nichtsdestotrotz hat man in der Mitte ein Zustand, also Entropy Pool. Es gibt eine Seed Funktion, die diesen Zufall keim nimmt, dass der Herkunft außerhalb des Systems hat. Zum Beispiel vom Betriebssystem leidet das aus der Hardware ab. Zum Beispiel von Festplatten, Latents oder von Tastaturanschlägen oder Mausbewegungen und so weiter. Man erhält also diesen 20-byte Wert eines Seeds. Das wird dann in den Zustand übernommen. Und der Rest der Operation passiert dann in den Zyklen. Und innerhalb dieser Zyklen wird dieser internen Zustand gestört. Und man leitet davon einen Output ab. Und im nächsten Zykl wird dieser Zustand wieder geändert. Und man erhält mehr Output und so erhält man dann den Stream. Im Modell sind alle diese Vorgänge deterministisch. Das heißt, all das ist komplett deterministisch. Die einzige Quelle von Zufall ist wirklich nur die Wahl, dass das sieht. Das heißt, wir werden jetzt weitergehen und diese ganze Kaskade als eine Funktion von einem MBC zu einem N-Bit aus Output gehen. Wir werden dieses Symbol von Zeit zu Zeit immer wieder sehen. Das ist, was wir betrachten werden, die Funktion G. Bevor ich das Problem vorstelle, dass wir lösen, möchte ich erstmal klarstellen, dass es viele Probleme gibt, die wir nicht lösen. Und das ist auch wichtig, ein paar von denen zu nennen. Das erste Problem, das wir nicht behandeln, ist die Wahl, das Siehts, das Kimes. Das ist ein ganz anderer Problem, aber das komplette Autokonal, dass diese Prozedur hier korrekt funktioniert. Das gab einen Vortrag über die Auswahl von Siehts, von Kimes gestern. Und da gibt es auch beliebte Fehler, die passieren können. Wenn man z.B. etwas mit Zeit benutzt, um Siehts zu generieren, dann wird man eine schlechte Zeit haben. Denn die Auflösung der Timer ist nicht groß genug. Das hat man in einem kleinen Bereich. Und auch, weil Zeit immer öffentlich verfügbar ist. Der Angreifer mag vielleicht wissen, was da benutzt wurde. Und dann fällt alles zusammen. Und übrigens, wenn man das in der Embedded-Welt macht, dann benisst du mir sehr leid, dann hat man wirklich sehr wenige Möglichkeiten, gute Siehts auszuwählen. Aber das ist zum Glück nicht unser Problem. Das andere, das wir nicht betrachten, ist, typischerweise, alle diese Funktionen haben kryptografische Bausteine. Und wir nehmen hier an, dass diese Blocks da sind. Wir können nicht wirklich prüfen, ob sie da sind, aber wir nehmen es einfach an. Und wir werden auch annehmen, dass es wirklich ein Weg Funktionen sind. Es gab nur einen Vorfall im Dual-Elyptic-Curve-Generator, wo es sich herausgestellt hat, dass diese Funktionen waren nicht ein Weg für alle, sondern für die NSA war es sogar zwei Wege. Aber das ist eine andere Geschichte. Aber eine andere Sache, die wir uns nicht kümmern, ist, wir nehmen sehr starke Angreifer nicht in Betracht. Also, wenn man einen Angreifer hat, der gewisse Kenntnis hat, dann ist man auf sich selbst gestellt. Wenn eine Geheimorganisation vor deinem Gebäude steht, dann können wir da auch nicht zugegenmachen. Aber wir können euch helfen, Entropieverlust zu erkennen. Es gibt verschiedene Möglichkeiten, Entropieverlust zu definieren. Also, die vor allen Dingen hier sind equivalent. Zum Beispiel, wenn man zwei Seeds hat, die dann selben Aus-Output generieren, dann nennt sie Entropieverlust. Wenn ein Teil des Seeds nicht für den Aus-Output benutzt wird, das heißt, es gibt weniger Ausgänge, als es Seed gibt. Das heißt, man verschwendet ein wenig der Entropie, die man gesammelt hat durch den Seed. Und wahrscheinlich verschwendet man sehr viel. Und dann wird die Ausgabe sehr viel vorhersehbar sein. Mathematisch geht das alles zurück auf ein Problem, dass die Funktion G nicht injektiv ist. Und darauf werden wir schauen, wir haben eine Maschinerie, um zu prüfen, ob Funktionen injektiv sind. Sicherheit, übrigens, ist immer über Injektivität. Entweder Injektivität oder nicht Injektivität, aber viele Sachen wie Privatsphäre und Ethikität können über diese Eigenschaft definiert werden. Formal, das ist einfach nur die mathematische Definition von Injektivität. Und das ist, was unser Tool überprüfen wird. Und jetzt wird uns etwas mehr Intuitivität übergegeben. Also, zunächst kommen wir mal, möchten wir zurückkommen, was im Debian OpenSSL-Disaster passiert ist. Das ist das Model. Das ist das Modell, das wir etwas übernommen haben, so wie wir hier sehen können, in der Mixfunktion. Wir haben noch die PID, die ProzessID hinzugefügt. Die OpenSSL nimmt nicht nur die C, sondern auch die ProzessID als Zufallseingabe, die es in der Mixfunktion verwendet, um den Zustand zu stören und dann den Outboot abzuleiten. Also, was passiert ist, war, dass eine Zeile entfernt wurde und der Seed wurde abgeschnitten. Schlechterweise hatten sie die PID in der Mixfunktion. Das heißt, der Zustand und der Outboot war, es sah immer noch zufällig aus. Also, wenn man den PID hätte, dann hätten wir immer denselben Outboot bekommen. Aber auf diese Art und Weise, das war nicht ein Schlüssel, das waren 32.000 Keys. Aber das war nicht, das war sehr schwer zu bemerken. Und wie man sehen kann, ist das ein sehr einfacher Fall von Entropieverlust. Man benutzt quasi überhaupt nichts von dem Seed. Was wir hier lernen können, ist, dass man den PNG separieren muss. Also, wir nehmen den Zufall, benutzen irgendwie, aber nicht in verschiedene Stellen mehr Zufallsdaten hinzufügen. Das wird uns später nochmal auftreten. Ein anderes beliebtes Beispiel ist, was im Android-Fall passiert ist. Hier ist ein großer Java-Integer-Array, das in dem PNG verwendet wird, und das nennt sich Seed. Aber der Seed ist nur hier. Im Allgemeinen, das ist der komplette Zustand. Und der Seed sollte von Java-Integers 0 bis 4 geschrieben sein. Und es gibt hier viele verschiedene Ausgabe-Möglichkeiten. Aber was aus Versehen passiert, das sollte ein Zeller abgeleitet werden. Aber der Pointer wurde nicht aktualisiert. Das heißt, es wurde hier mehr als die Hälfte des Seeds überschrieben. Und dann gab es nur noch 64-Bit, und das ist nicht mehr genug. Das war immer noch mehr, als bei Debian übriggeblieben ist. Aber man sieht, dass über die Hälfte einfach verschwunden ist. Und dass man solche Fälle nicht erkennen kann, wenn man nur die Ausgabe anguckt und nicht weiß, wie der PNG funktioniert. Hier ist ein anderer Fehler, einer, den wir gefunden haben, in LibG Crypt. Und wir sprechen später noch mehr ausführlicher drüber. Also der Benutzer von unserem Tool muss den PNG allein haben, den deterministischen Teil. Und alle anderen Entropiequellen entfernen die nicht direkt der Seed. Das sieht es so, dass das Tool direkt die Abhängigkeit vom Seed testen kann. Dann muss der Benutzer einen Scope auswählen, den er analysieren will. Das heißt, eine feste Länge von Eingabe und Ausgabe und für die wir die Effektivität testen wollen. Und typischerweise nehmen wir nur einen Zyklus. Und dann muss der Benutzer einen Weg, um die Kryptofunktionen auszuschalten. Denn das ist schwer festzustellen, ob die injektiv sind. Das ist der ganze Sinn der kryptografischen Funktionen. Das heißt, das Tool kann nicht prüfen, ob die Kryptofunktionen funktionieren, sondern will nur den PNG testen. Das heißt, dann muss man die Bedingungen erzeugen und checken, dass diese Bedingungen wahr sind. Und dann können wir gucken, ob Entropie verloren ging oder nicht. Das kann ich gerade kurz zeigen hier. Was man hier sieht, ist ein Teil von einem OpenSSL-Zufallszahlengenerator. Hier steht das Fügt-Zufallsdaten zu den internen Zustand hinzu. Da wurde was entfernt hier bei dem Fall. Und jetzt machen wir ein ganz einfaches Problem. Dieses hier zerstört ein Bit im Input. Das heißt, wir benutzen ein Bit, der Eingabe wird nicht benutzt dann in diesem Fall. Und jetzt starte ich die Analyse. Und die Analyse wird das Programm übersetzen in eine logische Formel. Die Formel beschreibt, was der Generator tatsächlich macht. Und dann dupliciert es die Formel und spezifiziert die Bedingung, dass wir zwei verschiedene Bedingungen haben und wendet diese Funktion an. Das sollte denselben Ausgabe ergeben. Und jetzt wird es aufgelöst. Und der Solver sagt, wir haben jetzt eine Lösung. Und der sagt, bei diesen beiden Eingaben bekommen wir dieselbe Ausgabe für zwei verschiedene Eingaben. Und jetzt müssen wir rausfinden, was hier passiert ist. Und man sieht es hier, hier ist genau ein Bit falsch. Warum wird dieses Bit nicht verwendet? Und dann würde man das vielleicht debacken wollen. Und dann findet man vielleicht diesen Befehl, den wir eingefügt haben. Dann entfernen wir den und dann starten wir die Analyse nochmal. Und das ganze Programm wird nochmal übersetzt in die logische Formel. Und das dauert eine Zeit. Es sind 30 Megabyte logische Formel. Dann verdoppeln wir das nochmal, weil wir das zweimal starten wollen mit verschiedenen Eingaben, die dieselbe Ausgabe ergeben. Und am Ende finden wir, der Solver sagt, ja, wir haben jetzt kein Ergebnis. Das heißt, es gibt kein Beispiel in diese Funktion zufällige Daten. Nicht benutzt. Und wie können wir mit solchen Funktionen umgehen? Das ist der Teil, den ich übersprungen habe. Und Vladimir wird jetzt erklären, wie wir damit umgehen. Das ist der Teil, den wir bisher unter den Teppich gekehrt haben. Und ich zeige euch ein Beispiel, was ihr hier oben seht. Es ist ein Aufruf von dem SHA-1 Hash. Und mit einem, das ist die Seedfunktion von dem OpenSSL PNG. Und das benutzt den Seed von außen und transferiert den internen Zustand. Und was man hier sieht, ist eine Verkettung von vier verschiedenen Sachen. Und ich kann euch sagen, dass beim ersten Aufruf wird nur der dritte Parameter hier, der BUFF, das ist der Parameter der Funktion, nur dieser dritte Teil wird entropierend halten. Und alle anderen Parameter haben feste Werte. Und alles zusammengenommen sind das 68 bytes oder so und der SHA-1 macht daraus einen 20-byte Digest. Und die Kryptografen versprechen uns, dass wenn die Eingabe mehr hat, wenigstens zwei hoch 160 verschiedene Werte, dann sieht man wenigstens zwei hoch 160 verschiedene Ausgaben. Das ist auf jeden Fall nötig. Aber wir können nicht wirklich die Injektivität von diesem Funktion testen, denn diese Funktion ist spezifisch entwickelt, um dies sehr, sehr teuer zu machen. Das heißt, wenn wir das testen könnten, wenn wir die Injektivität hier testen könnten, dann hätten wir wirklich einen Angriff auf SHA-1 oder wir können zumindest beweisen, dass es einen Angriff gibt. Das heißt, wir müssen das Problem vereinfachen und wir vereinfachen das, indem wir die nicht über SHA-1 nachdenken, sondern das Auslagern, sondern die Kryptografen kümmern sich um SHA-1 und wir überprüfen nur den Code, der außerhalb von SHA-1 ist. Das ist der Code, der nicht standardisiert ist und das ist der fehleranfällige Code. SHA-1 selbst ist ein Standardprimitiv und ein Standardimplementation. Es gibt Standard-Tests und es ist sehr, sehr schwer, das zu knacken. Aber es ist einfach, den Code außen drum zu bräuchten. Das heißt, wir gucken uns nur den Code außen drum rum an und wir machen das auf die folgende Art. Hier ist eine einfache Visualisierung von demselben Aufruf, wie oben zu sehen. Und jetzt gibt es zwei Schritte für ersetzen diesen Aufruf mit etwas über das wir einfacher Schlussfolgerung machen können und trotzdem noch sinnvolle Schlussfolgerungen zulässt. Das heißt, wir wollen diesen Aufruf ersetzen durch eine indjektive Funktion in einem bestimmten Sinn. Der erste Schritt ist, wir müssen rausfinden, den Teil rausfinden, welcher Teil der Eingabe die Entropie enthält. Und ja, das ist aber schwer, aber in Wirklichkeit ist es nicht so schwer, wie man denkt. Also zuerst müssen wir den Benutzer das machen lassen. Wir könnten das automatisieren, aber erst machen wir uns, das noch nicht versucht werden lassen, den Benutzer das machen. Durch Clues von den variablen Namen, Hinweise und die wir zeigen auch Gegenbeispiele und ich will später darüber sprechen, aber man könnte auch verschiedene Sachen ausprobieren. Hier gibt es zum Beispiel die Möglichkeit, man kann einfach drei verschiedene Sachen vielleicht auswählen. Das heißt, man hat hier eigentlich nicht genug für 20 Bytes. Man kann es einfach ausprobieren mit Brutforce und wenn man einen falschen Alarm kriegt, dann wird die Funktion nicht indjektiv sein, dann kann man das nochmal versuchen. Zuerst müssen wir einen Input finden, das 20 Bytes lang ist, weil die Ausgabe 20 Bytes lang ist und dann müssen wir diese Funktion durch was anderes ersetzen. Und hier haben wir Möglichkeiten, womit wir das ersetzen könnten. Die erste wäre, wir könnten das einfach ersetzen, diese SHA1 ersetzen durch die Identitätsfunktion und wir kopieren einfach den C direkt in die Ausgabe. Das ist sehr einfach und hat viele Vorteile, denn wenn man das macht, dann mit etwas Glück für die ganze PNG-Konstruktion zur Identitätsfunktion und die Ausgabe des PNG wird einfach sehr nach dem Sieg aussehen, vielleicht einfach nur den Sieg immer wiederholt. So kann man testen und man kann einfach überprüfen, dass der ganze andere Code gut funktioniert, aber diese Konstruktion ist nicht in Ordnung, weil wir eine Funktion mit einer nicht verwandten Funktion ersetzt haben. Aber oft wird es trotzdem funktionieren und die Ergebnisse werden aber trotzdem vertrauenswürdig sein. Denn typische PNGs kümmern sich gar nicht um die tatsächlichen Daten, die in dem Sieg stehen. Denn es wäre ganz komisch, wenn der PNG verschieden arbeiten würde, abhängig davon, welche Eingabendaten es gibt. Das heißt, man kann einfach irgendwelche den SHA1-Hash einfach durch irgendwas anderes ersetzen. Und das ist sehr nützlich und das ist sehr gut für die Bucking. Man kann ganz viele Sachen damit schon testen, aber es ist trotzdem nicht richtig. Aber was wir auch machen können, ist, wir haben ein formales Schlussfolgerungstool benutzen. Wir können statt der Identitätsfunktion nehmen. Wir können eine mathematische Konstruktion benutzen. Wir ersetzen diesen Teil, diese spezielle Funktion durch eine Abstraktion mit einer unterspezifizierten indjektiven Funktionen. Wir sagen nicht genau, was es ist, aber es muss injektiv sein. Und das ist eine Annäherung an die Hashfunktion und die Ergebnisse werden auch dann im Originalcode funktionieren. Was wir typischerweise machen würden wäre als Erstes wenn wir dies machen. Das hilft uns schon, Bugs zu finden und es wird Kollisionen finden. Und wir können den Trace angucken. Wir können das Bit Pattern des Seats angucken, wie sich das über den Ausgabe verteilt. Wir können Print Statements einbauen und gucken, wie das funktioniert. Aber das zeigen wir heute nicht. Aber wir haben eine nette Visualisierung davon. Aber am Ende benutzen wir die gute Idealisierung und zeigen, dass das funktioniert. Noch einige Wörter zur Implementation. Wir haben eine kleine Werbeeinblendung hier. Wir könnten das nicht machen, wenn wir nicht auf den Schultern von Riesen stehen würden. Und es gibt hier den Bounded Model Checker, CBMC, seinen Statisches Code-Analyse-Tool. Und man kann die Implementation in C oder Java reinstecken. Und es wird einfach neben selbst, wenn das ganz kompliziert oder komplex ist, wie OpenSSL oder Linux Kernel. Und das ist wirklich fantastisch. Das ist sehr robust. Und untersucht das Verhalten des Programms bis zu einer bestimmten Tiefe. Und es wird Sachen finden, bestimmte Sachen finden. Buffer Overflows. Es wird auch benutzerspezifizierte Assertions-Testen. Das heißt, selbst wenn man, wenn man nicht Kryptografie oder Haschfunktionen macht oder zuverzahlen Generatoren, kann ich das trotzdem sehr empfehlen, um die Implementation zu überprüfen. Auf der anderen Seite benutzen wir Minusat, ein Solver. Das ist auch ein fantastisches Stück Technologie. Und es gibt noch andere Verifikations-Tools. Aber diese beiden sind die, die wir kennen. Und es hat das NPV vollständig. Aber wir können da Gigabyte große Formeln reinstecken und innerhalb von Sekunden sagt er trotzdem, ob diese Funktion erfüllt werden kann. Und wir benutzen diese Tools. Wir kombinieren sie mit unserem eigenen Code und wir benutzen CBMC, um eine Beschreibung zu erzeugen, davon, was die Formel tut. Und wir können dann diese Formel benutzen, um Injektivität zu überprüfen und benutzen dann Minusat, um herauszufinden, ob es eine Verletzung der Injektivität gibt. Und wenn das der Fall ist, dann zeigt das die Traces bei den Seeds, die zu demselben Output geführt haben. Und es braucht einige Sekunden, aber das heißt, das kann man praktisch interaktiv benutzen. Was sind jetzt die Ergebnisse, die wir bekommen haben, indem wir das angewendet haben? Also das Werkzeug haben wir auf verschiedene PNGs angewendet. Zuerst der gute Teil. Wir haben diese hier überprüft und wir haben nichts Verdächtiges gefunden. Das Werkzeug konnte also verifizieren, dass das Werkzeug wirklich Injektiv ist. In Apache Harmony haben wir einen bekannten Entropiefelust entdeckt. Und wenn wir das Problem eingefügt haben, haben wir das entdeckt. Und wenn wir es entfernt haben, haben wir keine weitere Probleme gefunden. In OpenSL war es ähnlich. Wenn wir den Code entfernt haben, das Code stückt, dann konnten wir das entdecken. Wir haben auch andere Probleme identifiziert im Code, dass vielleicht oder vielleicht auch nicht das Ungesetz werden kann. Und hat Probleme, den zirkeleeren Buffer zu benutzen und einen Beid außerhalb des Buffers zu schreiben, komische Sachen zu machen. Aber alles im Allem, das war nicht alles nicht sehr fatal. Dann schließlich haben wir den kritischen Bug in GNU-PG gefunden, dass der dann gefixt wurde. Ich werde euch zeigen, wie der Bug funktioniert und wo das Problem liegt und wie der Bug so lange unerkannt bleiben konnte. So zunächst gab es dann ein Paper, das vorgeschlagen hatte, wie man einen PNG betreibt. Und erstmal möchte ich es vorstellen, wie es ursprünglich designed war. Erst haben wir den Buffer mit Zufallstaten, das Sie sehen ist die Störende, die die Mischfunktion, das den Buffer auf irgendeiner Art und Weise mischt. Was vorgeschlagen wurde, ist, man nimmt diese 84 Bytes, das Buffers, wenn der deine Hash-Funktion drauf ein und überschreibt dann die mittleren 20 Bytes, die wir hier sehen. Und diese Buffer würde dann nach oben gehen und nach dem Hashing würden wir zum nächsten Block gehen und das wieder haschen. Zum nächsten Block und so weiter und so fort, bis zum Ende, wo es dann sich wieder von vorne anfängt. Und der letzte, würde dann diesen Block und diesen Block vorne haschen. Und diese Buffer würde dann an den Benutzern gegeben. GNU-PG hat eine Hash-Funktion, die kleinere Input-Größen genommen hat. Das sind 64 und nicht 84. Für Gründe, die nicht so klar sind. Sie haben entschieden, okay, wir haben eine 60-Byte-Hash-Funktion, also wir lassen einfach den mittleren Teil aus. Wir überschreiben das sowieso, ich weiß auch nicht, warum, was die Intention dahinter war, aber was passiert in GNU-PG ist, wir würden die haschen, schreiben sie und so weiter und so fort, bis zum Ende. Und wir würden das und das nehmen und ein Hash davon und wir schreiben sie dann noch hier. Und diese Buffer sollte jetzt zufällig sein. Ist diese Buffer aber wirklich zufällig? Wenn wir diesen Block und diesen Block nehmen, dann sind sie hier und hier, dann würden wir diesen letzten Block kriegen. Der Buffer kann aber nicht zufällig sein, weil wir den letzten 20 Bytes ausrechnen, wenn wir diese 20 und diese 44 Bytes nehmen, sie haschen, dann kriegen wir genau diesen Block. Und das ist also was ein G-Crypt passiert ist. Also ein Implementationsproblem. Das ist also essentiell, was passiert ist. Die Konsequenzen, die man hier von ziehen kann, die Schlüssel waren hoffentlich nicht so schlimm, die Konsequenzen für die Schlüssel. Und glücklicherweise haben wir das Problem erkannt. Das Problem lag dafür. Eine sehr lange Zeit hatte verschiedene Security Audits. Niemand hat es erkannt. Und für mehrere Jahre alt, was wir davon übernehmen können, ist, dass das Audits essentiell sind. Das ist notwendig, dass man sich den Code anschaut. Aber der Code ist einfach zu komplex, um das voll selbst zu verstehen. Das heißt, wir müssen technische Hilfe nehmen, um das noch weiter zu verreizieren. Vielen Dank für Ihre Aufmerksamkeit. Und wir sind jetzt noch offen für Fragen. Vielen Dank. Falls ihr Fragen habt, dann stellt euch bitte an den Mikrofon ab. Es gibt vier an der Zahl. Falls ihr jetzt gehen möchtet, dann tut das bitte leise, sodass die Leute noch der Frage- und Antwort-Stunde zuhören können. Auf der rechten Seite des Mikrofons. Hallo. Vielen Dank für Ihren Vortrag. Sehr interessant. Gibt es eine Implementation für Normalsterbliche wie uns? Dass dann momentan ein Stack haben, zum Beispiel OpenGP und dann zum Beispiel 20 RSA-Schlüssel. Wir laden Sie hoch und ihr sagt uns dann, ob diese zufällig genug aussehen. Und also könnt ihr feststellen, ob mein System dann wirklich Zufall regeneriert. Wir versucht haben zu erklären, das sind die Probleme, die wir uns angeschaut haben, können nicht entkannt werden, wenn man einfach nur den Output anschaut. Also wenn man nur einen Output-Stream hat, dann schaut das immer noch zufällig aus. Also die statistischen Tests würden das dann erkennen. Aber die einzigen Sachen, die man Sachen machen kann, ist einfach bekannte Probleme zu schauen. Bei einem SSL, das heißt, man ist glücklicherweise nur ein Paar. Das heißt, man hatte diese 32.000 Kies und konnte diese überprüfen. Und wir schauen nur auf die Schlüssel und wir wissen nicht, nach was wir schauen sollen. Und ich glaube, das ist nicht möglich. Vorne rechts? Könnten eure Techniken auch andere Kryptografen angewendet werden wie Block Ciphers? Das ist eine gute Frage. Also ich denke, man könnte sie auf bestimmte Auxilia-Code anwenden, dann den die Primitiven begleitet. Also die technischen Techniken, die wir geschaut haben, sind rein informationstechnisch. Wir beschäftigen sich nicht mit Kryptografie als solches, aber selbst in kryptografischen Code braucht man auch diese Sachen wie Kierweiterung. Es sollte dieselben Inaktivitätseigenschaften haben, die wir untersucht haben. Also es gibt gewisse Anwendungen, aber die sind alle sehr begrenzt. Eine Frage aus dem IRC, vielleicht? Dann bitte, hinten links. Hallo. Wenn ich euch die Entropieverlust richtig verstanden habe, dann gibt es zwei verschiedene Seats, die denselben Ausgabe geben, sind ein Problem. Also es gab ein Problem mit Schaar 1 für OpenSSL und OpenSSL benutzt auch Schaar 1. Und wenn ich das richtig verstanden habe, wenn es eine Hash-Funktion gibt mit einer Kollision, dann wäre das auch ein Entropieverlust bedeutend. Wir erwarten, dass in den nächsten Jahren Schaar 1 Kollision das Problem auftreten. Also es gibt es ein Problem, wenn es eine Hash-Funktion benutzt, die nicht Kollisionsresistent ist. Ja, das ist etwas subtil. Es gibt zwei Antworten eigentlich darauf. Zunächst, erst wir gucken den Code an, der außerhalb der Scheinsfunktion ist. Denn das ist meistens wo die Fehler sind. Wir sagen nicht Schaar 1 ist das Problem von jemand anderem. Aber wir gucken die Indektivität von einer Funktion, die 20-weit Eingabe und Ausgabe hat. Und wenn man da eine Kollision findet, dann wird das ein Problem sein, dass der PRG Daten verliert. Und hoffentlich gibt es davon nicht so viele Probleme, denn viele sind, sind sie einfach zu finden. Aber im Prinzip wusste man wahrscheinlich, die Hash-Funktion dann aktualisieren in der PRG-Funktion. Wir können vielleicht später im Detail darüber reden. Ja, links vorne. In der Theorie of realistic RNG are the notions of forward and backward and enhanced backward secrecy. Wie ist es mit forward and backward enhanced secrecy? Wenn ich das richtig verstanden habe, ist eure Theorie darum, wenn man vorwärts geht, um Entropieverlust zu finden, wäre es prinzipiell möglich, auch zu entdecken, ob die enhanced backward secrecy nicht erfüllt werden kann. Also, wenn man alle weiteren Ausgaben kennt, kann man dann auch rückwärts gehen, um vorherrige Ausgaben erkennen, die berechnen zu können. Das ist eine gute Frage, da muss ich noch drüber nachdenken. Ich glaube, wir gucken uns secrecy eigentlich gar nicht an, nämlich weder forward-nach-backward secrecy, sondern wir gucken nur, wenn es aus zwei verschiedenen Cities dieselbe Ausgabe gibt und einfach nur bestimmte zufällige Ausgaben zu haben, bedeutet, dass man die nächste berechnen kann. In diesem Sinne guckt man die Injektivität der Funktion an. Aber was man für backward secrecy braucht, wäre die Umkehrfunktion. Nein, nicht nur, sondern die inverse Funktion, man hat die Ausgabefunktion und man könnte den Seed auf den Seed schließen. Aber backward secrecy würde bedeuten, dass man einen Teil der Ausgabefunktion hat, die in der Vergangenheit aufgetreten ist. Ja, ich meine nicht den Zustand, den Seed, sondern den kompletten Zustand. Die Funktion ist ja vom Seed zu der Ausgabe. Und klar zu machen, das Angriffsmodell ist hier, dass der Angreifer die Ausgabe sieht und versucht mit brute force den Seed zu erraten. Okay, wir haben doch eine Frage aus dem Internet. Im Wesentlichen gibt es zwei Fragen. Zuerst gibt es physische Implementationen von PRNG. Sind die besser oder müssen wir die genauso testen? Ich glaube, wir müssen die genauso testen. Und ja, weil sie typischerweise enthalten, die auch eine Hardware zufallsquelle und aber dann gibt es diese deterministische Expansion, die da noch drauf sitzt. Und das müssen wir auch überprüfen. Ja, die Antwort ist ja und das kann man auch machen. Vielen Dank. Und das zweite ist aus dem IRC einige Leute haben mit die Erklärung zu dem GNUIPG-Pack gesehen. Könnte das nochmal sagen, ohne den Laserpointer zu benutzen. Das Problem ist am Ende eigentlich, wenn man Blöcke nimmt, die nicht überschrieben werden, das heißt, so dass sie im Ausgabestream zu sehen sind und daraus den Hash macht, den man mit der Hash-Funktion, die man kennt, wenn man den GNUIPG-Code hat, dann kann man daraus die letzten 20 bytes machen, wenn man die letzten 44 und die vorletzten 20 hat und die zusammenhäscht, die ergeben die letzten 20 bytes. Und das ist das Problem. Denn dieser Teil ist dann nicht mehr zufällig. Anders ausgedrückt, wenn man den Stream hat und man guckt den letzten Chunk an in diesem Stream, dann ist alles, was von dem dieser Chunk abhängt, bekommt in demselben Stream vorher schon vor. Und das ist das Problem. Das heißt, wenn man dem Server diesen Stream gibt, dann weiß der Server alles, was nötig ist, um den letzten Chunk in diesem Stream zu berechnen. Es gibt keine zusätzlichen Daten, die das Server nicht kennt, die benutzt werden, um diesen letzten Chunk zu berechnen. Und zuerst noch mal von rechts. Ein Kommentar zu Hardware-Mementation. Denn normalerweise nimmt man 2 N-Bit Entropy-Stücke und komprimiert die in 1 N-Bit Entropy. Und das ist ein Problem für die Detection von Entropy-Loss, denn die Hardware hat ein BIOS. Und das ist in Ordnung, das ist nur ein Offset. Und ein BIOS zu haben ist okay. Aber man löst das, indem man 2 N-Bit Zahlen in einer N-Bit Zahl zusammenbaut. Und man kann dann den Entropy-Loss nicht mehr erkennen, weil man aus diesen 2 N-Bits ein N-Bit macht. Und das heißt, N-Bits sind schon verloren gegangen. Ja, aber wir nehmen an, dass der C tatsächlich normal verteilt ist. Und das ist eine Hardware-Entropy-Quelle. Das heißt, man hat nicht diese Verteilung. Und wenn man das zu einer Haschfunktion komprimiert, dann bekommt man eine gleiche Verteilung. Und dann verteilt man diese komprimierte Version. Also muss man hier vorsichtig sein, wenn man diesen Checker benutzt, denn die Eingabe ist nicht komplett gleich verteilt, mehr oder weniger, aber nicht perfekt. Und das liegt daran, dass die Hardware ein Analog-Design ist und man hat Offsets. Und das andere, was ich getan habe, ist, wenn man etwas wie das SSL-Problem hat, dann schreibe ich die erste Runde von den ersten 32 Bytes in ein Pfeil und dann überprüfe ich jedes Mal, das mache ich, überprüfe ich jedes Mal. Und dann überprüfe ich, ob das Pattern schon mal da war. Und es gibt dieses, das Birthday, das Geburtstagsparadox und wenn ich meinen Seed reduziere, dann bekomme ich die Quadratwurzel und wenn ich SSL habe nach 256 Interaktionen, habe ich schon eine 50% Chance, Wahrscheinlichkeit zu sehen, dass ich ein Problem habe. Ja, aber wir haben zum Beispiel gezeigt, die Margins sind hier viel größer. Ja, aber wenn jeder Benutzer diesen Check jedes Mal macht, dann ist die Chance, das zu sehen. Sehr gut. Okay, die anderen microphone, please. Okay. Hallo. Und du hast davon gesprochen, die Erzeugung zu überprüfen, indem man die Hash-Funktion vereinfacht, zum Beispiel Nr. 1 zu ersetzen durch Memcopy. Und ich habe mich gefragt, du hast gesagt, dass einige Implementationen vielleicht eine Ausgabe machen könnten als Seed-Material. Und mit Memcopy, und hast du vielleicht Beispiele davon? Ja. Es gibt echte Beispiele, zum Beispiel Norden SSL macht das. Und das gibt... Ja, noch eine Frage von links. Ja, ich finde mit dem Geist, dass es ja mehr formale Methoden gibt für sowas. Vielen Dank dafür. Und meine Frage ist, ihr könnt die Entropy verfolgen im Zustand in der Mischfunktion. Wie funktioniert das? Ist das ein Feature von dem Prover für CD-NR benutzt oder wie könnt ihr das wirklich machen? Wie könnt ihr die Entropy verfolgen und verfolgen, wo die genau verloren geht? Ja, der CD-Prover modelliert den gesamten Programm-Zustandsraum. Und jede Position, wo der Seed verwendet wird, sind Variablen in der logischen Formel, die der Prover ausgibt. Und auf diese Weise können wir die Daten verfolgen. Und ist das eine Eigenschaft des Provers? Oder ist das... Ich glaube, das ist ein etwas anderer Punkt. Das ist nicht Teil des Seed Provers. Das ist etwas, was wir machen nachdem der Prover das analysiert hat und fertig ist mit der Analyse. Was wir daraus bekommen, ist, wir bekommen ein Modell der Formel und wir erholen die Seeds daraus, die das Problem darstellen und dann lassen wir den PNG laufen mit diesen beiden Seeds und geben auf der Konsole die Zwischenzustände aus und schreiben die nebeneinander. Also ihr benutzt die Variablen, die die Injektivität zerstören und haben dann die beiden Seeds, durch die die Injektivität verloren geht. Okay, vielen Dank. Vladimeir und Felix.