生成大型单词列表的算法

4

好的,我知道这听起来很糟糕,好像我要用它做不道德的事情,但你可以相信我,我不会这样做。

我正在为我的计算机和信息安全课程写一篇论文,我选择的主题是哈希方法。在我的论文中,我提到的一个要点是MD5仅是单向的,而破解MD5哈希的唯一方法是不断制作字符串并使用MD5函数,然后将其与你想要破解的哈希进行比较。

我想建立一个非常简单的模拟程序,以展示在我的论文旁边(我们会进行演示,这将是一个很棒的东西),所以我想设计一个算法,使每个可能的字符组合成为一个长度最多为8个字符的字符串。例如,输出将是:

a、b、c、...、aa、ab、ac、...、ba、bb、bc等等等等。

如果可能的话,它需要包括字母、数字和符号。

我已经部分完成了这个算法,但不幸的是我的编程技能还不够。如果有人能为此提供完整的算法,我将非常感激。

再次说明,如果你认为我是个骗子,认为我要用这个来进行黑客攻击,你不必留下答案。

谢谢。:)


3
那需要很长时间才能运行。 - John Boker
4
如果你不知道该怎么做,也许你就不应该通过这门课程。 - Azeem.Butt
嗨,约翰,我知道实际上破解MD5需要多长时间,时间比我提交论文的时间要长得多! :) 但是我正在考虑只对像“abc”这样的字符串进行哈希处理,这样不会花费太长时间来破解,但可以显示出需要多长时间以及这些方法是如何完成的。谢谢 :) - Andy
大约2720亿,实际上 :) - Peter
1
这个过程中 远远 最慢的部分将是显示信息。同时不要预先生成所有信息 - RAM 比您的硬盘小得多 - 任何能填满硬盘的东西早就填满了 RAM。 - Loren Pechtel
显示剩余6条评论
5个回答

6
在Python中,itertools.product 函数可以满足你的大部分需求,不过它只能重复某个元素一定次数,所以你需要进行1到8的循环迭代(这并不难)。简而言之:
import itertools
import string

# whatever you wish as alphabet (lower/upper, digits, punct, &c)
myalphabet = string.ascii_lowercase + string.ascii_digits

def prods(maxlen, alphabet=myalphabet):
  for i in range(1, maxlen+1):
    for s in itertools.product(alphabet, repeat=i):
      yield ''.join(s)

当然,对于长度为N且重复K次(在您的情况下为8)的字母表,这将产生N + N^2 + ... + N^K个可能性(当N=36且K=8时为2,901,713,047,668个可能性),但是,在朋友之间,这有什么关系呢!-)

3
实现这个功能,我可能会将整数编码为36进制(或更高,如果你想要符号)。
1 = 1 2 = 2 ... a = 10 b = 12 ...
然后你就有了一个数字,比如38,进行一些除法运算,例如:
38/36 = 1 余数 2 = 12在36进制中
然后只需运行一个for循环,到您想要编码的最大数字,输出您的编码数字。
只是为了好玩,我为你写了这个:http://pastebin.antiyes.com/index.php?id=327

啊!这确实是一种有趣的方法。我稍后会回来看看是否还有其他人想到了什么,但这似乎非常可行。谢谢 :) - Andy

1

“唯一破解MD5哈希的方法是生成每个可能的字符串并寻找冲突”这种说法是不正确的。实际上,如果您可以访问原始文件,则可以修改它以使其MD5与您可以创建的另一个文件的MD5匹配。这在infosec.edu的一篇论文中有所描述。

即使您无法修改原始文件,也存在MD5校验和的彩虹表,可用于生成冲突。

这些事实使MD5不适用于密码或加密,事实上,美国政府已禁止其继续用于安全应用程序。


不是这样的。您所描述的MD5漏洞是一种碰撞攻击,需要原始消息和冒充者消息都在攻击者的控制下。这使得MD5对某些应用程序不适用,但对其他应用程序很好。目前尚未发现MD5存在任何实际的预像攻击,如果您收到一个任意文件而不受您控制,并且希望创建一个与该任意文件的MD5哈希匹配的冒充者明文,则需要进行此类攻击。http://www.vpnc.org/hash.html - Jason S
如果你实际上是在说和我一样的话,那么你应该让它更清晰明了。(不管怎样,引用的论文显然已经不再在线上可用。) - Jason S
确实是我想表达的意思,如果没说清楚,请原谅。而且我已经修复了URL。 - Dour High Arch

0
如果您已经可以访问密码的哈希版本,那么MD5从一开始就是有问题的。话虽如此,当涉及到破解哈希值时,您可能最好使用彩虹表, 字典攻击社交工程而不是您的暴力方法。既然您要求一个生成所有值的算法,也许以下内容会有所裨益(C#):
using System;
using System.Text;

namespace PossibiltyIterator
{
  class Program
  {
    static readonly char[] Symbols = {
      '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', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
      'I', 'J', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
      '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '!', '@', '#', '$', '%', '^', '&', 
      '*', '(', ')', '-', '_', '+', '=', '/', '\\', '[', ']', '{', '}', ';', ':', '\'', '"', 
      ',', '.', '<', '>', '?', '`', '~'
    };

    const int MaxLength = 8;

    static void BuildWord(int currentLength, int desiredLength, char[] word)
    {
      if (currentLength == desiredLength)
      {
        Console.WriteLine(word);
      }
      else
      {
        for (int value = 0; value < Symbols.Length; ++value)
        {
          word[currentLength] = Symbols[value];
          BuildWord(currentLength + 1, desiredLength, word);
        }
      }
    }

    static void Main(String[] args)
    {
      double totalValues = (Math.Pow(Symbols.Length, MaxLength + 1) - Symbols.Length)/(Symbols.Length - 1);
      Console.WriteLine("Warning! You are about to print: {0} values", totalValues);
      Console.WriteLine("Press any key to continue...");
      Console.ReadKey(true /* intercept */);

      for (int desiredLength = 1; desiredLength <= MaxLength; ++desiredLength)
      {
        BuildWord(0 /* currentLength */, desiredLength, new char[MaxLength]);
      }
    }

  }
}

说实话,这可以进一步优化。因为它首先构建所有长度为1的“单词”,然后在构建长度为2的“单词”时再次执行该操作。更明智的做法是先构建长度为MaxLength的“单词”,然后截去一个字母以构建长度为MaxLength-1的“单词”。
以下是优化版本...请注意,它不会按照最初请求的顺序返回单词。
using System;
using System.Text;

namespace PossibiltyIterator
{
  class Program
  {
    static readonly char[] Symbols = {
      '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', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
      'I', 'J', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 
      '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '!', '@', '#', '$', '%', '^', '&', 
      '*', '(', ')', '-', '_', '+', '=', '/', '\\', '[', ']', '{', '}', ';', ':', '\'', '"', 
      ',', '.', '<', '>', '?', '`', '~'
    };

    const int MaxLength = 8;

    static void BuildWord(int currentLength, int desiredLength, char[] word)
    {
      if (currentLength != desiredLength)
      {
        for (int value = 0; value < Symbols.Length; ++value)
        {
          word[currentLength] = Symbols[value];
          BuildWord(currentLength + 1, desiredLength, word);
        }
        word[currentLength] = '\0';
      }

      Console.WriteLine(word);
    }

    static void Main(String[] args)
    {
      double totalValues = (Math.Pow(Symbols.Length, MaxLength + 1) - Symbols.Length)/(Symbols.Length - 1);
      char[] word = new char[MaxLength];

      Console.WriteLine("Warning! You are about to print: {0} values", totalValues);
      Console.WriteLine("Press any key to continue...");
      Console.ReadKey(true /* intercept */);

      BuildWord(0 /* currentLength */, MaxLength, new char[MaxLength]);
    }

  }
}

递归栈的深度不应该超过MaxLength(也许是MaxLength+1),所以这种情况很少见。 - Rob Rolnick
你关于“MD5本来就是有问题的”这一评论是不正确的。对MD5的攻击是碰撞攻击,而不是预像攻击,并且需要攻击者创建两个明文文档。请参见您引用的网页的“漏洞分析”的第一段,或参见http://vpnc.org/hash.html。 - Jason S
我坚持我所说的话,特别是考虑到 @Dour High Arch 发布的内容。 “如果你有原始文件的访问权限,就可以修改它,使其MD5与任意文件的MD5匹配。这在infosec.edu的一篇论文中有描述。” - Rob Rolnick

0
为了完成这篇帖子,我们提供一个Java示例,它将打印出仅使用0-9和a-z字符的所有可能字符组合的Base64编码MD5。
MessageDigest digest = MessageDigest.getInstance("MD5");
int i = 0;
while (true)
{
    String raw = Integer.toString(i, Character.MAX_RADIX);
    byte[] md5 = digest.digest(raw.getBytes());
    String base64 = new BigInteger(1, md5).toString(16);
    System.out.println(raw + " = " + base64);
    i++;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接