Параллельный алгоритм грубой силы - PullRequest
2 голосов
/ 16 декабря 2010

Итак, я посмотрел на http://codahale.com/how-to-safely-store-a-password/# и мне стало любопытно, как быстро можно обрабатывать различные хэши на довольно мощном настольном компьютере, и я испытал желание протестировать его

Большинство алгоритмов, которые я видел, являются однопоточными, и меня поразило, что это будет действительно интересной проблемой при использовании расширений Parallel.net/Plinq и параллельных структур c # 4.0 (таких как ConcurrentBag и IProducerConsumer).

Итак, моя задача заключается в следующем: создать наиболее эффективный / эффективный инструмент проверки bruteforce для пароля n-длины и набора символов [x], используя распараллеливание, то есть генерировать все возможные строки заданного набора символов и длины, пока не будет найдено совпадение. Предположим, по крайней мере, два ядра и разумное количество оперативной памяти

Я собираюсь сделать это сам, пусть победит лучший мужчина / женщина :) 1009 *

РЕДАКТИРОВАТЬ

Первая попытка без сравнения производительности, ограниченной области действия и известной длины пароля

    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, довольно скоро вам понадобится хотя бы долго, хотя я сомневаюсь, что это продержит вас надолго с кодировками больших паролей. Думаю, вам нужно либо пойти на 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;

    }

1 Ответ

0 голосов
/ 17 декабря 2010

Почему метод NrCombinations, а не просто

long combinations = (long)Math.Pow(base, stringLength);

Я бы также порекомендовал против int для nrCombinations, потому что только с шестью символами с вашим базовым 36 алфавитом у вас будут проблемы (36 ^ 6> 2 ^ 31). Используйте long. Я не думаю, что BigInteger необходим, потому что, если вам нужны эти большие числа, грубая сила в любом случае не подойдет.

У меня есть идея, что можно было бы ускорить грубую силу, используя своего рода поток последовательности де Брюйна. Кажется разумным, но я должен вернуться к этому, потому что у меня нет кода, чтобы показать прямо сейчас.

...