6

几周后,我将为我的计算机和信息安全课程做一个安全演示,在这个演示中,我将展示不同攻击(字典、彩虹和蛮力)的优缺点。我可以很好地执行字典和彩虹攻击,但我需要即时生成蛮力攻击。我需要找到一种算法,让我可以循环遍历字母、符号和数字的每个组合,直到达到一定的字符长度。

例如,对于 12 的字符长度,第一代和最后几代将是:

a
ab
abc
abcd
...
...
zzzzzzzzzzzx
zzzzzzzzzzzy
zzzzzzzzzzzz

但它也会使用数字和符号,所以我很难解释……但我想你明白了。只使用 ASCII 表中的符号就可以了。

我可以用一个 ASCII 函数来用一个计数器来做这件事,但我就是无法在脑海中解决它。如果有人可以提供一些源代码(我可能会使用 C#)甚至是一些伪代码,我可以从中编写一个函数,那就太好了。

先感谢您。:)

4

5 回答 5

10

递归函数将让您运行 ValidChars 的所有组合:

    int maxlength = 12;
    string ValidChars;
    private void Dive(string prefix, int level)
    {
        level += 1;
        foreach (char c in ValidChars)
        {
            Console.WriteLine(prefix + c);
            if (level < maxlength)
            {
                Dive(prefix + c, level);
            }
        }
    }

将一组有效字符分配给 ValidChars,即您想要 maxlength 的最大字符串长度,然后调用Dive("", 0);并离开。

于 2010-09-03T23:23:09.673 回答
4

您需要从一组有效字符中生成所有字符组合;我们称之为 set validChars。基本上,每组长度为 N 的组合是其validChars自身 N 次的笛卡尔积。使用 Linq 很容易做到这一点:

char[] validChars = ...;

var combinationsOfLength1 =
    from c1 in validChars
    select new[] { c1 };

var combinationsOfLength2 =
    from c1 in validChars
    from c2 in validChars
    select new[] { c1, c2 };

...

var combinationsOfLength12 =
    from c1 in validChars
    from c2 in validChars
    ...
    from c12 in validChars
    select new[] { c1, c2 ... c12 };

var allCombinations =
    combinationsOfLength1
    .Concat(combinationsOfLength2)
    ...
    .Concat(combinationsOfLength12);

显然,您不想为每个长度手动编写代码,特别是如果您事先不知道最大长度...

Eric Lippert 有一篇关于生成任意数量序列的笛卡尔积的文章。使用CartesianProduct文章提供的扩展方法,可以生成长度为N的所有组合如下:

var combinationsOfLengthN = Enumerable.Repeat(validChars, N).CartesianProduct();

由于您想要从长度 1 到 MAX 的所有组合,您可以执行以下操作:

var allCombinations = 
    Enumerable
        .Range(1, MAX)
        .SelectMany(N => Enumerable.Repeat(validChars, N).CartesianProduct());

allCombinations是一个IEnumerable<IEnumerable<char>>,如果你想得到一个字符串序列的结果,你只需要添加一个投影:

var allCombinations = 
    Enumerable
        .Range(1, MAX)
        .SelectMany(N => Enumerable.Repeat(validChars, N).CartesianProduct())
        .Select(combination => new string(combination.ToArray()));

请注意,它当然不是最有效的解决方案,但至少它简短易读......

于 2010-09-04T00:07:05.787 回答
1

你可以试试这个代码,它使用递归打印所有可能的字符串 0 到 stringsLenght 字符长度,由从 firstRangeChar 到 lastRangeChar 的所有字符组合组成。

class BruteWriter
{
    static void Main(string[] args)
    {
        var bw = new BruteWriter();
        bw.WriteBruteStrings("");
    }

    private void WriteBruteStrings(string prefix)
    {
        Console.WriteLine(prefix);
        if (prefix.Length == stringsLenght)
            return;

        for (char c = firstRangeChar; c <= lastRangeChar; c++)
            WriteBruteStrings(prefix + c);

    }

    char firstRangeChar='A';
    char lastRangeChar='z';
    int stringsLenght=10;


}

这看起来比@dthorpe 的解决方案更快。我使用以下代码比较了算法:

class BruteWriter
    {
        static void Main(string[] args)
        {
            var st = new Stopwatch();
            var bw = new BruteWriter();
            st.Start();
            bw.WriteBruteStrings("");
            Console.WriteLine("First method: " + st.ElapsedMilliseconds);

            for (char c = bw.firstRangeChar; c <= bw.lastRangeChar; c++)
                bw.ValidChars += c;

            st.Start();
            bw.Dive("", 0);
            Console.WriteLine("Second method: " + st.ElapsedMilliseconds);

            Console.ReadLine();


        }

        private void WriteBruteStrings(string prefix)
        {
            if (prefix.Length == stringsLenght)
                return;

            for (char c = firstRangeChar; c <= lastRangeChar; c++)
                WriteBruteStrings(prefix + c);

        }

        char firstRangeChar='A';
        char lastRangeChar='R';
        int stringsLenght=5;



        int maxlength = 5;
        string ValidChars;
        private void Dive(string prefix, int level)
        {
            level += 1;
            foreach (char c in ValidChars)
            {
                if (level <= maxlength)
                {
                    Dive(prefix + c, level);
                }
            }
        }
    }

而且,在我的电脑上,我得到了这些结果:

First method: 247
Second method: 910
于 2010-09-03T23:35:27.943 回答
0
public void BruteStrings(int maxlength)
{
   for(var i=1;i<i<=maxlength;i++)
      BruteStrings(Enumerable.Repeat((byte)0,i));

}

public void BruteStrings(byte[] bytes)
{
   Console.WriteLine(bytes
                       .Cast<char>()
                       .Aggregate(new StringBuilder(), 
                          (sb,c) => sb.Append(c))
                       .ToString());

   if(bytes.All(b=>b.MaxValue)) return;

   bytes.Increment();

   BruteStrings(bytes);
}

public static void Increment(this byte[] bytes)
{
   bytes.Last() += 1;

   if(bytes.Last == byte.MinValue)
   {
      var lastByte = bytes.Last()
      bytes = bytes.Take(bytes.Count() - 1).ToArray().Increment();
      bytes = bytes.Concat(new[]{lastByte});
   }
}
于 2010-09-04T00:56:42.397 回答
0

我做的另一种选择是返回一个字符串。

我不关心这个东西的性能,因为它不适合真实世界的场景。

private void BruteForcePass(int maxLength)
    {
        var tempPass = "";
        while (tempPass.Length <= maxLength)
        {
            tempPass = GetNextString(tempPass);//Use char from 32 to 256
            //Do what you want
        }
    }

    private string GetNextString(string initialString, int minChar= 32, int maxChar = 256)
    {
        char nextChar;
        if (initialString.Length == 0)
        {
            nextChar = (char)minChar;//the initialString Length will increase
        }
        else if (initialString.Last() == (char)maxChar)
        {
            nextChar = (char)minChar;
            var tempString = initialString.Substring(0, initialString.Length -1);//we need to increment the char just before the last one
            initialString = GetNextString(tempString, minChar, maxChar); 
        }
        else
        {
            nextChar = (char)(initialString.Last() + 1);//Get the lash Char and increment it;
            initialString= initialString.Remove(initialString.Length - 1);//Remove the last char.
        }
        return initialString + nextChar;
    }
于 2012-12-13T15:24:43.133 回答