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 = "sha256hash  go.mod\n" ,中间用两个空格分隔,最后必须有一个环行符
# 3.将base64in作为输入给base64进行编码得到base64encode
# 4.字符串拼接得到go.sum中一样的结果 h1:base64encode

go.mod的hash计算可以通过shell模拟得出结果,但是对于整个模块的hash计算就无能为力了,下面通过shell命令模拟上述过程

$ sha256sum go.mod 
5a93925e1efdeecd8b5755d089fdba6dfb3c04eb85447e8dec8b31cdb44203ab  go.mod    #sha256hash
$ vim base64in.txt  
5a93925e1efdeecd8b5755d089fdba6dfb3c04eb85447e8dec8b31cdb44203ab  go.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结果

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

你可能感兴趣的:(go.sum中特殊hash如何计算)