并行暴力算法
所以我正在查看 http://codahale.com/how-to- safe-store-a-password/# 并开始好奇在一台功能强大的台式计算机上暴力破解不同散列的速度有多快,并试图对其进行测试,
但我见过的大多数算法都是单线程的,并且它让我震惊的是,使用 c# 4.0 Parallel.net/Plinq 扩展和并发结构(如 ConcurrentBag 和 IProducerConsumer)将是一个非常有趣的挑战。
所以我的任务如下,使用并行化构建 n 长度和字符集 [x] 的密码的最有效/性能的暴力检查器,即生成给定字符集和长度的所有可能的字符串,直到找到匹配。假设至少有两个核心和合理数量的内存,
我要自己尝试一下,让最好的男人/女人获胜:)
编辑
第一次尝试,没有比较性能和有限的范围和已知的密码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));
}
下一次尝试
使用 ParallelEnumerable 并不聪明,因为它的大小仅限于 int,您很快就需要至少 long,尽管我怀疑这会让您在使用大型密码字符集时保持很长时间。我猜你要么必须使用 BigInt,要么在那之后开始以某种方式分解它。
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;
}
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为什么使用
NrCombinations
方法,而不仅仅是我还建议不要使用
int
来使用nrCombinations
,因为只有 6 个字符与您的基本 36 字母表一起使用麻烦(36^6>2^31)。使用长
。我认为不需要BigInteger
,因为如果你需要大数字,那么暴力破解无论如何都不是一个选择。我有这样的想法:通过使用一种 De Bruijn 序列流来加速暴力破解是可能的。看起来很合理,但我必须重新考虑这一点,因为我现在没有代码可以显示。
Why the
NrCombinations
method and not justI would also recommend against
int
fornrCombinations
because with only six characters with your base 36 alphabet you will get in trouble (36^6 > 2^31). Uselong
. I don't thinkBigInteger
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.