pcp und pbp auf Cypherpunks
Gwen Hastings hat mich in einem Bugreport für pcp auf eine Diskussion auf der Cypherpunks Mailingliste über pcp vs. pbp aufmerksam gemacht. Gut, das ist nicht die echte Cypherpunks Liste von anno dazumal, aber immerhin. Sieht so aus, als ob ich mich mit dem Autor von pbp (ein Python Commandline Tool, das das gleiche wie mein pcp tut, allerdings mit mehr Features wie es aussieht) über Schlüsselformate etc einigen muss. Denn die Leute haben Recht: lieber einigen wir uns gleich von Anfang an, als das es Wildwuchs gibt. Mir ist das auch aus einem anderen Grund mehr als recht: in Ermangelung an Vorarbeiten oder vorhandenen Lösungen auf die ich aufsetzen konnte (wobei Lösungen wie x509 und Konsorten nicht in Frage kommen, too bloated), musste ich mir im Grunde alles selber ausdenken. Da ich eher der pragmatische Typ bin, hab ich halt einfach drauflos gecoded. Ja, funktionieren tut das alles soweit, aber ob das alles gute Entscheidungen waren? God knows.
Insofern ist das gut, dass das jetzt mal von Dritten demontiert wird. Ich hab zwar schon etwas Muffe, dass ich Kloppe krieg, aber da muss ich wohl durch. Zur Not muss ich halt pcp umschreiben, was ja kein Problem ist, lange regelmässige Zugfahrten sei Dank.
Jedenfalls zeigt das, dass Interesse vorhanden ist, was mich schonmal sehr freut. Und dass die Entwicklung weitergeht. Wir werden die NSA schon ficken :)
Update 2014-01-29:
Huch, es gibt noch eine Twittermeldung über PCP:
Update 2014-01-29:
Die wichtigsten Sachen wären soweit fertig. Ich mache jetzt blockweise Verschlüsselung, per Default im ECB Mode, per configure Parameter kann man aber auch auf CBC wechseln (--enable-cbc). Letzteres erscheint mir als die bessere Wahl, auch wenn die EBC Blöcke 32k gross sind. Für mehrere Empfänger verschlüsseln geht auch. Das Format sollte PBP kompatibel sein. Im Selfmode wird tatsächlich symetrische Verschlüsselung verwendet. Und man kann jetzt PBP Public Keys importieren oder exportieren.Update 2014-01-20:
Nachtrag: noch ein Funfact: Hauptkritik von Yuryi war ja wie erwähnt, dass ich die Key-ID bei verschlüsselten Dateien mitschicke, was ich nun gefixt hab. Heute hab ich die Manpage entsprechend upgedated und was stand da?:When using for encryption, the keyid will be added to the message so that the receiver knows who was the sender of the message (B. Oh Mann. Tatsächlich war mir das also offenbar schonmal durch den Sinn gegangen, dass das eventuell blöd ist, aber ich habs komplett vergessen!)
Wird aber noch besser: tatsächlich war es sogar so, dass ich gar nicht die Key-ID rausgeschrieben habe, sondern einen Hash davon. Eigentlich hätte ich die Kritik von Yuryi also zumindest was das betrifft, sauber abschmettern können. Ich werde alt, soviel steht mal fest. Aber ist nun auch egal, das Feature ist jetzt eh weg und das Tool wird dadurch insgesamt benutzerfreundlicher (und zwar wesentlich!).
Update 2014-01-20:
Einiges konnte ich heute im Zug angehen (siehe solved Marker oben). Als nächstes muss ich den Verschlüsselungs-Code aus src/ nach libpcp/ verschieben. Im Moment hab ich in libpcp zwar passende Wrapperfunktionen, die ganze Vorarbeit, I/O usw passiert aber in src/. Das ist schlecht, weil es dadurch nicht Teil der Library ist und insbesondere in der C++ API habe ich dann das Problem, das nochmal nachcoden zu müssen. Den Teil habe ich aber schon länger in der TODO Liste stehen, insofern alles cool.Wenn ich die Sachen ausgelagert habe, und der ganze I/O (d.h. Lesen des Inputs, Ver-oder Ent-schlüsselung, Schreiben des Outputs) in je einer Funktion ist, kann ich den 23kb-Blockmode von Stef implementieren, mehrere Empfänger einbauen etc pp. Vorher macht das keinen Sinn. Aber: wenn ich DAS habe, brauche ich "nur" noch eine Import/Export-Funktion für PBP-Schlüssel und schon sind PCP und PBP kompatibel. 2-3 Tage schätze ich mal, werd ich brauchen.
Update 2014-01-17:
Nachdem ich mir nun reichlich Gedanken gemacht habe und mich auch nochmal mit stef privat darüber ausgetauscht habe, erstelle ich hier mal eine Liste der Dinge, die ich in PCP falsch gemacht habe und ändern muss (mehr als note-to-self gedacht):- Key Derivation: der secret key eines PCP Schlüssels ist ja verschlüsselt, dazu wird vom Benutzer ein Passwort abgefragt. Man sollte jedoch nicht direkt das Passowort zum Verschlüsseln verwenden, sondern daraus einen Verschlüsselungs-Key erzeugen, "Key Derivation" genannt. Da libsodium keine solche Funktion anbietet, habe ich selber eine erstellt, nur als Provisorium gedacht. Die Methode hatte ich u.a. auf der ZeroMQ Mailingliste besprochen (dort ging es um das Erzeugen von Schlüsseln für CurveCP) und wir waren uns einig, dass meine Methode halbwegs ok sei. Ich hatte dabei aus dem Passwort einen Hash erzeugt und aus diesem Hash wieder einen Hash und so weiter, insgesamt 128000 mal. Das erschwert Bruteforceangriffe.
Nachdem sich herausgestellt hat, dass stef in pbp bereits scrypt verwendet, habe ich mich entschlossen, das nun auch zu tun. Ich habe die Sourcen des "scrypt" Dateiverschlüsselungstools aus den FreeBSD Ports in der Version 1.1.6 verwendet und 1:1 in pcp eingebaut, incl. autoconf Macros usw. Status: solved -
Key-IDs. Yuriy hat mich auf der Mailingliste wie vorherzusehen war, tatsächlich sprichwörtlich "verkloppt" für einige meiner Entscheidungen, eine davon war die Verwendung von Key-IDs. Meine PCP Schlüssel haben ja eine ID (errechnet als 2facher Jen-Hash aus dem Secretkey), u.a. weil ich für die Schlüssel-Datenbank (der Vault) irgendeinen geeigneten Identifier brauchte. Key-IDs erschienen mir eine gute Wahl, zumal die bei PGP auch benutzt werden. Nun sind Key-IDs an sich nichts schlechtes, aber es ist schlecht, die Key-ID einer verschlüsselten Datei beizufügen, damit der Empfänger weiss, von wem die Datei kam. Also präzise das, was ich derzeit in PCP mache.
Das muss ich ändern, und ich werde mich da an stef's pbp orientieren und statt dessen den Public Key des Absenders mitschicken. Das löst ausserdem gleich ein weiteres Problem: nämlich das des Schlüsselaustauschs. Bisher ist es bei PCP nämlich erforderlich, dass BEIDE Partner einer Kommunikation vorher ihre Schlüssel ausgetauscht haben müssen. Wenn ich aber den Public Key des Absenders in der verschlüsselten Datei mitschicke, muss dem Absender nur noch der Public Key des Empfängers bekannt sein. Also so, wie es derzeit auch bei PGP ist. Eine erhebliche Verbesserung. Status: solved (20.01.2014). - Nur long-term Keys in PCP. Ein weiterer Fehler, auf den mich sowohl Yuriy und stef aufmerksam gemacht haben, ist, dass ich in PCP den Main Secret Key des Absenders verwende. Gerade bei Curve25519 soll man aber nach Möglichkeit sogenannte single-use Keys verwenden. In pbp wird dazu beim Verschlüsseln einer Datei auf Absenderseite ein neues Schlüsselpaar erzeugt, mit dem Secret Key dieses Paars und dem bekannten Public Key des Empfängers wird dann verschlüsselt, der Public Key wird an das verschlüsselte Ergebnis gehängt (siehe oben). Gespeichert wird das Schlüsselpaar nicht. Da der Public Key, den der Empfänger zum Entschlüsseln braucht, mit beiliegt, ist das kein Problem. Der Empfänger braucht den Public Key dann auch nicht zu speichern. Allerdings müsste der zum Antworten dann immer noch den eigentlichen Public Key des Absenders haben, den dieser unabhängig davon veröffentlichen (oder mitschicken) müsste. Ich muss die Doku von pbp auch nochmal anschauen, ich meine, stef schickt bei pbp den auch gleich mit. Status: solved (20.01.2014).
- Derived Keys Feature. Mein "Derived Key" Feature wird durch den Punkt oben obsolete. Das hab ich mir tatsächlich nur ausgedacht um es einem potentiellen Angreifer schwieriger zu machen. Wenn aber eine Hälfte der verwendeten Schlüssel dynamisch ist, ist das nicht mehr notwendig. Ich werde das Feature daher aus dem Code entfernen. Im Nachhinein betrachtet ist das eh besser. Das ist ziemlich kompliziert und schwer zu verstehen, so schwer, dass ich selbst meine eigene Doku studieren muss, um mich zu erinnern wie das geht. Also weg damit. Status: solved (20.01.2014).
- Crypto in an online setting. Ein weiteres Problem, dass ich mit PCP habe, sind grosse Dateien. Derzeit lese ich die komplett in den Speicher und verschlüssele sie komplett. Auf dem PC normalerweise kein grosses Drama. Aber auf Mobil- oder Embeddedgeräten schon. Ich muss das also ändern und mit Buffern arbeiten. Stef hat 32 KB als maximale Buffergrösse vorgeschlagen, bzw verwendet die in pbp. Dem werde ich mich anschliessen (schon aus Gründen der Kompatibilität). Eine Datei wird also blockweise verschlüsselt und nicht in einem Rutsch. Und jeder Block wird wie eine eigene Nachricht behandelt. Status: solved (28.01.2014)
Es gibt ausserdem noch eine Reihe von Inkompatibilitäten zwischen pcp und pbp, einige davon werden sich in Wohlgefallen auflösen, wenn ich die oben aufgelisteten Designfehler behoben habe, übrig wäre dann noch:
-
Schlüsselexportformat. Das wird der schwierige Teil. PBP speichert derzeit keine Metadaten IM Schlüssel, sondern im Filesystem. Das mache ich völlig anders, bei PCP sind die Metadaten (Owner, Mail, ID, Checksumme, Seriennummer, Version, Erzeugungsdatum, etc) direkt IM Schlüssel enthalten. Das ist zwar im einzelnen praktisch, andererseits hat Stef's Lösung sowas nicht mitzuschicken viele Vorteile. Das werde ich irgendwie lösen müssen. Eine Variante wäre, bei exportieren Public Keys keine Metadaten anzuhängen. Status: solved (28.01.2014)
Hier muss ich noch hinzufügen, dass ich mich insofern geirrt habe, als dass in PBP Keys doch einige Metadaten enthalten sind, anscheinend hat Stef das bereits geändert. Wie dem auch sei, ich kann die jetzt exportieren und importieren (public only). -
Verschlüsselungsmethode/mehrere Empfänger. Wir machen beide in pbp und pcp im Grunde das gleiche, es ist aber unterschiedlich implementiert. Ich verwende in pcp einfach die NACL Funktion crypto_box() und gut ist. Diese Funktion erzeugt einen symetrischen Key, verschlüsselt damit (und mit einer Nonce) die Nachricht, verschlüsselt dann diesen Key mit dem public key des Empfängers und dem secret key des Absenders (curve25519) und hängt den an die Nachricht.
Stef hingegen macht in pbp zwar das gleiche, aber er macht es zu Fuss und verwendet nicht crypto_box(). Dadurch ist er in der Lage, eine Nachricht für mehrere Empfänger zu verschlüsseln, weil er nur den symetrischen Key für jeden Empfänger neu verschlüsseln muss. Ich muss in pcp in diesem Fall für jeden Empfänger alles neu verschlüsseln.
Damit einher geht auch eine Änderung des Formats einer verschlüsselten Datei, die nicht nur den Public Key des Absenders, sondern auch den Public Key des Empfängers enthält (soweit ich wie gesagt, die pbp Doku verstanden habe). Status: solved (24.01.2014) - ED25519 und Curve25519 Key getrennt erzeugen. Yuriy wies mich auf der Cypherpunksliste auf ein weiteres Problem hin: ich errechne derzeit den Verschlüsselungskey (Curve25519) aus dem Signaturkey (ED25519). In diesem speziellen Fall kann ich aber immerhin sagen, dass das nicht meine eigene Idee war (oder wie er es formulierte: "self invention of a square wheeled bicycle" *g*), sondern ein Vorschlag der libsodium Entwickler, die ich nämlich extra auf deren Mailingliste danach gefragt hatte. Nun, Yuriy meint, ich soll die beiden Keys getrennt erzeugen. Stef macht das in pbp übrigens auch so. Hm. Für die Kompatibilität zu pbp ist das zwar völlig egal, aber ich kann das leicht ändern. Das wären nur ein paar Zeilen. Status: solved (20.01.2014)
- Encoding. Hier wirds blöd. pbp verwendet Base85 und pcp verwendet Z85. Letzteres ist eine Abwandlung von Base85, allerdings kein weltweiter Standard. Andererseits ist bei dem Thema hier im Moment sowieso auf Standards "geschissen", nichts davon ist Standard, was ja auch Absicht ist. Denn die Standards sind ja kompromittiert wie wir inzwischen wissen. Jedenfalls habe ich keine rechte Lust, in C einen Base85 de/en-coder zu schreiben. Ich tendiere eher dazu, einen Z85 Encoder in Python zu schreiben und dafür einen Pullrequest an Stef zu schicken *g*. Mal sehen. Über kurz oder lang müssen wir jedenfalls das gleiche Encoding und in den Binärdaten das gleiche Format verwenden, sonst wird das nix. Status: open.
Tja, klingt nach viel Arbeit, riecht nach viel Arbeit und ist viel Arbeit. Etwas ärgerlich, dass der überwiegende Teil davon bei mir liegt. Aber was muss ich mir auch irgendwelche Dinge ausdenken, ich Honk. Aber das gute ist, dass ich dabei viel lerne und darum geht es mir persönlich eigentlich auch nur: immer was neues lernen. Ne Menge anderer Leute hätten Yuriys Kritik vielleicht beleidigt aufgefasst. Aber ich werde lieber ruppig eines besseren belehrt als gar nicht, und darauf kommt es an.