为什么Git不使用更现代的SHA?


90

我读到有关Git使用SHA-1摘要作为修订的ID的信息。为什么不使用更新版本的SHA?


2
性能是我能想到的唯一原因,SHA-1比SHA-2快。我个人认为这是一个错误的决定,因为SHA-1的抗碰撞能力很弱。
CodesInChaos

4
stackoverflow.com/questions/9392365/…-不完全匹配,但涵盖了类似的内容
softwariness 2015年

6
在2006年的git邮件列表中对此进行了讨论。请参阅整个主题。总结,Linus当时说SHA-1只需要足够独特,这样就不会发生冲突。SHA-1不是git的安全功能。“任何一味盲目接受来自不受信任来源的数据的人都以其他许多方式陷入困境,以至于哈希攻击根本就没有受到关注。” - 莱纳斯
TBC0

28
更新:SHA-1碰撞现在在野外粉碎了。它
drewr

2
2018年第一季度:支持替代SHA的工作正在进行中:请参阅下面的答案
VonC

Answers:


62

为什么不使用更新版本的SHA?

2017年12月:会的。Git 2.16(Q1 2018)是第一个说明和实现该意图的版本。

注意:请参阅下面的Git 2.19:它将是SHA-256

Git 2.16将提出一个基础架构,以定义Git中使用的哈希函数,并将开始努力探索各种代码路径中的哈希函数。

参见Ramsay Jones(``)的commit c250e02(2017年11月28日
请参见brian m的commit eb0ccfdcommit 78a6766commit f50e766abade65(2017年11月12日)。卡尔森(bk2204
(通过合并JUNIOÇ滨野- gitster-提交721cc43 12月13日2017)


添加表示哈希算法的结构

由于将来我们希望支持其他哈希算法,因此请添加一个代表哈希算法的结构以及所有必须伴随的数据
添加一个常数以轻松枚举哈希算法
实现函数typedefs以创建可被任何哈希算法使用的抽象API,并包装符合该API的现有SHA1函数。

公开十六进制大小和二进制大小的值
尽管一个值始终是另一个值的两倍,但是这两个值在整个代码库中都非常常用,并提供了两个值,从而提高了可读性。

在哈希算法结构中不要为空对象ID包含条目。
由于该值为全零,因此可以使用任何大小合适的全零对象ID,并且无需按哈希值存储给定的ID。

当前的哈希函数转换计划设想了一个时间,我们将接受来自用户的输入,这些输入可能采用SHA-1或NewHash格式。
由于我们不知道用户提供了哪个,因此添加一个代表未知算法常量,使我们能够指示必须查找正确的值。


将哈希算法支持与回购设置集成在一起

在将来的Git版本中,我们计划支持其他哈希算法。
将哈希算法的枚举与存储库设置集成在一起,并将指向枚举数据的指针存储在struct repository中
当然,我们目前仅支持SHA-1,因此请将此值硬编码在中 read_repository_format
将来,我们将从配置中枚举此值。

添加一个常量,the_hash_algohash_algo指向存储库全局中的结构指针。
请注意,这是用于将数据序列化到磁盘的哈希,而不是用于向用户显示项目的哈希。
过渡计划预计这些可能会有所不同。
我们可以在以后添加一个其他元素(例如ui_hash_algo)来提供这种情况。


对于Git 2.19(2018年第三季度),2018年8月更新,Git似乎选择SHA-256作为NewHash。

参见Jonathan Nieder()的commit 0ed8d8d(04 Aug 2018 。 见提交13f5e09通过(2018年7月25日)ÆvarArnfjörðBjarmason( ) (由Junio C Hamano合并--commit 34f2297中,2018年8月20日)artagnon
avar
gitster

dochash-function-transition:选择SHA-256作为NewHash

从安全性的角度来看,似乎SHA-256,BLAKE2,SHA3-256,K12等都具有相似的安全性。
从安全角度来看,所有这些都是不错的选择。

SHA-256具有许多优点:

  • 它已经存在了一段时间,被广泛使用,并且几乎每个加密库(OpenSSL,mbedTLS,CryptoNG,SecureTransport等)都支持它。

  • 当与SHA1DC进行比较时,即使没有加速,大多数矢量SHA-256实现也确实更快。

  • 如果我们正在使用OpenPGP(甚至我想是CMS)进行签名,那么我们将使用SHA-2,因此当我们的安全性依赖于两个单独的算法时,这两个方法就没有意义了当我们仅依靠一个人时,一个人就可能破坏安全性。

所以SHA-256是
这样更新哈希函数转换设计文档。

在此修补程序之后,没有剩余字符串“ NewHash”的实例,除了2008年作为的变量名 t/t9700/test.pl与无关。


您可以看到Git 2.20(Q4 2018)正在进行向SHA 256的过渡:

提交0d7c419提交dda6346提交eccb5a5提交93eb00f提交d8a3a69提交fbd0e37提交f690b6b提交49d1660提交268babd提交fa13080提交7b5e614提交58ce21b提交2f0c9e9提交825544a(2018年10月15日)由布赖恩米。卡尔森(bk2204
提交6afedba通过(2018年10月15日)SZEDER的Gabor( )szeder
(由合并JUNIOÇ滨野- gitster-提交d829d49,2018年10月30日)

替换硬编码的常量

根据需要,使用GIT_MAX_HEXSZ或 替换几个基于40的常量the_hash_algo
将的所有用法转换GIT_SHA1_HEXSZ为use,the_hash_algo以便它们适合任何给定的哈希长度。
代替在十六进制对象ID的大小上使用硬编码常量,而改用parse_oid_hex解析后的对象ID之后的那一点的计算指针。

GIT_SHA1_HEXSZ被Git 2.22(Q2 2019)进一步删除/替换并提交d4e568b


Git 2.21(2019年第一季度)将继续这种过渡,该版本添加了sha-256哈希,并将其插入代码以允许使用“ NewHash”构建Git。

提交4b4e291提交27dc04c提交13eeedb提交c166599提交37649b7提交a2ce0a7提交50c817e提交9a3a0ff提交0dab712提交47edb64(2018年11月14日),以及提交2f90b9d提交1ccf07c(2018年10月22日)由布赖恩米。卡尔森(bk2204
(由Junio C gitsterHamano合并--commit 33e4ae9中,2019年1月29日)

添加SHA-256支持的基本实现(2019年2月)

SHA-1很弱,我们需要过渡到新的哈希函数。
一段时间以来,我们将此新功能称为NewHash
最近,我们决定选择SHA-256作为NewHash
选择SHA-256背后的原因在该线程中以及哈希函数转换文档的提交历史中都有概述

添加基于off的SHA-256的基本实现libtomcrypt,该实现在公共领域中。
对其进行优化和重组,以满足我们的编码标准。
从SHA-1块实现中提取更新和最终函数,因为我们对所有编译器都知道这些函数正确。此实现比SHA-1慢,但是将来的提交中将引入更多性能更好的实现。

在哈希算法列表中连接SHA-256,并添加一个测试算法可以正常工作的测试。

请注意,使用此修补程序,仍无法在Git中切换为使用SHA-256。
需要其他补丁来准备代码以处理更大的哈希算法,并且需要进一步的测试修复。

hash:使用OpenSSL添加SHA-256实现

我们已经有适用于SHA-1的OpenSSL例程,因此也要添加SHA-256的例程。

在Core i7-6600U上,此SHA-256实现与SHA1DC SHA-1实现相比具有优势:

SHA-1: 157 MiB/s (64 byte chunks); 337 MiB/s (16 KiB chunks)
SHA-256: 165 MiB/s (64 byte chunks); 408 MiB/s (16 KiB chunks)

sha256:使用添加SHA-256实现 libgcrypt

通常,使用汇编语言编写的加密例程比C语言可以获得更好的性能,SHA-256也是如此。
此外,由于许可原因,大多数Linux发行版无法分发链接到OpenSSL的Git。

大多数具有GnuPG的系统也将具有libgcrypt,因为它是GnuPG的依赖项。
libgcrypt对于几KiB或更大的消息,它也比SHA1DC实现更快。

为了进行比较,在Core i7-6600U上,此实现以355 MiB / s的速度处理16个KiB块,而SHA1DC以337 MiB / s的速度处理等效的块。

此外,libgcrypt已根据LGPL 2.1许可,该协议与GPL兼容。添加使用libgcrypt的SHA-256实现。


Git 2.24(Q4 2019)继续进行升级

提交aaa95df提交be8e172提交3f34d70提交fc06be3提交69fa337提交3a4d7aa提交e0cb7cd提交8d4d86b提交f6ca67d提交dd336a5提交894c0f6提交4439c7a提交95518fa提交e84f357提交fe9fec4提交976ff7e提交703d2d4提交9d958cc提交7962e04提交费用4930(2019年8月18日)by brian m。卡尔森(bk2204
(通过合并JUNIOÇ滨野- gitster-提交676278f,2019年10月11日)

代替使用GIT_SHA1_HEXSZ和硬编码的常量,切换到使用the_hash_algo


使用Git 2.26(Q1 2020),测试脚本已准备好在对象名称将使用SHA-256的那一天。

提交277eb5a提交44b6c05提交7a868c5提交1b8f39f提交a8c17e3提交8320722提交74ad99b提交ba1be1a提交cba472d提交82d5aeb提交3c5e65c提交235d3cd提交1d86c8f提交525a7f1提交7a1bcb2提交cb78f4f提交717c939提交08a9dd8提交215b60b提交194264c(2019年12月21日)by brian m。卡尔森(bk2204
(通过合并JUNIOÇ滨野- gitster-提交f52ab33,2020年2月5日)

例:

t4204:使散列大小独立

签字人:brian m。卡尔森

使用$OID_REGEX而不是硬编码的正则表达式。

因此,不要使用:

grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output

测试正在使用

grep "^$OID_REGEX $(git rev-parse HEAD)$" output

OID_REGEX来自提交bdee9cd通过(2018年5月13日),布赖恩·米 卡尔森(bk2204
(由Junio C gitsterHamano合并--commit 9472b13中,2018年5月30日,Git v2.18.0-rc0)

t/test-lib:介绍 OID_REGEX

签字人:brian m。卡尔森

当前,我们有一个变量,$_x40,其中包含一个与完整的40个字符的十六进制常量匹配的正则表达式。

但是,有了NewHash,我们将拥有超过40个字符的对象ID。

在这种情况下,$_x40将是一个令人困惑的名称。

创建一个$OID_REGEX变量,该变量将始终反映与适当的对象ID匹配的正则表达式,而不管当前哈希的长度如何。

而且,仍在测试中:

提交f303765提交edf0424提交5db24dc提交d341e08提交88ed241提交48c10cc提交f7ae8e6提交e70649b提交a30f93b提交a79eec2提交796d138提交417e45e提交dfa5f53提交f743e8f提交72f936b提交5df0f11提交07877f3提交6025e89提交7b1a182提交94db7e3brian m。bk2204提交db12505(2020年2月7日)卡尔森(
(由Junio C gitsterHamano合并--5af345a号提交中,2020年2月17日)

t5703:使用SHA-256进行测试

签字人:brian m。卡尔森

该测试使用的对象ID的长度为40个十六进制字符,导致在以SHA-256作为哈希值运行时,该测试不仅不通过,而且挂起。

使用test_oid_init和将此值更改为固定的伪对象ID test_oid

此外,请确保使用带有字段的剪切(而不是固定长度)来提取适当长度的对象ID。


一些代码路径被赋予了一个存储库实例作为参数,以便在存储库中工作,但是将the_repository实例传递给其被调用者,后者已通过Git 2.26(2020年第一季度)进行了清理(某种程度上)。

请参阅Matheus Tavares()的提交b98d188提交2dcde20提交7ad5c44提交c8123e7提交5ec9b8a提交a651946提交eb999b3(2020年1月30日(通过合并JUNIOÇ滨野- -提交78e67cd,2020年2月14日)matheustavares
gitster

sha1-file:允许check_object_signature()处理任何回购

签字人:Matheus Tavares

某些调用者check_object_signature()可以在任意存储库上工作,但存储库不会传递给此函数。而是the_repository始终在内部使用。
要解决可能存在的不一致,请允许该函数接收结构存储库,并使那些调用程序传递正在处理的存储库。

基于:

sha1-file:传递git_hash_algohash_object_file()

签字人:Matheus Tavares

允许hash_object_file()通过引入上的任意回购工作git_hash_algo参数。更改在其作用域内具有结构存储库指针的调用者,以git_hash_algo从所述存储库传递。
对于所有其他呼叫者,请传递the_hash_algo,已在内部使用hash_object_file()
此功能将在以下修补程序中使用,以使其check_object_signature()能够在任意存储库上使用(反过来,该存储库将用于修复object.c:parse_object()上的不一致)。


1
另外,请不要忘记Git v2.13.0及更高版本随后默认情况下移至强化的SHA-1实现,这不易受到SHAttered攻击。参见stackoverflow.com/a/43355918/6309
VonC '18年

1:谷歌产生冲突shattered.io在2017年2月(估计费用$ 110,000)2:南洋理工大学产生了碰撞sha-mbles.github.io 在2019年1月(估计费用$ 11K之间- $ 45,000)现在是时候Git超越SHA1
bristweb

@bristweb“现在是Git超越SHA1的时候了”:我同意,对于Git 2.25(今天发布),这一举动是一回事。git rev-parse现在可以打印将使用的哈希值:stackoverflow.com/a/58862319/6309。空树有一个新的SHA2 ID:stackoverflow.com/a/9766506/6309
VonC

有了这种哈希算法可扩展性,CRC32终于可以再次发光。
沃尔夫

52

更新:上面的问题和答案是从2015年开始的。此后,Google宣布了第一次SHA-1冲突:https : //security.googleblog.com/2017/02/announcing-first-sha1-collision.html


显然,我只能从外面推测为什么Git继续使用SHA-1,但这可能是以下原因之一:

  1. Git是Linus Torvald的创作,Linus显然现在不想用另一种哈希算法替代SHA-1。
  2. 他提出合理的说法,即基于SHA-1的成功碰撞对Git的攻击要比实现自身的碰撞要困难得多,并且考虑到SHA-1的脆弱性没有应有的程度,没有被完全破坏,这使其与实际情况相去甚远。至少在今天是可行的攻击。此外,他指出,如果碰撞对象比现有对象晚到,则“成功”攻击将收效甚微,因为后者被认为与有效对象相同且被忽略(尽管其他人指出,相反的情况可能会发生。
  3. 更改软件非常耗时且容易出错,尤其是当存在必须迁移的基于现有协议的现有基础结构和数据时。即使是那些以加密安全性为系统重点的软件和硬件产品生产商,也仍在逐步远离SHA-1和其他弱算法的过程中。试想一下所有这些硬编码的unsigned char[20]缓冲区;-),从一开始就为加密敏捷性进行编程要容易得多,而不是以后对其进行改造。
  4. SHA-1的性能优于各种SHA-2哈希(可能现在还不算是一个大问题,但在10年前可能是一个关键点),并且SHA-2的存储容量更大。

一些链接:

我个人的观点是,尽管实际的攻击可能尚需时日,但即使确实发生,人们也可能最初会通过改变散列算法本身的方式减轻攻击,如果您确实关心安全性,那您应该犯错谨慎选择算法,并不断提高安全性,因为攻击者的能力也只朝一个方向发展,因此将Git用作榜样是不明智的,尤其是作为Git的目的使用SHA-1并不意味着要加密安全。


7
“您可能会有试图恶意的人。他们不会成功。N̶o̶b̶o̶d̶y̶̶h̶a̶s̶̶b̶e̶e̶n̶̶a̶b̶l̶e̶̶t̶o̶̶b̶r̶e̶a̶k̶̶S̶H̶A̶-̶1̶纯粹是一致性检查。” -Linus Torvalds
Shakti

9
Git的哈希值必须安全,以确保人们在其代码上放置的安全签名可以验证任何内容。这些签名标志着这些哈希的巨大树。如果该树的某个分支发生冲突,则可以在签名通过时插入恶意代码。Git现在被广泛使用。需要进行哈希升级。
FuzzyTew17年

根据“崩溃”需要考虑两件事:1.使用SHA-1。-SHA-1用作荣耀的校验和,以防止意外损坏。-SHA-1用作生成器函数,以提供一个(有点小)方便的十六进制数字来指定其内容可寻址存储中的对象(即,荣耀的文件名生成器)。-它是负责安全性的已签名提交(例如:公共密钥密码术。不是sha-1)
DrYak

2.可行性-经过大量的GPU时间,Google设法生成了一对区块系列。-两者都散列到相同的SHA-1总和(这就是冲突)-它们完全是乱码(很难证明为什么您的提交中间有一个巨大的二进制垃圾块)。-破碎的演示依赖于一种方法来呈现不同的行为,具体取决于存在哪个随机二进制垃圾。PDF(在其后面隐藏了嵌入脚本语言)是可能的。在纯文本源上,这将变得更加困难(想想C语言竞赛)
DrYak

@DrYak对于2:让我们假设您正在跟踪带注释字段的photoshop文档。或其他带有meta标签的媒体文件。这是游戏开发中的典型案例。但是通常不会在每次更改时都对它们进行检查:如果提交消息中显示“针对大小进行优化”,为什么还要检查元标记?
Arne Babenhauserheide

5

这是关于从SHA1迁移到Mercurial的紧迫性的讨论,但它也适用于Git:https : //www.mercurial-scm.org/wiki/mpm/SHA1

简而言之:如果您今天不十分勤快,则漏洞比sha1要糟糕得多。但是尽管如此,Mercurial还是在10多年前就开始准备从sha1迁移出去。

多年来,为SHA1的后续产品改型Mercurial的数据结构和协议的工作正在进行中。10年前,随着RevlogNG的推出,Mercurial 0.9在我们的revlog结构中为更大的哈希分配了存储空间。最近引入的bundle2格式支持通过网络交换不同的哈希类型。剩下的剩下的就是选择替换功能和选择向后兼容策略。

如果git在Mercurial之前没有从sha1迁移过来,则始终可以通过使用hg-git保留本地Mercurial镜像来增加另一级别的安全性。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.