From 3039a9af995a1bee639d9c02c707826e3fabf9f9 Mon Sep 17 00:00:00 2001 From: Manuel Kamper Date: Sun, 14 Apr 2019 21:22:05 +0200 Subject: [PATCH] added passwordgenerator --- Mk0.Tools.Password/Mk0.Tools.Password.csproj | 1 + Mk0.Tools.Password/PasswordGenerator.cs | 168 ++++++++++++++++++ Mk0.Tools.Password/Properties/AssemblyInfo.cs | 4 +- 3 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 Mk0.Tools.Password/PasswordGenerator.cs diff --git a/Mk0.Tools.Password/Mk0.Tools.Password.csproj b/Mk0.Tools.Password/Mk0.Tools.Password.csproj index 8572be2..1d1f05c 100644 --- a/Mk0.Tools.Password/Mk0.Tools.Password.csproj +++ b/Mk0.Tools.Password/Mk0.Tools.Password.csproj @@ -41,6 +41,7 @@ + diff --git a/Mk0.Tools.Password/PasswordGenerator.cs b/Mk0.Tools.Password/PasswordGenerator.cs new file mode 100644 index 0000000..52a635f --- /dev/null +++ b/Mk0.Tools.Password/PasswordGenerator.cs @@ -0,0 +1,168 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Mk0.Tools.Password +{ + public class PasswordGenerator + { + private int minLength = 8; + private int maxLength = 128; + private int maxAttempts = 10000; + + private const string LOWERCASE_CHARACTERS = "abcdefghijklmnopqrstuvwxyz"; + private const string UPPERCASE_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + private const string NUMERIC_CHARACTERS = "0123456789"; + private const string SPECIAL_CHARACTERS = @"!#$%&*@\"; + + private int length; + private bool lowercase; + private bool uppercase; + private bool numeric; + private bool specialchars; + + public PasswordGenerator() + { + length = 8; + lowercase = true; + uppercase = true; + numeric = true; + specialchars = true; + } + + public PasswordGenerator(int length) + { + this.length = length; + lowercase = true; + uppercase = true; + numeric = true; + specialchars = true; + } + + public PasswordGenerator(bool lowercase = true, bool uppercase = true, bool numeric = true, bool specialchars = true) + { + length = 8; + this.lowercase = lowercase; + this.uppercase = uppercase; + this.numeric = numeric; + this.specialchars = specialchars; + } + + public PasswordGenerator(int length, bool lowercase = true, bool uppercase = true, bool numeric = true, bool specialchars = true) + { + this.length = length; + this.lowercase = lowercase; + this.uppercase = uppercase; + this.numeric = numeric; + this.specialchars = specialchars; + } + + public string Next() + { + string password; + if (!LengthIsValid()) + + { + password = string.Format("Password length invalid. Must be between {0} and {1} characters long", minLength, maxLength); + } + else + { + int passwordAttempts = 0; + do + { + password = GenerateRandomPassword(); + passwordAttempts++; + } + while (passwordAttempts < maxAttempts && !PasswordIsValid(password)); + + password = PasswordIsValid(password) ? password : "Try again"; + } + + return password; + } + + private string BuildCharacterSet() + { + StringBuilder characterSet = new StringBuilder(); + if (lowercase) + { + characterSet.Append(LOWERCASE_CHARACTERS); + } + + if (uppercase) + { + characterSet.Append(UPPERCASE_CHARACTERS); + } + + if (numeric) + { + characterSet.Append(NUMERIC_CHARACTERS); + } + + if (specialchars) + { + characterSet.Append(SPECIAL_CHARACTERS); + } + + return characterSet.ToString(); + } + + private string GenerateRandomPassword() + { + const int MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS = 2; + char[] password = new char[length]; + + char[] characters = BuildCharacterSet().ToCharArray(); + char[] shuffledChars = Shuffle(characters.Select(x => x)).ToArray(); + + string shuffledCharacterSet = string.Join(null, shuffledChars); + int characterSetLength = shuffledCharacterSet.Length; + + Random random = new Random(); + for (int characterPosition = 0; characterPosition < length; characterPosition++) + { + password[characterPosition] = shuffledCharacterSet[random.Next(characterSetLength - 1)]; + + bool moreThanTwoIdenticalInARow = + characterPosition > MAXIMUM_IDENTICAL_CONSECUTIVE_CHARS + && password[characterPosition] == password[characterPosition - 1] + && password[characterPosition - 1] == password[characterPosition - 2]; + + if (moreThanTwoIdenticalInARow) + { + characterPosition--; + } + } + + return string.Join(null, password); + } + + private bool PasswordIsValid(string password) + { + const string REGEX_LOWERCASE = @"[a-z]"; + const string REGEX_UPPERCASE = @"[A-Z]"; + const string REGEX_NUMERIC = @"[\d]"; + const string REGEX_SPECIAL = @"([!#$%&*@\\])+"; + + bool lowerCaseIsValid = !lowercase || (lowercase && Regex.IsMatch(password, REGEX_LOWERCASE)); + bool upperCaseIsValid = !uppercase || (uppercase && Regex.IsMatch(password, REGEX_UPPERCASE)); + bool numericIsValid = !numeric || (numeric && Regex.IsMatch(password, REGEX_NUMERIC)); + bool specialIsValid = !specialchars || (specialchars && Regex.IsMatch(password, REGEX_SPECIAL)); + + return lowerCaseIsValid && upperCaseIsValid && numericIsValid && specialIsValid && LengthIsValid(); + } + + private bool LengthIsValid() + { + return length >= minLength && length <= maxLength; + } + + private IEnumerable Shuffle(IEnumerable items) + { + return from item in items orderby Guid.NewGuid() ascending select item; + } + } +} diff --git a/Mk0.Tools.Password/Properties/AssemblyInfo.cs b/Mk0.Tools.Password/Properties/AssemblyInfo.cs index 8aa3779..9289133 100644 --- a/Mk0.Tools.Password/Properties/AssemblyInfo.cs +++ b/Mk0.Tools.Password/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ using System.Runtime.InteropServices; // Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, // indem Sie "*" wie unten gezeigt eingeben: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.1.0.0")] +[assembly: AssemblyFileVersion("1.1.0.0")]