So I was looking at http://codahale.com/how-to-safely-store-a-password/# and became curious how fast different hash could be bruteforced on a somewhat powerful desktop computer and was tempted to test it
Most of the algorithms I've seen though are single-threaded and it struck me that this would be a really interesting challenge in using c# 4.0 Parallel.net/Plinq extensions and concurrent structures (like ConcurrentBag and IProducerConsumer).
So my task is as follows, build the most efficient/performant bruteforce checker of a password of n-length and charset[x] using parallelization, ie generate all possible strings of a given charset and length until a match is found. Assume at least two cores and reasonable amount of ram
I'm going to give it a whirl myself, let the best man/woman win :)
EDIT
First attempt without comparing performance yet and limited scope and known password length
char[] chars = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
public long NrCombinations(int nrChars, int stringLength)
{
Func<long, int, long> power = null;
power = (i, p) => p == 1 ? i : i * power(i, p - 1);
return power(nrChars, stringLength);
}
public static bool StringArrayEquals(char[] a, char[] b)
{
if (a.Length != b.Length)
return false;
for (int i = 0; i < a.Length; i++)
{
if (!a[i].Equals(b[i]))
return false;
}
return true;
}
public char[] GenerateString(int i, int stringLength)
{
char[] current = new char[stringLength];
for (int i = 0; i < stringLength; i++)
{
double remainder = i % this.chars.Length;
i = i / this.chars.Length;
current[i] = this.chars[(int) remainder];
}
return current;
}
public bool IsMatch(int i, char[] password)
{
return StringArrayEquals(GenerateString(i, password.Length), password);
}
private int GetMatching(string passwordString)
{
开发者_运维技巧 char[] password = passwordString.ToArray();
int nrCombinations = (int)NrCombinations(this.chars.Length, password.Length);
return ParallelEnumerable.Range(0, nrCombinations).WithDegreeOfParallelism(10).FirstOrDefault(i => IsMatch(i, password));
}
Next Attempt
Using ParallelEnumerable wasnt to clever since it's restricted to int in size, you pretty soon need atleast long even though I doubt that will hold you for long with large passwords charsets. Guess you either have to go BigInt or start breaking it down somehow after that.
public long NrCombinations(int nrChars, int stringLength)
{
Func<long, int, long> power = null;
power = (i, p) => p == 1 ? i : i * power(i, p - 1);
return power(nrChars, stringLength);
}
public string GenerateString(long number, int sentenceLength)
{
char[] current = new char[sentenceLength];
for (int i = 0; i < sentenceLength; i++)
{
double remainder = number % this.chars.Length;
number = number / this.chars.Length;
current[i] = this.chars[(int) remainder];
}
return new string(current);
}
public bool IsMatch(string hash, long i, int passwordLength)
{
string generated = GenerateString(i, passwordLength);
string hashed = GetMasterHash(generated, this.site);
return string.Equals(hashed, hash);
}
private string GetMatching(string hash,int passwordLength)
{
string result = string.Empty;
int stringlength = passwordLength;
long nrCombinations = NrCombinations(this.chars.Length, stringlength);
long x = 0;
Parallel.For(0, nrCombinations, (i, loopState) =>
{
if (IsMatch(hash,i, passwordLength))
{
x = i;
loopState.Stop();
return;
}
});
if (x > 0)
{
result = this.GenerateString(x, passwordLength);
}
return result;
}
Why the NrCombinations
method and not just
long combinations = (long)Math.Pow(base, stringLength);
I would also recommend against int
for nrCombinations
because with only six characters with your base 36 alphabet you will get in trouble (36^6 > 2^31). Use long
. I don't think BigInteger
is needed because if you need that big numbers brute force will not be an option anyway.
I have this idea that it might be possible to speed up brute force by using a kind of De Bruijn sequence stream. Seems reasonable but I have to get back on that because I have no code to show right now.
精彩评论