Kleines Krypto-Gewinnspiel



  • Hallo zusammen,

    ich hab mal nen Verschlüsselungsalgorithmus geschrieben. Mir ist klar, dass ich nicht der beste Programmierer bin und auch kein hochbegabter Kryptograph. Ich möchte hier auch keinen zweiten AES schreiben. Es soll ein simpler Algorithmus sein, welchen ich schnell in einfache Scriptsprachen implementieren kann. Zusätzlich soll er aber so sicher sein, dass ein durchschnittlicher IT-Techniker oder Systemadministrator ihn nicht knacken kann. Ebenso sollen auch Programmierer ohne kryptographische Kenntnisse dran verzweifeln. Und wer sich mit dem Thema auskennt sollte es zumindest nicht gleich in 5min rausbekommen. Ich habe euch dazu den Algorithmus gepostet. Zusätzlich bekommt ihr ein Chiffrat (in hexadezimaler Form). Schafft ihr es das Chiffrat zu entschlüsseln, bekommt der erste der es schafft einen PaySafeCard-Code im Wert von 20€. Bruteforce zählt natürlich nicht als gelöst. Außerdem möchte ich, dass ihr mir schreibt, wie ihr den Algorithmus geknackt habt und mir vielleicht ein paar Verbesserungsvorschläge gebt.

    Kleiner Tipp noch: Beim Compiler bitte unsigned chars als Standard einstellen, sonst könnte es Gemecker geben. Bei VS geht das mit dem Parameter /J.

    Ich hoffe es versuchen sich ein paar Leute dran. Ich wünsche euch viel Erfolg^^
    Falls man hier keine Gewinnspiele im Forum machen darf, so kann der Thread einfach gelöscht werden, sry^^.

    Algorithmus:

    #include <iostream>
    #include <string>
    #include <limits.h>
     
     
     
    void CheckAsciiPos(short& pos) {
        if (std::numeric_limits<char>::is_signed) {
            if (pos > 127)
                pos -= 256;
            if (pos < -128)
                pos += 256;
        }
        else {
            if (pos > 255)
                pos -= 256;
            if (pos < 0)
                pos += 256;
        }
    }
     
     
     
    std::string encrypt(std::string plaintext, std::string password) {
     
        int passPos = 0;
        short asciiPosCipher;
        short passCounter = 1;
        short asciiPosPass;
        std::string cipher;
     
        for (unsigned int i = 0; i < plaintext.length(); i++) { //do for every character in string
     
            if (passPos >= password.length()) //after password ends start
                passPos = 0; //start from the beginning
            if (passCounter > 255)
                passCounter = 0;
            asciiPosPass = (password[passPos] + passCounter); //shift password char around passCounter
            CheckAsciiPos(asciiPosPass); //checks and corrects position pos in asciitable
            asciiPosPass ^= password[passPos]; //xor shifted password char with original password char
            asciiPosCipher = plaintext[i] ^ asciiPosPass; //xor this with plaintext char
            asciiPosCipher += asciiPosPass; //shift both to result
            CheckAsciiPos(asciiPosCipher);
            cipher += static_cast<char>(asciiPosCipher); //cast them to char an add to cipher-text
            passPos++; //next char in password
            passCounter++;
        }
     
        return cipher;
    }
     
     
     
    std::string decrypt(std::string cipher, std::string password) {
     
        int passPos = 0;
        short asciiPosResult;
        short passCounter = 1;
        short asciiPosPass;
        std::string result;
     
        for (unsigned int i = 0; i < cipher.length(); i++) {
     
            if (passPos >= password.length())
                passPos = 0;
            if (passCounter > 255)
                passCounter = 0;
            asciiPosPass = (password[passPos] + passCounter);
            CheckAsciiPos(asciiPosPass);
            asciiPosPass ^= password[passPos];
            asciiPosResult = cipher[i] - asciiPosPass;
            asciiPosResult ^= asciiPosPass;
            CheckAsciiPos(asciiPosResult);
            result += static_cast<char>(asciiPosResult);
            passPos++;
            passCounter++;
        }
     
        return result;
    }
     
     
     
    int main() {
     
    std::string plaintext = "Thats a test. This message will be encrypted";
        std::string password = "here is a password";
        std::string cipher;
        std::string result;
     
     
        std::cout << "Plaintext: " << plaintext << std::endl << "Plaintext Hex: ";
        for (auto dummy : plaintext) {
            std::cout << std::hex << static_cast<int>(dummy);
        }
     
     
        cipher = encrypt(plaintext, password);
        std::cout << std::endl << std::endl  << "Cipher: " << cipher << std::endl << "Cipher Hex: ";
        for (auto dummy : cipher) {
            std::cout << std::hex << static_cast<int>(dummy);
        }
     
     
        result = decrypt(cipher, password);
        std::cout << std::endl << std::endl << "Result: " << result << std::endl << "Result Hex: ";;
        for (auto dummy : result) {
            std::cout << std::hex << static_cast<int>(dummy);
        }
       
        return 0;
    }
    

    Chiffrat:

    4a6f70743e897b753e5bcd698c7a81797bcc918e4a6ba2a0ae7598a87d6f75a06e657865b66e6fd0776f6f84c6728581738f90c9
    


  • D.h. dein Cyphertext ist mit einem unbekannten Key unbekannter Länge verschlüsselt und wir sollen den Klartext rausbekommen?
    Aus einem einzigen Cyphertext, ohne weitere Hinweise?

    Das ist selbst bei sehr einfachen Verschlüsselungen schwer. Besonders wenn der Cyphertext kurz und der Key vergleichsweise lange ist.

    Extremfall: Der Key ist gleich lange wie der Text (oder gar länger als der Text). In dem Fall ist sogar eine Verschlüsselung mit einem der primitivsten Algorithmen wie z.B. XOR unknackbar.


  • Mod

    Ein Verfahren, das für den Laien schwer bis nicht zu knacken ist, aber für Profis kein Problem ist? Wozu soll das gut sein? Entweder ist ein Verfahren sicher oder man kann's auch gleich sein lassen. Zumal deine Methode nicht weniger aufwändig ist, als einfach einen der sicheren Algorithmen zu benutzen. Den einzigen Zweck dafür kann ich in kniffligen Ratespielen wie diesem hier sehen, wobei deine Frage hier halt viel zu schwer aussieht (siehe @hustbaer ) als dass ich Lust hätte, mich daran zu versuchen.



  • Nunja, also wenn ich mir mal den Rijndael-Algorithmus anschaue, welcher unter anderen aufgrund der "Einfachheit" zum AES gewählt wurde, dann gehört da einiges mehr dazu. Schon die mathematischen Zusammenhänge der S-Boxen erschließen sich mir nicht und die Mechanismen hinter MixColums und der KeyExpansion sind schon um ein vieles komplexer. Die Frage die ich mir zu meinem Algorithmus gestellt habe, ist eben wie sicher er ist. Ich denke wenn ich das ganze jetzt bei einem richtigen Krypto - Wettbewerb einreiche, ernte ich reichlich Spott weil ja wirklich nicht viel dazu ist. Deshalb stellte ich mir die Frage, ob vielleicht hier im Forum Programmierer dabei sind, die sich mit so etwas auskennen. Es gibt ja Leute die gern an solchen Aufgaben knobeln. (Bei meinem Beispiel ist der Key übrigens kürzer als der Plaintext).

    Wenn ihr mir jetzt sagt, dass es mit den Informationen die ich euch gegeben habe so gut wie nicht möglich ist, dann reicht mir das eigentlich schon. Denn wenn man das Chiffrat kennt, zusätzlich auch den kompletten Algorithmus und dennoch ohne Passwort nicht darauf schließen kann, was der Plaintext war, ist mir das ganze sicher genug. Selbstverständlich, nutze ich das Verfahren nicht bei Software, über welche dritte jetzt empfindliche Daten verschicken usw.. Da nutze ich auch die offiziellen Standarts: AES, TLS, oder PBKDF2. Es geht mir nur drum kleinere Projekte mal damit zu verschlüsseln.

    Ein konkretes Beispiel wäre da zum Beispiel ein Gameserver, von welchem mehrmals Scriptdaten geklaut wurden, weil die Spieler die Missionsdateien herunterladen und diese dann im Klartext vorliegen. Allerdings habe ich weder genug Kenntnisse dort komplizierte Standarts nachzubauen noch die Möglichkeiten welche mir zum Beispiel C / C++ zur Verfügung stellen. Eine einfache Verschlüsselung wie bei meinem Beispiel würde wahrscheinlich dazu führen, dass die Scriptdiebe die Lust verlieren und ich hätte keine Probleme den Algorithmus in der Scriptsprache zu schreiben. Und selbst wenn jemand den Algorithmus dort leaked, kommen die Angreifer nicht weiter solange sie das Passwort nicht kennen.

    Ich hoffe ihr versteht durch mein Beispiel warum ich mir das ganze ausgedacht habe. Es geht mir nur darum, dass ich keine offensichtlichen Fehler in meinen Gedanken habe und jemand sagt: "Ach, dass bekommt man doch in 10min raus weil...."

    Die verwundbaren Stellen der Vigenére Chiffre (Häufigkeitsanalyse und einfach herausfindbare Keylänge) habe ich damit hoffentlich gut umgangen.


  • Mod

    @zhavok sagte in Kleines Krypto-Gewinnspiel:

    Ein konkretes Beispiel wäre da zum Beispiel ein Gameserver, von welchem mehrmals Scriptdaten geklaut wurden, weil die Spieler die Missionsdateien herunterladen und diese dann im Klartext vorliegen. Allerdings habe ich weder genug Kenntnisse dort komplizierte Standarts nachzubauen noch die Möglichkeiten welche mir zum Beispiel C / C++ zur Verfügung stellen. Eine einfache Verschlüsselung wie bei meinem Beispiel würde wahrscheinlich dazu führen, dass die Scriptdiebe die Lust verlieren und ich hätte keine Probleme den Algorithmus in der Scriptsprache zu schreiben. Und selbst wenn jemand den Algorithmus dort leaked, kommen die Angreifer nicht weiter solange sie das Passwort nicht kennen.

    Häh? Aber was spricht denn gegen ein normales Verfahren? Du willst nicht, dass jemand die Daten liest. Fertig. Wieso dann komplizierte Sonderwege gehen?

    Wobei es sowieso zwecklos ist, irgendetwas zu verschlüsseln, das ein Client auf dem Rechner des Nutzers entschlüsselt. Der Nutzer kann schließlich trivial in den Speicher des Clients gucken und dort die entschlüsselten Daten mitlesen.

    Zum anderen Thema: Es gibt hier im Forum durchaus schon genügend Leute, die sich mit dem Thema auskennen. Aber es ist halt abschreckend mühselig, sich mit deinem Rätsel zu beschäftigen. An sich hat jeder sichere Verschlüsselungsalgorithmus mathematisch beweisbare Gründe, wieso er sicher ist. Gibt es keinen solchen Beweis und der Algorithmus mischt bloß wild ein bisschen Text, bis er so aussieht wie ein übliches Chiffrat, dann ist das Cargo Cult. Trotzdem ist das für einen Einzelkämpfer mit amateurkenntnissen in seiner Freizeit eine hohe Hürde zu entschlüsseln.



  • Gegen ein normales Verfahren spricht, dass ich es nicht schaffe ein solches Verfahren in einer Scriptsprache, die dazu vorgesehen ist zum Beispiel Fahrzeuge zu spawnen oder Spielcharaktere von A nach B zu laufen zu lassen, nachzubauen. Zwar kann ich dort trotzdem mit Variablen arbeiten, aber eins der heutigen Verschlüsselungverfahren dort einzubauen würde ich nicht hinbekommen.



  • Jede (professionelle) Skriptsprache kann doch Funktionen aus externen Libs benutzen?!



  • Momentan basiert dein Verfahren ausschließlich auf Security by Obscurity und zumindest bei sensiblen Daten ist das ungeeignet. Sobald du mit deinem Key eine weitere Nachricht kodierst und/oder bekannt ist was im Klartext überhaupt zu erwarten ist, wird dein Verfahren sehr angreifbar.

    Sofern dein Key völlig zufällig ist, geheim bleibt, du ihn nur einmalig nutzt, er mindestens so lang ist wie der Klarttext, sollte dein Verfahren allerdings sicher sein (One-Time-Pad).

    Wenn es dir aber ausschließlich darum geht Daten zu verschleiern, dann kann ein bisschen Spielerei mit XOR vielleicht tatsächlich ausreichend sein. Eine Garantie dafür gibt es aber aufgrund der Unsicherheit dieses Verfahrens nicht.



  • Ich rede auch nicht von "professionellen Scriptsprachen" sondern von Sprachen die die Hersteller extra für das Spiel entwickelt haben und sonst nirgends Anwendung finden.


  • Gesperrt

    @dummie sagte in Kleines Krypto-Gewinnspiel:

    Momentan basiert dein Verfahren ausschließlich auf Security by Obscurity

    Den Quellcode zeigt er ja. Er verrät nur Originalnachricht und Key nicht. So wie ich es sehe ist das eine simple XOR-Verschlüsselung, wobei allerdings noch die Position der Zeichen eine Rolle spielt. Das soll sicherstellen, dass Klartextzeichen XOR Keybyte ein unterschiedliches Cypherbyte ergeben wenn sie sich an unterschiedlichen Positionen befinden.

    IMHO für Noobs eine harte Nuss, aber für Erfahrene ein altbekannter Trick und sicherlich einfach zu knacken.


  • Mod

    @zhavok sagte in Kleines Krypto-Gewinnspiel:

    Ich rede auch nicht von "professionellen Scriptsprachen" sondern von Sprachen die die Hersteller extra für das Spiel entwickelt haben und sonst nirgends Anwendung finden.

    Ok, das ist ein ziemlich akzeptabler Grund.

    Wobei nach wie vor gilt, was ich schon sagte: Wenn das Ding sowieso auf Seiten des Cheaters entschlüsselt wird, dann nützt das Verschlüsseln auf dem Transportweg herzlich wenig. In den Arbeitsspeicher eines laufenden Spiels zu gucken ist die grundlegendste Cheattechnik überhaupt.



  • Da hast du vollkommen Recht @SeppJ . Evtl könnte mans vom Server schicken lassen. Ich glaube die Verbindung vom Server zu Client ist verschlüsselt. Bin mir aber nicht sicher. Aber danke trotzdem schonmal euren beiden Antworten., Auch vielen Dank für die Richtigstellung und deine Einschätzung des Ganzen @RBS2 . Du hast das ganze mit unterschiedlichen Positionen richtig interpretiert. Genau deshalb wird das Passwort auch immer weiter geshiftet.

    Das ist schonmal ein Statement womit ich etwas anfangen kann.



  • @zhavok sagte in Kleines Krypto-Gewinnspiel:

    Evtl könnte mans vom Server schicken lassen. Ich glaube die Verbindung vom Server zu Client ist verschlüsselt.

    Das hört sich für mich nicht so an, als ob du das verstanden hättest.
    Es ist viel einfacher, in den Arbeitsspeicher eines Prozesses (des Clients) reinzuschauen oder den Prozess zu debuggen, als irgendeine Verschlüsselung zu knacken. Wenn der Benutzer Kontroller über den Prozess hat, dann hat er die Daten auch irgendwann entschlüsselt im Speicher vorliegen und kann sie einfach abgreifen.


  • Gesperrt

    @zhavok
    Lustige XOR-Verschlüsselungen bekommst du mit kryptografischen Hash-Funktionen hin. Nimm z.B. eine Hash-Funktion die 32 Bytes liefert. Die fütterst du mit dem Passwort und hash'd den output wieder und wieder, bekommst also jede Mal 32 Bytes dazu, usw. Wenn du genügend Keymaterial hast (mindestens Plaintext-Länge), dann XORst du einfach deinen Plaintext damit und bekommst einen üblen Datensalat, den dir so schnell niemand entschlüsselt, der das Passwort nicht kennt.



  • Ich wüsste aber keine Möglichkeit wie man das Auslesen aus dem RAM jemals vermeiden kann. Man wird sicher früher oder später immer an den Punkt kommen wo die Scripte in den Arbeitsspeicher eingelesen werden. Das wird sich auch nicht einfach verhindern lassen. Aber die Verschlüsselung ist sicher immer noch besser als die Scripte im Klartext mit zu schicken. Es gibt sogar Tools zum obfuscaten der Missionsdaten und Seiten die (wesentlich einfachere) Verschlüsselungen anbieten. Diese haben theoretisch alle das Problem mit Memory Scannern. Aber mir ist nicht bekannt, dass es schon mal jemand so weit geschafft, dass er danach die Scripte im Klartext vorliegen hatte.

    @RBS2 Das ist richtig. Eine sehr ähnliche Idee hatte ich auch schon mal wo anders geäußert^^. Das ganze hat nur den unschönen Beigeschmack, dass der Schlüssel dadurch sehr sehr lang wird. Nehme ich alle Scripts zusammen komme ich auf eine hübsche Größe von ca 8mb. Also müssten die Schlüssel insgesamt auch 8mb füllen. Und ich müsste dann auch schauen ob ich tatsächlich einen geläufigen Hash-Algorithmus ins Spiel bringen übertragen kann, Das könnte auch sehr knifflig werden. Abgesehen von diesen Problemen aber kein schlechter Vorschlag.



  • Das Gewinnspiel ist nun offiziell beendet. Der Algorithmus wurde geknackt :smiling_face_with_open_mouth:


Anmelden zum Antworten