PowerShell – 13.1 – Simpler Passwortgenerator Version 2

Nach einer Analyse des Scriptes mit einem guten Freund (welcher ein exzellenter Programmierer ist) haben wir das Script in Punkten Sicherheit und Performance etwas optimiert. Die Do-While Schleife war hier in diesem Falle etwas schlecht gewählt, da die Schleife durch das doppelt genutzte get-Random viel zu oft durch gelaufen ist. Ein Beispiel: bei einem 100 stelligen Passwort ist diese Schleife ±160 mal durchgelaufen, bei 1000 Stellen steigt dies extrem auf über ±1360. Ist dann noch definiert, dass nur große Buchstaben gewählt werden sollen ist das Script dann eher für die Tonne. Denn hier durchläuft das Script die Schleife gleich ±4000 mal. Das ist absolut nicht tragbar in Sachen Performance. Es kann im Worste Case bei falsch gerundeten Zahlen oder ähnlichem passieren, dass die Schleife eine Endlosschleife wird. Ebenfalls habe ich festgestellt das Get-Random nicht so schnell umgesetzt werden kann wie ein erzeugtes Random Objekt mittels $Random =  New-Object Random. Dieses lässt sich einfacher wieder verwenden. So wird auch bspw. Random in C# aufgerufen. Grundlage ist hier das .NET Framework. Vorab sei gesagt, der Passwort Generator der Version 2 ist weniger anfällig für Falschangaben und berechnet ein Passwort schneller als die erste Version. Dennoch läuft eine Version in C# deutlich schneller. Aber dazu ein anderes Mal mehr.

Was habe ich im Script genutzt

Für dieses Script habe ich mehrere bereits beschriebene Elemente genutzt. Der Generator basiert auf mehreren Instanzen von Random. Die in Version 1 genutzte  Switch- oder auch Case-Schleife (PowerShell – 11.1 – Logfiles mit einer Function erstellen) ist rausgeflogen. Ich nutze in dieser Version nur noch einfache For-Schleifen. Die benötigteZeit für das Script wird weiterhin ermittelt. Dies kann entweder mit Measure-Command (PowerShell – Scriptdauer messen Teil 2) oder mit einer selbstgeschrieben Variante (PowerShell – Scriptdauer messen Teil 1) gemessen werden. Ich habe mich im Script für meine selbst erstellte Variante entschieden. Zu guter Letzt nutze ich die Funktion Runden (Round) aus der Mathematikbibliothek (Math).

Input des Scriptes

Im Script müssen mehrere Variablen angeben werden. Diese habe ich in der folgenden Tabelle näher beschrieben.

Name Typ Beschreibung
$PWDLength Int32 Diese Variable legt die Länge des Passwortes fest. Definiert ist sie als Int32 damit auch besonders lange Passwörter möglich sind (bis zu 2.147.483.647 Zeichen).
$AmountABC_percent Int Diese Variable legt den prozentualen Wert der Großbuchstaben (A-Z) fest. Dieser Wert kann von 0 bis 100 gesetzt werden. Wobei Gesamtsummer aller $Amount* Variablen nicht über 100 sein darf.
$AmountABCsm_percent Int Diese Variable legt den prozentualen Wert der Kleinbuchstaben fest (a-z). Dieser Wert kann von 0 bis 100 gesetzt werden. Wobei Gesamtsummer aller $Amount* Variablen nicht über 100 sein darf.
$AmountNR_percent Int Diese Variable legt den prozentualen Wert der Ziffern(0-9) fest. Dieser Wert kann von 0 bis 100 gesetzt werden. Wobei Gesamtsummer aller $Amount* Variablen nicht über 100 sein darf.
$AmountSign_percent Int Diese Variable legt den prozentualen Wert der Sonderzeichen ($,!,%,^) fest. Dieser Wert kann von 0 bis 100 gesetzt werden. Wobei Gesamtsummer aller $Amount* Variablen nicht über 100 sein darf.
$AllAmounts_percent Int

Diese Variable fast alle $Amount* Variablen zusammen. Anschließend wird geprüft, ob diese größer gleich 100 ist. Ist sie größer als 100 wird ein Fehler ausgegeben mit dem Hinweis das die Werte angepasst werden müssen. Ist diese Variable kleiner 100 wird der Wert von $AmountABC_percent solange um jeweils 1 erhöht bis der Wert von $AllAmounts_percent 100 entspricht.

Funktionsweise des Scriptes

Nachdem die oben genannten Werte angeben sind geht es im Script wie folgt weiter. Es wird zu erst geprüft, ob die Variable $AllAmounts_percent  kleiner 100 ist. Trifft dies zu, wird der Wert der Variable $AmountABC_percent (Anzahl Großbuchstaben) jeweils um eins erhöht bis $AllAmounts_percent gleich 100 ist. Übersteigt $AllAmounts_percent jedoch den Wert 100 bricht das Script mit der Fehlermeldung „Prozentuale Werte sind über 100%!“ ab. Ausgelöst durch break.

Im nächsten Schritt werden vier Arrays ($Chars_*) initiiert für Groß- und Kleinbuchstaben, Ziffern sowie für Sonderzeichen. Diese können beliebig erweitert werden.

Nun werden zwei als String deklarierte Variablen $UserPassword0 und $UserPassword angelegt. Die Variable $UserPassword0 wird für eine spätere For-Schleife verwendet. Inhalt der Variable $UserPassword ist am Ende das generierte Passwort. Dazu müssen sie vorher bereits existieren.

Es werden zwei weitere Arrays gebildet, $AllAmounts_array und $AllAmountsArray. Das Array $AllAmounts_array enthält alle vier Werte der $Amount* Variablen. $AllAmountsArray wird zunächst nur initiiert. Dieses wird für die folgende For-Schleife benötigt. Weiterhin wird eine Variable $CountAmmount gerbildet. Diese dient zur Prüfung ob die gewählte Passwortlänge erreicht wurde.

In der folgenden For-Schleife kommt die Round Funktion der Math Bibliothek zum Einsatz. Hier breche ich die angegebenen prozentualen Werte auf Ganzahlen (Integer) herunter. Dazu nehme ich die Länge des Passwortes geteilt durch 100. Das Ergebnis wird anschließend mit dem Wert von $AllAmounts_array[$i] multipliziert. $i entspricht jeweils dem Wert von $AmountABC_percent, $AmountABCsm_percent, $AmountNR_percent oder $AmountSign_percent.

Die gesamt ermittelten Werte von $AllAmountsArray werden auf die entsprechenden $Amount*_numeric Variablen verteilt. Es kann sein das die Gesamtsumme nicht 100 erreicht. Dies kommt durch das Runden der Prozentangaben.

In der folgenden If-Schleife wir der Wert von $CountAmmount geprüft. Ist dieser nicht 100 wird auch hier wieder der Anteil von Großbuchstaben ($AmountABC_numeric) erhöht. Somit ist gewehrleistet, das die Passwortlänge in jedem Fall erreicht wird.

Anschließend wird das Random Objekt erzeugt und die Summen der einzelnen $Chars_* Array’s in $Chars_*_count Variablen gespeichert. Diese werden anschließend in der nächsten For-Schleife verwendet. Warum werden die Summen nochmals in extra Variablen gespeichert? Der Grund liegt hier in der Performance. Wenn der Wert $Variable.Count in der For-Schleife abgerufen wird, wird dieser jedes mal erneut ausgelesen. Das geht auf den Prozessor und verursacht mehr Last. Die Variable hingegen ist bereits gesetzt und im Speicher.

Nach diesen ganzem Vorgeplänkel kommt nun der eigentliche und spannende Teil, das Zusammenstellen des Passwortes. In der For-Schleife wird $i solange hochgezählt bis dieser die Länge von $PWDLength erreicht hat. In der Schleife selbst werden die einzelnen $Ammount*_numeric Werte jeweils mittels einer If-Bedingung runtergezählt solange diese größer oder gleich 0 sind. In der einzelnen If-Bedingung wird dann dem String $UserPasswort0 ein zufälliges Zeichen angehangen. Beispielsweise sieht bei einem 10 stelligen Passwort mit gleicher Verteilung der Prozentwerte (je 25%) die Variable $UserPasswort0 nach der For.-Schleife wie folgt aus: Vk7!Le0?AP.

Das ist natürlich noch nicht schön anzusehen, da es hier einen sichtbaren Algorithmus gibt. Deshalb wird anschließend das Ganze nochmal „gemixt“. Dazu wird der String $Userpassword0 in ein Array $UserPasswordArr übergeben mittels der Funktion .ToCharArray().

In einer For-Schleife vertausche ich einfach immer eine zufällige Stelle des Array mit einer anderen. Das geht solange bis $i gleich der Hälfte der Passwortlänge ist. Ein beliebiges Feld eines Array lässt sich unter PowerShell wie folgt füllen. $Array[2] =“Eintrag in 3.Feld des Array“. Um hier den Tausch der Variablen zu bewerkstelligen benötige ich eine Hilfsvariable $tmp. In der Hilfsvariable wird der erste Wert zwischengespeichert. Anschließend wird dieser mit dem zweiten Werten überschrieben. Der zweite Wert wird dann von der $tmp Variable überschrieben. So wurde Wert eins zu Wert zwei und umgekehrt.

Jetzt muss ich aus dem Array $UserPasswordArr wieder ein String machen. Hierzu nutze ich einfach eine Foreach-Schleife und hänge dem String $UserPasword die einzelnen Felder des Array an.

Anschließend folgt nur noch der Output. Hier wird zu erst das Passwort angezeigt, gefolgt von der Länge des Passwortes. Darunter wird noch die benötigte Zeit angeben die das Script gebraucht hat. Fertig 🙂

Weitere Features

Das Script werde ich noch als Funktion umschreiben damit die Angabe der Werte einfacher von der Hand gehen. Zudem möchte ich das Script mit einer GUI verstehen und als umgewandelte ausführbare Datei (EXE) erstellen. Sodass ein einfache Starten als Tool möglich ist. Diesen Vorgang werde ich natürlich auch hier wieder detailliert beschreiben.

Eines der größeren Schritte soll dann die Aufnahme in ein selbst erstelltes Modul werden. Das Modul soll dann mehrere praktische Scripte enthalten und stets erweitert werden. Hierzu werde ich dann eine eigene Reihe von Artikeln auf meinem Blog verfassen.

Beide Versionen habe ich auch in die DLs gepackt.

[wpfilebase tag=file id=7 /]

[wpfilebase tag=file id=8 /]

Das komplette Script

Hier nun das Script in seiner vollen Länge mit Header und Versionsverwaltung. Beispielausgaben des Scriptes stehen darunter.

Ausgabe des Script

Mit steigender Länge des Passwortes benötigt das Script entsprechend mehr Zeit. Das Script lässt sich garantiert noch etwas performanter gestalten, aber ich denke für ein Passwort mit 100 Stellen sind 39 ms ganz in Ordnung. Aus optischen Gründen habe ich die Passwörter in der Ausgabe als String in Kochkommas gestellt. Die Kochkommas werden in der normalen Ausgabe nicht angezeigt.

Viele Grüße

rewe

Ein Gedanke zu „PowerShell – 13.1 – Simpler Passwortgenerator Version 2“

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert