Passwort generator mit Bedingungen



  • ich soll einen Passwortgenerator in C++ erstellen mit folgenden Bedingungen:

    • 30 Zeichen
    • mindestens 1 Kleinbuchstabe
    • 6 Großbuchstaben
    • mindestens 8 Ziffern
    • 2 bis 5 Sonderzeichen

    Ich habe bis jetzt nur geschafft einen Zufallsgenerator für alle Zeichen zu erstellen und mir fällt es etwas schwer die Bedingungen miteinzubinden. Kann mir jemand ein paar Tipps geben? Danke schon mal im Voraus!

    #include <iostream>
    #include <time.h>

    using namespace std;

    int main() {
    srand(time(0));
    string pass;

    string data = "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789"
    ";,:.+-*/%><=!~^&|[]{}()";
    for (int i=0; i<=30; i++)
    {

    pass = pass + data[rand()% 100];
    }

    cout << "Your password: " << pass;

    return 0;
    }



  • Hallo

    @helpinfo sagte in Passwort generator mit Bedingungen:

    rand()% 100

    Was macht das?
    Ich würde mehrere "Zeichentöpfe" nehmen (Kleinbuchstaben, Großbuchstaben,...) und daraus sooft ziehen, wie es die Bedingungen erfordern.
    Dabei ist natürlich darauf zu achten, dass im Resultat-String nichts überschrieben wird.
    Wenn du es hässlich machen möchtest, würde es im Sinne der Aufgabe auch reichen die Bedingungen hintereinander auszuführen (erste Zeichen aus Kleinbuckstaben-Topf, 2-7 aus Grossbuchstaben,...)



  • @Jockelx sagte in Passwort generator mit Bedingungen:

    Wenn du es hässlich machen möchtest, würde es im Sinne der Aufgabe auch reichen die Bedingungen hintereinander auszuführen (erste Zeichen aus Kleinbuckstaben-Topf, 2-7 aus Grossbuchstaben,...)

    Na klar, warum soll das hässlich sein?
    Am Ende einmal den Ergebnisstring shufflen, und fertig ...



  • @Belli sagte in Passwort generator mit Bedingungen:

    Na klar, warum soll das hässlich sein?

    Weil ich nichts von shufflen geschrieben habe!? Und dann passt es zur Aufgabe, ist aber hässlich.



  • @Belli wie shuffle ich die einzelnen bedingungen in einem string?


  • Mod

    @helpinfo sagte in Passwort generator mit Bedingungen:

    @Belli wie shuffle ich die einzelnen bedingungen in einem string?

    Du sollst erst die Bedingungen nacheinander ausführen und damit ein Zwischenpasswort wie "hghedsewFGSWE8723834!##^" erzeugen. Und das mischt du dann durch.



  • Ich würde vielleicht eher in Richtug des <random> headers schauen und dort was mit std::random_device und std::mt19937 basteln. Generell sollte hier noch gesagt werden (was aber eigentlich klar ist), dass du die Passwörter aus deinem Zufallsgenerator nicht für irgendwelche Kryptoprozesse nimmst. Also du solltest das so auch nicht für einen eigenen Passwortmanager und erst recht nicht zur Verschlüsselung von Daten nutzen.


  • Mod

    Bis auf die zu kleine Entropie für den Seed ist das absolut in Ordnung, Passwörter so zu erzeugen. Na gut, das mit der zu kleinen Entropie für den Seed ist ein sehr gewichtiges Problem (Da war doch mal was mit einem bekannten Kryptosytstem, das genau dieses Problem hatte…) und nicht so ganz einfach zu beheben. Aber vom Prinzip her ist hier sonst alles ok.



  • @SeppJ sagte in Passwort generator mit Bedingungen:

    Bis auf die zu kleine Entropie für den Seed ist das absolut in Ordnung, Passwörter so zu erzeugen.

    Vielleicht noch untersteichen, das das für den mt19937 gilt, und nicht für den LCG der hinter rand() steckt. Und natürlich sollte der Seed aus ner robusten Quelle stammen und nicht unbedingt von time(). Und gabs da nicht mal was mit dem seeden des mt19937? Der hat ein paar hundert Byte internen State, ich meine mal irgendwo in nem Vortrag gehört zu haben das es zumindest nicht ganz einfach ist, die Implementierung der Standardbibliothek korrekt zu seeden. Bin da aber nicht super-bewandert drin 😉

    Andererseits ist es wohl eine Übungsaufgabe, daher nicht ganz so wichtig, aber dennoch erwähnenswert, wenn man mal einen ernsthaften Generator stricken will.


  • Mod

    Häh? Dass es aus time() stammt ist das Problem, nicht der Zufallsgenerator. Du wirst beim 30 Zeichen mit rand garantiert keine Probleme mit Korrelationen haben. Das Problem ist, dass es heute nur 86400 verschiedene time-Werte gab, dieses Jahr nur 31,536,000 und selbst diese Dekade nur 10x mehr. Was verschwindend geringe Zahlen für einen Computer sind, um alle Möglichkeiten durchzuprobieren, weil man ja weiß, dass das Passwort wahrscheinlich irgendwann in diesem Jahrzehnt erzeugt wurde. Viel, viel, viel weniger Möglichkeiten als ein 30-Zeichen-Passwort hätte, selbst wenn man die minimalen Korrelationen in rand zur Hilfe zieht.



  • Hier ein paar Gedanken zum Thema Seed des mt19937. Wobei ich jetzt noch nicht verstanden habe, warum das für den mt19937 ein größeres Problem sein sollte, als für rand(). Habe da auf die Schnelle auch nichts zu gefunden.

    https://stackoverflow.com/a/45069417



  • @SeppJ sagte in Passwort generator mit Bedingungen:

    Häh? Dass es aus time() stammt ist das Problem, nicht der Zufallsgenerator. Du wirst beim 30 Zeichen mit rand garantiert keine Probleme mit Korrelationen haben.

    Mein Gedanke war hier eher, dass z.B. ein 32-Bit-rand() mit dieser Methode nur 2322^{32} verschiedene Passwörter generieren kann, wenn man nicht noch ein paar extra srand() mit guten Seeds dazwischen schiebt. Das ist die Anzahl aller möglichen Zufallssequenzen und das schränkt meines erachtens bei 30 Zeichen langen Passwörtern des Passwort-Raum ganz schön ein.

    Wenn ich mal die Passwort-Regeln mal außer acht lasse, dann habe ich bei 30 aus 100 Zeichen 10030=1060100^{30}=10^{60} mögliche Passwörter, von denen aber nur etwa 4.291094.29 \cdot 10^{9} abgedeckt werden, oder etwa 1.8410191.84 \cdot 10^{19} bei nem 64-Bit-rand(). Das sind schon ganz schön viele Größenordnungen weniger.



  • @Schlangenmensch sagte in Passwort generator mit Bedingungen:

    Hier ein paar Gedanken zum Thema Seed des mt19937. Wobei ich jetzt noch nicht verstanden habe, warum das für den mt19937 ein größeres Problem sein sollte, als für rand(). Habe da auf die Schnelle auch nichts zu gefunden.

    Da müsste ich auch nochmal genauer suchen, habe da nur eine vage Erinnerung. Die Seed-Funktion, die nur einen einzigen Integer-Result-Typen entgegennimmt ist aber nicht ausreichend, den muss man schon mit einer Sequenz aus Seeds füttern, wie viele das auch immer sein müssen um den kompletten internen Zustand korrekt zu initialisieren.

    (btw., vielleicht driftet das hier mal wieder etwas zu speziell ab - immerhin scheint das nur eine Übungsaufgabe zu sein 😉 )


  • Mod

    @Finnegan sagte in Passwort generator mit Bedingungen:

    Mein Gedanke war hier eher, dass z.B. ein 32-Bit-rand() mit dieser Methode nur 2322^{32} verschiedene Passwörter generieren kann, wenn man nicht noch ein paar extra srand() mit guten Seeds dazwischen schiebt. Das ist die Anzahl aller möglichen Zufallssequenzen und das schränkt meines erachtens bei 30 Zeichen langen Passwörtern des Passwort-Raum ganz schön ein.

    Ahh, das meintest du. Ja, stimmt. Ich dachte, du wolltest auf irgendwelche Korrelationen zwischen den Zeichen aus.


  • Gesperrt

    Ich möchte auch meinen Versuch zum Besten geben:

    #include <stdexcept>
    
    #include <iostream>
    
    #include <random>
    
    #include <vector>
    
    #include <algorithm>
    
    using namespace std;
    
    vector < vector < char16_t >> all_chars;
    int32_t all_size = 0;
    
    void init() {
      if (all_size != 0) {
        throw logic_error("already init");
      } {
        vector < char16_t > v;
        for (char16_t i = 'a'; i <= 'z'; i++) {
          v.push_back(i);
        }
        all_chars.push_back(v);
      } {
        vector < char16_t > v;
        for (char16_t i = 'A'; i <= 'Z'; i++) {
          v.push_back(i);
        }
        all_chars.push_back(v);
      } {
        vector < char16_t > v;
        for (char16_t i = '0'; i <= '9'; i++) {
          v.push_back(i);
        }
        all_chars.push_back(v);
      } {
        vector < char16_t > v;
        for (char16_t i = '!'; i <= '/'; i++) {
          v.push_back(i);
        }
        all_chars.push_back(v);
      }
      for (auto i: all_chars) {
        all_size += i.size();
      }
    }
    
    char16_t get_ch(int32_t i) {
      if (i < 0 || i >= all_size) {
        throw invalid_argument("");
      }
      for (int j = 0; j < all_chars.size(); j++) {
        if (i < all_chars[j].size()) {
          return all_chars[j][i];
        }
        i -= all_chars[j].size();
      }
      return 0;
    }
    
    int is_valid(string s) {
      {
        int i = 0;
        int c = 0;
        for (auto j: s) {
          if (find(all_chars[i].begin(), all_chars[i].end(), j) != all_chars[i].end()) {
            c++;
          }
        }
        if (c == 0) {
          return i;
        }
      } {
        int i = 1;
        int c = 0;
        for (auto j: s) {
          if (find(all_chars[i].begin(), all_chars[i].end(), j) != all_chars[i].end()) {
            c++;
          }
        }
        if (c < 6) {
          return i;
        }
      } {
        int i = 2;
        int c = 0;
        for (auto j: s) {
          if (find(all_chars[i].begin(), all_chars[i].end(), j) != all_chars[i].end()) {
            c++;
          }
        }
        if (c < 8) {
          return i;
        }
      } {
        int i = 3;
        int c = 0;
        for (auto j: s) {
          if (find(all_chars[i].begin(), all_chars[i].end(), j) != all_chars[i].end()) {
            c++;
          }
        }
        if (c < 2 || c > 5) {
          return i;
        }
      }
      return 4;
    }
    
    string get_pw() {
      string s = ""; {
        random_device rd; // obtain a random number from hardware
        mt19937 gen(rd()); // seed the generator
        uniform_int_distribution < > distr(0, all_size - 1); // define the range
        while (s.size() < 30) {
          s += (char) get_ch(distr(gen));
        }
      } {
        random_device rd;
        mt19937 gen(rd());
        uniform_int_distribution < > distr1(0, all_size - 1);
        int v;
        while ((v = is_valid(s)) != 4) {
          uniform_int_distribution < > distr2(0, all_chars[v].size() - 1);
          int r1 = distr1(gen);
          int r2 = distr2(gen);
          s[r1] = (char) all_chars[v][r2];
        }
      }
      return s;
    }
    
    int main() {
      init();
      cout << get_pw();
      return 0;
    }
    

    Wäre sehr "lieb", wenn da mal jemand drüberschauen könnte...


  • Mod

    Wenn sich der fast gleiche Code 5x wiederholt, macht man was falsch.


  • Gesperrt

    Dieser Beitrag wurde gelöscht!

  • Gesperrt

    Ok:

    #include <stdexcept>
    
    #include <iostream>
    
    #include <random>
    
    #include <vector>
    
    #include <algorithm>
    
    using namespace std;
    
    vector < vector < char16_t >> all_chars;
    int32_t all_size = 0;
    
    void add(char16_t from, char16_t to) {
      vector < char16_t > v;
      for (char16_t i = from; i <= to; i++) {
        v.push_back(i);
      }
      all_chars.push_back(v);
      all_size += v.size();
    }
    
    void init() {
      if (all_size != 0) {
        throw logic_error("already init");
      }
      add('a', 'z');
      add('A', 'Z');
      add('0', '9');
      add('!', '/');
      add('a', 'z');
    }
    
    char16_t get_ch(int32_t i) {
      if (i < 0 || i >= all_size) {
        throw invalid_argument("");
      }
      for (int j = 0; j < all_chars.size(); j++) {
        if (i < all_chars[j].size()) {
          return all_chars[j][i];
        }
        i -= all_chars[j].size();
      }
      return 0;
    }
    
    bool is_valid(string s, int i, int min, int max) {
      int c = 0;
      for (auto j: s) {
        if (find(all_chars[i].begin(), all_chars[i].end(), j) != all_chars[i].end()) {
          c++;
        }
      }
      return c >= min && c <= max;
    }
    
    int is_valid(string s) {
      if (!is_valid(s, 0, 1, all_size)) {
        return 0;
      }
      if (!is_valid(s, 1, 6, all_size)) {
        return 1;
      }
      if (!is_valid(s, 2, 8, all_size)) {
        return 2;
      }
      if (!is_valid(s, 3, 2, 5)) {
        return 3;
      }
      return 4;
    }
    
    string get_pw() {
      string s = ""; {
        random_device rd; // obtain a random number from hardware
        mt19937 gen(rd()); // seed the generator
        uniform_int_distribution < > distr(0, all_size - 1); // define the range
        while (s.size() < 30) {
          s += (char) get_ch(distr(gen));
        }
      } {
        random_device rd;
        mt19937 gen(rd());
        uniform_int_distribution < > distr1(0, all_size - 1);
        int v;
        while ((v = is_valid(s)) != 4) {
          uniform_int_distribution < > distr2(0, all_chars[v].size() - 1);
          int r1 = distr1(gen);
          int r2 = distr2(gen);
          s[r1] = (char) all_chars[v][r2];
        }
      }
      return s;
    }
    
    int main() {
      init();
      cout << get_pw();
      return 0;
    }
    

    Beispiel für ein sicheres Passwort: qJb1t3SdXL3-iymtN+90h1rOS,z8+7 😉 (Nur ein Spaß, jedes "bekannte" Passwort ist nicht mehr sicher...)

    Aber... ich laufe doch damit in ein Halteproblem - oder nicht?



  • @Jockelx sagte in Passwort generator mit Bedingungen:

    @Belli sagte in Passwort generator mit Bedingungen:

    Na klar, warum soll das hässlich sein?

    Weil ich nichts von shufflen geschrieben habe!? Und dann passt es zur Aufgabe, ist aber hässlich.

    Ach ja klar, weil Du es nicht geschrieben hast, logisch ...



  • @helpinfo sagte in Passwort generator mit Bedingungen:

    @Belli wie shuffle ich die einzelnen bedingungen in einem string?

    mit std::random_shuffle


  • Mod

    @EinNutzer0 sagte in Passwort generator mit Bedingungen:

    @SeppJ sagte in Passwort generator mit Bedingungen:

    Wenn sich der fast gleiche Code 5x wiederholt, macht man was falsch.

    fast 😉

    Ich weiß schon, was ich gesagt habe. Dass du das nicht verstehst, weiß ich. Aber trotzdem ist meine Aussage korrekt, dass du hier was falsch machst, mit genau der genannten Begründung.


Anmelden zum Antworten