跳转到内容
HexaTransfer
返回博客
加密与安全

哈希函数详解:简单验证文件完整性

哈希函数对传输后验证文件完整性至关重要。了解SHA-256和MD5如何确保文件无损到达。

哈希函数接受任意输入,产生固定长度的摘要——SHA-256 始终输出 256 位(32 字节),无论输入是一条短消息还是一个 10 GB 的视频。改变输入中的任意一个比特,大约一半的输出比特随之翻转。这种单向、确定性的特性使哈希成为验证文件完整性的首选工具:传输前计算 SHA-256(文件),接收后再次计算,两者一致则文件完好送达。Linux 发行版用它验证 ISO 镜像,Git 用它标识提交,HexaTransfer 等服务用它确认多吉字节上传无损完成。

哈希函数的核心保证

密码学哈希函数由三个核心属性定义:

  • 确定性。 相同输入始终产生相同输出。SHA-256("hello") 恒为 2cf24dba5fb0a30e...
  • 原像抗性。 给定哈希值,无法高效找到能产生该值的输入。
  • 抗碰撞性。 无法高效找到两个不同输入产生相同哈希值。

另有两种实用特性:

  • 雪崩效应。 改变一个输入比特,约 50% 的输出比特发生翻转。使哈希无法用于搜索,但非常适合文件指纹。
  • 固定输出长度。 SHA-256 为 32 字节,SHA-512 为 64 字节,BLAKE2b 为 64 字节,与输入大小无关。

哈希不是加密。它是单向的——无法从输出还原输入。这正是其设计意图。

SHA 家族

由 NIST 在 FIPS 180-4 和 FIPS 202 中标准化的安全哈希算法家族:

  • SHA-1 — 160 位,2017 年被 Google SHAttered 攻击攻破,不要用于安全场景。
  • SHA-2(SHA-224、SHA-256、SHA-384、SHA-512)。 现代系统的主力,SHA-256 占主导。
  • SHA-3(Keccak)。 不同构造(海绵结构而非 Merkle-Damgård),2015 年标准化,作为 SHA-2 潜在弱点的后备方案,但该弱点至今未实际出现。

SHA-256 是 TLS 证书签名、Bitcoin 挖矿和 Git 使用的算法,也是文件传输服务执行完整性校验的标准。支持 SHA 扩展指令的现代 CPU 单核吞吐量约为 2–4 GB/s。

MD5 和 SHA-1 为何在安全场景中已成过去

MD5(1991 年)产生 128 位哈希,曾是业界标准,直到 2004 年碰撞攻击被公开演示。2012 年,Flame 恶意软件利用 MD5 碰撞攻击伪造了微软代码签名证书。今天,在普通笔记本电脑上几秒钟即可生成 MD5 碰撞。

SHA-1 存活时间更长,但在 2017 年被 Google SHAttered 攻击攻破——该攻击耗费 110 GPU 年算力后产生了两个 SHA-1 哈希相同的 PDF 文件,如今在云 GPU 上花费不到 10 万美元即可复现。

两者仍适用于非安全场景:检测意外数据损坏、存储去重、缓存键指纹。但不适用于数字签名、密码验证,或攻击者可从伪造匹配中获益的任何场景。

BLAKE2 和 BLAKE3:速度与安全的兼顾

BLAKE2(2012 年)和 BLAKE3(2020 年)以 SHA-256 两到十倍的速度实现 SHA-3 级别的安全性。BLAKE3 单线程吞吐量约 6 GB/s,且在多核上线性扩展——16 核机器可达 100+ GB/s。

采用率持续增长:WireGuard 使用 BLAKE2s 进行认证,Zcash 使用 BLAKE2b,b3sum 正逐渐成为开发工具中 sha256sum 的替代品。处理多吉字节上传的文件传输服务越来越多地采用 BLAKE3,避免哈希计算成为性能瓶颈。

目前浏览器的 Web Crypto API 尚未暴露 BLAKE3,因此 JavaScript 实现依赖 WASM 编译的参考代码,在浏览器中速度约为 500 MB/s。

哈希在文件传输工作流中的作用

哈希在多个关键环节发挥价值:

  • 上传后完整性校验。 客户端上传时计算 SHA-256,服务器到达时再次计算,不匹配则触发重新上传。S3 使用 MD5 完成此操作,因为速度比抗碰撞性更重要。
  • 分块上传验证。 大文件分割为 4 MB 或 5 MB 的块,每块有独立哈希,哈希树(Merkle 树)为整个文件生成单一根哈希。
  • 去重存储。 两个用户上传相同文件时,哈希匹配,存储只保存一份。Dropbox 的块级去重和 CDN 缓存均使用此机制。
  • 下载验证。 部分服务在下载页面显示 SHA-256,供接收方自行核验。
  • 版本标识。 Git 使用 SHA-1(正在迁移至 SHA-256)作为提交 ID——文件内容决定其身份标识。

HMAC 扩展:从完整性到真实性

纯哈希可以验证完整性,但无法验证真实性——任何人都可以计算 SHA-256(文件)。添加密钥将哈希转变为消息认证码(MAC):只有持有密钥的人才能生成或验证 MAC。

HMAC(RFC 2104)是标准构造:HMAC(key, msg) = SHA-256(key' ⊕ opad ‖ SHA-256(key' ⊕ ipad ‖ msg))。用于 TLS 1.2、以 HS256 签名的 JWT、AWS 请求签名以及许多会话 cookie 方案。

在文件传输中,HMAC 的角色体现在 AES-GCM 的认证标签(使用 GHASH 而非 HMAC,但作用相同)以及部分服务的 API 请求签名中。

Merkle 树:大规模数据的哈希方案

对于超大文件或文件集合,每次都对全部内容重新哈希是低效的。Merkle 树将哈希组织成二叉树结构:叶节点是块哈希,内部节点是其子节点的哈希,根哈希代表整个数据集。

主要优势:

  • 高效更新。 修改一个块只需重新哈希 log(n) 个节点。
  • 包含证明。 只需 log(n) 个兄弟哈希即可证明特定块属于根哈希。
  • 并行计算。 各分支可独立并行哈希。

BitTorrent(v2 以后)、IPFS 内容寻址、Git 树对象、证书透明日志和区块链交易根均使用 Merkle 树。文件传输服务使用它支持断点续传,对部分已上传内容进行验证。

密码哈希与文件哈希的区别

哈希的另一个应用:将密码转换为可安全存储的摘要。简单的 SHA-256(密码) 远远不够——GPU 集群每秒可计算数十亿次 SHA-256,任何常见密码都会被瞬间破解。

专用密码哈希函数通过增加计算成本来应对:

  • PBKDF2-HMAC-SHA-256:60 万次迭代(OWASP 2023 建议值)。
  • bcrypt:成本因子 12(每次哈希约 250 毫秒)。
  • scrypt:内存硬化,抵抗 GPU 大规模并行攻击。
  • Argon2id:当前最佳实践,兼具内存硬化和抗并行攻击特性。

目标不在于哈希算法本身的安全性,而是让每次猜测成本足够高,使离线暴力破解对强度合理的密码变得不可行。

手动验证下载文件

任何需要关注的文件都可以用命令行工具进行验证。在 macOS 或 Linux 上:

shasum -a 256 ubuntu-24.04.iso

在 Windows PowerShell 上:

Get-FileHash ubuntu-24.04.iso -Algorithm SHA256

将输出与 ubuntu.com 上发布的哈希对比。匹配则文件下载完整,与 Canonical 签名的版本一致。不匹配则说明下载损坏或文件已被替换。

要获得最高信任级别,可用 GPG 和 Canonical 签名密钥验证哈希文件本身的签名。签名哈希文件→文件哈希→文件的多层链条,正是 Linux 发行版几十年来维护信任的方式。

评估文件传输服务的完整性处理能力

向文件传输服务商询问以下四个问题,值得认真对待:

  • 用什么哈希算法验证上传?(SHA-256 或 BLAKE3 均可;MD5 仅适用于损坏检测;对此沉默是一个警示信号。)
  • 是否向接收方显示哈希值?(并非所有服务都这样做,但这是加分项。)
  • 分块上传是否进行 Merkle 树验证?
  • 是否提供跨端点哈希比对的方式?

SwissTransfer、Tresorit、Proton Drive 和 HexaTransfer 均在传输过程中计算 SHA-256 并在到达时验证。完整性校验失败会触发受影响块的自动重传,而不是导致整个传输任务失败。

在 hexatransfer.com 上试试 — 免费、无需注册、最多 10 GB。

通过端到端加密安全发送大文件

通过端到端加密免费传输最大10GB的文件。无需注册账户。文件在上传前在浏览器中加密,其他人无法读取。

发送文件