using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Security.Cryptography; using DistributedPasswordCracker.Client.Models; using DistributedPasswordCracker.Client.Utilities; namespace DistributedPasswordCracker.Client { public class Cracking { /// /// The algorithm used for encryption. /// Must be exactly the same algorithm that was used to encrypt the passwords in the password file /// private readonly HashAlgorithm _messageDigest; public Cracking() { _messageDigest = new SHA1CryptoServiceProvider(); //_messageDigest = new MD5CryptoServiceProvider(); // seems to be same speed } /// /// Runs the password cracking algorithm /// public string RunCracking(string [] dictionary) { Stopwatch stopwatch = Stopwatch.StartNew(); List userInfos = PasswordFileHandler.ReadPasswordFile("passwords.txt"); //Console.WriteLine("passwd opeend"); List results = new List(); for(int i = 0; i < dictionary.Length; i++) { String dictionaryEntry = dictionary[i]; IEnumerable partialResult = CheckWordWithVariations(dictionaryEntry, userInfos); results.AddRange(partialResult); } stopwatch.Stop(); //Console.WriteLine(string.Join(", ", results)); //Console.WriteLine("Out of {0} password {1} was found ", userInfos.Count, results.Count); //Console.WriteLine(); //Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed); string output = ""; for(int i = 0; i < results.Count; i++) output += $"{results[i].UserName}:{results[i].Password}|"; return output; } /// /// Generates a lot of variations, encrypts each of the and compares it to all entries in the password file /// /// A single word from the dictionary /// List of (username, encrypted password) pairs from the password file /// A list of (username, readable password) pairs. The list might be empty private IEnumerable CheckWordWithVariations(String dictionaryEntry, List userInfos) { List result = new List(); //might be empty String possiblePassword = dictionaryEntry; IEnumerable partialResult = CheckSingleWord(userInfos, possiblePassword); result.AddRange(partialResult); String possiblePasswordUpperCase = dictionaryEntry.ToUpper(); IEnumerable partialResultUpperCase = CheckSingleWord(userInfos, possiblePasswordUpperCase); result.AddRange(partialResultUpperCase); String possiblePasswordCapitalized = StringUtilities.Capitalize(dictionaryEntry); IEnumerable partialResultCapitalized = CheckSingleWord(userInfos, possiblePasswordCapitalized); result.AddRange(partialResultCapitalized); String possiblePasswordReverse = StringUtilities.Reverse(dictionaryEntry); IEnumerable partialResultReverse = CheckSingleWord(userInfos, possiblePasswordReverse); result.AddRange(partialResultReverse); for (int i = 0; i < 100; i++) { String possiblePasswordEndDigit = dictionaryEntry + i; IEnumerable partialResultEndDigit = CheckSingleWord(userInfos, possiblePasswordEndDigit); result.AddRange(partialResultEndDigit); } for (int i = 0; i < 100; i++) { String possiblePasswordStartDigit = i + dictionaryEntry; IEnumerable partialResultStartDigit = CheckSingleWord(userInfos, possiblePasswordStartDigit); result.AddRange(partialResultStartDigit); } for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { String possiblePasswordStartEndDigit = i + dictionaryEntry + j; IEnumerable partialResultStartEndDigit = CheckSingleWord(userInfos, possiblePasswordStartEndDigit); result.AddRange(partialResultStartEndDigit); } } return result; } /// /// Checks a single word (or rather a variation of a word): Encrypts and compares to all entries in the password file /// /// /// List of (username, encrypted password) pairs from the password file /// A list of (username, readable password) pairs. The list might be empty private IEnumerable CheckSingleWord(IEnumerable userInfos, String possiblePassword) { char[] charArray = possiblePassword.ToCharArray(); byte[] passwordAsBytes = Array.ConvertAll(charArray, PasswordFileHandler.GetConverter()); byte[] encryptedPassword = _messageDigest.ComputeHash(passwordAsBytes); //string encryptedPasswordBase64 = System.Convert.ToBase64String(encryptedPassword); List results = new List(); foreach (UserInfo userInfo in userInfos) { if (CompareBytes(userInfo.EntryptedPassword, encryptedPassword)) //compares byte arrays { results.Add(new UserInfoClearText(userInfo.Username, possiblePassword)); Console.WriteLine(userInfo.Username + " " + possiblePassword); } } return results; } /// /// Compares to byte arrays. Encrypted words are byte arrays /// /// /// /// private static bool CompareBytes(IList firstArray, IList secondArray) { //if (secondArray == null) //{ // throw new ArgumentNullException("firstArray"); //} //if (secondArray == null) //{ // throw new ArgumentNullException("secondArray"); //} if (firstArray.Count != secondArray.Count) { return false; } for (int i = 0; i < firstArray.Count; i++) { if (firstArray[i] != secondArray[i]) return false; } return true; } } }