diff --git a/j1-Passwoerter/README.md b/j1-Passwoerter/README.md new file mode 100644 index 0000000..b894a46 --- /dev/null +++ b/j1-Passwoerter/README.md @@ -0,0 +1,57 @@ +# Allgemeine Informationen + +Die Grundidee für meinen Passwortgenerator ist das Passwort aus richtigen Wörtern zu bilden. +Als erstes Argument muss man einen Dateipfad zu der Textdatei mit einer Liste von Wörtern, die von einem Zeilenumbruch getrennt sind, verwenden. +Unter wörter.txt ist ein Beispiel dafür ([Quelle](https://www.netzmafia.de/software/wordlists/deutsch.txt)). +Das Passwort wird zu stdout ausgegeben. + +# Regeln für das generierte Passwort + +1. Zufällige Wörter werden aus der Wörterliste ausgewählt. +2. Am Anfang des Passworts und zwischen den Wörtern steht eine Ziffer. +3. Am Ende steht ein Satzzeichen. + +# Funktionsweise + +Als erstes wird die angebene Textdatei mit der Wörterliste ausgelesen. +Alle Zeilenumbrüche werden durch \0 ersetzt und Pointer zu jedem Wort in einem Array gespeichert. +``` +for(char *i = woerterText; (uintptr_t)i < dest; ++i) { + if(*i == '\n') { + char *nextWord = i + 1; + woerter = acl_arraylist_append(woerter, &nextWord); + pointerCheck(woerter); + *i = '\0'; + } +} +``` +Danach werden Bytes mit zufälligen Werten von `/dev/random` ausgelesen.
+` fread(randomInt, sizeof *randomInt, randomInt_len, randomFile);`
+Dafür habe ich mich entschieden, da dieser ein krypografisch sicherer Zufallszahlengenerator ist. +Passwörter, die mit Pseudozufallszahlengeneratoren generiert werden, sind einfach zu knacken, da bei diesen jede Zufallszahl von der vorherigen abhängt. +Oft wird als Startwert auch noch die aktuelle Zeit benutzt, was das Ganze noch unsicherer macht. +Auf Basis der Zufahlszahlen wird dann das Passwort aus Wörtern und Ziffern zusammengesetzt. +``` +for(uint32_t i = wordsForPass_len; i < randomInt_len; ++i, ++j) { + char buf[2]; + buf[1] = '\0'; + sprintf(buf, "%" PRIu32, randomInt[i] % 10); + strcat(password, buf); + strcat(password, wordsForPass[j]); +} +``` +Zum Schluss wird noch ein zufälliges Satzzeichen angehängt. +``` +const char specialCharacter[] = {'?', '.', ',', '!', ';'}; +char randomSpecialCharacter[] = {specialCharacter[randomInt[randomInt_len - 1] +% (sizeof specialCharacter - 1)], '\0'}; +``` +Dann wird das Passwort wird schließlich ausgegeben. + +# Beispiel + +Beipielausgabe: `0zaehneknirschend8verraeterischem6veranstaltet,`
+Die Textdatei in diesem Fall wörter.txt wurde ausgelesen, \\n durch \0 ersetzt um das Ende vom String zu markieren. +Danach wurden Pointer zu jedem Wort der Textdatei erstellt. +Anschließend wurden die Wörter zaehneknischend, verraeterischem, veranstaltet, die Ziffern 0, 8, 6 ausgewählt und zusammengesetzt. +Ein Komma wurde angehängt und das Passwort schließlich ausgegeben. diff --git a/j1-Passwoerter/j1 b/j1-Passwoerter/j1 index 7182997..b848cfa 100755 Binary files a/j1-Passwoerter/j1 and b/j1-Passwoerter/j1 differ diff --git a/j1-Passwoerter/src/main.c b/j1-Passwoerter/src/main.c index 8d815d7..0959611 100644 --- a/j1-Passwoerter/src/main.c +++ b/j1-Passwoerter/src/main.c @@ -1,13 +1,3 @@ -/* Die Grundidee für meinen Passwortgenrator ist richtigen Wörtern zu bilden. - * Als erstes Argument muss man den Programm einen Dateipfad zu der Textdatei mit Liste von Wörtern, die mit \n getrennt sind. - * Unter wörter.txt ist ein Beispiel dafür. Quelle: https://www.netzmafia.de/software/wordlists/deutsch.txt - * Das Passwort wird zu stdout ausgegeben. - * - * Regeln für das generierte Passwort: - * 1. zufäfflige Wörter werden aus der Wörterliste ausgewählt. - * 2. Am Anfang des Passworts und zwischen den Wörtern steht eine Ziffer. - * 3. Am Ende steht ein Satzzeichen. - */ #include #include #include @@ -19,7 +9,7 @@ #define wordCount 3 // Anzahl der Wörter des Passworts #define randomInt_len (2 * wordCount) #define wordsForPass_len randomInt_len / 2 -void pointerCheck(void *pointer) { +void pointerCheck(void *pointer) { // Funktion um auf NULL Pointer zu checken und den Fehler auszugeben. if(pointer == NULL) { perror("Error: "); exit(-1); @@ -27,33 +17,45 @@ void pointerCheck(void *pointer) { } int main(int argc, char *argv[]) { - if(argc != 2) printf("file argument required"); + if(argc != 2) { + printf("file argument required"); // checkt ob der Nutzer die richtige Anzahl von Argumenten verwendet hat. + exit(-1); + } bool sucess; - FILE *fp = fopen(argv[1], "rb"); // im binären Modus zu lesen ist deutlich schneller als im Textmodus, da man dort jede Zeile einzeln lesen muss. So wurde aus mehreren Sekunden Wartezeit keine bemerkbare Verzögerung. + + /* im binären Modus zu lesen ist deutlich schneller als im Textmodus, da man dort jede Zeile einzeln lesen muss. + * So wurde aus mehreren Sekunden Wartezeit eine nicht bemerkbare Verzögerung. */ + FILE *fp = fopen(argv[1], "rb"); char *woerterText = acl_ReadTextFile(fp, &sucess); if(!sucess) perror("Error: "); fclose(fp); unsigned len = strlen(woerterText); uintptr_t dest = (uintptr_t)woerterText + len; - char **woerter = acl_arraylist_create(1, sizeof *woerter); + + /* erstellt ein Array für die Pointer zu den Wörtern. + * Man könnte auch erst die Zeilenumbrüche zählen, um den Arbeitsspeicher auf einmal anzufragen. + * Dies würde das Programm vermutlich etwas schneller machen. + * Jedoch ist das Programm so einfacher zu verstehen und im Vergleich zum Auslesen der Textdatei wäre die Geschwindigkeitsverbesserung sehr gering. */ + char **woerter = acl_arraylist_create(1, sizeof *woerter); pointerCheck(woerter); woerter[0] = woerterText; for(char *i = woerterText; (uintptr_t)i < dest; ++i) { if(*i == '\n') { char *nextWord = i + 1; - woerter = acl_arraylist_append(woerter, &nextWord); // Pointer werden zu Begin jedes Wortes erstellt. + woerter = acl_arraylist_append(woerter, &nextWord); // Pointer werden am Anfang jedes Wortes erstellt. pointerCheck(woerter); - *i = '\0'; // \n wird mit \0 ersetzt um das Ende des Strings markieren. + *i = '\0'; // \n wird durch \0 ersetzt um das Ende des Strings markieren. // diesen Weg habe ich gewählt um viele memory allocations zu vermeiden. } } - FILE *randomFile = fopen("/dev/random", "rb"); + FILE *randomFile = fopen("/dev/random", "rb"); // /dev/random ist ein kryptografisch sicherer Zufallszahlengenerator. uint32_t randomInt[randomInt_len]; fread(randomInt, sizeof *randomInt, randomInt_len, randomFile); size_t passLen = wordsForPass_len + 1; // weil Ziffern im Passwort gleich oft vorkommen wie Wörter. + 1 für ein Satzzeichen am Ende char *wordsForPass[wordsForPass_len]; + // Die Länge des Passwortes wird berechnet. for(uint32_t i = 0; i < wordsForPass_len; ++i) { - wordsForPass[i] = woerter[randomInt[i] % acl_arraylist_len(woerter)]; // der modulo operator wird verwendet um die Zahlfallszahl auf den gewünschten Zahlenbereich zu reduzieren. + wordsForPass[i] = woerter[randomInt[i] % acl_arraylist_len(woerter)]; // der modulo Operator wird verwendet um die Zufallszahl auf den gewünschten Zahlenbereich zu reduzieren. passLen += strlen(wordsForPass[i]); } char *password = malloc(passLen + 1); @@ -66,7 +68,9 @@ int main(int argc, char *argv[]) { strcat(password, buf); strcat(password, wordsForPass[j]); } + free(woerterText); + // ein zufälliges Sonderzeichen wird angehängt. const char specialCharacter[] = {'?', '.', ',', '!', ';'}; char randomSpecialCharacter[] = {specialCharacter[randomInt[randomInt_len - 1] % (sizeof specialCharacter - 1)], '\0'}; - printf("%s", strcat(password, randomSpecialCharacter)); + printf("%s\n", strcat(password, randomSpecialCharacter)); }