找出一个可变长度的字符串?

Posted

技术标签:

【中文标题】找出一个可变长度的字符串?【英文标题】:Figure out a String of variable length? 【发布时间】:2011-08-25 22:02:47 【问题描述】:

我有一个字符串的 MD5 哈希,存储为 String。我正在写一个小程序,通过蛮力找出原始字符串。

我想遍历char 的一个子集。

下面的代码适用于String.length() == 0

我不知道如何编辑此代码以使用可变长度Strings。我觉得我在递归的正确轨道上,但不能再进一步了。

我有以下代码:

    public void attempt(String initial, String md5) 

    for (char c = ' '; c < '~'; ++c) 
        attempt = initial + Character.toString(c);
        generatedMd5 = generateMD5(attempt);
        System.out.println(attempt);
        if (hashesMatch(md5, generatedMd5)) 
            break;
         else attempt(attempt, md5);
    

注意:我应该提到这是针对 MD5 的学术研究。

【问题讨论】:

如果这是您的实际代码而不是示例,您需要在其中添加深度检查(否则您只会生成充满空格的字符串,直到您用完堆栈)并且您需要返回匹配成功,并在您的尝试调用中对此进行测试,以便您在找到匹配项时真正停止。但是您可能想研究尽可能多地优化 MD5 函数,或者以某种方式在许多 CPU 或 GPU 上并行运行散列 - 这是迄今为止您最慢的一步。除了奇怪的简单情况,您永远找不到这样的匹配项 - 这将花费太长时间。 请修复您显示的源代码,它不完整。 我修正了第一段的措辞 首先运行一些关于您需要运行的 MD5 检查数量的计算。粗略估计 MD5 需要多长时间 -> 惊讶于您的计算需要多长时间。 【参考方案1】:

您正在执行“Depth first”搜索(并且深度无限!),如果您不添加一些深度检查,这几乎肯定会失败(耗尽您的堆栈)。

应该可能更好可能想做一个Breadth first search:你的循环应该首先尝试所有导致添加字符的组合,然后才尝试递归调用每个增强字符串的方法。

在任何情况下,您都应该始终添加一些深度检查。

已编辑:三思而后行,我不太确定您是否应该先坚持深度。广度优先在这里仅适用于较小的深度和组合(字符范围)。一种可能的实现方式

  // Breadth first returns null if not found
  public String bruteforce(List<String> prefixes, String md5,int availdepth) 
    if(availabledepth<0) return null;
    List<String> newprefixes = new ArrayList<String>();
    for(String prefix : prefixes) 
        for (char c = ' '; c < '~'; ++c) 
          String attempt = prefix + Character.toString(c);
          generatedMd5 = generateMD5(attempt);
          if (hashesMatch(md5, generatedMd5)) 
            return attempt;
          newprefixes.add(attempt);
       
    
    // no success in this level go for next
    return bruteforce(newprefixes,md5,availddepth-1);
  


  // Depth first - returns null if not found
  public String bruteforce(String prefix, String md5,int availdepth) 
    if(availdepth <= 0) return null;
    for (char c = ' '; c < '~'; ++c) 
          String attempt = prefix + Character.toString(c);
          if (hashesMatch(md5, generateMD5(attempt))) 
            return attempt;
          String res = bruteforce(attempt, md5, availdepth-1);
          if(res != null) return res;
       
    return null;
  

【讨论】:

我不确定我是否理解其中的含义。我添加了 100 的深度检查,但最终得到了一长串 100 个空格。如何修改它以尝试:a、b、c、aa、ab、ac、ba... 等等? 不客气。但请记住,这具有随深度呈指数级增长的空间,它可能仅对小尺寸有效。在其他地方,采用原始(深度优先)方法- 适当注明。一个简单的 3 个字符的字符串需要 10 多秒。奇怪的是,空间的解决速度要快得多。这无疑是因为它们是 char 序列中的“第一” 我添加了一个深度呼吸实现 - 未经测试 深度优先的实现,奇怪的是,在“尝试”字符串上需要一个 .trim()(方法的第 7 行)【参考方案2】:

你们中的第一个不返回结果...

其次,您首先在无限空间上进行深度(它永远不会结束......)

public String attempt(String initial, String md5,int depth) 
    if(depth < 0)return null;//failed backtrack
    for (char c = ' '; c < '~'; ++c) 
        attempt = initial + Character.toString(c);
        generatedMd5 = generateMD5(attempt);
        System.out.println(attempt);
        if (hashesMatch(md5, generatedMd5)) 
            return attempt;//success
         else 
            String res = attempt(attempt, md5,depth-1);
            if(res!=null)return res;
        
    

这是一个有界深度优先,意味着它不会比深度更进一步递归(当它找不到任何东西时返回 null

以下可用于遍历整个空间,深度可达 10000

String attempt(String initial,String md5)
    for(int i = 5;i<10000;i++)
        String res = attempt(initial,md5,i);
        if(res!= null)return res;
    
    return null;//let's not go overboard on recursion

我在 10000 的递归上设置了一个最大大小,以使其在可预见的将来某个时候结束

【讨论】:

以上是关于找出一个可变长度的字符串?的主要内容,如果未能解决你的问题,请参考以下文章

创建一个可变长度的字符串,填充一个重复的字符

跨多行拆分可变长度分隔字符串(SQL)

可变长度前缀字符串的操作

使用python中的struct模块打包和解包可变长度数组/字符串

mysql - 如何确定存储可变字符串的字段的长度?

如何生成具有可变长度的随机字符串