SHA-256 哈希详解:区块链和 TLS 背后的功臣
什么是 SHA-256?
SHA-256 是 SHA-2(Secure Hash Algorithm 2)家族中最常用的成员,由 NSA(美国国家安全局)在 2001 年设计。它的工作是:接收任意长度的输入,输出一个固定 256 位(32 字节)的哈希值。
不管你输入的是一个字母 “a”,还是一整部《红楼梦》的电子版,SHA-256 输出的始终是 256 位,不多不少。
我第一次真正接触到 SHA-256 是在做文件完整性校验的时候。下载了一个 Linux ISO,网站上面附了一串看着像乱码的东西——e3b0c44298fc1c14...——我当时没太在意,觉得就是一些校验手段而已。后来才知道,这串字符背后的设计思想,是整个现代密码学基础设施的基石。
哈希函数到底要满足什么条件?
理解 SHA-256 之前,得先理解加密哈希函数必须满足的几条硬性要求:
- 确定性:同样的输入,永远产生同样的输出。哪怕在不同机器、不同时间、不同操作系统上跑。
- 单向性:给了哈希值,算不出原始输入。这跟加密不同——加密有解密的钥匙,哈希是单向阀门。
- 雪崩效应:输入改一个 bit,输出就天翻地覆。你可以试试在工具里输入 “hello” 和 “Hello”,SHA-256 结果几乎完全不相干。
- 抗碰撞性:在计算上不可行地找到两个不同输入产生相同哈希值的情况。
这四条里第四点最难,也是评价一个哈希算法好坏的核心指标。SHA-1 被淘汰,根本原因就是碰撞攻击从”理论上可能”变成了”实际可行”。
SHA-256 的工作原理
SHA-256 的处理过程可以分为两大步:预处理和压缩迭代。
预处理:把消息整理整齐
原始消息往往不是 512 位的整数倍,所以 SHA-256 的第一步就是填充。填充规则很严格:
- 在消息末尾附加一个
1位(标记填充开始) - 追加若干个
0位,直到消息长度模 512 余 448 - 用一个 64 位的二进制数表示原始消息的长度(以位为单位),追加到最后
经过这三步,消息总长度就是 512 位的整数倍了。这像极了一个固定大小的快递盒子——不管你买的是蚂蚁还是大象,SHA-256 都先把它们打包成统一规格再处理。
压缩函数:核心的 64 轮运算
填充后的消息按 512 位一块依次处理。每处理一块,SHA-256 的压缩函数执行 64 轮运算。初始的 8 个 32 位工作变量来自前 8 个素数(2、3、5、7、11、13、17、19)平方根的小数部分——这个鬼才的设计首次出现在 NSA 的 SHA 规范里,把算法和数学常数绑定在一起,消除了”后门”的嫌疑。
每轮运算混合了四种操作:
- Ch(Choose):根据一个比特位的值选择两个输入中的一个
- Maj(Majority):取三个输入中多数出现 1 的位
- Σ0 和 Σ1:用循环右移和 XOR 实现比特扩散
64 轮下来,哪怕你只改变了输入消息中的一个比特,雪崩效应也会把整个 256 位的哈希值搅得天翻地覆。
最终输出
所有 512 位块都处理完后,8 个 32 位的工作变量拼接起来就是最终的 256 位(64 个十六进制字符)哈希值。
核心特性
| 特性 | 说明 |
|---|---|
| 输出长度 | 256 位(32 字节,64 个十六进制字符) |
| 内部状态 | 512 位分组,8 个 32 位工作变量 |
| 轮数 | 64 轮 |
| 结构 | Merkle-Damgård 构造(按顺序逐块处理) |
| 抗量子性 | 部分——Grover 算法能将 256 位安全性降低到 128 位 |
| 标准化 | FIPS PUB 180-4 |
Merkle-Damgård 结构是 SHA-2 的核心构造方式,它的特点是:当前块的输出依赖于之前所有块的处理结果。好处是简单高效,但也带来了一个著名问题——长度扩展攻击。简单说,如果你知道 SHA-256(M) 和消息 M 的长度,即使不知道 M 本身,也能算出 SHA-256(M + padding + extra)。这就是为什么 HMAC 处理内部和外层哈希两次,来堵住这个漏洞。
实际应用场景
1. 比特币挖矿
这可能是 SHA-256 最”出圈”的应用。比特币的 PoW(工作量证明)机制要求矿工不断尝试不同的 nonce 值,对区块头做双重 SHA-256,直到结果小于某个目标值:
SHA-256(SHA-256(block_header))
这个过程俗称”挖矿”,本质上是在暴力搜索一个满足条件的 nonce。SHA-256 的单向性和伪随机性让搜索变成了纯粹的算力竞争,没有”聪明办法”可以绕过。
有一次我拿树莓派跑了一晚上的比特币挖矿模拟,一个满满足条件的 nonce 都没找到。那一刻直观地理解了全网算力有多恐怖——ASIC 矿机每秒钟做上百万亿次 SHA-256,一台机器的算力抵得上上百万台普通电脑。
2. TLS 证书链
你访问网站时,浏览器验证 SSL 证书可信链的每一步都依赖 SHA-256。证书签发时,CA 对证书内容计算 SHA-256 哈希,然后用 CA 的私钥对哈希签名。浏览器拿到证书后,用 CA 的公钥验证签名——这个过程之所以安全,前提就是 SHA-256 的抗碰撞性。
如果 SHA-256 被攻破、出现了有效的碰撞攻击,整个公钥基础设施(PKI)就会土崩瓦解——攻击者可以生成一个和合法证书哈希相同的假证书。
3. Git 内容寻址
Git 是一个以内容为寻址方式的版本控制系统。每个 commit、每个文件、每个 tree 对象,都有一个以它的 SHA-1 哈希值命名的 ID。虽然 Git 目前还在用 SHA-1(正在迁移到 SHA-256),但原理完全一样。
你在 git log 看到的那些 40 位的十六进制字符串,就是对 commit 数据的哈希摘要。改了文件里任何一行,哈希就变了,Git 立刻知道内容被改动了。
4. 文件完整性校验
下载软件安装包时,官网经常附带一个 SHA-256 校验和。你在本地算一下下载文件的 SHA-256,和官网公布的值对比,一致的话就说明文件在传输过程中完整无损。
不过有一说一,如果你从 HTTP 下载文件又从同一个 HTTP 取校验值,攻击者可以同时篡改。真正的保护来自 HTTPS + 数字签名,SHA-256 校验值更多是防传输错误和 CDN 缓存污染。
5. JWT 签名
JWT 的 HS256 签名算法实质上是 HMAC-SHA256(Payload, Secret)。服务端用私密字符串对 Payload 计算 HMAC,在收到请求时再次计算并比对。如果 Payload 被改了一个比特,HMAC 就对不上,请求就被拒绝。
常见误区
误区一:哈希可以”解密”还原原始数据
这是搜索引擎里常见的搜索词——“SHA-256 解密”。事实上,哈希不是加密,不存在”解密”操作。你在大众密码数据库里查到”e3b0c44298fc1c14…”对应的是空字符串,那是有人提前算好了存起来的,不是算法本身能逆向。这叫”彩虹表查询”,不是解密。加盐(Salt)就是为了让预先算好的彩虹表失效。
误区二:SHA-256 永远不会碰撞
理论上,输入空间无限大(任意长度),输出空间只有 256 位(2^256 种可能),碰撞必然存在——鸽巢原理。只是 2^256 ≈ 10^77,这个数比可观测宇宙中的原子总数还大得多,所以在实际中找不到碰撞。话虽如此,数学上”必然有”和方法上”找到”是两码事,目前没有人能用少于 2^128 次运算的概率找到 SHA-256 的有效碰撞。
误区三:SHA-256 和 SHA-2 是一样的
SHA-2 是一个家族,包含 SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。它们核心算法相同但输出长度和内部状态不同。SHA-256 只是其中最常用的一成员。SHA-224 和 SHA-256 共享 32 位内部运算,SHA-384 和 SHA-512 用的是 64 位。
SHA-256 vs SHA-1 vs SHA-3
| SHA-1 | SHA-256 | SHA-3 (Keccak) | |
|---|---|---|---|
| 输出长度 | 160 位 | 256 位 | 224/256/384/512 位 |
| 内部结构 | Merkle-Damgård | Merkle-Damgård | 海绵结构(Sponge) |
| 安全状态 | 已攻破(SHAttered) | 安全 | 安全(备用) |
| 抗长度扩展 | 弱 | 弱 | 强 |
| 标准化年份 | 1995 | 2001 | 2015 |
SHA-1 的终结始于 2017 年 Google 宣布的 SHAttered 攻击——生成了两个不同 PDF 文件但 SHA-1 哈希相同的实例,打破了密码学社区对 SHA-1 抗碰撞性的最后信念。各大浏览器随后逐步关闭了 SHA-1 证书支持。
SHA-3 走了一条完全不同的路。它的海绵结构(Sponge Construction)天然免疫长度扩展攻击,理论上也更抗量子攻击。但 SHA-256 目前在安全领域仍占主导地位,SHA-3 主要作为一个”后备方案”存在——万一哪天 SHA-2 出问题,业界能有立刻可用的替代品。
常见问题
Q: SHA-256 和 AES-256 的 “256” 是一个意思吗?
完全不是。SHA-256 的 256 是输出哈希值的位数。AES-256 的 256 是密钥的位数。一个是输出来多少,一个是用什么钥匙,别搞混了。
Q: 怎么验证下载文件的 SHA-256?
Windows 用 certutil -hashfile <文件> SHA256,Linux/macOS 用 sha256sum <文件>。把输出的字符串和官网公布的哈希值逐字比对——少一个字符或者大小写不对都不行。
Q: SHA-256 在密码存储里足够安全吗?
SHA-256 本身不够。它计算速度太快了——用 GPU 可以在一秒内算出数亿个哈希值,这让暴力猜密码变得非常高效。用于密码存储的方案应该是 bcrypt、scrypt 或 Argon2——它们故意把哈希算得慢、吃内存,让暴力破解寸步难行。
Q: 什么是比特币的”难度调整”?
比特币网络每 2016 个区块(约两周)调整一次挖矿难度。难度值决定了矿工需要找到多少个前导零的 SHA-256 哈希才能出块。全网算力越高、找 nonce 越快,难度就自动上调,让出块时间稳定在 10 分钟左右。
Q: SHA-256 会被量子计算机攻破吗?
量子计算机用 Grover 算法能把 SHA-256 的抗碰撞安全性从 256 位降到 128 位。128 位仍然是一个相当安全的值——至少需要大约 2^128/√计算能力的量子操作,以目前人类认知的物理限制来看,这是天文数字。但密码学界的态度是”别等出事了再换”,所以才有了 SHA-3 和正在标准化的 NIST 后量子哈希竞赛。