我读到Git使用SHA-1摘要作为修订版的ID。为什么它不使用更现代的版本的SHA?
我读到Git使用SHA-1摘要作为修订版的ID。为什么它不使用更现代的版本的SHA?
为什么不使用更现代的SHA版本?
2017年12月:将会使用更现代的版本。Git 2.16(2018年第一季度)是首个展示和实现此意图的版本。
注意:请参阅下文的Git 2.19:它将采用 SHA-256 。
Git 2.16将提供一个基础设施来定义Git中使用的哈希函数,并开始努力将其穿透到各种代码路径中。
查看 提交 c250e02 (2017年11月28日) 由 Ramsay Jones (``) 执行。
查看 提交 eb0ccfd, 提交 78a6766, 提交 f50e766, 提交 abade65 (2017年11月12日) 由 brian m. carlson(bk2204
)执行。
(由Junio C Hamano -- gitster
--合并于提交721cc43, 2017年12月13日)
typedefs
以创建可用于任何哈希算法的抽象API,并为符合此API的现有SHA1函数提供包装器。
公开十六进制大小和二进制大小的值。
虽然其中一个始终是另一个的两倍,但这两个值在整个代码库中都被广泛使用,同时提供这两个值可以提高可读性。
不要在哈希算法结构中包含空对象ID的条目。
由于该值全部为零,因此可以使用适当大小的全零对象ID,并且无需在每个哈希基础上存储给定的对象ID。
当前的哈希函数过渡计划设想了一个时间,我们将接受用户可能以SHA-1或NewHash格式输入的内容。
由于我们无法知道用户提供的是哪一个,因此添加一个表示未知算法的常量以允许我们指示我们必须查找正确的值。
read_repository_format
中硬编码此值。the_hash_algo
,它指向全局仓库中的hash_algo
结构指针。ui_hash_algo
)来处理这种情况。
2018年8月更新,对于Git 2.19(2018年第三季度),Git似乎选择了SHA-256作为NewHash。
请参见commit 0ed8d8d(2018年8月4日)由Jonathan Nieder(artagnon
)提交。
请参见commit 13f5e09(2018年7月25日)由Ævar Arnfjörð Bjarmason(avar
)提交。
(由Junio C Hamano -- gitster
--合并于commit 34f2297,2018年8月20日)
从安全角度来看,SHA-256、BLAKE2、SHA3-256、K12等算法被认为具有类似的安全性能。从安全角度来看,它们都是不错的选择。文档
哈希函数转换
:选择SHA-256作为NewHash
您可以在 Git 2.20 (2018年第四季度) 中看到这种转换到 SHA 256 的进展:
查看 commit 0d7c419, commit dda6346, commit eccb5a5, commit 93eb00f, commit d8a3a69, commit fbd0e37, commit f690b6b, commit 49d1660, commit 268babd, commit fa13080, commit 7b5e614, commit 58ce21b, commit 2f0c9e9, commit 825544a (2018年10月15日) 由 brian m. carlson (bk2204
) 提交。
查看 commit 6afedba (2018年10月15日) 由 SZEDER Gábor (szeder
) 提交。
(在 commit d829d49 中由 Junio C Hamano -- gitster
-- 合并,于2018年10月30日)
GIT_MAX_HEXSZ
或the_hash_algo
的引用,视情况而定。GIT_SHA1_HEXSZ
的地方转换为使用the_hash_algo
,以便适用于任何给定的哈希长度。parse_oid_hex
解析后指向对象ID之后的计算指针。
GIT_SHA1_HEXSZ
在Git 2.22(2019年第二季度)进一步删除/替换,详见commit d4e568b。
随着Git 2.21(2019年第一季度)的推出,这种过渡将继续,它添加了sha-256哈希并通过代码插入它,以允许使用“NewHash”构建Git。
请参见 commit 4b4e291、commit 27dc04c、commit 13eeedb、commit c166599、commit 37649b7、commit a2ce0a7、commit 50c817e、commit 9a3a0ff、commit 0dab712、commit 47edb64(2018年11月14日)和commit 2f90b9d、commit 1ccf07c(2018年10月22日)由brian m. carlson (bk2204
)。
(由Junio C Hamano -- gitster
--于commit 33e4ae9,2019年1月29日合并)
SHA-1已经不安全了,我们需要过渡到一个新的哈希函数。
有一段时间,我们将这个新函数称为NewHash
。
最近,我们决定选择SHA-256作为NewHash
。
在这个讨论主题中解释了选择SHA-256的原因,在哈希函数过渡文档的提交历史中也有介绍。
基于公共领域中的libtomcrypt
添加了SHA-256的基本实现,进行了优化和重构以满足我们的编码标准。从SHA-1块实现中提取出更新和最终函数,因为我们知道这些函数在所有编译器上都能正确运行。这个实现比SHA-1更慢,但更高性能的实现将在未来的提交中引入。
将SHA-256连接到哈希算法列表中,并添加一个测试,验证算法是否正确工作。
请注意,使用此补丁仍然不能切换到在Git中使用SHA-256。
需要其他补丁来准备代码以处理更大的哈希算法,还需要进一步修复测试问题。
hash
:使用OpenSSL添加SHA-256实现We already have OpenSSL routines available for SHA-1, so add routines for SHA-256 as well.
On a Core i7-6600U, this SHA-256 implementation compares favorably to the SHA1DC SHA-1 implementation:
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
: 添加一个使用libgcrypt
的SHA-256实现libgcrypt
,因为它是GnuPG的依赖项。libgcrypt
也比SHA1DC实现更快。libgcrypt
的许可证为LGPL 2.1,与GPL兼容。添加使用libgcrypt的SHA-256实现。
Git 2.24(2019年第4季度)的升级工作正在进行中。
查看commit aaa95df, commit be8e172, commit 3f34d70, commit fc06be3, commit 69fa337, commit 3a4d7aa, commit e0cb7cd, commit 8d4d86b, commit f6ca67d, commit dd336a5, commit 894c0f6, commit 4439c7a, commit 95518fa, commit e84f357, commit fe9fec4, commit 976ff7e, commit 703d2d4, commit 9d958cc, commit 7962e04, commit fee4930 (2019年8月18日) 由brian m. carlson (bk2204
)提交。
(由Junio C Hamano -- gitster
--于commit 676278f合并,2019年10月11日)
不要使用
GIT_SHA1_HEXSZ
和硬编码的常量,改用the_hash_algo
。
在 Git 2.26(2020年第一季度)中,测试脚本已准备好应对对象名称使用 SHA-256 的情况。
请查看以下提交记录:commit 277eb5a,commit 44b6c05,commit 7a868c5,commit 1b8f39f,commit a8c17e3,commit 8320722,commit 74ad99b,commit ba1be1a,commit cba472d,commit 82d5aeb,commit 3c5e65c,commit 235d3cd,commit 1d86c8f,commit 525a7f1,commit 7a1bcb2,commit cb78f4f,commit 717c939,commit 08a9dd8,commit 215b60b,commit 194264c(截至2019年12月21日),这些提交记录由brian m. carlson (bk2204
)提交。
(于2020年2月5日合并,合并者为Junio C Hamano -- gitster
--,commit f52ab33)
例子:
t4204
: 使哈希大小独立Signed-off-by: brian m. carlson
使用
$OID_REGEX
而不是硬编码的正则表达式。
因此,不要使用:
grep "^[a-f0-9]\{40\} $(git rev-parse HEAD)$" output
测试正在使用
grep "^$OID_REGEX $(git rev-parse HEAD)$" output
而 OID_REGEX
来自 commit bdee9cd (2018年5月13日)由 brian m. carlson (bk2204
) 提交。
(由 Junio C Hamano -- gitster
-- 合并在 commit 9472b13 中,于2018年5月30日,Git v2.18.0-rc0)
t/test-lib
:引入OID_REGEX
签名作者:brian m. carlson
目前我们有一个变量$_x40
,其中包含匹配完整的40个字符十六进制常量的正则表达式。
然而,使用NewHash
后,我们将拥有比40个字符更长的对象ID。
在这种情况下,$_x40
将是一个令人困惑的名称。
创建一个$OID_REGEX
变量,它将始终反映与当前哈希长度无关的适当对象ID匹配的正则表达式。
还有,用于测试:
请看commit f303765,commit edf0424,commit 5db24dc,commit d341e08,commit 88ed241,commit 48c10cc,commit f7ae8e6,commit e70649b,commit a30f93b,commit a79eec2,commit 796d138,commit 417e45e,commit dfa5f53,commit f743e8f,commit 72f936b,commit 5df0f11,commit 07877f3,commit 6025e89,commit 7b1a182,commit 94db7e3,commit db12505 (2020年2月7日) 由brian m. carlson (bk2204
)提交。
(由Junio C Hamano -- gitster
--于commit 5af345a合并,2020年2月17日)
t5703
: 使测试能够与SHA-256一起使用签名:brian m. carlson
该测试使用了一个40个十六进制字符长度的对象ID,导致测试不仅不能通过,而且在使用SHA-256作为哈希时会挂起。
使用
test_oid_init
和test_oid
将此值更改为固定的虚拟对象ID。此外,确保我们使用字段切割而不是固定长度来提取适当长度的对象ID。
一些代码路径将存储库实例作为参数传递给工作存储库的函数,并将the_repository
实例传递给其调用者,这已在 Git 2.26(2020年第一季度)中得到了(某种程度上的)清理。
查看commit b98d188, commit 2dcde20, commit 7ad5c44, commit c8123e7, commit 5ec9b8a, commit a651946, commit eb999b3 (2020年1月30日) 由Matheus Tavares (matheustavares
)提交。
(由Junio C Hamano -- gitster
--合并于commit 78e67cd,2020年2月14日)
sha1-file
: 允许check_object_signature()
处理任何仓库签名:Matheus Tavares
check_object_signature()
的某些调用者可以处理任意存储库,但存储库并未传递给该函数。相反,内部始终使用the_repository
。
为了修复可能的不一致性,允许该函数接收一个 struct repository 并使这些调用者传递正在处理的存储库。
基于:
引入一个git_hash_algo参数,使hash_object_file()能够在任意仓库上工作。更改具有struct repository指针的调用者的调用方式,以传递来自所述repo的git_hash_algo。
sha1-file
: 将git_hash_algo
传递给hash_object_file()
签名:Matheus Tavares
Git 2.38 (2022年第三季度)新增了对libnettle
的支持,因为已添加了SHA256实现。
请参见提交e555735(2022年7月10日),由brian m. carlson (bk2204
)进行。
(由Junio C Hamano -- gitster
--合并于提交4af2138,2022年7月18日)
对于SHA-256,我们目前支持OpenSSL和libgcrypt,因为这两个库包含了可以利用本地处理器指令的优化实现。然而:
sha256
:增加对Nettle的支持签名:
brian m. carlson
libgcrypt
更好的选择,因为在许多发行版中,GnuTLS(使用Nettle)用于HTTPS,因此从实际角度来看,在大多数系统上都会可用。因此,应该优先考虑它,而不是libgcrypt
和我们内置的实现。git gc
(man),使用Nettle比我们的块SHA-256实现可以获得12%的性能提升,这是由于通用汇编改进所致。使用SHA-NI,2 GiB文件的原始SHA-256性能从块SHA-256的7.296秒提高到Nettle的1.523秒。git rev-parse
现在能够打印将要使用的哈希值:https://dev59.com/p2ox5IYBdhLWcg3wl1P4#58862319。空树也有一个新的SHA2 id:https://dev59.com/UGkw5IYBdhLWcg3wm74h#9766506。 - VonC更新: 上述问题和答案来自2015年。此后,谷歌宣布了第一个SHA-1碰撞:https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html
显然,我只能从外部推测Git为什么继续使用SHA-1,但以下可能是原因之一:
unsigned char[20]
缓冲区, 后期改动要比开始加密敏捷性更容易。一些链接:
我个人的看法是,虽然实际攻击可能需要一些时间,即使攻击发生时人们可能会先采取其他手段来缓解而不是更改哈希算法本身,但如果您关心安全性,您应该在选择算法时谨慎行事,并不断提高安全强度,因为攻击者的能力也只朝着一种方向发展,因此以Git作为榜样是不明智的,特别是因为它使用SHA-1的目的并不是声称具有加密安全性。
如果Git在Mercurial之前不迁移离开sha1,您可以通过使用hg-git保留本地Mercurial镜像来添加另一层安全性。多年来,人们一直在修改Mercurial的数据结构和协议,以适应SHA1的后继者。在Mercurial 0.9中,随着RevlogNG的引入,我们为较大的哈希值分配了存储空间。最近引入的bundle2格式支持在网络上交换不同类型的哈希值。唯一剩下的问题是选择替代函数和选择向后兼容策略。