MD5 - Crypter

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Furbynat0r
User
Beiträge: 9
Registriert: Dienstag 27. Februar 2018, 09:43

Dienstag 27. Februar 2018, 09:47

Hallo Leute,

ich bin gerade dabei mit Verschlüsselungen usw rumzuspielen. Ich weiß, das MD5 ausgelutscht und unsicher ist, allerdings dient dies nur dem Lernzweck :).

Ich möchte gerne das mein Script das Salt nimmt und dieses mit MD5 verschlüsselt. Danach wird das Passwort genommen und dies auch mit MD5 verschlüsselt.

Danach sollen die beiden Hashwerte aneinander gesetzt werden (salt,passwort) und das nochmals mir MD5 verschlüsselt werden.

Mein Script schaut aktuell so aus:

Code: Alles auswählen

import hashlib
name = b"passwort"
salt = b"salt"

passwort = hashlib.md5(name)
salz = hashlib.md5(salt)

ab = (passwort.hexdigest())
ac = (salz.hexdigest())

fertig = ac,ab

salti = hashlib.md5(fertig)
print (salti.hexdigest())
Ich weiß, den Code könnte man noch optimieren :D.

Es geht mir nur darum, wenn ich das ausführe, dann erhalte ich den Fehler:
TypeError: object supporting the buffer API required

Ich werde aktuell überhaupt nicht schlau wo der Fehler ist :(.

Danke für eure Hilfe :)
Sirius3
User
Beiträge: 7777
Registriert: Sonntag 21. Oktober 2012, 17:20

Dienstag 27. Februar 2018, 10:39

@Furbynat0r: `fertig` ist ein Tuple und von Tuple können keine Hashes gebildet werden. Erzeuge einen String, wandle diesen in in Bytes um, und dann hast Du wieder etwas, über das man einen Hash berechnen kann.
Furbynat0r
User
Beiträge: 9
Registriert: Dienstag 27. Februar 2018, 09:43

Dienstag 27. Februar 2018, 11:57

Ah ok :)

Habs soweit umgebaut und es funtkioniert sogar :)....

Code: Alles auswählen

import hashlib
name = b"testen"
salt = b"0xWFlX3w"
 
passwort = hashlib.md5(name)
salz = hashlib.md5(salt)
 
ab = (passwort.hexdigest())
ac = (salz.hexdigest())
 
fertig = ac,ab

string = ''.join(fertig)
byt = bytes(string,'UTF-8')

fertighash = hashlib.md5(byt)
fertigencode = fertighash.hexdigest()
print(fertigencode)
Jetzt würde mich zum abschluss einfach interessieren, wie man den Code noch etwas optimiert.

Vielen Dank für deine Hilfe!! :)
DasIch
User
Beiträge: 2447
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Dienstag 27. Februar 2018, 12:07

Unabhängig davon das MD5 unsicher ist und auch noch nie wirklich dafür geeignet war Passwörter zu hashen, ist es komplette Zeitverschwendung den Salt zu hashen.

Wenn du dies nicht mehr tust, hast du auch gleich den Code optimiert.
Sirius3
User
Beiträge: 7777
Registriert: Sonntag 21. Oktober 2012, 17:20

Dienstag 27. Februar 2018, 13:09

@Furbynat0r: wenn man exakt zwei Elemente hat, und die auch noch extra in ein Tupel packt, dann ist join die falsche Methode. join verwendet man für Listen mit beliebiger Anzahl an Elementen.

`ac`, `ab`, `fertig` und `byt` sind schlechte Namen, weil sie nichts aussagen.

Am besten schreibt man sich eine Funktion, für Dinge, die immer wieder auftreten:

Code: Alles auswählen

import hashlib

def md5hex(bytes):
    return hashlib.md5(bytes).hexdigest().encode('ASCII')

password = b"testen"
salt = b"0xWFlX3w"
 
hash = md5hex(md5hex(password) + md5hex(salt))
print(hash)
Benutzeravatar
DeaD_EyE
User
Beiträge: 179
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Mittwoch 28. Februar 2018, 10:46

Gestern habe ich mich in bisschen in sqlite3 eingearbeitet.
Ich habe eine kleine Datenbank für Logins angelegt.
Hier mal einen Ausschnitt aus dem Code, wie ich die Hashes generiere:

Code: Alles auswählen

import hashlib
import os


def gen_salt():
    """
    Generates a salt with 10 bytes
    """
    return os.urandom(10)


def hash_pw(password, salt):
    """
    Hashes each password with a given salt.
    :param password: str
    :param salt: bytes
    :return: hashed password as bytes
    """
    return hashlib.pbkdf2_hmac('sha512', password.encode(), salt, 10)


def check_pw(password, hash, salt):
    """
    Checks the password with given hash and salt.
    :param password: str
    :param hash: bytes
    :param salt: bytes
    :return: bool
    """
    pw_hash = hash_pw(password, salt)
    return pw_hash == hash
Ich speichere einfach für jeden User einen individuellen Hash. Keine Ahnung ob das überhaupt notwendig ist, aber ich mache das so.
Wenn du dann z.B. einen User anlegen willst:

Code: Alles auswählen

from collections import namedtuple


Row = namedtuple('User', 'username password salt')
username = 'Foo'
password = 'Bar'
salt = gen_salt()
hashed_password = hash_pw(password, salt)

user = Row(username, hashed_password, salt)
print(user)

Code: Alles auswählen

User(username='Foo', password=b"TX\x99\xd5UH\xbd\x0e/\xc4\x114\xd3pN\xed\x9f\xf9yp\xdb\x18\xf4\x95_\x13*'C*\x0f\x1d\x93\xf5\x08b8\x06\xa0.\xff\x04\xe8=B.\x18\x16:\x93\xdf\xbb\x94'\x01\x90\x19O\xb0\xf4\xb5\xd2\xeeV", salt=b'U\x00?\xce\x02$\xb2B\xfa\x03')
Nun das eingegebene Passwort überprüfen:

Code: Alles auswählen

wrong_password = 'Foo'
right_password = 'Bar'

if check_pw(wrong_password ,user.password, user.salt):
   print(wrong_password, 'is ok.')
else:
   print(wrong_password, 'is wrong.')


if check_pw('Bar' ,user.password, user.salt):
    print(right_password, 'is ok')
else:
    print(right_password, 'is wrong.')
Falls noch grobe Fehler drin sind, bitte sagen. Ich bin auch noch dabei zu lernen was Sicher ist und was man besser gar nicht tun sollte.
sourceserver.info - sourceserver.info/wiki/ - Support für HL2-Server
Benutzeravatar
DeaD_EyE
User
Beiträge: 179
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Mittwoch 28. Februar 2018, 11:44

Update: Schau mal hier: https://docs.python.org/3.6/library/crypt.html#examples

Da ist es noch einfacher. Zuerst generierst du einen Hash:

Code: Alles auswählen

import crypt
import hmac


my_clear_text_password = 'FooBar'
password_in_database = crypt.crypt(my_clear_text_password)

password_to_check = 'FooBar'

#password check
is_valid = hmac.compare_digest(crypt.crypt(password_to_check, password_in_database), password_in_database)
compare_digest umgeht timing attacks und crypt.crypt kümmert sich um gute Hashwerte.
sourceserver.info - sourceserver.info/wiki/ - Support für HL2-Server
DasIch
User
Beiträge: 2447
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Mittwoch 28. Februar 2018, 12:44

crypt ist nur minimal besser als MD5. pbkdf2 ist mit sinnvollen Parametern eine gute Wahl, bei 10 Iterationen kann man aber tatsächlich auch einfach crypt nutzen.

Grundsätzliche Empfehlung: Wenn man nicht bereit ist sich im Detail mit der Problematik auseinanderzusetzen, sollte man da einen sehr großen Abstand halten.
Benutzeravatar
DeaD_EyE
User
Beiträge: 179
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Mittwoch 28. Februar 2018, 15:26

Hab mal gegeoogelt.

Zu crypt: https://en.wikipedia.org/wiki/Crypt_(Unix)
Zusammenfassung: Ist gebrochen, ist obsolete

Zu pbkdf2: https://cryptosense.com/parameter-choice-for-pbkdf2/

Empfohlen wird:
  • 64 bit salt (in meinem Beispiel sind es 80 Bit)
  • SHA-512
  • 10.000 Iterationen
Jedenfalls werde ich noch hmac.compare_digest verwenden und bei pbkdf2 bleiben. Es kommt bei mir zwar nicht auf Sicherheit an, aber ich wollte es schon richtig implementieren. Man kann halt auch ganz viel falsch machen und es funktioniert trotzdem.
sourceserver.info - sourceserver.info/wiki/ - Support für HL2-Server
DasIch
User
Beiträge: 2447
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Mittwoch 28. Februar 2018, 20:19

Die Recommendation des Blog Posts ist nicht 10.000, sie ist >=10.000
[...]use an iteration count of at least 10000, more if you can do it “while still allowing acceptable server performance”.
Man sollte also ernsthaft überlegen mehr zu nutzen, wenn man in die Vergangenheit reist, den die Empfehlung kommt aus 2016.

1Password welches auch diesen Algorithmus nutzt, verwendet 100.000 Iterationen. Django tut dies ebenfalls und dass auch schon seit einem Jahr.

10.000 ist also ein bis zwei Größenordnungen von richtig entfernt, wer im Trend liegen will ist vielleicht schon bei 1.000.000 Iterationen.

Das sich dieser Parameter so oft ändert, führt auch zu einem zweiten Problem. Man braucht zwingend einen Mechanismus um diese Parameter zu verändern, ggfs. sogar den Algorithmus selbst falls dieser mal unsicher wird.
Antworten