Passwort-Sicherheit & Basic Kryptologie

Wichtiger Hinweis: Bitte ändert nicht manuell die Schriftfarbe auf schwarz sondern belasst es bei der Standardeinstellung. Somit tragt ihr dazu bei dass euer Text auch bei Verwendung unseren dunklen Forenstils noch lesbar ist!

Tipp: Ihr wollt längere Codeausschnitte oder Logfiles bereitstellen? Benutzt unseren eigenen PasteBin-Dienst Link
  • Hey Leute,


    ich wollte euch ganz kurz in die Basics der Kryptologie einführen, da scheinbar einige das mit den Passwörtern noch nicht verstanden haben ^^


    Erst einmal klären wir ein paar Fachbegriffe:


    Einwegfunktionen
    Eine "echte" Einwegfunktion verändert einen Wert und lässt ihn (offiziell) nicht wieder zurückrechnen
    Ein (schlechtes) Beispiel ist z.B.

    Code
    neuerwert = (alterwert * 2) ^ (alterwert / 5)

    Aus dem alten Wert lässt sich ruck-zuck ein neuer Wert berechnen, anders herum kann es zu Schwierigkeiten kommen und man müsste mit Raten anfangen...
    Für die, die mir nicht glauben: neuerwert = 4,3125 Wer das zurückrechnet, dem schicke ich per Post einen Lollie :D


    Einwegfunktionen mit Falltür In diesem Beispiel: Public-Key-Verfahren
    Nun gibt es einige Einwegfunktionen, die man doch zurückrechnen kann, aber nicht so, wie man sie berechnet hat.
    Das mag jetzt kompliziert klingen (ist es auch), aber ich stelle das mal bildlich da, erkläre das dann danach:

    • Ihr habt eine Poststelle (o.ä.) an der jeder eine Eisenkasette hat
    • Wollt ihr etwas verschlüsseln, macht ihr die Kasette zu und lasst das Schloss einklicken.
    • Nun kann niemand mehr an den Inhalt rein (außer er nutzt Gewalt, aber wir gehen von netten Leuten aus)
    • Der, dem die Kassette gehört, geht nun in die Poststelle, öffnet die Kasette mit seinem Schlüssel und hat den Inhalt vorliegen


    Ein tägliches Beispiel davon, und genau davon, finden wir täglich: HTTP mit SSL ( https )
    Beim Public-Key-Verfahren gibt es einen Public-Key und einen Private-Key. Der Public-Key ist öffentlich bekannt und das Schloss der Kassette, der Private-Key der Schlüssel.


    Hash
    Ein Hash ist eine Einwegfunktion. Das bedeutet, man kann ihn nicht zurückberechnen, man kann aber "probieren"


    Salts ( Salz )
    Salts sind noch mal ein Aufsatz auf den Hash, weil dabei 2 "Passwörter" existieren - eines wird vom Server bei der ersten Erstellung des Accountes erstellt, das andere kommt von Benutzer.
    Dann werden beide aneinander gehängt und gehasht. Davon der Hash und der Salt werden gespeichert.
    Beispiel:

    Code
    Benutzerpasswort: helloworld
    Salt: kdbjyhbfdxkjyhxdbkjsf
    Vor dem Hash: helloworldkdbjyhbfdxkjyhxdbkjsf
    Gehasht: hdhggksdhfmkfudjdyuhglgfj

    Gespeichert wird der Salt und "Gehasht", dann wird das jedes mal neu zusammengesetzt.
    Der Vorteil von Salts liegt darin, dass ein (hoffentlich nicht) Hacker die Hash-Summen nicht einfach in einer großen Datenbank nachschlägt, da der gesaltete Hash von dem normalen Hash unterscheidet.


    Pepper ( Pfeffer )
    Der Pepper ist im Prinzip ein "globaler Salt", der für alle Accounts gleich ist und, genau wieder Salt, optional alleine oder in Verbindung mit ihm genutzt werden kann. Pfeffer und Salz ergänzen sich prima, da, sollte jemand Zugriff auf die Datenbank haben, er den Pepper nicht kennt, sollte er ihn aber kennen und in den Jahren vor dem Hack eine Datenbank mit dem Pepper angelegt haben über den Salt stolpert. Außerdem macht er den String vor dem Hashen noch etwas länger :whistling:


    Kollisionen
    Kollisionen existieren, wenn 2 Werte den selben Hash haben. Eine Beispiel-Kollision für MD5:

    Nun ist es sehr unwarscheinlich, dass ein anderer Benutzer just dieses Passwort hat, aber wenn man genug Zeit hat kann man zu eigentlich jeden Hash eine Kollision finden


    Verschlüsselung
    Eine Verschlüsselung ist kein Hash !
    Eine Verschlüsselung zeichnet sich dadurch aus, dass man sie wieder entschlüsseln kann - unterschieden wird dabei zwischen symetrisch und asymetrisch. Bei ersteres wird zum Ver- und Entschlüsseln das gleiche Passwort genutzt ( Beispiel: AES ), bei zweiteren sind die Passwörter unterschiedlich ( Beispiel: DES, Public-Key-Verfahren. Natürlich kann man das auch mischen, dass das Passwort asymetrisch gespeichert / gesendet wird und danach auf symetrische verfahren zugegriffen wird ( "Hybride Verschlüsselung" ) - der Vorteil liegt dabei daran, dass man nicht den Geschwindigkeitsverlust von dem asymetrischen Verschlüsselungsverfahren einbüßt, das Passwort sicher übertragen kann und die Verbindung danach auch noch sicher ist.


    Kodierungen
    Eine Kodierung unterscheidet sich von einer Verschlüsselung dadurch, dass die Kodierung kein Passwort hat. Als ein bekanntes Beispiel dient Base64 oder Caesar. Problematisch wird es u.a. bei der Rot-"Verschlüsselung", da dort theoretisch auch ein Passwort genutzt wird, es sich aber schnell erraten lässt - und das Caesar theoretisch auch nur Rot13 ist, könnte man es ja auch als Passwort einstufen :whistling:


    Wie realisiere ich jetzt einen sicheren Login ?

    • Der Benutzer registriert sich und gibt sein Passwort ein.
    • Wir generieren für das Passwort einen Salt und hashen das beides zusammen
    • Gesalteter Hash und Salt kommen in die Datei/Datenbank/...
    • Bei der Passwortabfrage hängen wir an das eingegebene Passwort wieder den Salt an
    • Jetzt hashen wir die zusammenstellung oben und vergleichen das mit dem gesaltenem Hash
    • Stimmt das überein, ist das Passwort richtig

    Als Hilfe dafür habe ich 2 Funktionen definiert (findet ihr gaaaaaanz unten), eine erzeugt einen Salt beliebiger Länge, die andere Hasht den Salt und das Passwort zu beliebiger Länge.
    Beispiel zur Nutzung: new salt[64];
    new pwhash[128];


    GenerateSalt(64, salt); // Wir erstellen einen zufälligen Salt für den Benutzer
    CreateSaltedHash(inputtext, salt, 128, pwhash); // Wir erstellen einen salted Hash des Passwortes ( inputtext <=> Passwort ) Wichtig ist, und das wiederhole ich jetzt noch einmal, dass der Salt mitgespeichert wird.
    Denn ein anderer Salt ergibt ein anderen Hash.
    Vergleichen können wir die Passwörter nun folgendermaßen: new pwhash[128];


    CreateSaltedHash(inputtext, PInfo[playerid][pSalt], 128, pwhash); // Wir erstellen einen salted Hash des Passwortes ( inputtext <=> Passwort )
    if(strcmp(PInfo[playerid][pSaltedHash], pwhash, false) == 0)
    SendClientMessage(playerid, 0xFF00FF, "Du hast dich eingeloggt");
    else
    SendClientMessage(playerid, 0xFFFF00, "Login falsch");


    MD5
    MD5 ist ein Algorithmus, der sich mittlerweile sehr durchgesetzt hat - wie alle anderen Hashfunktionen lässt auch er sich nicht wieder "zurückumwandeln", es ist aber auch hier möglich, den originalen Wert zu "erraten" ( dauert aber etwas ). MD5 gibt unabhängig von dem normalen Passwort einen 32 Byte langen String zurück der die Zeichen 0 - 9 und a - f / A - F hat.
    Hier findet ihr eine Include von Y-Less, mit der ihr MD5 in SA:MP umsetzen könnt. Empfohlen wird aber auch hier, einen Salt hinzuzuschalten, da es für MD5 wesentlich größere Datenbanken gibt. Ein Beispiel ohne Salt währe folgendes: new hash[32];
    hash = MD5_Hash("test"); Und mit dem Salt könnte man es wie folgt umsetzen: new salt[32];
    new password[20 + 32]; // 20 Zeichen + 32 Zeichen vom Salt
    new hash[32];
    GenerateSalt(32, salt);
    format(password, sizeof(password), "%s%s", inputtext, salt);
    hash = MD5_Hash(password); Bei beiden Beispielen haben wir dann in der variable "Hash" den Hash, den wir eintragen. Im Zewiten brauchen wir zusätzlich noch den Salt, den wir speichern ;)


    Auf der Basis meiner Salt- und Hashsysteme unten, die ich übrigens selber geschrieben habe (deswegen hat das auch so lange gedauert :cursing:) könnt ihr übrigens eure eigenen Hashsysteme basteln :)
    Dazu müsst ihr nur das Array erweitern und bei der CreateSaltedHash den 2.ten Operator der Modulorechnung anpassen ;)


    Ich hoffe, ich konnte euch der Passwortsicherheit ein Stücken näher bringen :)


    Tion


    Auch jetzt gilt, wie immer: Fragen sind zum Fragen da, Feedback ist erwünscht (heute auch mal negatives) und Ideen können eingebracht werden



    Hash- und Saltfunktion
    forward GenerateSalt(length, salt[]);
    public GenerateSalt(length, salt[])
    {
    new saltchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    for(new i = 0; i < length - 1; i++)
    {
    salt[i] = saltchars[random(strlen(saltchars) - 2) + 1];
    }
    salt[length - 1] = 0;
    return true;
    }

    Hash- und Saltfunktion
    forward CreateSaltedHash(string[], salt[], length, dest[]);
    public CreateSaltedHash(string[], salt[], length, dest[])
    {
    new hashchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    new c1, c2;
    for(new i = 0; i < length - 1; i++)
    {
    if(c1 >= strlen(string) - 1) c1 = 0;
    if(c2 >= strlen(salt) - 1) c2 = 0;
    dest[i] = hashchars[(string[c1] * salt[c2]) % 63];
    c1++; c2++;
    }
    dest[length - 1] = 0;
    } 100.000 Durchgänge brauchen bei einem 16-stelligen Salt und einem resultierendem 16-Stelligen Hash etwa 3 Sekunden.
    Testscript: #include <a_samp>

    Hash- und Saltfunktion
    #define SALT_LENGTH 16 // Wie lang soll der Salt sein ?
    #define HASH_LENGTH 16 // Wie lang soll der Hash sein ?

    Hash- und Saltfunktion
    public OnGameModeInit()
    {
    new password[20] = "Supersicheres PW";
    new salt[SALT_LENGTH] = "hfgthdgtfhgbdgf";
    new saltedpw[HASH_LENGTH];

    new messungen = 100000;
    new tmp = 0;
    new gesammt = 0;

    for(new i = 0; i < messungen; i+= 10)
    {
    tmp = GetTickCount();
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    GenerateSalt(SALT_LENGTH, salt);
    CreateSaltedHash(password, salt, HASH_LENGTH, saltedpw);
    gesammt += GetTickCount() - tmp;
    }

    printf("%50s%5d", "Messungen:", messungen);
    printf("%50s%5d", "Gesammtzeit:", gesammt);
    printf("%50s%5f", "Durchschnitt:", (gesammt / messungen));
    return true;
    }

    Hash- und Saltfunktion
    forward GenerateSalt(length, salt[]);
    public GenerateSalt(length, salt[])
    {
    new saltchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    for(new i = 0; i < length - 1; i++)
    {
    salt[i] = saltchars[random(strlen(saltchars) - 2) + 1];
    }
    salt[length - 1] = 0;
    return true;
    }

    Hash- und Saltfunktion
    forward CreateSaltedHash(string[], salt[], length, dest[]);
    public CreateSaltedHash(string[], salt[], length, dest[])
    {
    new hashchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    new c1, c2;
    for(new i = 0; i < length - 1; i++)
    {
    if(c1 >= strlen(string) - 1) c1 = 0;
    if(c2 >= strlen(salt) - 1) c2 = 0;
    dest[i] = hashchars[(string[c1] * salt[c2]) % 63];
    c1++; c2++;
    }
    dest[length - 1] = 0;
    }

    Webdesign (bevorzugt backend) • Android-Development • node.js • Pawn • Linux
    Reverse Engineering • Social Engineering • Cryptoanalyse • PGP-Key
    Referenzen[color=#696969]Mein Facebook-Acc

    3 Mal editiert, zuletzt von Tion () aus folgendem Grund: MD5, Pfeffer, Verschlüsselung

  • Zitat

    (Wahrscheinlich sind die meisten zu dumm)

    Dies ist ziemlich beleidigend für "die meisten" die du meinst. :thumbdown:
    Einigen Menschen ist es halt zu kompliziert :pinch:
    denke du würdest es auch nicht nett finden wenn man dich dumm nennt nur weil du mal was nicht verstehst.
    Ich bitte dich nächstesmal auf deine wortwahl zu achten

    >> sPa.M << go, go,Bann me, Bann me

  • Gefällt mir, da doch immer wieder Hashes und Verschlüsselungen durcheinander geworfen werden.
    Du erwähnst ja Salts zum "sichereren" Hashen. Du könntest deshalb, auch wenns nicht so wichtig ist, auch noch auf die Pepper und deren Unterschied zu Salts eingehen.
    Aber ansonsten ist das Turorial verständlich und sauber geschrieben.


    edit: lol ich seh grad, dass der Tread schon alt ist. Da hat Hami wohl was ausgegraben :D Naja, schaden tut es sicher nicht.

    Einmal editiert, zuletzt von Hagi ()

  • Gefällt mir, da doch immer wieder Hashes und Verschlüsselungen durcheinander geworfen werden.
    Du erwähnst ja Salts zum "sichereren" Hashen. Du könntest deshalb, auch wenns nicht so wichtig ist, auch noch auf die Pepper und deren Unterschied zu Salts eingehen.

    Okay, auch das kann ich machen - obwohl es nur ein paar Wörter dazu zu sagen gibt :D


    Mich wundert es gerade leicht, dass der Thread nach 10 Monaten plötztlich so viel Aufmerksamkeit bekommt ^^

  • was ausgegraben

    Nein, ich fand den Thread hilfreich ;)


    MD5 ist keine Verschlüssung.

    Oh, wusste ich nicht, naja es verschlüsselt (richtige Wortwahl?) aber ein (Pass-)Wort


    danke dir :thumbup:

    Kein Problem, wir danken dir ^^


    Ich bitte dich nächstesmal auf deine wortwahl zu achten

    Tut mir leid ;(

  • Ist zwar ein alter Thread aber ich denke der wird noch als Vorblid genutzt. Wieso kennt mein Script die Begriffe wie Hash nicht? Muss ich mir da ein Include downloaden und wenn ja wo und welches?

  • Ist zwar ein alter Thread aber ich denke der wird noch als Vorblid genutzt. Wieso kennt mein Script die Begriffe wie Hash nicht? Muss ich mir da ein Include downloaden und wenn ja wo und welches?

    In dem Release SA:MP 0.3.7 R1 wurde die Funktion http://wiki.sa-mp.com/wiki/SHA256_PassHash hinzugefügt. Falls dir diese nicht reicht, musst du auf ein PlugIn wie:

    zurückgreifen.