【问题标题】:How does SHA generate unique codes for big files in gitSHA如何为git中的大文件生成唯一代码
【发布时间】:2016-04-20 12:59:18
【问题描述】:

使用 Git 我不明白如何使用 SHA 生成一个 40 位十六进制数字代码,然后可以将其映射到任何可能长达数百行的文件。

按照我的想法,假设字符串'1' -> 00...01,字符串'2' -> 00..02,字符串'a34ed..fc' -> a34ed ..fc 等,因此哈希映射会自行返回,那么很明显所有哈希码都会很快用完,并且任何 41 个字符长的字符串都将重用其中一个代码。

我也知道 SHA 不保证它永远是唯一的,但我不知道它是如何接近有用的。

【问题讨论】:

  • 如果没有用,git 就不会工作。但显然确实如此。
  • 是的,如果您的存储库中有 2^160 个文件,那么 SHA 哈希将不再起作用。
  • 其实由于birthday paradox,问题会从2^80文件开始。这仍然比我们世界的任何物理限制都重要。
  • 我以为是文件的内容被散列了,文件的数量无关紧要?使用我的示例,包含一个 41 个字符串的单个文件不能被唯一地散列权。
  • 相关:schneier.com/blog/archives/2015/10/sha-1_freestart.html 第一个记录在案的 SHA-1 近乎碰撞花了 10 天时间在专门用于该任务的 64-GPU 集群上发生。发生在您的 git 存储库中。您多次赢得强力球彩票的几率要高得多。

标签: git sha


【解决方案1】:

SHA-1 哈希的长度为 160 位。这给了你 2160,或者正好

1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976

可能的哈希值。

假设哈希值或多或少是不可预测的,那么两个文件意外具有相同哈希值的可能性微乎其微,以至于根本不值得担心。

引用 Scott Chacon 的书"Pro Git"

但是,您应该意识到这不太可能发生 情景是。 SHA-1 摘要为 20 字节或 160 位。的数量 需要随机散列的对象以确保单个对象的概率为 50% 碰撞大约是 280

...

下面是一个示例,让您了解如何获得 SHA-1 冲突。如果地球上所有 65 亿人都在编程, 每一秒,每个人都在生成等价的代码 整个 Linux 内核历史(100 万个 Git 对象)和推送 将它放到一个巨大的 Git 存储库中,这需要 5 年的时间 存储库包含足够多的对象以有 50% 的概率 单个 SHA-1 对象冲突。存在更高的概率,每个 您的编程团队成员将被狼袭击并杀死 在同一晚发生无关事件。

确实必须有两个 21 字节的文件具有相同的 SHA-1 哈希(因为有 2168 个这样的文件并且只有 2160 个可能的 SHA -1 哈希)。 从未发现过此类文件。

更新:截至 2017 年 2 月,已生成两个具有相同 SHA-1 校验和的不同 PDF 文件,使用的技术比暴力攻击快 100,000 倍以上。详情在这里:https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html

Linux Torvalds(Git 的作者)已在此处发布(初步)回复:http://marc.info/?l=git&m=148787047422954

查看 cmets,似乎 OP 最初的误解是假设 SHA-1 哈希可用于确定文件的内容。它不能。 Git 使用 SHA-1 来构造文件或其他对象的 name。该文件本身存储在.git/objects 目录下的某个位置。例如,具有哈希的文件

ff5a5eff8c90da934937165c9d0e9f96f9ecaf75

可能存储在

.git/objects/ff/5a5eff8c90da934937165c9d0e9f96f9ecaf75

-- 并且该文件可以任意大。 (当然没那么简单;git 使用了很多技巧来组合相似的文件并以其他方式压缩数据。)感谢 Patrick Schlüter 的评论。

【讨论】:

  • 但是如果我的仓库包含所有文件怎么办? - 美国国家安全局
  • @MikeCovington:没有。
  • 是的,我知道这有很多可能性,但我仍然不明白我给出的示例如何仅用 40 个字符就没有用完所有可能性。我在这里缺少什么?
  • @user2802557:这是一种单向转换;您无法从 20 字节校验和中取回原始文件。两个任意文件的哈希值不是 100% 肯定是不同的 - 但它们几乎 100% 肯定是唯一的。如果你在一个 repo 中有一百万个文件,几乎可以肯定它们都有不同的 SHA-1 哈希值。这足以让它发挥作用。
  • 它没有。对象本身使用 zlib 压缩,其内容的 sha1 被计算并用作文件名。前 2 个十六进制数字作为目录,后 38 个数字作为文件名。如果您查看 .git/objects ,您可以清楚地看到文件不是 40 字节大小。
【解决方案2】:

事实上,我所说的“安全边际”决定了你可以存储多少对象。

广泛引用的“大约 280”数字是您有大约 50% 的哈希冲突机会的点。为了将机会保持在大约 1/1018 以下,存储库中不同对象的数量不应超过大约 1.7 万亿 (1.71x1015)。

(我为我正在写的一本书做了一些数学运算;我还没有让真正的数学家检查它,但是当我针对其他哈希大小运行相同类型的数字时,我的输出与 those on Wikipedia 一致,不管它值多少钱。:-) )

编辑添加:这是近似公式。令 r 为哈希函数的基数(因此 r 对于 SHA-1 是 2160)和 U是所需的唯一性概率(因此 U 对于通常的“50% 安全几率,50% 碰撞几率”统计数据为 0.5。散列输入的最大数量为:

(1 + sqrt(1 + 8r ln (1 / U)) / 2

1 / .5 的自然对数大约是 0.693,所以我们有大约 sqrt(4r)/2,当然也就大约 sqrt(r )。因此,对于 k 位散列,“50% 的唯一性概率”发生在大约 k/2 个散列之后。

要查看(大致)我是如何得到我的数字的——在 1015 个对象附近——让 U = 1 - 10-18。这个数字的自然对数基本上是原来的 10-18,这意味着我们将 260 的大部分从 r 范围内剔除,剩下大约2100。它的平方根大约是 250,大约是 1015

【讨论】:

  • 关于意外 SHA-1 冲突的说法是正确的,但故意的 SHA-1 冲突正迅速变得更加可行。 security.googleblog.com/2017/02/…
  • @KeithThompson:是的,我在其他一些答案中提到了这一点。有趣的是,Mercurial 为 SHA-256 留有空间,但格式没有变化。 Git 不会:tree 对象尤其将二进制 SHA-1 值存储在 20 字节字段中。更糟糕的是,许多额外的 Git 脚本假定哈希正好是 40 个字符长(尤其是空哈希是 40 0s)。
【解决方案3】:

犯的错误是SHA代码没有用于生成任何文件的内容,内容由Git单独存储。 SHA 代码仅用作提交的密钥。提交不能只是从 1 开始编号并增加的原因是因为使用 Git,不同的人可以在同一个项目的不同分支上工作,在不知道彼此的情况下进行提交。当这些合并在一起时,我们仍然需要提交来拥有唯一的键。使密钥绝对唯一的最佳方法是使用 SHA 之类的东西创建唯一代码,并且正如其他人所解释的那样,获得相同密钥的概率几乎为零。

【讨论】:

    猜你喜欢
    • 2017-06-17
    • 2017-06-28
    • 2017-05-08
    • 2011-08-19
    • 2013-05-04
    • 2019-06-17
    • 1970-01-01
    • 2017-03-24
    • 2010-09-18
    相关资源
    最近更新 更多