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 List RunCracking(string [] dictionary)
{
Stopwatch stopwatch = Stopwatch.StartNew();
List userInfos =
PasswordFileHandler.ReadPasswordFile("passwords.txt");
Console.WriteLine("passwd opeend");
List result = new List();
for(int i = 0; i < dictionary.Length; i++)
{
String dictionaryEntry = dictionary[i];
IEnumerable partialResult = CheckWordWithVariations(dictionaryEntry, userInfos);
result.AddRange(partialResult);
}
stopwatch.Stop();
Console.WriteLine(string.Join(", ", result));
Console.WriteLine("Out of {0} password {1} was found ", userInfos.Count, result.Count);
Console.WriteLine();
Console.WriteLine("Time elapsed: {0}", stopwatch.Elapsed);
return result;
}
///
/// 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;
}
}
}