Wow ihr seid aber beim erzeugen von Schlüsseln kreativ
1. Gegen Bruteforce kann man sich den ganzen Käse sparen. Die Ver-/Entschlüsselungsroutinen (AES) verwenden immer das gleiche Interface und erfordern immer die gleichen Eingabedaten (Ein Hoch auf Standards). Da könnt ihr die Bits hin und her schubsen, wie ihr wollt. Bruteforce-Attacken sind zwar nicht die effektivsten. Aber wer das wirklich vorhat, der setzt nicht am Tool an, sondern beim Algorithmus. Es ist definitiv effektiver, die Daten direkt mit Zufallsdaten oder durchzählen zu entschlüsseln, als die Schlüsselerzeugung des Tools selbst zu penetrieren.
2. Wer beim cracken der Verschlüsselung Zeit sparen will, verwendet entweder Dictonaries oder Rainbow-Tables und jagt dann diese durch die Routinen des Tools. Und da ist wie auch schon beim Login auf Webseiten die Divise: "Je länger ein Durchgang dauert, um so länger dauert das cracken!"
Ihr legt den Fokus einfach viel zu stark darauf, aus dem Master-Passwort Datensalat zu machen und vergesst dabei, das ihr kaum Zeit dabei verschwendet. Die Key-Derivation-Funktionen wie das Blowfisch-Passwort der password_hash Bibliothek (PHP) oder PBKDF2 gehören mittlerweile zu den Quasi-Standards in der Passwortsicherheit. Der Grund dafür ist einleuchtend. Egal wie viele Schritte ihr beim verschleiern eures Passwortes macht. Wenn ein Angreifer mit einem kompilierten Cracking-Tool 100.000 Durchläufe die Sekunde schafft, ist es deutlich unsicherer, als wenn eine Derivation-Funktion von sich aus in der Sekunde 300.000 Durchläufe macht und der Cracker dadurch nur ein Versuch pro Sekunde schafft!
3. Die Auflösung des Schlüssels sowie der Initialisierungsvektor haben eine feste Auflösung. Wer also 256 Bit fährt (was definitiv zu empfehlen ist), kann dort auch nur 256 Bit unterbringen. Nicht 257 und auch nicht 255. 256 Bit! Egal wie aufwendig man den Schlüssel erzeugt und wie lang das ganze ist. Man muss es immer auf die 256 Bit herunterbrechen oder aufblasen. Einfach abschneiden ist Fatal, da es die Kollisionswahrscheinlichkeit erhöht. Aufblasen ist auch nicht Ideal, da die unnötige Luft irgendwo gespeichert sein muss, damit die Schlüsselerzeugung die Luft nicht selbst noch Bruteforcen muss. Das sinnvollste ist und bleibt ein Hash in 256 Bit länge, ohne großartig dran rumzuwursten. Denn der Wertebereich für Druckbare Zeichen ist deutlich geringer als der Wertebereich, der in die Bytes gepackt werden kann. Krytografische Hashfunktionen sind daraufhin optimiert, so eindeutig wie möglich eine Repräsentation eines Datenstücks zu erzeugen und dabei den vollständigen Wertebereich eines Bytes zu nutzen. Die Hexadezimale Darstellung eines solchen Hashes ist im Grunde auch nichts anderes als eine Repräsentation der Zahlen, die dadurch erzeugt wurden. Am Ende sind es 256³² Zahlen-Kombinationen und es ist vollkommen egal, wie ihr sie bekommen habt. Beim Bruteforcen schubst man die Zahlen dort direkt rein und dann interessiert das Wie nicht mehr. Aber sollte man auf Grund von unnötig aufgeblasenen Quelldaten eine Kollision erzeugen, kann es schon wieder ungemütlich werden.
PS: Ich habe da noch etwas vergessen zu erwähnen. Die Passwortlänge sollte zwar eine Mindestanzahl an Zeichen haben. Aber das obere Limit sollte hoch liegen. Sogar bis 128 Zeichen würde ich erlauben, da die Auflösung an Druckbaren Zeichen viel geringer ist als die an Bytes. Aus diesem Grund sollte man auch niemals den Einsatz einer Zeichenklasse verbieten, da man das Passwort um Auflösung beraubt und dadurch erheblich weniger Kombinationen probiert werden müssen. Sonderzeichen müssen erlaubt sein! Denn es macht einen riesigen Unterschied, ob Cracker nun generell Sonderzeichen mit einbeziehen müssen oder ausschließen können.
4. Zwischenverschlüsselung von Daten macht auch wenig Sinn. Denn die Daten für die Verschlüsselung müssen ja auch irgendwo herkommen. Man benötigt dort auch wieder einen Schlüssel und mit dem CBC Verfahren einen Vektor. Wie soll man sich das Vorstellen? Man verschlüsselt den Initialisierungsvektor für die Hauptverschlüssellung sowie dem Passwort als Hash mit welchem Schlüssel und welchem Vektor nochmal? Das Datenstück ist im Vergleich zum vollständig zu verschlüsselndem Dokument sehr klein, was die Entschlüssellungszeit drastisch senkt. Je nach Implementierung kann man sich mit dieser Idee sogar eine Hintertür öffnen. Sowas würde ich generell schon einmal lassen.
5. Das Entschlüsseln dauert in der Masse relativ lang. Man selbst als Nutzer merkt es allerdings kaum, da man es ja nicht 1.000 mal oder öfter hintereinander macht. Speichert also das Passwort nirgends als Hash. Das ist Blödsinn. Ihr würdet euch selbst einer effektiven Crackerbremse berauben, da man versuchen wird, den Hash zu cracken als die Daten. Und wer das Passwort zum Hash hat, kommt auch an die Daten!
Ich würde also so vorgehen:
1. Programm wird zum ersten mal gestartet und man muss das Masterpasswort festlegen. Dabei werden mindestens 8 Stellen vorausgestzt. Die Länge kann gerne bis 64 oder mehr sein. Es wird ein kryptografisch sicherer Salt erzeugt, der dann an das Passwort gehängt oder davor gesetzt wird. Dann wird eine Datei erzeugt, in der eine Zufallszahl zwischen 100.000 und 899.999 sowie der Salt geschrieben werden. Der Salt sowie auch diese Zahl brauchen nicht geheim sein, da der Salt gegen Dictonaries helfen soll und die Zahl gegen Rainbow-Tables. In beiden Fällen liegen unveränderliche Datenbestände vor, die nicht mal so eben in ein paar Monaten auf genau diesen Salt oder die Anzahl der Cycles verändert werden kann.
2. Das Passwort und der Salt werden zusammen um die zufällig generierte Anzahl + 100.000 (also mindestens 200.000 und maximal 999.999) mit sich selbst gehashed (Key-Derivation Funktion wie PBKDF2). Dictonary-Attacken rechnen also mindestens pro Passwort zwischen einer und 4 Sekunden. Völlig ineffektiv. Das versucht keiner!
3. Es werden 10 Initialisierungsvektoren erzeugt und gespeichert. Diese müssen auch nicht geheim sein, da das Programm diesen sowieso benötigt. Ich verwende die 10 als Pepper. Es wird nur mit einem verschlüsselt. Nur welcher wird bei jedem Verschlüssellungsdurchgang zufällig gewählt. Da ich als Nutzer der Software das Passwort natürlich richtig eingebe, werden die Daten mit jedem Vektor entschlüsselt, bis ein Vektor ein valides Ergebnis liefert und die Daten offen liegen. Bis hierhin wird der Schlüssel sowie das Passwort nirgends gespeichert und das bleibt auch so. Im Idealfall aber muss beim Bruteforcen sowie bei den anderen Angriffsmethoden jeder Vektor zusätzlich zur Derivation-Funktion probiert werden, was den zeitlichen Aufwand um das 10fache anschwellen lassen kann. Man darf niemals vergessen, das der Nutzer bei korrekter Eingabe seines Passworts nur geringe zeitliche Einbußen hat (bis auf die Derivation. Aber für die Sicherheit kann er im Ernstfall auch mal 1-4 Sekunden warten).
4. Um eine Erfolgreiche Ver- und Entschlüsselung festzustellen, werden die Daten in einem etablierten und prüfbaren Format gespeichert. Dafür bieten sich JSON, XML oder SQLite an. Ich würde aber die ersten beiden vorziehen. Liefert CatchJSON oder XMLStatus keinen Fehler, war Passwort sowie Initialisierungsvektor richtig und die Daten werden bereitgestellt. Liefern sie aber 0 bzw. Fehler zurück, macht das Programm mit dem nächsten Vektor weiter. Hat er alle Vektoren durch und alle liefern Fehler, ist das Passwort falsch! Und dafür musste wie schon gesagt nirgends das Passwort gespeichert werden.
5. Verschlüsselt so viel wie möglich in einem Dokument. Verschlüsselt niemals jedes Passwort aus dem Manager einzeln. Denn die größe des Dokuments ist entscheidend für die Entschlüssellungsdauer und diese ist wiederum entscheidend für das Bruteforcen. Wenn 100 Zeichen pro Dokument verschlüsselt werden, dann ist wahrscheinlich das Auswürfeln eines Schlüssels für den nächsten Versucht langsamer als das entschlüsseln selbst. Ich empfehle daher, den kompletten Bestand auf einmal zu verschlüsseln und dabei auch noch ein wenig aufzupusten. Dafür eignet sich XML am besten. Nehme einfach Knoten mit aussagekräftige Namen und keine Abkürzungen. Dadurch wird das Dokument gut aufgeblasen und es dauert länger.
6. Um die Routinen des Tools selbst nicht für das cracken zu missbrauchen, sollte das Tool nach jeder z.B. dritten Falscheingabe ein Delay erzeugen und die nächste Eingabe herauszögern. Ein paar Sekunden reichen dafür schon und die Effektivität für das Cracken über das Programm selbst sinkt erheblich.
Zusammengefasst:
Rohe Bruteforce-Attacken kann man weder verhindern, noch erschweren, da AES in jeder Sprache identische Daten zum arbeiten benötigt. Schlüssel in fester Länge und Vektor in fester länge. Wer also mit Bruteforcing das Dokument knacken will, geht überhaupt nicht den Umweg über die Schlüsselerzeugung, sondern jagd seine Daten direkt in den AES-Algorithmus.
Für Dictonary sowie Rainbow-Table Attacken auf den Schlüssel sorgen Salt's und eine Variable Anzahl an Cycles für eine Key-Derivationfunktion der Schlüssel für Sicherheit. Beides muss nicht geheim gehalten werden. Denn nur weil ein Angreifer den Salt kennt, tauchen in den Dictonaries nicht von heut auf morgen Passwörter mit dem Salt auf. Genauso ist es mit den Cycles. Nur weil der Angreifer jetzt weiß, das die Derivation-Function 321.574 mal durchläuft, füllen sich die Rainbow-Tables nicht mit Hashes, die auf diese Anzahl passen. Und wer jetzt bedenken wegen dem Salt und dem Bruteforcen hat. Für diesen Zweck benötigt man dann wieder die Derivation, die durch die Anzahl an Durchläufen für Bruteforcing völlig ineffektiv ist!
Durch die möglichst Hohe Auflösung des Passwortes zwischen 8 und 64 Zeichen oder noch mehr ist außerdem das Spektrum an möglichen Passwörtern gigantisch. Mit den ganzen Mittelchen ist die effektivste Angriffsart zweifelsfrei der Bruteforce direkt auf den Algorithmus. Und wie ich schon gesagt habe, kann man gegen diesen nichts ausrichten und bei 256³² Kombinationen für den Schlüssel und wenn gewünscht 10 unterschiedlichen Vektoren ist das vor allem bei einem großen Dokument verschwenkte Zeit. Die Mühe macht sich keiner.
PS: PBKDF2 für PureBasic gibt es:
Code:
https://github.com/reVerBxTc/PBExpress/ ... ecurity.pb
Doku:
https://github.com/reVerBxTc/PBExpress/ ... rity-Modul
Ist aber auch hier im Forum zu finden:
http://www.purebasic.fr/german/viewtopi ... =8&t=29268