go.sum中特殊hash如何计算

Golang为了依赖的安全考虑,在go.mod的基础上引入了go.sum,go.sum文件的作用主要是记录项目依赖的hash值,防止被人修改。
在分析具体项目的go.sum文件后可以发现go.sum中不仅记录了go.mod等的hash值,也记录了整个模块的hash值,这是为什么呢?
这样作的目的主要是在下载整个模块内部的时候可找到子依赖,使得可以并行下载多个依赖。
起初我以为go.sum中记录的hash值是通过sha256直接计算再进行base64编码后的结果,但是在实际操作验证时得到的base64值和go.sum中记录的总是对不上,因此通过查看go的源码(/usr/local/go/src/cmd/go/下面对/usr/local/go/src/cmd/vendor/golang.org/x/mod/sumdb/dirhash包下有引用依赖,这里也是实现go.sum的底层算法核心)发现Golang对文件的hash和整个项目的hash计算并不是简单的sha256计算和base64编码。
案例分析

cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= # 上面的大致意思是 /go.mod h1: # 第一段是模块依赖路径 # 第二段是版本信息/具体文件 # 第三段是针对该文件内容计算的sha256哈希值再进行bash64编码的值 # 其中h1代表的意思就是sha256+base64

特殊hash计算
go.mod的特殊hash计算
# 输入:go.mod的文件路径 # 步骤: # 1.打开go.mod文件读取文件内容进行sha256哈希计算,得到sha256hash # 2.构建新的字符串 base64in = "sha256hashgo.mod\n" ,中间用两个空格分隔,最后必须有一个环行符 # 3.将base64in作为输入给base64进行编码得到base64encode # 4.字符串拼接得到go.sum中一样的结果 h1:base64encode

go.mod的hash计算可以通过shell模拟得出结果,但是对于整个模块的hash计算就无能为力了,下面通过shell命令模拟上述过程
$ sha256sum go.mod 5a93925e1efdeecd8b5755d089fdba6dfb3c04eb85447e8dec8b31cdb44203abgo.mod#sha256hash $ vim base64in.txt 5a93925e1efdeecd8b5755d089fdba6dfb3c04eb85447e8dec8b31cdb44203abgo.mod# base64in字符串,注意下面的环行符不能少,不然和Golang中的结果对不上$ sha256sum base64in.txt| xxd -r -ps | base64 +DbmgtsW3Ksw3QccfHlswRDLj07woKf4ku0C0xYA7u0=#base64encode # 最终的结果经过字符串拼接即可得到 h1:+DbmgtsW3Ksw3QccfHlswRDLj07woKf4ku0C0xYA7u0= #在写入go.sum时需要同时写上 /go.mod h1:+DbmgtsW3Ksw3QccfHlswRDLj07woKf4ku0C0xYA7u0=

整个模块的特殊hash计算
对整个模块进行hash计算时不是直接对打包好的zip包求hash,而是对解压后的文件进行遍历hash计算后再进行一次总的hash计算,这样作的目的是避免因为zip算法进行打包时由于字节的差异导致对整个zip包的hash结果不一致
# 输入:模块所在目录和模块在的导入路径(在源码中使用时的那个导入路径) # 步骤: # 1. 遍历模块中所有文件 # 只考虑文件,不考虑目录 # 忽略.git目录内的所有文件 # 拼接每个文件相对路径与导入路径到一起 # 例如:导入路径 "github.com/spf13/cobra",该包中command.go文件经过拼接后为:github.com/spf13/cobra/command.go # 将遍历的结果存储在一个列表中方便后面计算hash # 2. 对上一步得到的列表进行排序 (排序主是保证hash结果一致) # 3.然后进行遍历hash,其计算过程是在排序后的列表中读取一个文件进行sha256 hash 将"ha256hash github.com/spf13/cobra/command.go\n"字符串拼接在后一个文件hash结果前面,以此类推最后得到一个所有文件hash结果的字符串 # 4.对上面的长字符串再进行sha256 hash计算得到结果sha256hash进行base64编码得到base64encode # 5.在写入go.sum时类似如下: github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= # 第一行是对整个包的hash结果 # 第二行是对go.mod的hash结果

【go.sum中特殊hash如何计算】上面的过程都可以在Golang源码中找到,在github找到了一位大神也对这种特殊的hash进行了复现:https://hub.fastgit.org/vikyd...

    推荐阅读