吉特
英语▾ 主题Ş 版本2.45.2 哈希函数转换上次更新于2.45.2

目标

将Git从SHA-1迁移到更强的哈希函数。

背景

Git版本控制系统的核心是内容寻址文件系统。它使用SHA-1散列函数命名内容。对于例如,文件、目录和修订由散列引用值不同于其他传统版本控制系统中的文件或版本通过序列号引用。散列的使用处理其内容的功能具有以下优点:

  • 完整性检查很容易。例如,位翻转很容易检测到,因为损坏内容的散列与其名称不匹配。

  • 对象查找速度很快。

使用加密安全的散列函数会带来额外的优势:

  • 对象名可以签名,第三方可以将哈希信任为处理签名对象及其引用的所有对象。

  • 使用Git协议的通信和带外通信方法有一个短的可靠字符串,可用于可靠地地址存储的内容。

随着时间的推移,安全部门发现了SHA-1中的一些缺陷研究人员。2017年2月23日,SHAttered袭击(https://shattered.io)演示了实际的SHA-1哈希冲突。

Git v2.13.0和后来的版本被移动到一个加固的SHA-1默认情况下实现,不易受到SHAttered攻击,但SHA-1仍然很弱。

因此,明智的做法是绕过SHA-1的任何变体转换为新的散列。无法保证未来对SHA-1的攻击不会在未来发布,而这些攻击可能不可行缓解措施。

如果SHA-1及其变体被真正破坏,Git的散列函数无法再被视为加密安全。这会影响散列值的通信,因为我们无法信任给定的哈希值表示已知的良好内容版本演讲者的意图。

SHA-1仍然具有其他特性,如快速对象查找和安全错误检查,但其他哈希函数也同样适用被认为是加密安全的。

哈希的选择

替换硬化SHA-1的散列值应大于SHA-1是:我们希望它在实践中对at是值得信赖和有用的至少10年。

其他一些相关属性:

  1. 256位散列(长度足以匹配常见安全实践;不是过长会影响性能和磁盘使用)。

  2. 应广泛提供高质量的实施(例如OpenSSL和Apple CommonCrypto)。

  3. 哈希函数的属性应符合Git的需要(例如Git需要碰撞和第二次预成像阻力,而不需要长度延伸阻力)。

  4. 作为一个tiebreaker,散列的计算速度应该很快(幸运的是许多竞争者比SHA-1更快)。

SHA-1的后续散列有几个竞争者,包括SHA-256、SHA-512/256、SHA-256x16、K12和BLAKE2bp-256。

2018年末,该项目选择SHA-256作为其后续哈希。

参见0ed8d8da374(doc hash-function-transition:选择SHA-256为NewHash,2018-08-04)和当时众多的邮件列表线程,尤其是从https://lore.kernel.org/git/20180609224913.GC38834@genre.crustytothspast.net/了解更多信息。

目标

  1. 可以一次在一个本地存储库中转换到SHA-256。

    1. 不需要任何其他方采取行动。

    2. SHA-256存储库可以与SHA-1 Git服务器通信(推/取)。

    3. 用户可以对对象使用SHA-1和SHA-256标识符可互换(请参阅下面的“命令行上的对象名称”)。

    4. 新签名的对象使用了比SHA-1的安全保证。

  2. 允许从SHA-1完全过渡。

    1. SHA-1兼容性的本地元数据可以从存储库,如果不再需要与SHA-1兼容。

  3. 整个过程的可维护性。

    1. 对象格式保持简单和一致。

    2. 创建通用存储库转换工具。

非目标

  1. 向Git协议添加SHA-256支持。这很有价值下一步是合理的,但这超出了初始设计的范围。

  2. 透明地提高已签署的现有SHA-1的安全性物体。

  3. 在单个对象中使用多个哈希函数混合对象存储库。

  4. 抓住机会修复Git格式中的其他错误协议。

  5. 浅层克隆并提取到SHA-256存储库中。(这将当我们将SHA-256支持添加到Git协议时发生更改。)

  6. 跳过将项目的一些子模块提取到SHA-256中存储库。(这还取决于Git中的SHA-256支持协议。)

概述

我们引入了一个新的存储库格式扩展。具有此功能的存储库启用扩展后,使用SHA-256而不是SHA-1来命名对象。这会影响对象名称和对象内容-这两个名称对象和对象中对其他对象的所有引用是切换到新的散列函数。

旧版本的Git无法读取SHA-256存储库。

除了包文件,SHA-256存储库还存储双向SHA-256和SHA-1对象名称之间的映射。生成映射并可以使用“git-fsck”进行验证。对象查找使用此映射以允许使用对象的SHA-1和SHA-256名称命名对象可以互换。

显示对象的“git cat-file”和“git hash-object”增益选项以其SHA-1形式编写一个给定SHA-1格式的对象要求该对象引用的所有对象都存在于对象数据库,以便可以使用适当的名称对其进行命名(使用双向散列映射)。

从基于SHA-1的服务器提取将提取的对象转换为SHA-256在双向映射表中形成并记录映射(详见下文)。推送到基于SHA-1的服务器转换对象被推送到SHA-1表单中,因此服务器不必了解客户端正在使用的哈希函数。

详细设计

存储库格式扩展

SHA-256存储库使用存储库格式版本1(请参见Documentation/technical/repository-version.txt)及扩展对象格式兼容对象格式:

[核心]repositoryFormatVersion=1[扩展]objectFormat=sha256compatObjectFormat=sha1

设置的组合core.repositoryFormatVersion=1填充扩展名*确保Git的所有版本都晚于0.99.9升将死亡,而不是尝试在SHA-256上操作存储库,而不是生成错误消息。

#在v0.99.9l和v2.7.0之间$git状态致命错误:预期的git repo版本<=0,找到1#v2.7.0之后$git状态致命:发现未知的存储库扩展:对象格式兼容对象格式

有关这些方面的更多详细信息,请参阅下面的“过渡计划”部分存储库扩展。

对象名称

对象可以通过其40个十六进制数字SHA-1名称或64个来命名十六进制数字SHA-256名称,加上从中派生的名称(请参见gitrevisions(7))。

对象的SHA-1名称是其类型、长度、一个nul字节和对象的SHA-1内容。这是Git中用于命名对象的传统<sha1>。

对象的SHA-256名称是其类型、长度、nul字节和对象的SHA-256内容。

对象格式

名为的标记、提交或树对象的字节序列形式的内容由SHA-1和SHA-256命名的对象不同,因为由SHA-256-名称命名的对象引用按SHA-256名称命名的其他对象和按SHA-1名称命名的对象通过SHA-1名称引用其他对象。

对象的SHA-256内容与其SHA-1内容相同,但对象引用的对象使用其SHA-256名称命名而不是SHA-1名称。因为blob对象不引用任何其他对象,其SHA-1内容和SHA-256内容相同。

该格式允许SHA-256内容和SHA-1含量。

对象存储

松散对象使用zlib压缩,而压缩对象使用压缩中描述的格式gitformat-pack[5],就像今天。压缩和存储的内容使用SHA-256内容而不是SHA-1内容。

包装索引

打包索引(.idx)文件使用支持多个哈希函数。它们的格式如下(所有整数都是网络字节顺序):

  • 页眉显示在开头,由以下内容组成:

    • 4字节压缩索引签名:\377吨

    • 4字节版本号:3

    • 标头部分的4字节长度,包括签名和版本号

    • 包中包含的4字节对象数

    • 此包索引中的4字节对象格式数:2

    • 对于每个对象格式:

      • 4字节格式标识符(例如。,沙阿1对于SHA-1)

      • 缩短对象名称的4字节长度(以字节为单位)。这是在缩短的中命名所需的尽可能短的长度对象名称表毫不含糊。

      • 4字节整数,记录与此格式相关的表格存储在此索引文件中,作为与开头的偏移量。

    • 从文件开头到尾部的4字节偏移量。

    • 零个或多个附加键/值对(4字节键,4字节值)。仅支持一个密钥:PSRC公司参见“松散物体“and unreachable objects”部分,了解受支持的值以及如何使用。保留所有其他密钥。读者必须忽略无法识别的键。

  • 零个或多个NUL字节。这可以选择性地用于改进下面完整对象名称表的对齐方式。

  • 第一种对象格式的表:

    • 简短对象名称的排序表。这些是的前缀打包在一起的此打包文件中所有对象的名称没有偏移值以减少二进制文件的缓存占用空间搜索特定的对象名称。

    • 按打包顺序列出完整对象名称的表。这允许解决对“包文件中的第n个对象”的引用(来自可达位图或从另一个对象的下一个表格式)设置为其对象名。

    • 将对象名称顺序映射到打包顺序的4字节值表。对于排序的简短对象名称表中的对象此表中相应索引处的值是同一对象的上一个表。这可以用于在可达位图或以其他对象格式查找其名称。

    • 压缩对象数据的4字节CRC32值表,位于对象在包文件中出现的顺序。这是为了允许压缩数据将在在没有未检测到的数据损坏的情况下重新打包。

    • 4字节偏移值表。对于表中的对象排序缩短的对象名称,对应的值此表中的索引指示该对象可以在何处找到包文件。这些通常是31位压缩文件偏移量,但大偏移量被编码为下一个表的索引最高有效位集。

    • 包含8字节偏移项的表(对于小于2 GiB)。打包文件是用大量使用的对象组织的前面,所以大多数对象引用不需要引用这张桌子。

  • 零个或多个NUL字节。

  • 第二种对象格式的表,其布局与上述相同,不包括CRC32值表。

  • 零个或多个NUL字节。

  • 拖车由以下部件组成:

    • 结束时20字节SHA-256校验和的副本相应的包文件。

    • 20字节SHA-256校验和。

松散对象索引

新文件$GIT_OBJECT_DIR/losee-OBJECT-idx包含以下信息所有松散物体。其格式为

#松散对象idx(sha256-名称SP sha1-名称LF)*

其中对象名称为十六进制格式。文件不是排序。

松散对象索引通过锁定文件$GIT_OBJECT_DIR/loose-OBJECT-idx.lock。添加新松散对象:

  1. 像今天一样,将松散对象写入临时文件。

  2. 使用O_CREAT|O_EXCL打开lose-object-idx.lock以获取锁。

  3. 将松散对象重命名到位。

  4. 用O_APPEND打开lose-object-idx并写入新对象

  5. 取消链接loose-object-idx.lock以释放锁定。

要删除条目(例如“git-pack-refs”或“git-prenme”中的条目):

  1. 使用O_CREAT|O_EXCL打开lose-object-idx.lock以获取锁定。

  2. 将新内容写入loose-object-idx.lock。

  3. 取消链接任何要移除的松散对象。

  4. 重命名以替换lose-object-idx,释放锁。

翻译表

索引文件支持SHA-1名称之间的双向映射和SHA-256名称。查找过程与普通对象类似查找。例如,要将SHA-1名称转换为SHA-256名称:

  1. 在idx文件中查找对象。如果在idx的截断SHA-1名称排序列表,然后:

    1. 阅读要打包的SHA-1名称顺序中的相应条目名称顺序映射。

    2. 读取完整SHA-1名称表中的相应条目以确认我们找到了正确的对象。如果是,那么

    3. 读取完整SHA-256名称表中的相应条目。这是对象的SHA-256名称。

  2. 检查有无松动的物体。读取lose-object-idx中的行,直到我们找到了匹配项。

步骤(1)所用的时间与普通对象查找相同:O(包数*日志(每个包的对象数))。步骤(2)需要O(数量松散物体)时间。为了保持良好的性能,这是必要的使松散物体的数量保持在较低水平。参见“松散物体和有关详细信息,请参阅下面的“unreachableobjects”部分。

由于所有生成新对象的操作(例如“git提交”)都会添加将新对象映射到相应的索引,则可以进行此映射对象存储中的所有对象。

读取对象的SHA-1内容

可以通过转换所有SHA-256名称来读取对象的SHA-1内容它的SHA-256内容引用了使用转换表的SHA-1名称。

提取

从基于SHA-1的服务器获取数据需要在SHA-1之间进行转换以及基于SHA-256的动态表示。

客户端上的ref广告中指定的SHA-1可以转换为SHA-256并使用翻译表。

谈判今天继续进行。本地生成的任何“has”都是在发送到服务器之前转换为SHA-1,以及SHA-1服务器提到的在查找时转换为SHA-256本地。

协商后,服务器发送包含请求的对象。我们使用以下命令将包文件转换为SHA-256格式以下步骤:

  1. index-pack:膨胀包文件中的每个对象并计算其SHA-1。对象可以包含OBJ_REF_DELTA格式的增量客户端在本地拥有的对象。可以查找这些对象使用转换表及其SHA-1内容读取为如上所述,以解决增量。

  2. 拓扑排序:从谈判中的“需要”开始阶段,遍历包中的对象并发出它们的列表,以反向拓扑排序顺序排除blob,每个blob对象在列表中的位置晚于它引用的所有对象。(此列表仅包含可从“wants”访问的对象。如果来自服务器的包包含其他无关对象,然后它们将被丢弃。)

  3. 转换为SHA-256:打开一个新的SHA-255包文件。从拓扑结构上阅读刚刚生成的排序列表。对于每个对象,将其充气SHA-1内容,转换为SHA-256内容,并将其写入SHA-256打包。记录新的SHA-1←→SHA-256映射条目,以便在idx中使用。

  4. 排序:重新排序新包中的条目以匹配对象的顺序在包中,服务器生成并包含blob。编写SHA-256 idx文件

  5. 清理:删除基于SHA-1的包文件、索引和在步骤1中从服务器获得的拓扑排序列表和2。

步骤3要求新对象引用的每个对象都位于翻译表。这就是为什么拓扑排序步骤是必要的。

作为优化,步骤1可以编写一个文件来描述非blob对象它从包文件引用中膨胀的每个对象。这个使步骤2中的拓扑排序成为可能,而不会使第二次出现在packfile中的对象。对象需要在步骤3中再次充气,总共两次充气。

为了获得良好的读时性能,步骤4可能是必需的。“吉特服务器上的“pack-objects”优化包文件以获得良好的数据位置(请参阅Documentation/technical/pack-heuristics.txt)。

这个过程的细节可能会改变。这需要一些尝试使其表现良好。

推动

Push比fetch更简单,因为推送的对象已在转换表中。SHA-1内容可以按照“Reading”(读取对象的SHA-1内容”部分,以生成git编写的包发送回。

签署的承诺

我们在提交对象格式中添加了一个新字段“gpgsig-sha256”,以允许在不依赖SHA-1的情况下签署提交。它类似于现有“gpgsig”字段。它的签名有效载荷是删除任何“gpgsig”和“gpgsig-sha256”字段的commit对象。

这意味着可以对提交进行签名

  1. 仅使用SHA-1,就像在现有的签名提交对象中一样

  2. 通过同时使用gpgsig-sha256和gpgsig,同时使用SHA-1和SHA-256领域。

  3. 只使用SHA-256,只使用gpgsig-sha256字段。

旧版本的“git verify-commit”可以在中验证gpgsig签名案例(1)和(2)没有修改,并将案例(3)视为普通的未签名提交。

签名的标记

我们在标记对象格式中添加了一个新字段“gpgsig-sha256”,以允许在不依赖SHA-1的情况下对标记进行签名。它的签名有效载荷是标记的SHA-256内容及其gpgsig-sha256字段和“-----BEGIN PGP签名-----“删除了分隔的正文签名。

这意味着可以对标签进行签名

  1. 仅使用SHA-1,如在现有的签名标记对象中

  2. 同时使用SHA-1和SHA-256,通过使用gpgsig-sha256和体内签名。

  3. 只使用SHA-256,只使用gpgsig-sha256字段。

Mergetag嵌入

提交的SHA-1内容中的mergetag字段包含由该提交合并的标记的SHA-1内容。

同一提交的SHA-256内容中的mergetag字段包含同一标签的SHA-256内容。

子模块

要转换记录的子模块指针,需要转换子模块存储库到位。子模块的转换表可用于查找新哈希。

松散物体和无法触及的物体

在lose-object-idx中快速查找需要loose的数量对象不会长得太高。

“git-gc--auto”当前正在等待6700个松散对象在将它们合并到包文件之前显示。我们需要测量以找到一个更合适的阈值。

“git-gc--auto”当前正在等待出现50个包在组合packfiles之前。更积极地包装松散物体可能会导致包文件的数量增长过快。这可能是通过使用类似于马丁·菲克指数的策略来缓解滚动垃圾收集脚本:https://gerrit-review.googlesource.com/c/gerrit网站/+/35215

“git-gc”当前会排除它在中遇到的任何无法访问的对象在以下情况下,将文件打包到松散对象,以防止发生竞争修剪它们(以防另一个进程同时编写新的引用即将删除对象的对象)。这导致存在的松散对象数量和磁盘空间激增由于delta形式的对象被替换为独立对象而导致的用法松散物体。更糟糕的是,松散物体仍然存在竞争。

相反,“git-gc”需要将无法访问的对象移动到新的标记为UNREACHABLE_GARBAGE的包文件(使用PSRC字段;请参阅(见下文)。为了避免在编写引用即将被删除的对象,写入新对象的代码路径将需要从UNREACHABLE_GARBAGE包中复制任何对象请参阅新的非UNREACHABLE_GARBAGE包(或松散对象)。如果UNREACHABLE_GARBAGE的创建时间(作为由文件的mtime指示)已经足够长了。

为了避免UNREACHABLE_GARBAGE包的扩散,可以在某些情况下合并。如果“gc.garbageTtl”设置为大于一天,则在单个日历日内创建包,UTC,可以合并在一起。生成的包文件将具有m时间在当天午夜之前,因此这将使有效最大值ttl垃圾ttl+1天。如果“gc.garbageTtl”少于一天,然后我们将日历日划分为ttl的三分之一的间隔持续时间。可以合并在相同间隔内创建的包一起。生成的包文件将在结束之前具有mtime间隔,因此这使得有效最大ttl等于垃圾Tl*4/3。

这个规则来自Thirumala Reddy Mutchukota的JGit更改https://git.eclipse.org/r/90465

UNREACHABLE_GARBAGE设置位于包的PSRC字段中索引。更一般地说,该字段指示包的来源:

  • 1(PACK_SOURCE_RECEIVE)表示通过网络接收的包

  • 2(PACK_SOURCE_AUTO)表示由轻量级“gc--自动”操作

  • 3(PACK_SOURCE_GC)用于由完整GC创建的包

  • 4(PACK_SOURCE_UNREACHABLE_GARBAGE)用于潜在垃圾由gc发现

  • 5(PACK_SOURCE_INSERT),用于本地创建的对象直接写入包文件,例如从“git add”中写入

此信息对于调试和“gc--auto”对要合并的包进行适当的选择。

注意事项

无效的对象

从SHA-1内容到SHA-256内容的转换保留了原始对象中的中断(例如,使用前导0,路径未正确排序的树对象,以及在没有作者或提交者的情况下提交对象)。这是故意的允许转换为往返的设计功能。

更严重的破坏对象(例如,带有截断的“树”的提交标题行)无法转换,但当前Git无法使用无论如何。

浅克隆和子模块

因为它要求所有引用的对象在本地生成的转换表,此设计不支持浅克隆或未蚀刻子模块。协议改进可能允许解除此限制。

备选方案

出于同样的原因,SHA-256存储库不能从SHA-1存储库使用对象/info/alternates或$GIT_ALTERNATE_OBJECT_RE位置。

git注释

“git-notes”工具使用对象的SHA-1名称作为键来注释对象。此设计没有描述迁移notes树以使用的方法SHA-256名称。预计迁移将单独进行(针对使用notes树根目录下的文件描述以下内容的示例它使用的散列)。

服务器端成本

在Git协议获得SHA-256支持之前,使用基于SHA-255的存储强烈建议不要在公共Git服务器上使用。一次Git协议获得了SHA-256支持,基于SHA-255的服务器可能不支持支持SHA-1兼容性,避免可能非常昂贵的在克隆期间重新编码散列并鼓励对等方进行现代化。

这里描述的设计允许SHA-1客户端获取个人SHA-256存储库,因为它并不比允许来自该存储库的推送。这种支持需要加以保护通过配置选项-像git.kernel.org这样的服务器预计大量客户不会承担这一成本。

签名的含义

签名提交和标记的签名有效负载没有显式地命名用于标识对象的哈希。如果有一天Git接受了一个新的与当前SHA-1长度相同的散列函数(40十六进制数字)或SHA-256(64个十六进制数字)对象,然后对象签名中PGP签名有效负载背后的意图是不清楚的:

对象e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7类型commit标签v2.12.0标记员Junio C Hamano<gitster@pobox.com> 1487962205 -0800
基特2.12

这是否意味着Git v2.12.0是使用SHA-1名称的提交e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7或使用提交新的40位数字手名e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7?

幸运的是,SHA-256和SHA-1的长度不同。如果Git启动使用另一个具有相同长度的散列来命名对象,然后它将需要使用该散列将签名有效载荷的格式更改为解决这个问题。

命令行上的对象名称

为了支持过渡(见下面的过渡计划),本设计支持四种不同的操作模式:

  1. (“暗启动”)将用户输入的对象名称视为SHA-1和将写入输出的任何对象名称转换为SHA-1,但存储对象使用SHA-256。这允许用户在没有可见的行为变化,性能除外。这允许运行假设SHA-1哈希函数的偶数测试,以健全性检查新模式的行为。

  2. (“早期转换”)允许SHA-1和SHA-256对象名输入。写入输出的任何对象名称都使用SHA-1。这允许用户继续使用SHA-1与对等方进行通信(例如通过电子邮件)尚未迁移并为模式3做准备。

  3. (“后期转换”)允许SHA-1和SHA-256对象名输入。写入输出的任何对象名称都使用SHA-256。在这个模式下,用户使用更安全的对象命名方法违约。只要他们的大多数同龄人处于模式2或模式3。

  4. (“转换后”)将用户输入的对象名称视为SHA-256,并使用SHA-256写入输出。这比模式3更安全因为输入被错误解释的风险较小使用了错误的散列函数。

模式在配置中指定。

用户还可以显式指定要用于特定的修订说明符和输出,覆盖模式。对于例子:

git—输出格式=sha1 log abac87a^{sha1}。。f787cac^{sha256}

过渡计划

一些初始步骤可以彼此独立执行:

  • 添加散列函数API(vtable)

  • 教fsck容忍gpgsig-sha256字段

  • 将gpgsig-*从“git commit--modify”复制的字段中排除

  • 用SHA1测试注释依赖于SHA-1值的测试先决条件

  • 使用“struct object_id”、GIT_MAX_RAWSZ和GIT_MAX_HEXSZ一致地而不是“unsigned char”和硬编码常数20和40。

  • 引入索引v3

  • 添加对PSRC字段的支持和更安全的对象修剪

第一个用户可见的更改是引入了objectFormat扩展名(不带compatObjectFormat)。这需要:

  • 教fsck关于这种操作模式

  • 计算对象名称时使用散列函数API(vtable)

  • 对对象签名并验证签名

  • 拒绝从不兼容的储存库

接下来介绍compatObjectFormat:

  • 实现lose-object-idx

  • 在对象格式之间转换对象名称

  • 在对象格式之间转换对象内容

  • 生成和验证compat格式的签名

  • 将新对象添加到对象存储

  • --输出格式选项

  • ^{sha1}和^{sha256}修订符号

  • 配置以指定默认输入和输出格式(请参阅上面的“命令行上的对象名称”)

下一步是支持对SHA-1存储库的提取和推送:

  • 允许使用compat格式推送到存储库

  • 生成提取的SHA-1名称的拓扑排序列表物体

  • 将获取的包文件转换为SHA-256格式并生成idx文件

  • 重新排序以匹配获取的包文件中对象的顺序

支持获取的基础结构还允许转换现有的存储库。在转换的存储库和新克隆中,最终用户可以获得对新哈希函数的支持,而不会对行为(请参阅“命令行上的对象名称”中的“暗启动”第节)。特别是,这允许用户验证SHA-256签名在存储库中的对象上,它应该确保转换代码生产稳定,为更广泛的使用做好准备。

随着时间的推移,项目将鼓励用户采用“早期“过渡”和“后期过渡”模式,以利用新的、更经得起未来考验的SHA-256对象名称。

当同时设置objectFormat和compatObjectFormat时,命令生成签名将生成SHA-1和SHA-256签名默认情况下,支持新用户和旧用户。

在大量使用SHA-256的项目中,可以鼓励用户采用避免意外隐含使用的“后过渡”模式SHA-1对象名称的。

一旦大量用户升级到Git版本可以验证SHA-256签名并已转换其现有签名存储库来支持验证,我们可以添加对设置为仅生成SHA-256签名。预计将在至少一年后。

这也是宣传转换能力的好时机存储库仅使用SHA-256,去掉所有与SHA-1相关的元数据。这通过消除翻译提高了性能通过避免意外发生的可能性来提高开销和安全性依靠SHA-1的安全。

更新Git的协议以允许服务器指定哪个哈希它支持的功能也是这一转变的重要组成部分。本文件中未详细讨论,但本过渡计划假设它发生了。:)

考虑的备选方案

在升旗日升级参与特定项目的每个人

像Linux内核这样的项目既大又复杂,足以立即切换基于存储库的所有项目是不可行的。

不仅所有开发人员和服务器运营商都支持开发人员必须在同一个标记日切换,但要支持工具(持续集成、代码审查、错误跟踪等)必须也要进行调整。这也使得很难获得早期反馈来自一些项目参与者的测试收养。

并行使用散列函数

(例如。https://lore.kernel.org/git/22708.8913.864049.452252@chiark.greenend.org.uk网站/)新创建的对象将由新散列寻址,但在内部这样的对象(例如提交)仍然可以寻址对象使用旧的散列函数。

  • 您不能将其历史记录(可分性所需)信任于没有进一步工作的未来

  • 随着支持的哈希函数数量的增加,维护负担也随之增加(它们永远不会消失,所以会积累)。在本提案中,由比较后,转换的对象将丢失对SHA-1的所有引用。

具有多个哈希的签名对象

而不是在提交和标记对象中引入gpgsig-sha256字段对于SHA-256基于内容的签名,此设计的早期版本添加了“hash sha256<SHA-256 name>”字段以加强现有的基于SHA-1内容的签名。

换句话说,使用单个签名来证明对象使用两个哈希函数的内容。这有一些优点:

  • 使用一个签名而不是两个签名可以加快签名过程。

  • 有一个带有两个散列的签名有效负载,签名者可以证明SHA-1名称和SHA-256名称引用同一对象。

  • 所有用户使用相同的签名。签名可能损坏使用当前版本的git快速检测。

然而,它也有缺点:

  • 验证签名对象需要访问所有它引用的对象,即使在转换完成之后其他任何东西都不再需要翻译表。为了支持这样,该设计添加了诸如“hash sha1 tree<SHA-1 name>”之类的字段并将“hash sha1 parent<SHA-1 name>”添加到已签名的提交,使转换过程复杂化。

  • 允许不带SHA-1的签名对象(对于转换后完整)使设计更加复杂,需要“nohash sha1”字段以禁止在SHA-256内容中包含“hash sha1”字段和签名有效载荷。

延迟填充的翻译表

建造翻译表的一些工作可以推迟推送时间,但这会使推送过程大大复杂化并减慢推送速度。在创建对象的同时计算SHA-1名称流式传输到磁盘并计算其SHA-256名称应该是可接受的成本。

文档历史记录

2017-03-03jrnieder@gmail.com合并了乔纳森坦米和斯贝尔的建议:

  • 描述每个哈希类型的签名对象的用途

  • 使用第一散列函数

2017年3月6日jrnieder@gmail.com

  • 使用SHA3-256代替SHA2(谢谢,莱纳斯和布莱恩·卡尔森)。[1][2]

  • 使基于SHA3的签名成为单独的字段,避免了“hash”和“nohash”字段(多亏了peff[3])。

  • 添加一个排序阶段以获取(感谢Junio注意到了这一需要为此)。

  • 在获取期间从拓扑排序中忽略blob(多亏了peff)。

  • 在注意事项中讨论备用、git注释和git服务器部分(感谢Junio Hamano、brian m.carlson[4]和Shawn皮尔斯)。

  • 澄清整个过程中的语言(感谢各种评论,尤其是朱尼奥)。

  • 使用占位符NewHash代替SHA3-256

  • 描述选择哈希函数的标准。

  • 包括过渡计划(特别感谢Brandon Williams充实这些想法)

  • 定义翻译表(谢谢,肖恩·皮尔斯[5],乔纳森Tan和Masaya Suzuki)

  • 通过更积极地打包,避免松散的物体开销“git-gc--自动”

后来的历史:

  • 有关后续文件的历史记录,请参阅git.git中此文件的历史编辑。此文档历史记录不再保留为现在对提交日志来说是多余的

参考文献:

[1] https://lore.kernel.org/git/CA网站+55aFzJtejiCjV0e43型+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@mail.gmail.com/[2] https://lore.kernel.org/git/CA网站+55华氏度+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/[3] https://lore.kernel.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net公司/[4] https://lore.kernel.org/git/2017304224936.rqqtkdvfjgyezsht@genre.crustytohspaste.net[5] https://lore.kernel.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@邮箱.gmail.com/
滚动到顶部