Parallel Brute-Force Algorithm

一曲冷凌霜 提交于 2019-12-21 22:39:28

问题


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;

    }

回答1:


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.



来源:https://stackoverflow.com/questions/4463379/parallel-brute-force-algorithm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!