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=
# 上面的大致意思是
<module> <version>/go.mod h1:<sha256hash+base64>
# 第一段是模块依赖路径
# 第二段是版本信息/具体文件
# 第三段是针对该文件内容计算的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时需要同时写上<module> <version>/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-checksum.git

go.sum中特殊hash如何计算相关推荐

  1. HashMap中的Hash码怎么计算,为什么要这样做?

    HashMap面试系列(1) Q:HashMap中的Hash码如何计算?为什么要这么做? 注意:HashCode()是对象的Hash码,和HashMap中的Hash码不是同一个东西 1.8版本如下 s ...

  2. 全网把Map中的hash()分析的最透彻的文章,别无二家。

    你知道HashMap中hash方法的具体实现吗?你知道HashTable.ConcurrentHashMap中hash方法的实现以及原因吗?你知道为什么要这么实现吗?你知道为什么JDK 7和JDK 8 ...

  3. HashMap中的hash函数

    在写一个HashSet时候有个需求,是判断HashSet中是否已经存在对象,存在则取出,不存在则add添加.HashSet也是通过HashMap实现,只用了HashMap的key,value都存储一个 ...

  4. libevent中的hash表

    libevent中的hash表的代码在ht-internal文件中,在添加io事件,signal事件时,底层是在操作  event_io_map和event_signal_map 1. hash的 ...

  5. C++中的Hash容器总结

    散列Hash函数是一种特殊的映射函数, 散列表Hash Table由散列函数所产生的一种数据结构. 这是一种非常重要的数据结构. 首先, 先了解散列表在数据结构方面的基础: 散列表是用于存储动态集的一 ...

  6. Python操作Redis中的hash

    Redis 数据库hash数据类型是一个string类型的key和value的映射表,适用于存储对象.Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿).  Python的re ...

  7. history模式监听_面试题:VueRouter中的 hash 模式和 history 模式有什么区别

    面试题:VueRouter中的 hash 模式和 history 模式有什么区别 hash模式 hash 模式的路由中带有 # 号 hash 模式通过 window.onhashchange 方法监听 ...

  8. hash地址_redis中的hash扩容、渐进式rehash过程

    背景: redis字典(hash表)当数据越来越多的时候,就会发生扩容,也就是rehash 对比:java中的hashmap,当数据数量达到阈值的时候(0.75),就会发生rehash,hash表长度 ...

  9. bat从数组中找出相同数字并删除_全网把Map中的hash()分析的最透彻的文章,别无二家...

    原文地址:https://mp.weixin.qq.com/s/qCHkzs4JPOipB-ZzqrfbeQ 作者: Hollis 你知道HashMap中hash方法的具体实现吗? 你知道HashTa ...

最新文章

  1. 不写代码,用图形界面搞机器学习:MIT发布“全球最快AutoML”,刷新DARPA比赛成绩...
  2. python爬百度翻译-Python爬虫实现百度翻译功能过程详解
  3. python requests库api_Python+requests库发送接口入参为xml格式的接口请求
  4. python和php可以一起用吗_Apache同时支持PHP和Python的配置方法
  5. java什么是网络接口_java 网络编程 -- IP地址的表示与网络接口信息的获取(InetAddress和NetworkInterface)...
  6. 用python编写最简单的记事本_Python使用字典实现的简单记事本功能示例
  7. android 根据资源名称,如何在Android中按名称访问可绘制资源
  8. uint32_t 是常数吗_UINT_MAX常数,带C ++示例
  9. 学以致用二十二-----写一个基本环境设置的脚本
  10. HarmonyOS 正式登陆华为手机,4月陆续升级!
  11. TCP/IP基础总结性学习(2)
  12. 大型网站技术学习-3. 容器Docker与kubernetes
  13. 问答网站系统Question2Answer评测
  14. 系统分析与设计课程项目总结
  15. python常用文件操作和解析xml文件
  16. 变量的定义、类型、注释、拼接字符串、选择循环结构、读取文件
  17. mysql drop语句怎么用_SQL DROP 语句
  18. 阮一峰:值得分享给开发者的 Authing 身份云
  19. Sen2Cor-02.05.05处理哨兵数据的坑
  20. 用户体验思考与flex三坑:元素不均分、溢出不省略和垂直不滚动

热门文章

  1. 华为手机截屏怎么截长图_华为手机竟然有6种截屏方法,你用过几种?3种以上的手机没白买...
  2. 内蒙古电力交易对数据中心用电费用的影响分析
  3. 给数据中心来个例行“体检”——动力系统
  4. 剑三 计算机中丢失,剑网3指尖江湖:剑侠情缘中“丢失”的几年,竟在腾讯游戏被找到...
  5. 用python计算贷款_Python基于Logistic回归建模计算某银行在降低贷款拖欠率的数据示例...
  6. Jenkins 设置镜像_我常用的SpringBoot+Jenkins自动化部署技巧,贼好用,推荐给大家...
  7. CSDN:因博主近期注重写专栏文章(已超过150篇),订阅博主专栏人数在突增,近期很有可能提高专栏价格(已订阅的不受影响),提前声明,敬请理解!
  8. 集成学习-Boosting集成学习算法LightGBM
  9. Http请求Response Code含义
  10. linux系统如何进行录屏