Knocks/BackEnd/Knoks.Framework/Security/PasswordStrength.cs

137 lines
5.3 KiB
C#

using System.Text.RegularExpressions;
using System.Threading.Tasks;
//https://stephenhaunts.com/2014/01/31/checking-the-strength-of-a-password/
//https://github.com/danielmiessler/SecLists/tree/master/Passwords
namespace Knoks.Framework.Security
{
public sealed class PasswordStrength : IPasswordStrength
{
private readonly static string[] _weakPasswordList = { "welcome", "123456", "password", "12345678", "qwerty", "123456789", "12345", "1234", "111111", "1234567", "dragon", "123123", "baseball", "abc123", "football", "monkey", "letmein", "696969", "shadow", "master", "666666", "qwertyuiop", "123321", "mustang", "1234567890", "michael", "654321", "pussy", "superman", "1qaz2wsx", "7777777", "fuckyou", "121212", "000000", "qazwsx", "123qwe", "killer", "trustno1", "jordan", "jennifer", "zxcvbnm", "asdfgh", "hunter", "buster", "soccer", "harley", "batman", "andrew", "tigger", "sunshine", "iloveyou", "fuckme", "2000", "charlie", "robert", "thomas", "hockey", "ranger", "daniel", "starwars", "klaster", "112233", "george", "asshole", "computer", "michelle", "jessica", "pepper", "1111", "zxcvbn", "555555", "11111111", "131313", "freedom", "777777", "pass", "fuck", "maggie", "159753", "aaaaaa", "ginger", "princess", "joshua", "cheese", "amanda", "summer", "love", "ashley", "6969", "nicole", "chelsea", "biteme", "matthew", "access", "yankees", "987654321", "dallas", "austin", "thunder", "taylor", "matrix" };
public async Task<PasswordScore> CheckStrength(string password)
{
return await Task.Run(() =>
{
int score = 0;
if (string.IsNullOrEmpty(password))
{
return PasswordScore.Blank;
}
if (IsPasswordInWeakList(password))
{
return PasswordScore.Weak;
}
if (password.Length < 1)
{
return PasswordScore.Blank;
}
if (password.Length < 4)
{
return PasswordScore.VeryWeak;
}
if (password.Length >= 8)
{
score++;
}
if (password.Length >= 10)
{
score++;
}
if (Regex.Match(password, @"\d", RegexOptions.ECMAScript).Success)
{
score++;
}
if (Regex.Match(password, @"[a-z]", RegexOptions.ECMAScript).Success &&
Regex.Match(password, @"[A-Z]", RegexOptions.ECMAScript).Success)
{
score++;
}
if (Regex.Match(password, @"[!,@,#,$,%,^,&,*,?,_,~,-,£,(,)]", RegexOptions.ECMAScript).Success)
{
score++;
}
return (PasswordScore)score;
});
}
private static bool IsPasswordInWeakList(string password)
{
foreach (string weakPassword in _weakPasswordList)
{
if (string.Compare(password, weakPassword, System.StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
if (PerformSubstitutions(weakPassword, password))
{
return true;
}
}
return false;
}
private static bool PerformSubstitutions(string weakPassword, string password)
{
char[] vowels = { 'A', 'a', 'e', 'i', 'o', 's', 'S' };
char[] vowelSubstitution = { '4', '@', '3', '1', '0', '$', '5' };
ReplaceLettersWithSubStitutions(password, vowels, vowelSubstitution);
if (string.Compare(ReplaceLettersWithSubStitutions(weakPassword, vowels, vowelSubstitution), password, System.StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
char[] qwerty = { 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P' };
char[] qwertySubstitution = { '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' };
if (string.Compare(ReplaceLettersWithSubStitutions(weakPassword, qwerty, qwertySubstitution), password, System.StringComparison.OrdinalIgnoreCase) == 0)
{
return true;
}
return false;
}
private static string ReplaceLettersWithSubStitutions(string password, char[] original, char[] substitution)
{
string newPassword = string.Empty;
foreach (char c in password)
{
bool numberAdded = false;
for (int q = 0; q < original.Length; q++)
{
if (c == original[q])
{
newPassword = newPassword + substitution[q];
numberAdded = true;
break;
}
}
if (!numberAdded)
{
newPassword = newPassword + c;
}
}
return newPassword;
}
}
}