So erstellen Sie eine krypto-isomorphe Bibliothek mit Javascript und WebAssembly

Seien wir ehrlich: Wir lieben Geheimnisse. Wir teilen Geheimnisse mit unseren besten Freunden, wir bewahren Geheimnisse vor unseren Eltern auf und schreiben geheime Tagebücher, um ihnen unsere tiefsten Gedanken mitzuteilen. Im Laufe der Jahrhunderte hat sich diese natürliche Neigung vom Wahnsinn einiger Mathematiker zu einer tatsächlichen Wissenschaft entwickelt, die an Universitäten auf der ganzen Welt gelehrt wird. In der Vergangenheit wurde die Kunst, Geheimnisse zu bewahren, die wir heute als Kryptographie bezeichnen, fast ausschließlich für den privaten Informationsaustausch zwischen Ländern verwendet. In der Gegenwart ist es allgegenwärtig.

„Die Welt lebt von Codes und Chiffren, John. Vom Millionen-Pfund-Sicherheitssystem in der Bank bis zum Geldautomaten, an dem Sie Ausnahmen gemacht haben. Kryptographie ist in jedem Moment unseres Wachsens zu spüren “- Sherlock Holmes

Mit dem Aufkommen des Internets ist die Privatsphäre in der Tat zu einem Hauptanliegen geworden. Während des Zweiten Weltkriegs waren die Enigma-Maschinen entscheidend für den Sieg und die Niederlage Deutschlands. Aber im Zeitalter des Internets sind die Informationen von Haus aus digital und jeder Computer ist eine hochentwickelte Enigma-Maschine. Es ist daher nicht verwunderlich, dass wir unseren Wunsch nach Geheimhaltung in Code eingekapselt haben und Computersysteme selbst damit beauftragt haben, Geheimnisse für uns zu verwahren. Die Kunst der Geheimhaltung besteht nicht mehr darin, dem feindlichen Feld Chiffren zu stehlen. Es geht vielmehr darum, Maschinen zu bauen, die miteinander kommunizieren können, ohne dass Dritte die Nachricht entschlüsseln. Heutzutage ist die Kryptografie ein unverzichtbares Instrument zum Schutz von Informationen geworden: Unser Bankkonto, unsere E-Mails, unsere Online-Browsing-Gewohnheiten sind alle durch Kryptografie geschützt. Das Einsatzspektrum ist immens. Die kryptografische Kommunikation wird verwendet, um Nachrichten aus einer Entfernung von mehreren Kilometern in Sekundenbruchteilen privat auszutauschen, aber auch, um persönliche Daten, die nur wir zurücklesen können, sicher zu speichern. In der modernen Welt ist Kryptographie der Klebstoff, der die Welt zusammenhält.

Angesichts all dessen bedeutet Privatsphäre nicht nur Freiheit von öffentlicher Kontrolle, sondern auch persönliche Sicherheit und ist in der Tat ein grundlegendes Menschenrecht und muss als solches geschützt werden.

Die Suche nach dem Heiligen Gral in Web-Kryptobibliotheken

Hier in Cubbit haben wir den Traum, die Dateninfrastruktur zu dezentralisieren. Dazu benötigen wir eine Webanwendung, in der Benutzer von überall auf der Welt aus auf ihre Dateien zugreifen und diese speichern können. Aus diesem Grund haben wir mit der Suche nach verfügbaren Web-Kryptobibliotheken begonnen, die im Browser ausgeführt werden. Obwohl viele von ihnen im Laufe der Jahre aufgetaucht sind, hat niemand aus drei Hauptgründen unsere Anforderungen hinsichtlich Verschlüsselungsgeschwindigkeit und Benutzerfreundlichkeit erfüllt:

  • Übermäßig komplizierte APIs.
  • Schlechte Leistung beim Verschlüsseln / Entschlüsseln von Dateien (Kryptografie ist eine rechenintensive Anwendung und hat in Javascript in der Regel eine schlechte Leistung erbracht).
  • Mangel an Standards, die wir zum Aufbau unserer Krypto-Architektur benötigen.

Grund Nr. 0: Web-Kryptobibliotheken sind kompliziert

Lassen Sie uns diese Gründe genauer untersuchen.

Erstens gehen wir davon aus, dass OpenSSL der De-facto-Kryptografiestandard ist, da viele Unternehmen ihn in ihren Sicherheits-Workflow übernehmen. Da es jedoch in C geschrieben wurde, enthält es furchtbare API-Signaturen und ist immer noch schlecht dokumentiert, sodass die Lernkurve steiler ist als bei anderen Technologien. Daher bemühen sich alle aufkommenden Kryptobibliotheken, ihre Codebasis so kompatibel wie möglich mit OpenSSL zu halten, um die API für neue Entwickler nicht zu vereinfachen.

Grund 1: Krypto im Web ist unsicher UND langsam

Zweitens hat die Entwicklung der Webtechnologien dazu geführt, dass Browser der Einfachheit halber nur Javascript verwenden. Trotzdem ist Javascript nicht die beste Sprache für rechenintensive Aufgaben, und raten Sie mal, Kryptographie ist eine rechenintensive Aufgabe. Aufgrund seiner zunehmenden Verbreitung ist es oft die erste Wahl für viele aufstrebende Entwickler bei ihrer ersten Erfahrung. Ergebnis: Viele von ihnen fingen an, fehlerhaften Code zu schreiben, wodurch die Sprache voller Sicherheitsprobleme war.

Grund 2: Mangelnde Unterstützung für ECC und andere Standards in vielen Bibliotheken

Schließlich enthält keine der gefundenen Bibliotheken alle Standardalgorithmen, die wir implementieren müssen. Beispielsweise unterstützte keiner die Kryptographie mit elliptischen Kurven. Darüber hinaus eignet sich jedes einzelne mehr für ein bestimmtes Verschlüsselungsprotokoll als für andere, und wir verwenden eine Vielzahl von Verschlüsselungsprotokollen.

Lasst uns beginnen

Um all diese Probleme zu lösen, haben wir begonnen, unsere Kryptobibliothek im eigenen Haus zu entwickeln. Wir haben es mit drei klaren Zielen entworfen:

  1. Isomorphismus
  2. Geschwindigkeit der Dateiverschlüsselung
  3. Erfinden Sie das Rad niemals neu, es sei denn, es ist rechtwinklig

Isomorphismus bezieht sich auf das Konzept des universellen Codes, d. H. Einmal schreiben, überall ausführen.

Die Geschwindigkeit der Dateiverschlüsselung bedeutet, dass unsere Kryptobibliothek Dateien schnell verschlüsseln sollte, um die bestmögliche Benutzererfahrung zu erzielen.

Das dritte Prinzip ist unser Code-Ansatz. Mit anderen Worten, da Zeit die wertvollste Ressource im Universum ist, sollte sie niemals verschwendet werden, wenn es bereits effiziente Lösungen gibt. Sie sollten auch nicht verschwendet werden, wenn sie nicht versuchen, Blut aus einem Stein zu holen. In einem solchen Fall ist der Aufbau einer neuen Lösung immer der beste und schnellste Weg.

Im Internet

Wir haben Stunden und Stunden damit verbracht, eine Bibliothek mit den Funktionen und Leistungen, die wir brauchten, (erneut) zu durchsuchen, ohne Erfolg. Also beschlossen wir, den Kompilierungspfad auszuprobieren.

Was? Javascript kompilieren? Wie?

Danke an Emscripten!

Emscripten ist eine ziemlich neue Technologie mit einigen sehr interessanten Behauptungen:

Emscripten ist eine Toolchain zum Kompilieren in asm.js und WebAssembly, die mit LLVM erstellt wurde und es Ihnen ermöglicht, C und C ++ im Web mit nahezu nativer Geschwindigkeit ohne Plugins auszuführen.

Einen Versuch wert, findest du nicht?

Wir haben mit der Implementierung von ED25519 begonnen. Emscripten hat eine eigene Bibliothek, die in den Bindungen enthalten sein muss.

Ein wichtiger Gesichtspunkt ist die Speicherverwaltung. In der Javascript-Welt sind wir als Entwickler daran gewöhnt, an den Greatest Garbage Collector zu glauben, der es uns ermöglicht, alle speicherbezogenen Aspekte einfach zu ignorieren. Um den Emscripten-Code jedoch erfolgreich zu verwenden, müssen wir uns mit malloc und free um den gemeinsamen Speicher kümmern.

const heap_seed = em_array_malloc ((self as any) .enigma, seed);
ED25519.create_keypair (heap_seed.byteOffset, seed.length);
em_array_free ((self as any) .enigma, heap_seed);

Mit diesem Arbeitsergebnis in der Tasche sind wir zu einem anderen Thema übergegangen: dem AES-Streaming-Modus. Wir haben bei unseren Recherchen keine sehr guten Ergebnisse erzielt und versuchen es daher mit OpenSSL. Dies implizierte, dass die Codebasis mit Emscripten kompiliert werden musste; Leider fehlte die Dokumentation. Nach einiger Zeit fanden wir empirisch das Verfahren, um die Ergebnisse zu erzielen.

das heißt, die folgenden Schritte:

  1. Schließen Sie alle nicht unbedingt erforderlichen Chiffren aus
  2. Cross-Compile
  3. Verlinke mit deinem Code

Und…

Auf Node.js

Typescript, die typisierte Obermenge von Javascript von Microsoft, ist das Herzstück des Tech-Stacks hier in Cubbit. Daher wäre es selbstverständlich gewesen, den kryptografischen Stapel auch in Typescript zu erstellen. Performance und Kryptografie passen jedoch perfekt zu Muttersprachen wie C ++, während Typescript, wie bereits erwähnt, für die Aufgabe ungeeignet ist.

Daher haben wir uns für Node.js als Primärsprache entschieden, da wir damit Add-Ons nutzen können, um systemeigenen Code einfach zu integrieren. In dieser Hinsicht ist die N-API ein großartiges Tool des Node.js-Teams, eine API, die über alle Node.js-Versionen hinweg stabil ist: Sie wird nur einmal erstellt und auf jeder späteren Hauptversion ohne erneute Kompilierung ausgeführt.

Darüber hinaus ist die Verwendung ganz einfach:

Verpacken und exportieren Sie einfach die Objekte und Funktionen, die Sie mit der Javascript-Welt teilen möchten, und lassen Sie den Compiler die harte Arbeit für Sie erledigen.

Enigma, eine schnelle universelle Kryptobibliothek

Und so war Enigma nach ein paar Monaten Forschung und Programmierung zum Leben erweckt worden.

Enigma ist eine Kryptobibliothek, die so konzipiert ist, dass sie auf Browsern effizient funktioniert, indem sie auf coole Technologien wie WebCrypto und WebAssembly zurückgreift. Unser Ziel ist es, die wichtigsten Krypto-Standardalgorithmen sowie eine Reihe von Dienstprogrammen bereitzustellen, um dem "Standard" -Entwickler die Verwendung zu vereinfachen.

Um die Übernahme weiter zu vereinfachen, haben wir Enigma isomorph gemacht, d. H. Sowohl mit Node.js als auch mit dem Web kompatibel, damit es interoperabel ist, ohne eine einzige Codezeile zu ändern. Der Code sollte universell sein, gemäß dem WORA-Motto, d. H. "Einmal schreiben, überall ausführen".

Wie man es benutzt

Jetzt darfst du sagen: „Ok, cool! Aber wie kann ich es benutzen? “Zuerst müssen Sie es installieren. Da Enigma ein NPM-Modul ist, können Sie einfach den folgenden Befehl in Ihr Terminal eingeben:

npm install @ cubbit / enigma

oder wenn Sie Garn bevorzugen:

Garn hinzufügen @ Cubbit / Rätsel

Jetzt ist Enigma installiert und Teil Ihrer Abhängigkeiten.

Dann ist es an der Zeit, damit zu beginnen!

Nehmen wir an, Sie möchten eine Nachricht mit AES-256 verschlüsseln (um einfach zu beginnen). Auf geht's. Als erstes müssen wir Enigma initialisieren. Da nativer Code verwendet wird, um die Leistung zu steigern, müssen wir warten, bis der Browser ihn lädt, bevor wir die Bibliothek verwenden können.

HINWEIS: Der folgende Code ist in Typescript geschrieben, aber Sie können natürlich auch in reinem Javascript schreiben!

Unser Ziel ist es, eine einfache Textzeichenfolge zu verschlüsseln.

Da es sich bei AES256 um einen symmetrischen Verschlüsselungsalgorithmus handelt, müssen Sie denselben Schlüssel verwenden, den Sie zum Verschlüsseln der Nachricht verwendet haben, um sie wieder zu entschlüsseln. So etwas wie:

Angenommen, wir möchten eine Datei verschlüsseln, bevor sie an das Netzwerk gesendet wird. Nun, Sie müssen wissen, dass die meisten vorhandenen Browser Einschränkungen hinsichtlich des maximalen Speichers aufweisen, der von einer Webseite zugewiesen werden kann. Beispielsweise kann Google Chrome maximal 1,5 GB RAM zuweisen. Außerdem funktionieren Blockverschlüsselungsalgorithmen im Allgemeinen besser mit kleinen Datenblöcken. Es wird daher nicht empfohlen, die gesamte Datei zu verschlüsseln, sondern sie schrittweise zu verschlüsseln. In diesem Bereich bietet Node.js ein sehr praktisches und gut gestaltetes Tool zum Bearbeiten von Datenströmen: das Stream-Objekt. Wir ließen uns daher von der Bereitstellung einer nahtlosen API inspirieren.

Die Stärke dieser Art von Syntax besteht darin, dass Sie Pipes zusammenfügen können, um die verschlüsselte Datei automatisch über das Netzwerk zu senden, während sie verschlüsselt wird. Magie! :)

file_stream.pipe (aes_stream) .pipe (socket);

Enigma bietet viel mehr Funktionen. Wenn Sie interessiert sind, können Sie das Repository besuchen und einen Beitrag leisten.

Die Ergebnisse

Wir führen eine Reihe von Benchmarks durch, um Enigma mit anderen vorhandenen Bibliotheken für das Web zu vergleichen. Hier sind die Ergebnisse (Chrome 72 auf I7-7820HQ - niedriger ist besser):

AES-Verschlüsselung. Weniger ist besser

Wie Sie sehen, funktioniert Enigma am besten, wenn Sie Dateien verschlüsseln und verarbeiten, anstatt kleine Zeichenfolgen zu verschlüsseln. Tatsächlich führen wir einen kleinen Overhead ein, indem wir die Webassembly-Binärdateien laden. Dies ist jedoch ein entscheidender Faktor, wenn wir größere Datenmengen, wie z. B. Dateien, verschlüsseln müssen.

Unsere Vision für die Zukunft von Enigma

Unser Ziel ist es, eine leistungsfähige und einfache kryptografische Bibliothek zu erstellen.

Wir werden Bibliotheken weiterhin mit unseren APIs verpacken, um mehr Algorithmen zu implementieren und bessere Leistungen zu erzielen. Wir haben Enigma mit Blick auf Benutzerfreundlichkeit und Leistung entwickelt und werden weiter daran arbeiten, es zu verbessern.

PS. Enigma wurde als kryptografische Schicht für Cubbit entwickelt, die jetzt die verteilte Cloud startet. Wenn Sie mehr wissen möchten, lesen Sie es hier.