Effektive Verschlüsselung von Zahlenketten

bitmuncher

Senior-Nerd
Hi,

Auch auf die Gefahr, dass es dumm klingen mag, stelle ich meine Frage hier einfach mal. ;)
Ich suche derzeit nach einer Möglichkeit Zahlenketten (12345, 472134 usw) mit variabler Länge effektiv zu verschlüsseln. Allerdings bin ich dabei auf einige Probleme gestossen. Aufgrund der geringen Menge an möglichen Zeichen sind Side-Channel-Angriffe (z.B. bei RSA) stark vereinfacht, so dass sich mir langsam die Frage stellt, ob und (wenn ja) wie ich Zahlenketten am Besten verschlüsseln kann.

Eine Idee war, dass man rein theoretisch in einem Array jeder Zahl eine Zeichenkette zuordnen kann (1 = a%cF&, 2 = t34K$ usw), wo sich dann aber wieder die Frage stellt, ob es nicht zumindest theoretisch möglich wäre dieses Array aus dem RAM auszulesen (z.B. durch Debugging des Prozesses).

Wenn also jemand eine Idee hat, wie ich trotz der geringen Anzahl an möglichen Zeichen bei Zahlenketten eine effektive Verschlüsselung hinbekomme, immer her damit. :) Evtl. gibt es ja auch einen Algorithmus, der besonders bei Zahlenketten seine Stärken zeigt.

Falls sich da garnichts findet, müsste ich halt eine andere Möglichkeit finden Zahlenketten während der Übertragung von Rechner A zu Rechner B effektiv unleserlich zu machen (einmal-Keys o.ä.), allerdings wäre mir eine ordentliche Verschlüsselung schon lieber.
 
Md5 wäre ne möglichkeit.

Doch musst du dann immer mit dem Hashwert rechnen. - Man kann den Hash logischerweise nicht mehr "entschlüsseln".

Aber kurze reine Zahlenketten sind IMHO mit Bruteforce schnell geknackt. Ich würde dir (sofern es nur Zahlen sein dürfen), "Einmal-Keys" empfelen.

Mfg
IsNull
 
Du solltest auf keinen Fall einen festen, nicht von einem Schlüssel abhängigen Algorithmus verwenden, da man diesen auch ohne Probleme wieder aus dem Programm rekonstruieren kann. (wie z.B. dein Beispiel mit dem Array) Außerdem ist das dann lediglich eine Codierung und keine Verschlüsselung.
MD5 würde nicht funktionieren, da so weit ich das sehe die Zeichenketten auch wieder entschlüsselt werden sollen.
Man könnte z.B mittels Diffie-Hellman einen Schlüssel bestimmen und dann mit Rijndael o.ä. verschlüsseln.
 
Nun gut, dann müsste ich also auch noch digitale Unterschriften und/oder Message Authentication implementieren, wenn ich Diffie-Hellman nutzen würde. Nur so könnte ich ja sicher stellen, dass auch ein Man-in-the-Middle keine Gefahr darstellt, denn natürlich soll auch die Integrität der Daten sichergestellt bleiben. Will ja nicht, dass nachher bei Rechner B der falsche Wert ankommt.
Aber die Idee klingt schonmal gut. Werde mal sehen, wie ich das am Besten in die Praxis umsetzen kann. :)
 
Original von bitmuncher
Nun gut, dann müsste ich also auch noch digitale Unterschriften und/oder Message Authentication implementieren, wenn ich Diffie-Hellman nutzen würde. Nur so könnte ich ja sicher stellen, dass auch ein Man-in-the-Middle keine Gefahr darstellt, denn natürlich soll auch die Integrität der Daten sichergestellt bleiben. Will ja nicht, dass nachher bei Rechner B der falsche Wert ankommt.
Aber die Idee klingt schonmal gut. Werde mal sehen, wie ich das am Besten in die Praxis umsetzen kann. :)

Für's Signieren bräuchte man aber eine bereits bestehende PKI und wenn man diese bereits zu Verfügung hätte, könnte man auch direkt asymmetrische Verschlüsselung nutzen, anstatt den Umweg über DH zu gehen.(Bzw. einfach einen Schlüssel für $symmetrisches_verfahren per RSA o.ä. verschlüsseln und verschicken)
Allerdings fällt mir auch keine hundertprozentig sichere Lösung ein, wie man MITM-Angriffe komplett verhindern könnte, ohne irgendwelche Vorraussetzungen.
 
Hallo,
also alle (modernen) Verschlüsselungs-Verfahren arbeiten mit Zahlen, wobei diese dann meistens 128 Bit lang sind. Es besteht also generell kein Unterschied, ob man nun einen String in eine 128 Bit Zahl umwandelt, oder direkt mit Zahlen hantiert.

Um dir helfen zu können, müssten wir aber noch wissen:
Wie groß sind die Zahlen?
Soll ein Key, wovon ich ausgehen, eine Rolle spielen?

Bei 5 bis max. 10 stellige Zahlen könnte man sogar ein One-Time-Pad verwenden, was dann vorraussetzt, dass das Passwort 8 Zeichen (a-z) lang sein muss (bei max. 10 stellige Zahlen).
 
Es geht um statistische Daten, die von Rechner A an Rechner B weiter gereicht werden sollen ohne dass jemand sie unterwegs abfangen und verwerten kann. Aufgrund der Unterschiedlichkeit der Daten, die erhoben werden, können sie zwischen 2 und 18 Stellen schwanken. Die Daten die dabei übermittelt werden, haben immer die Form

StatistikID Wert

bestehen also ausschliesslich aus Zahlenwerten, wobei StatistikID eine 7-stellig Zahl ist. Der Unterschied zwischen Strings und Zahlen liegt darin, dass bei Zahlen nunmal nur 10 mögliche Zeichen vorhanden sind, was, wenn ich nicht völlig falsch liege, Side-Channel-Angriffe um einiges vereinfachen dürfte. Zumindest RSA u.ä. aufgebaute Algorithmen halte ich daher eher für unbrauchbar.

Ob ein Key Verwendung findet, liegt ganz in meiner Hand, habe da also keine Vorgaben was die Implementierung angeht, aber ich gehe erstmal davon aus, dass ich einen verwenden werde. Den Key würde in diesem Fall dann ein dritter Rechner zur Verfügung stellen, wo durch Paket-Filter sichergestellt wird, dass nur die 2 Rechner, die an der Transaktion beteiligt sind, einen Key beziehen bzw. hochladen können. So zumindest bisher meine Planung. Der Vorgang einer Übertragung wäre also:

Rechner A loggt sich auf Rechner C (dem "Key-Server") ein und hinterlegt dort einen Key, an dem vermerkt wird, für welche IP mit welcher MAC-Adresse er bestimmt ist, sofern für diese IP/MAC-Kombi noch kein Key existiert. Rechner C gibt dann für diese IP den entsprechenden Port frei. Rechner B mit der beim Key vermerkten IP und MAC-Adresse loggt sich auf Rechner C ein und holt sich seinen Key ab (nutzt seine MAC-Adresse für den Login und ein Passwort, das direkt für diesen Rechner festgelegt ist), woraufhin der Port auf Rechner C für diese IP wieder gesperrt wird. Rechner B verbindet nun zu Rechner A und holt sich dort die mit dem Key verschlüsselten Daten ab und entschlüsselt sie dann um sie in einem Interface dann weiter zu verwenden.

Wie gesagt... das ist meine bisherige Planung, aber es gibt da noch einige Schwachstellen (z.B. das Hinterlegen des Keys auf Rechner C und die Freischaltung bzw. Validierung der Verbindung zum Abholen des Keys), die ich noch ausräumen muss, wo ich aber diverse Lösungsansätze schon habe. Evtl. lasse ich Rechner C noch ein 1mal-Passwort an Rechner B schicken, das dieser dann zum Login nutzt o.ä.. Daher stellt sich mir momentan nur die Frage, wie ich die Statistik-Daten trotz der geringen Anzahl an möglichen enthaltenen Zeichen effektiv unleserlich machen kann.

Momentan ist halt alles noch reine Planung. Da ich ein Zeitfenster bis Ende Juli 07 habe, möchte ich diesmal auch eine intensive Planungsphase machen bevor ich mich ans Coden mache und nachher nur Schrott bei rauskommt. Hardware ist glücklicher genug vorhanden. 5 Rechner stehen mir zum Testen zur Verfügung. :)
 
Hallo,
Original von bitmuncher
Der Unterschied zwischen Strings und Zahlen liegt darin, dass bei Zahlen nunmal nur 10 mögliche Zeichen vorhanden sind.
Dies spielt keine Rolle, da du die Zahl dann als Zahl behandelst und nicht als String mit nur 10 verschiedenen Zeichen.
Oder anders gesagt: Beides wird binär, also aus 1 und 0, dargestellt.

Die Zahl '310 872 140 911' würde dem Hex-Code: 48 61 6C 6C 6F und dies dem String 'Hallo' entsprechen. Wie du siehst, ist es eigentlich egal, ob man Zahlen verwendet oder Strings. Denn damit das Verschlüsselungsverfahren rechnen kann, wandelt es den String-Block in eine Zahl um.

Hier also z.B. so:
Code:
H << 4
a << 3
l << 2
l << 1
o << 0
==
48 << 4
61 << 3
6C << 2
6C << 1
6F << 0

Das Ergebnis der Rechnung (310 872 140 911) wird dann der Verschlüsselungsfunktion übergeben. Oftmals hat die Funktion vier Int-Werte als Argument (oder ein Int-Array der größe 4) und ein Argument für das Key-Array. Mit Strings wird dort i.d.R. gar nicht gerechnet.

Bsp XTEA:
void encipher(unsigned int num_rounds, unsigned long* v, unsigned long* k)
{
//...
}

Wobei v ein 2-Elemente Array ist (der linke & rechte Block), und k ein 4-Elemente Array (der Key).



Das ganze per RSA zu kodieren, wäre nicht Sinnvoll. Besser wäre es, per RSA oder Diffie-Hellman, einen 128 Bit Key auszutauschen und dann die Daten symetrisch zu verschlüsseln.
Und genau dieses Prinzip verwendet SSL/TLS. Deswegen würde ich dir empfehlen, eine SSL/TLS Library für deine Programmiersprache zu suchen und die gesamte Kommunikation zwischen Server & Client zu verschlüsseln.

Sofern die Library gut geschrieben ist, dann musst du beim Server nur deinen private RSA Key angeben (+ evt. Zertifikat) und dann den SSL Port auf lauschen stellen.
Der Client ruft dann eine Funktion auf in der Library auf, welche sich mit dem Port verbindet und nachdem die Verbindung ausgehandelt ist, kannst du ganz normal das Socket Programmieren, also deine ganz normalen Socket-Funktionen verwenden. Das dazwischen noch eine Veschlüsselung besteht, merkst du i.d.R. nicht, nur die Prozedur fürs Port-Lauschen und für den Verbindungsaufbau ändert sich etwas.
 
Ok, so wie es aussieht, habe ich gut damit getan, dass ich mir vorhin noch "Applied Cryptography" bestellt habe. Hab da sichtlich noch Wissenslücken über die Details, weswegen ich ja ein schon vorhandenes Verfahren anwenden wollte. Danke, dass du mir diese Wissenlücken gezeigt hast, jetzt weiss ich wenigstens, was ich noch alles nachlesen muss. :)

Wichtig ist mir, dass der Schlüssel möglichst nicht auf den Rechnern A und B dauerhaft vorhanden ist, sondern generiert, ausgetauscht und wieder gelöscht wird. Es soll also bei jeder Übertragung ein neuer Schlüssel verwendet werden. Ob das bei SSL der Fall ist, weiss ich jetzt nicht (werde ich aber gleich mal nachlesen, wie das dort abläuft), aber daher kam die Idee einen "Key-Verteiler" einzusetzen. Ich will halt unbedingt sicherstellen, dass auch ein Man-in-the-Middle-Angriff möglichst schwierig wird, wenn niemand vorhersagen kann welche Port der "Key-Verteiler" für IP x.x.x.x (also Rechner B) öffnen wird. Rechner A und der Key-Verteiler bilden dabei ein abgetrenntes Subnetz, so dass die Übertragung des Keys von Rechner A zum Verteiler unmöglich abhörbar sein dürfte, denn das läuft über ein extra Netzwerk-Device, während die Clients (also Rechner B) über's Internet verbunden sein werden. Dabei soll sowohl die Integrität als auch die Unlesbarkeit der Daten während der Übertragung sichergestellt werden, da sowohl die Verfälschung als auch der Diebstahl der Daten fatal wäre.

Ich werde definitiv C für die Programmierung verwenden, da es die Sprache ist, die ich am Besten beherrsche (war die erste, die ich gelernt habe und entsprechend habe ich damit mehr Erfahrung als mit anderen Sprachen), sie unter Linux (neben Assembler) die beste Performance liefert und die meisten Algorithmen als C-Code im Netz zur Verfügung stehen, so dass ich "das Rad nicht nochmal neu erfinden" muss. :)
 
Hallo,
Original von bitmuncher
Ob das bei SSL der Fall ist, weiss ich jetzt nicht.
Bei normalem SSL wird der geheime Key normalerweise für 1 Jahr verwendet.

Den SSL Aufbau kann man sich grob so vorstellen:
Der Client sendet eine Anfrage an den Server, dass er gerne eine Verbindung mit dem Port xyz aufbauen möchte.
Der Server sendet darauf hin seinen öffentlichen RSA-Key. Danach wird dann ein zufälliger Sitzungsschlüssel für z.B. AES generiert und diesen sendet der Client per RSA Verschlüsselt an den Server.
Die restliche Kommunikation überflogt dann per AES Verschlüsselung.


Man verwendet einen geheimen RSA Key normalerweise für 1 Jahr, da dieser oft einhergeht mit einem signiertem Zertifikat (dass der Recher wirklich der Rechner ist, den er vorgibt zu sein) was alles etwas zeitaufwendiger ist.

Da du aber denk ich mal ohne Zertifikate arbeiten möchtest, welches eine erschwerte Infrastruktur für dich bedeuten würde, könntest du auch bei jedem Verbindungsaufbau den RSA Key neu generieren lassen, so dass jeder Client einen anderen öffentlichen Schlüssel zugestellt bekommt und der Server bei jeder Kommunikation einen anderen geheimen RSA-Key verwendet.


Allerdings ist hier ein Problem wegen Man-In-The-Middle: Hier helfen Zertifikate, welches dem Computer 192.168.0.1 bestätigt, dass er der Computer ist.
Das Problem ist die Signierung.
Sich selber ein Zertifikat auszustellen, welches einem bescheinigt, dass du der und der Rechner bist, bringt nichts.
Darum brauchst du einen vertrauenswürdigen Dritten, der dein Zertifikat signiert (unterschreibt).

Du kannst dir das wie ein Perso vorstellen: Einfach ein normaler Zettel, wo drauf steht, dass du Klaus Mustermann bist, hat keine Sicherheit.
Siginiert aber jetzt der Staat auf dem Zettel, dass du Klaus Mustermann bist, dann hat dieses Sicherheit.

Verwendest du HTTPs, dann haben Seiten, wo das Zertifikat wichtig ist, dieses signiert, z.B. das Zertifikat von deiner Bank. Da die Dritten dies aber nicht kostenlos machen, haben kleinere Seiten ein unsigniertes Zertifikat.

Um kosten zu sparen, könntest du selber einen vertrauenswürdigen Dritten erstellen, dem der Server und der Client vertrauen, und dieser könnte dann der Zertifikat signieren.
Ein Man-In-The-Middle müsste dann zusätzlich noch den geheimen Key des vertrauenswürdigen Dritten klauen.

Ist natürlich kompilizierter zu realisieren und ein ständiger RSA-Key wechsel entfällt damit auch.


Aber in 'Angewandte Kryptographie' von Bruce Schneier wird dies im Kapitel 'Protokolle' (dort dann Schlüsselaustausch/Vertrauenswürdige Dritte oder so), sehr gut erklärt.
 
Das Zertifikat-Prinzip von SSL war mir durchaus klar. Dass das allerdings gleich den Schlüssel umfasst nicht. Hatte gehofft, dass das auch ohne Zertifikate geht, aber so wie es aussieht ist eine SSL-Implementierung ohne Verwendung eines Zertifikat nicht möglich. Damit fällt SSL also schonmal raus, denn der Schlüssel gehört ja quasi zum Zertifikat, was hiesse, dass ich bei jeder Verbindung einen Schlüssel _und_ ein Zertifikat erstellen müsste.
Die Vertrauenswürdigkeit der Kommunikationspartner werde ich durch diese IP->MAC-Passwort-Kombination sicherstellen, d.h. jeder Client muss zur Anmeldung diese 3 Daten verwenden. Er muss die richtige IP haben, die dazugehörige MAC-Adresse übertragen und das richtige Passwort für diese IP-MAC-Kombi nutzen, wenn er sich den Key abholt.
Momentan schau ich mir geraden an, wie die Jungs vom OpenSSH-Projekt das realisiert haben, denn die verwenden ja nur RSA-Keys für die Verschlüsselung. Für mich sieht das momentan nach einem brauchbaren Prinzip aus, wobei ich anders als bei SSH den Key nicht dauerhaft abspeichern würde, sondern jedes Mal einen neuen vom Key-Verteiler abholen lasse. Aber bevor ich mich da an die Implementierung mache werde ich wohl warten bis das Buch da ist, um noch einiges mehr über Vor- und Nachteile der einzelnen Verschlüsselungsalgorithmen zu erfahren.
Bis hierher aber schonmal vielen Dank für die ausführlichen Infos. :) Gibt noch vieles, wo ich mich noch einarbeiten muss. Irgendwie hatte ich gehofft, dass es einfacher wird, aber man kann halt nicht alles haben. ;)

PS: Mist, das Buch gibt's auch auf deutsch? Naja, zu spät. Nun hab ich die englische Version bestellt, ist aber auch nicht weiter schlimm. Wobei es auf deutsch natürlich noch etwas einfacher gewesen wäre. :(
 
Hallo,
sonst eine Möglichkeit wäre auch noch: Kerberos

Dies würde dann den Vorschlag mit der vertrauenswürdigen dritten Partei/Person umsetzen.
Sofern ich mich nicht irre, wird aber in dem Buch das Verfahren von Kerberos vorgestellt. Evt. ist das ja eine Lösung für dich.

Allerdings ist der Key bei SSL nicht im Zertifikat enthalten, sondern nur der Fingerabdruck des Keys. Sprich das Verfahren dürfte auch ohne Zertifikat laufen, allerdings:
SSL ist ohne eine zertifikatsbasierte Authentisierung problematisch, wenn ein Man-In-The-Middle-Angriff erfolgt: Ist der MITM vor der Übergabe des Schlüssels aktiv, kann er mit beiden Seiten den Schlüssel tauschen und so den gesamten Datenverkehr im Klartext mitschneiden.

Quelle
 
Zurück
Oben