2014-01-11 9 views
9

Ich lerne Python. Ich kann nicht herausfinden, warum hashlib.sha512(salt + password).hexdigest() nicht die erwarteten Ergebnisse liefert.hashlib vs crypt.crypt() in Python. Warum unterschiedliche Ergebnisse?

Ich bin auf der Suche nach einer reinen Python-Implementierung der Entsprechung von Ulrich Drepper sha512crypt.c algorithm. (Es dauerte eine Weile, bis ich herausgefunden hatte, wonach ich suchte.)

Laut der man-Seite für crypt auf meinem Ubuntu 12.04-System verwendet crypt SHA-512 (weil die Strings mit $ 6 $ beginnen).

Der folgende Code überprüft, dass das Verhalten erwartet wird, wenn ich Python-Wrapper der Systemkrypta (d. H. Crypt.crypt()) aufrufen. Ich möchte hashlib.sha512 oder eine andere Python-Bibliothek verwenden, um dasselbe Ergebnis wie crypt.crypt() zu erhalten. Wie?

Dieser Code zeigt das Problem ich begegnet:

import hashlib, crypt 

ctype = "6" #for sha512 (see man crypt) 
salt = "qwerty" 
insalt = '${}${}$'.format(ctype, salt) 
password = "AMOROSO8282" 

value1 = hashlib.sha512(salt + password).hexdigest() #what's wrong with this one? 
value2 = crypt.crypt(password, insalt) #this one is correct on Ubuntu 12.04 
if not value1 == value2: 
    print("{}\n{}\n\n".format(value1, value2)) 

Nach der Krypta Manpage, SHA-512 beträgt 86 Zeichen. Der Aufruf crypt() in dem obigen Code entspricht dem. Allerdings ist die Ausgabe von hashlib.sha512 länger als 86 Zeichen, so ist etwas weiter Weg zwischen diesen beiden implmentations ...

Hier ist die Ausgabe für diejenigen, die nicht wollen, um den Code auszuführen:

051f606027bd42c1aae0d71d049fdaedbcfd28bad056597b3f908d22f91cbe7b29fd0cdda4b26956397b044ed75d50c11d0c3331d3cb157eecd9481c4480e455 
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/ 

Ein weiterer Versuch basierend auf der ersten Rückmeldung hier. Kein Erfolg noch:

import hashlib, crypt, base64 

ctype = "6" #for sha512 (see man crypt) 
salt = "qwerty" 
insalt = '${}${}$'.format(ctype, salt) 
password = "AMOROSO8282" 

value1 = base64.b64encode(hashlib.sha512(salt + password).digest()) 
value2 = crypt.crypt(password, insalt) #this one is correct 
if not value1 == value2: 
    print("{}\n{}\n\n".format(value1, value2)) 
+0

Ist Ihr Passwort (mit Ausnahme der Zahlen) ein Wort in Portugiesisch absichtlich oder war es ein peinlicher Zufall? Nur neugierig ':)' – JMCF125

+1

Dieses Passwort ist ein echtes Passwort aus einer der großen Datenbanken von echten gestohlenen Passwörter, fwiw gezogen. – MountainX

+0

Ich sehe. Ohne Salz wäre es in der Tat leicht zu knacken, sagen wir, mit einem aus einem kleinen portugiesischen Wörterbuch hergestellten Regenbogentisch. BTW, +1, das ist eine interessante Frage, obwohl ich Python nicht benutze. – JMCF125

Antwort

11

Hier ist die Lösung. Es gibt auch mehr Details zu dieser anderen Frage: Python implementation of sha512_crypt.c wo es zeigt, dass das Backend von Passlib eine reine Python-Implementierung von sha512_crypt enthält (und die Python-Implementierung wird aufgerufen, wenn crypt.crypt() nicht auf dem OS verfügbar ist).

sudo $ pip installieren passlib

import passlib.hash, crypt 

ctype = "6" #for sha512 (see man crypt) 
salt = "qwerty" 
insalt = '${}${}$'.format(ctype, salt) 
password = "AMOROSO8282" 

value1 = sha512_crypt.encrypt(password, salt=salt, rounds=5000) 
value2 = crypt.crypt(password, insalt) 
if not value1 == value2: 
    print("algorithms do not match") 
print("{}\n{}\n\n".format(value1, value2)) 

Hier ist die Ausgabe:

$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/ 
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/ 

Ein wichtiger Punkt ist, dass Passlib eine reine Python-Implementierung von sha512_crypt hat, dass es benutzen werden, wenn das System doesn‘ t haben die Crypt-Implementierung, die aktuelle Linux-Systeme haben (zB http://www.akkadia.org/drepper/SHA-crypt.txt).

Siehe Dokumentation für PassLib hier:

passlib - Passwort-Hashing-Bibliothek für Python - Google Project Hosting
https://code.google.com/p/passlib/

Passlib 1.6.2 Dokumentation - Passlib v1.6.2 Dokumentation
http://pythonhosted.org/passlib/

passlib-Benutzer - Google Groups
Kurzanleitung

Neue Anwendung - Passlib v1.6.2 Dokumentation
http://pythonhosted.org/passlib/new_app_quickstart.html#sha512-crypt

passlib.hash.sha512_crypt - SHA-512 Crypt - Passlib v1.6.2 Dokumentation
http://pythonhosted.org/passlib/lib/passlib.hash.sha512_crypt.html#passlib.hash.sha512_crypt

4

Ihre Passwörter sind nicht die gleiche Länge haben, ist, dass, weil die crypt() Ausgabe Base64 codiert ist und Sie verwenden hexdigest für value1.

Statt hexdigest, sollten Sie versuchen, etwas zu tun, wie

value1 = crypt_base64(hashlib.sha512(salt + password)) 

mit crypt_base64 wie die bash implementation, letzten Teil doHash() Funktion.

+0

Guter Vorschlag, aber Ihre Antwort ist nicht ausreichend. Können Sie basierend auf meinem einfachen Beispiel funktionierenden Python-Code bereitstellen? Ich habe meine Antwort mit base64-Kodierung aktualisiert, aber die beiden Ergebnisse stimmen immer noch nicht überein. – MountainX

+1

@MountainX Sie irren sich zu denken, dass das Bash-Skript "Standard" b64-Codierung implementiert. crypt_base64 kann nicht einfach implementiert werden, indem b64encode von base64 aufgerufen wird. –

+0

Vielen Dank für Ihre Antwort. Es hat mir geholfen, auf den richtigen Weg zu kommen. Siehe meine Antwort für eine "Ready to Run" -Lösung. – MountainX

7

Das Handbuch von crypt ist ungenau (sogar irreführend). Die von crypt mit den Spitznamen "MD5", "SHA-256" oder "SHA-512" verwendeten Algorithmen sind in Wirklichkeit Algorithmen , die auf diesen Grundelementen aufgebaut sind. Sie sind password-based key derivation functions und verwenden den Hash, um key strengthening auszuführen. Ein Ein hat zwei Eigenschaften: Es muss das Passwort mit einem einzigartigen Salz kombinieren (um Versuche zu verhindern, viele Passwörter auf einmal zu knacken), und es muss langsam sein (weil das den Angreifer mehr verletzt als der Verteidiger seit dem Angreifer muss eine große Anzahl von Kombinationen ausprobieren). Alltägliche Hash-Algorithmen wie MD5 und die SHA-Familien sind so konzipiert, dass sie schnell und so schnell wie möglich sind und trotzdem die gewünschten Sicherheitseigenschaften haben. Eine Möglichkeit, einen Passwort-Hash-Algorithmus zu erstellen, besteht darin, einen kryptografischen Hash-Algorithmus zu verwenden und diesen mehrmals zu durchlaufen. Während dies isn't ideal (weil es bessere Techniken gibt, die es schwieriger machen, dedizierte Hardware für Passwort-Cracking zu bauen), ist es ausreichend.

Die Wikipedia article for crypt(3) bietet eine kurze Erklärung und hat Zeiger auf primäre Quellen.Linux und FreeBSD-man-Seiten sind arm, aber Solaris's hat genug Informationen nicht (die Links zu crypt.conf(4) und dann crypt_sha512 und die anderen folgen) irreführend. Sie können auch Is user password in ubuntu 13.04 in plain text? und Is there repetition in the Solaris 11 hash routine? Can I add some?

Der richtige Weg, um die Ausgabe von crypt in Python lesen zu berechnen sind crypt.crypt zu nennen.

+0

Vielen Dank für Ihre Antwort. Es hat mir geholfen, auf den richtigen Weg zu kommen. – MountainX

Verwandte Themen