Masterpasswort speichern

Alles, was nicht direkt mit Python-Problemen zu tun hat. Dies ist auch der perfekte Platz für Jobangebote.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Guten Morgen,

ich hab' mir einen Passwortgenerator gebastelt, der mir aus einem Servicenamen und einem Masterpasswort ein Passwort generiert und dieses auch ablegt. Nun ist es so, dass bei Eingabe eines fehlerhaften Masterpasswortes natürlich auch nicht das ursprünglich generierte Passwort erstellt wird, was dann auch erst auffällt, wenn man sich damit nicht einloggen kann... ;-)

Welche Möglichkeiten gibt es denn, das Masterpasswort auf Richtigkeit zu überprüfen? Mir fällt als einzige Möglichkeit nur ein, das Masterpasswort mit sich selbst zu verschlüsseln. Jetzt bin ich mir aber nicht sicher, ob das eine sichere Sache ist? Kann jemand, der weiß, dass A(VM+L9Cg1t3tn|z mit sich selbst verschlüsselt wurde, auf den Klartext schließen?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@mutetella: das kommt natürlich auf die Verschlüsselung an. Gute Verschlüsselung kann sich sogar selbst sicher verschlüsseln. Für einen Passwortgenerator würde man aber eher eine Hash-Funktion verwenden.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

@Sirius3
Deine Antwort offenbart dann doch grundlegende Unkenntnis meinerseits... :wink: Zum Generieren der Passwörter verwende ich eine Hash-Funktion, aus einem Masterpasswort + salt wird also sowas wie 'A(VM+L9Cg1t3tn|z'. Die Funktion sieht so aus:

Code: Alles auswählen

# The second element of each tuple defines the number
# of chars which should contain in the password.
# The sum of these numbers results in the password length
CHARSET = (
    ('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 5),
    ('abcdefghijklmnopqrstuvwxyz', 5),
    ('0123456789', 3),
    ('`~!@#$%^&*()_-+={}|[]:;<>?,./', 3),
)

def create_password(algorithm, masterpassword, salt):
    def _char_picker(number):
        for chars, length in CHARSET:
            divisor = len(chars)
            for i in range(length):
                number, index = divmod(number, divisor)
                yield chars[index]
    binary_hash = hashlib.pbkdf2_hmac(algorithm, masterpassword, salt, 100000)
    hexdec_hash = hexlify(binary_hash)
    number = int(hexdec_hash, 16)
    password = list(_char_picker(number))
    random.shuffle(password, lambda: number % 0.8)
    return ''.join(password)
Könnte man aus dem Rückgabewert von ``create_password('sha256', 'my_passphrase', 'my_passphrase')`` auf den string 'my_passphrase' schließen?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

mutetella hat geschrieben:Könnte man aus dem Rückgabewert von ``create_password('sha256', 'my_passphrase', 'my_passphrase')`` auf den string 'my_passphrase' schließen?
Das ``hashlib.pbkdf2_hmac`` mit 100k Durchgängen dürfte das derzeit hinreichend vereiteln. Was ich mich frage - warum das shuffle am Ende? Da bin ich mir nicht sicher, ob die rückwärtige Abbildung durch das ``lambda: number % 0.8`` nicht doch trivial werden könnte.

Edit:
Wenn im Code nachvollziehbar ist, dass immer das Passwort auch als Salt genutzt wird, dürfte die Sicherheit auf PBKDF2 ohne Salt zurückfallen. Besser ist es da, den Salt in der Länge der Ausgabe der Hashfunktion zufällig erstellen zu lassen und mit zurückzugeben.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

jerch hat geschrieben:Was ich mich frage - warum das shuffle am Ende?
Das hat eigentlich nur kosmetische Gründe, damit aus einem 'QPGWSeikie799,-:' ein 'QP-GW9Se,ik9ie:7' wird.
jerch hat geschrieben:Besser ist es da, den Salt in der Länge der Ausgabe der Hashfunktion zufällig erstellen zu lassen und mit zurückzugeben.
Um das Masterpasswort, das zuvor mit sich selbst und einem salt verschlüsselt wurde, wieder zu entschlüsseln, müsste ich ja das salt unverschlüsselt ablegen... oder wie sonst könnte ich es wieder verwenden?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ich würde es jetzt so machen:

1. Via os.urandom ein salt erstellen.
2. Via pycrypto das salt verschlüsseln und ablegen.
3. Aus dem Masterpasswort samt salt einen hash erzeugen, der dann für spätere Vergleiche geeignet ist.

Passt das?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

mutetella hat geschrieben:Um das Masterpasswort, das zuvor mit sich selbst und einem salt verschlüsselt wurde, wieder zu entschlüsseln, müsste ich ja das salt unverschlüsselt ablegen... oder wie sonst könnte ich es wieder verwenden?
Genau, der Salt wird plaintext abgelegt. Das ist bei kryptografischen Hashalgorithmen kein Problem, da es keine Ähnlichkeit von Schlüsselnachbarn gibt - heisst selbst bei Teilkenntnis eines Schlüssels bleibt die Aufdeckung der verbleibenden unbekannten Zeichen abhängig von der Anzahl gleich hart (Achtung MD5 ist was die Kollisionsfindung angeht inzwischen vulnerabel). Wichtig ist, dass das eigentliche Masterpasswort nicht zu trivial ist - also einen großen Zeichenraum hat, lang genug ist und Vorhersagen über Zeichenfolgen ins Leere laufen (rainbow attacks). Damit bleibt dann nur noch brute force - was die "teuren" Hashalgorithmen mit Laufzeit beantworten.
Womit willst Du den Salt mit pycrypto verschlüsseln?
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

jerch hat geschrieben:... heisst selbst bei Teilkenntnis eines Schlüssels bleibt die Aufdeckung der verbleibenden unbekannten Zeichen abhängig von der Anzahl gleich hart ...
Dann verstehe ich nicht, weshalb ein Salt im plaintext abgelegt wird bzw. überhaupt ein Salt, das bekannt ist, verwendet werden sollte?
jerch hat geschrieben:Womit willst Du den Salt mit pycrypto verschlüsseln?
Ehrliche Antwort? Keine Ahnung, ich würde halt eine der üblichen Verdächtigen nehmen, pycrypto bietet mir AES, RC2, ARC4, Blowfish, CAST-128, DES, Triple-DES, RSA OAEP, RSA v1.5 und XOR.
Jetzt würde ich die Verfahren einfach mal googlen und dann das nehmen, bei dem ich am meisten Aussagen à la '... derzeit das Sicherste ...' zu lesen bekomm'... ;-)

Kein einfaches Thema für jemanden, der gerade mal die Grundrechenarten beherrscht und deshalb keinen Zugang zum Thema Kryptografie findet... ;-)

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
BlackJack

@mutetella: „Salz“ ist dazu da das die gleichen Daten nicht zum gleichen Hashwert führen, damit man keine vorberechneten Tabellen mit den häufigsten Passwörtern verwenden kann und damit wenn das gleiche Passwort mehrfach vorkommt man das nicht einfach daran erkennen kann das die zum gleichen Hashwert führen.

Es muss bekannt sein um die Prüfung durchzuführen und es kann ruhig im Plaintext vorliegen weil das dem Angreifer keinen Vorteil bringt. Das Vorhandensein erhöht/garantiert den Rechenaufwand.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Ok, das leuchtet mir jetzt soweit ein! Vielen Dank für Eure Hilfe!

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Während ich darüber nachgedacht habe, ob ich das Masterpasswort einfach zusammen mit den Passwörtern in einem json file ablegen soll, hatte ich folgende Idee:
  1. Ich wandel die Passwortdaten in json um.
  2. Mit dem Masterpasswort + salt erzeuge ich aus dem json string einen hash und speichere diesen mit dem salt als plaintext ab.
  3. Nach Eingabe des Masterpasswortes wird in einem ``try:... except:...`` Block versucht, aus dem zurückgewonnen json string die Passwortdaten herzustellen. Wenn das im ``except:...`` landet, war wohl das Masterpasswort falsch.
Was haltet ihr von der Idee?

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ich glaube du hast da einen Denkfehler oder die falschen Begriffe in der Aufzählung ;)

Bzw. Ich würde direkt eine 2-Faktor Authentifizierung nutzten...

Die eigentlichen Daten mit einem langen, zufälligen String verschlüsseln. Diesen String wiederum mit Masterpasswort verschlüsseln. So kann man das masterpaswort ändern, ohne die kompletten Daten zu ändern...

Ich nutzte aber einfach was fertiges: KeePass... Denn neben dem ganzen verschlüsseln, wird die Sache erst brauchbar mit einer GUI drum rum...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

jens hat geschrieben:Ich würde direkt eine 2-Faktor Authentifizierung nutzten...
Das mache ich bereits so ähnlich (glaube ich zumindest...):
  1. Von ``os.urandom`` lasse ich mir einen Zufallsstring erstellen.
  2. Aus dem Namen des Dienstes (z. B. 'plus.google.com') und dem Zufallsstring als salt erstelle ich dann das Passwort.
  3. Für beides, Dienstnamen und Passwort, erstelle ich dann mit dem Masterpasswort je einen hash, die ich in einem dict ablege. Aus z. B. 'plus.google.com' und seinem Passwort 'rtlgrmpf' wird dann

    Code: Alles auswählen

    {'aa6dc8d029257a4776feed3d61b08bded8cef3f60fb6a300b485ed82f6d0b705': 'ba540dcf23bd4a5d401160950ed15b9d30b88b0e05ee90c089234bf05569c6aa'}
So, und mit diesem dict würde ich dann die 3 Punkte durchlaufen...
jens hat geschrieben:... wird die Sache erst brauchbar mit einer GUI drum rum...
Das halte ich jetzt für ein Gerücht... :D

mutetella
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Antworten