【问题标题】:Backing out data from an MD5 checksum从 MD5 校验和中备份数据
【发布时间】:2016-05-29 13:17:30
【问题描述】:

假设您有一个由 N 个 64 字节元素组成的数组计算得出的 MD5 和。我想用新元素替换源数组中任意索引处的元素。然后,我不想通过 MD5 函数重新运行它来重新计算 MD5 总和,而是想从结果中“减去”旧元素并将新数据“添加”到其中。

为了更清楚一点,这里有一些伪 Scala:

class Block {
  var summary: MD5Result

  // The key reason behind this question is that the elements might not be
  // loaded. With a large array, it can get expensive to load everything just to
  // update a single thing.
  var data: Array[Option[Element]]

  def replaceElement(block: Block, index: Integer, newElement: Element) = {
    // we can know the element that we're replacing
    val oldElement = block.data(index) match {
        case Some(x) => x
        case None    => loadData(index) // <- this is expensive
      }

    // update the MD5 using this magic function
    summary = replaceMD5(summary, index, oldElement, newElement)
  }
}

replaceMD5 可以实现吗?虽然所有迹象都表明“这正在破坏(弱)加密哈希”,但实际的 MD5 算法似乎支持这样做(但我可能遗漏了一些明显的东西)。

【问题讨论】:

  • TTBOMK MD5 计算严格按递增顺序处理字节。如果是这样,您可以在每个 64 字节单元之后记录 MD5 计算的中间(状态)值序列:然后如果 data[i] 发生更改,您可以从这一点重新开始 MD5 计算,即仅重新计算剩余的 ( n-i+1)*64 字节。如果变化是均匀随机的,这将平均节省一半的计算量。 TTBOMK 任何更改都会以不可预知的方式改变所有“下游”状态,因此我怀疑是否可以采取任何措施来缓解即将开始的更改。
  • 我相信如果不花更多时间然后重新运行 md5,这是不可能的。您能否说明为什么您认为实际的 MD5 算法似乎支持这样做
  • 问题不在于重新运行算法的计算时间——而是我必须执行昂贵的操作 (IO) 来确定哪些数据甚至可以提供给算法。
  • @SalvadorDali:显然 MD5 在设计时并没有考虑到这种疯狂的操作。我没有明确的理由相信这是可能的,但它似乎应该是,如果它的计算成本很高的话。如果不可能,那就这样吧。

标签: algorithm hash md5


【解决方案1】:

我想我更好地理解你现在想要做什么。我下面的解决方案没有假设任何关于 MD5 计算,但涉及 IO 和存储大量 MD5 哈希之间的权衡。它不是计算整个数据集的简单 MD5 哈希,而是计算一个不同的 MD5 哈希,但它应该具有相同的重要属性:对任何元素的任何更改(极大地)都会改变它。

  1. 一开始,决定块大小 b 使得
    • 您可以从磁盘(或您所说的任何 IO)中读取 b 值每次更改元素,并且
    • 您可以在内存中保留 2n/b 个 MD5 哈希值。
  2. 创建 MD5 哈希的二叉树。这棵树中的每个叶子都是大小为 b 块的 MD5 散列。每个内部节点都是其两个子节点的 MD5 哈希。我们将使用这棵树的根的哈希作为“MD5”哈希。
  3. 当元素 i 发生变化时,读取块 RoundDown(i/b) 中的 b 元素,为此计算新的 MD5 哈希,然后将更改传播到树上(这最多需要 log2(n) 步) .

【讨论】:

  • 虽然我喜欢你的回答,但这是我想要摆脱的确切事情 (en.wikipedia.org/wiki/Merkle_tree)。
  • 虽然我很喜欢你的评论,但它会真正帮助表明你已经尝试/考虑过这个想法并驳回了它(顺便说一句:为什么?)。跨度>
  • 公平点。简短的回答是,从使用的角度来看,不必处理跟踪这棵树的所有内部节点会容易得多(最低级别的块以万亿表示,所以即使分支因子很大,也没有办法将内部节点存储在内存中)。我宁愿在这里根本不使用 MD5(并使用允许我想要的操作的汇总系统),但也有一些外部因素迫使我这样做。我真的希望有一些神奇的数学可以用来解决整个世界:-)
  • 拥有数万亿个叶子,我想在内存中适应树所需的块大小将是巨大的 :( 我会问哈希是否需要始终是最新的 ,或者它是否真的足以定期更新 - 如果后者足够,那么您可以按索引对更新进行排序,将影响单个块的所有更新批处理在一起,并获得更多收益你的加载块降压。
  • 是的——这基本上就是我所在的位置。不幸的是,你总是在这里权衡块大小。块越大,获得的批处理就越多,但重新加载的成本就越高。我认为我必须处理的数据量属于“需要大量工程时间的难题”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-02
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
  • 2016-01-18
  • 2011-05-25
相关资源
最近更新 更多