Dieser Artikel ist Teil des Magazins 'Access im Unternehmen', Ausgabe 1.
Kennwörter generieren
Für den einen oder anderen Zweck möchten Sie vielleicht Kennwörter generieren oder in einer Benutzeroberfläche die Möglichkeit zum Generieren von Kennwörtern anbieten. Wenn Sie etwa Benutzer zu einer Benutzerverwaltung hinzufügen, sollten Sie ein initiales Kennwort definieren, das der Benutzer dann bei der ersten Anmeldung ändert. Das Generieren von Kennwörtern wird allerdings umso komplizierter, je mehr Anforderungen es gibt. Einfach nur ein paar Zeichen zufällig auszuwählen, ist noch einfach, aber wenn es Bedingungen gibt, wie sie in sensiblen Umgebungen vorherrschen, soll ein Kennwort beispielsweise mindestens einen Kleinbuchstaben, einen Großbuchstaben, eine Zahl und ein Sonderzeichen enthalten. Diese Anforderungen wollen wir in der hier vorgestellten Funktion natürlich auch unterstützen.
Kennwort mit bestimmter Zeichenanzahl
Die einfachste Variante ermittelt einfach ein Kennwort mit beliebigen Zeichen aus einem bestimmten Zeichenpool, wobei wir mit dem einzigen Parameter der Funktion namens KennwortGenerierenEinfach die Anzahl der Zeichen angeben (siehe Listing 1).
Public Function KennwortGenerierenEinfach(intLaenge As Integer)
Const strZeichen As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!""§$%&()[]{}?**#:;,.-+<>"
Dim strKennwort As String
Dim i As Integer
Randomize
For i = 1 To intLaenge
strKennwort = strKennwort & Mid(strZeichen, Fix(Len(strZeichen) * Rnd) + 1, 1)
Next
KennwortGenerierenEinfach = strKennwort
End Function
Listing 1: Generieren eines einfachen Kennworts
Die Funktion definiert eine Konstante, die alle vorgesehenen Zeichen enthält – in diesem Fall alle Großbuchstaben, alle Kleinbuchstaben, alle Zahlen und einige Sonderzeichen:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!""§$%&()[]{}?**#:;,.-+<>
Nach der Definition der beiden übrigen Variablen strKennwort zum Speichern des zusammengesetzten Kennworts und i als Laufvariable der For Next-Schleife initialisiert die Funktion mit der Randomize-Funktion den Zufallszahlengenerator.
Die Rnd-Funktion, die eine Zufallszahl ermittelt, liefert nämlich sonst nach jedem neuen Start der Access-Anwendung die gleichen Ergebnisse. Sie können das ausprobieren, indem Sie im Direktbereich die Rnd-Funktion wie folgt aufrufen:
Debug.Print Rnd()
0,7055475
Nach dem Schließen und erneutem Öffnen der Anwendung erhalten Sie mit dem Aufruf der Rnd()-Funktion auch das gleiche Ergebnis. Wenn Sie jedoch zuvor einmal die Randomize-Anweisung aufrufen, wird die Rnd()-Funktion auf Basis der Timer()-Funktion initialisiert und liefert somit immer andere Werte.
In der For...Next-Schleife durchlaufen wir die Zahlen von 1 bis zu der mit dem Parameter intLaenge angegebenen Zeichenzahl. In der einzigen Anweisung innerhalb der Schleife fügen wir der Variablen strKennwort jeweils ein zufällig aus der Konstanten strZeichen ausgewähltes Zeichen aus. Damit die Funktion Rnd() auch genau einen der Werte von 1 bis 87 liefert, was dem ersten und dem letzten Zeichen der Konstanten strZeichen entspricht, multiplizieren wir das Ergebnis der Rnd()-Funktion, das immer einen Wert zwischen 0 und 1 liefert, mit der Anzahl der Zeichen, runden das Ergebnis und addieren dann den Wert 1 hinzu. Die Mid-Funktion ermittelt dann genau den Wert mit der angegebenen Position aus der Zeichenkette strZeichen.
Kennwort mit bestimmten Anforderungen
Nun bauen wir eine weitere, etwas leistungsfähigere Variante der Funktion. Diese erhält vier weitere Parameter mit dem Datentyp Boolean, die wie folgt heißen:
- bolGrossbuchstaben: Gibt an, ob das Kennwort Großbuchstaben enthalten soll.
- bolKleinbuchstaben: Gibt an, ob das Kennwort Kleinbuchstaben enthalten soll.
- bolZahlen: Gibt an, ob das Kennwort Zahlen enthalten soll.
- bolSonderzeichen: Gibt an, ob das Kennwort Sonderzeichen enthalten soll.
Die vier Parameter legen also fest, aus welchen Zeichen das Kennwort bestehen soll.
Abhängig von den Angaben beim Aufruf wird die Ermittlung des Kennwort etwas aufwendiger, denn: Wir wollen nicht etwa die verschiedenen angeforderten Zeichen an einer bestimmten Stelle zurückgeben.
Das wäre einfach: Dann könnten wir zu Beginn einen Großbuchstaben wählen, dann einen Kleinbuchstaben, eine Zahl und schließlich ein Sonderzeichen und den Rest der angeforderten Zeichen für das Kennwort mit beliebigen Zeichen.
Die angeforderten Elemente, also Groß- und Kleinbuchstaben, Zahlen und Sonderzeichen, sollen in beliebiger Reihenfolge im Kennwort auftauchen. Das in einen Algorithmus zu fassen, ist mit etwas Denkarbeit verbunden.
Wir haben uns für den folgenden Ansatz entschieden: Wir starten mit einer Zeichenfolge als Kennwort, die ausschließlich Leerzeichen enthält. Dann prüfen wir die vier Boolean-Parameter und fügen an zufällig ausgewählte Stellen die geforderten Zeichen hinzu. Schließlich füllen wir die noch leeren Stellen mit Zeichen aus dem kompletten Pool auf.
Den Ansatz finden Sie in der Funktion KennwortGenerieren, deren ersten Teil wir in Listing 2 abgebildet haben. Hier finden Sie zunächst die Parameterliste, die aus der Anzahl der gewünschten Zeichen und den vier bereits beschriebenen Parametern besteht. Alle Parameter sind optional und erhalten den Wert True, wenn sie beim Aufruf nicht angegeben werden.
Public Function KennwortGenerieren(intLaenge As Integer, Optional bolGrossbuchstaben As Boolean = True, _
Optional bolKleinbuchstaben As Boolean = True, Optional bolZahlen As Boolean = True, _
Optional bolSonderzeichen As Boolean = True)
Const strGrossbuchstaben As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Const strKleinbuchstaben As String = "abcdefghijklmnopqrstuvwxyz"
Const strZahlen As String = "0123456789"
Const strSonderzeichen As String = "!""§$%&()[]{}?**#:;,.-+<>"
Dim strZeichen As String
Dim strKennwort As String
Dim intPositionZufall As Integer
Dim strZeichenZufall As String
Dim i As Integer
Dim intZeichen As Integer
intZeichen = Abs(bolGrossbuchstaben) + Abs(bolKleinbuchstaben) + Abs(bolZahlen) + Abs(bolSonderzeichen)
If intLaenge < intZeichen Then
MsgBox "Die Länge muss mindestens " & intZeichen & " Zeichen betragen."
Exit Function
End If
strKennwort = Space(intLaenge)
Randomize
If bolGrossbuchstaben = True Then
intPositionZufall = Fix(intLaenge * Rnd) + 1
strZeichenZufall = Mid(strGrossbuchstaben, Fix(Len(strGrossbuchstaben) * Rnd) + 1, 1)
strKennwort = Left(strKennwort, intPositionZufall - 1) & strZeichenZufall & Mid(strKennwort, intPositionZufall + 1)
strZeichen = strZeichen & strGrossbuchstaben
End If
Do While bolKleinbuchstaben = True
intPositionZufall = Fix(intLaenge * Rnd) + 1
If Mid(strKennwort, intPositionZufall, 1) = " " Then
strZeichenZufall = Mid(strKleinbuchstaben, Fix(Len(strKleinbuchstaben) * Rnd) + 1, 1)
strKennwort = Left(strKennwort, intPositionZufall - 1) & strZeichenZufall & Mid(strKennwort, _
intPositionZufall + 1)
bolKleinbuchstaben = False
strZeichen = strZeichen & strKleinbuchstaben
End If
Loop
Do While bolZahlen = True
intPositionZufall = Fix(intLaenge * Rnd) + 1
If Mid(strKennwort, intPositionZufall, 1) = " " Then
strZeichenZufall = Mid(strZahlen, Fix(Len(strZahlen) * Rnd) + 1, 1)
strKennwort = Left(strKennwort, intPositionZufall - 1) & strZeichenZufall & Mid(strKennwort, _
intPositionZufall + 1)
bolZahlen = False
strZeichen = strZeichen & strZahlen
End If
Loop
Listing 2: Funktion KennwortGenerieren, Teil 1
Die Liste der möglichen Zeichen geben wir hier nicht als einzelne Konstante an, sondern wir deklarieren vier verschiedene Konstanten, von denen jede die Zeichen eines bestimmten Typs aufnimmt – also Großbuchstaben, Kleinbuchstaben, Zahlen und Sonderzeichen.
Bevor die Funktion die eigentliche Aufgabe erledigt, prüft sie, ob die Anzahl der Zeichen für das Kennwort mindestens so groß ist wie die Anzahl der gewählten Optionen für die Pflichtzeichen wie Großbuchstaben et cetera. Anderenfalls bricht die Funktion mit einer Meldung ab.
Dann füllt die Funktion das Kennwort in der Variablen strKennwort über die Space-Funktion mit Leerzeichen, und zwar entsprechend der im Parameter intLaenge angegebenen Anzahl. Die Randomize-Anweisung initialisiert wieder die Rnd()-Funktion. Danach prüft die Funktion, ob dem Kennwort Großbuchstaben hinzugefügt werden sollen. Das ist der Fall, wenn der Parameter bolGrossbuchstaben den Wert True hat. In diesem Fall ermittelt die Funktion per Rnd-Funktion eine Position im Kennwort (in intPositionZufall) sowie ebenfalls mit der Rnd-Funktion eines der Element der Konstanten strGrossbuchstaben und somit den einzufügenden Großbuchstaben (landet in strZeichenZufall). Das Kennwort wird nun neu zusammengesetzt aus drei Zeichenketten:
- den Zeichen bis zur ermittelten Position aus intPositionZufall, die wir mit der Left-Funktion ermitteln,
- dem Zufallszeichen aus strZeichenZufall und
- den Zeichen hinter der ermittelten Position ais intPositionZufall.
Wenn wir also für intLaenge den Wert 10 übergeben haben und bolGrossbuchstaben den Wert True hat, erhalten wir etwa für intPositionZufall den Wert 5 und für strZeichenZufall den Wert B.
Unser Kennwort besteht danach also aus vier Leerzeichen, dem Buchstaben B und weiteren fünf Leerzeichen.
Der letzte Schritt in dieser If...Then-Bedingung überträgt den Inhalt der Konstanten strGrossbuchstaben in die Variable strZeichen. Diese verwenden wir später, wenn wir die noch leeren Stellen des Kennworts mit den zulässigen Zeichen auffüllen wollen. In diesem Fall hatte bolGrossbuchstaben den Wert True, also darf auch mehr als ein Großbuchstabe im Kennwort vorkommen.
Danach kümmern wir uns um den Parameter bolKleinbuchstaben. Hat dieser den Wert True, soll das Kennwort mindestens einen Kleinbuchstaben enthalten.
Die Aufgabe, eine geeignete Position zum Einfügen des Kleinbuchstabens zu finden, ist etwas schwieriger als beim Finden der Position für den Großbuchstaben: Während uns bei diesem Schritt noch ein komplett leeres, lediglich aus Leerzeichen bestehendes Kennwort vorlag, in das wir an einer beliebigen Stelle den ersten Großbuchstaben einsetzen konnten, ist nun schon eine Stelle mit dem Großbuchstaben besetzt.
Das müssen wir bei der Ermittlung der Position für den Kleinbuchstaben berücksichtigen. Dabei verwenden wir eine Do While-Schleife, die wir solange durchlaufen, bis wir eine Position im Kennwort gefunden haben, die ein Leerzeichen enthält. Als Bedingung für das Fortführen der Do While-Schleife verwenden wir den Wert von bolGrossbuchstaben. Das ist deshalb praktisch, weil dieser Parameter direkt angibt, ob wir überhaupt einen Kleinbuchstaben im Kennwort benötigen.
Falls der Aufruf den Wert False enthielt, wird diese Schleife gar nicht erst durchlaufen. Anderenfalls jedoch starten wir in die Schleife, indem wir eine neue Zufallsposition ermitteln und diese in der Variablen intPositionZufall speichern.
Danach prüfen wir in einer If...Then-Bedingung, ob die Position des Kennworts, die der Position aus intPositionZufall entspricht, noch ein Leerzeichen enthält. Falls nicht, endet der erste Durchlauf der Do While-Schleife und diese wird erneut durchlaufen. Das geschieht solange, bis wir zufällig eine Position mit einem Leerzeichen im Kennwort aus strKennwort entdecken.
Ist das schließlich der Fall, ermitteln wir einen der Kleinbuchstaben aus der Konstanten strKleinbuchstaben und speichern diesen in der Variablen strZeichenZufall. Dann fügen wir dieses Zeichen an der gewünschten Stelle im Kennwort ein, indem wir wieder den Teil des Kennworts bis zur ermittelten Position, den zufällig ermittelten Kleinbuchstaben und den Teil des Kennworts hinter der ermittelten Position zusammensetzen.
Angenommen, wir hätten als Position den Wert 7 und als Kleinbuchstaben das Zeichen c ermittelt, würde unser Kennwort also nun etwa so aussehen (die Unterstriche dienen als Platzhalter für das Leerzeichen):
____B_c___
Auch hier fügen wir, wenn bolKleinbuchstaben den Wert True hat und wir einen Kleinbuchstaben in das Kennwort eingefügt haben, noch den Inhalt der Konstanten strKleinbuchstaben zur Variablen strZeichen hinzu, die später die restlichen Zeichen beisteuert.
Danach geht es auf ähnliche Weise für die Zahlen weiter. Wir durchlaufen wieder eine Do While-Schleife, bis wir eine Position gefunden haben, die noch ein Leerzeichen enthält und fügen dann eine zufällige Zahl an der passenden Stelle ein. Die Zeichenkette strZeichen wird dann um den Inhalt der Variablen strZahlen erweitert.
Unser Kennwort könnte nun etwa so aussehen:
9___B_c___
Und auf die gleiche Art fügen wir dem Kennwort noch ein Sonderzeichen hinzu, falls bolSonderzeichen den Wert True hat. (siehe Listing 3) Die Sonderzeichen aus strSonderzeichen landen in diesem Fall in der Variablen strZeichen. Danach lautet unser Kennwort etwa so:
...Fortsetzung
Do While bolSonderzeichen = True
intPositionZufall = Fix(intLaenge * Rnd) + 1
strZeichenZufall = Mid(strSonderzeichen, Fix(Len(strSonderzeichen) * Rnd) + 1, 1)
If Mid(strKennwort, intPositionZufall, 1) = " " Then
strKennwort = Left(strKennwort, intPositionZufall - 1) & strZeichenZufall & Mid(strKennwort, _
intPositionZufall + 1)
bolSonderzeichen = False
strZeichen = strZeichen & strSonderzeichen
End If
Loop
For i = 1 To intLaenge
If Mid(strKennwort, i, 1) = " " Then
strZeichenZufall = Mid(strZeichen, Fix(Len(strZeichen) * Rnd) + 1, 1)
strKennwort = Left(strKennwort, i - 1) & strZeichenZufall & Mid(strKennwort, i + 1)
End If
Next
KennwortGenerieren = strKennwort
End Function
Listing 3: Funktion KennwortGenerieren, Teil 2
9___B_c__%
Nachdem wir von allen gewünschten Zeichentypen jeweils ein Zeichen im Kennwort untergebracht haben, durchlaufen wir in einer For...Next-Schleife noch einmal alle Positionen und ersetzen diejenigen, die noch ein Leerzeichen enthalten, durch ein zufällig ausgewähltes Element der in strZeichen zusammengestellten zulässigen Zeichen.
Schließlich liefern wir das so zusammengestellte Kennwort an die aufrufende Routine zurück.