哈希函数的定义
密码学哈希函数 H 是一个确定性函数,将任意长度的输入映射为固定长度的输出(称为哈希值、摘要或指纹):
h = H(M),其中 M 为任意长度消息,h 为固定长度输出
例如 SHA-256 无论输入是 1 字节还是 1 TB,输出总是 256 位(32 字节)。
哈希函数的五大性质
- 确定性(Deterministic):相同输入永远产生相同输出。H("hello") 每次结果一样。
- 快速计算(Computationally Efficient):对于任意输入,计算哈希值应当很快。SHA-256 在现代 CPU 上可达数 GB/s。
- 抗原像性(Pre-image Resistance):给定哈希值 h,很难找到 M 使得 H(M) = h。即"给定输出,找不到输入"。这是单向性的体现。
- 抗第二原像性(Second Pre-image Resistance):给定输入 M₁,很难找到 M₂ ≠ M₁ 使得 H(M₁) = H(M₂)。即"给定一个输入,找不到另一个同输出的输入"。
- 抗碰撞性(Collision Resistance):很难找到任意两个不同的 M₁ ≠ M₂ 使得 H(M₁) = H(M₂)。即"任意找一对碰撞都不可行"。
性质之间的关系
抗碰撞性 → 抗第二原像性 → 抗原像性(前者蕴含后者)。因此抗碰撞性是最强的要求。
安全强度
对于 n 位哈希函数:
- 抗原像攻击:需要约 2n 次运算
- 抗第二原像攻击:需要约 2n 次运算
- 抗碰撞攻击:由于生日悖论,只需约 2n/2 次运算
所以 SHA-256 的碰撞安全强度为 128 位,原像安全强度为 256 位。
哈希函数的应用场景
数据完整性验证
计算文件或消息的哈希值,传输后重新计算并比对。若哈希值一致,则数据未被篡改(假设哈希函数安全且哈希值本身未被篡改)。
数字签名
不对整个消息签名(消息可能很长),而是对消息的哈希值签名。签名 = Sign(H(M))。效率高且安全。
密码存储
数据库中不存储明文密码,而是存储 H(password + salt)。验证时对输入密码做同样哈希后比对。即使数据库泄露,攻击者也无法直接获取密码。
数据结构
- 哈希表:用哈希函数将键映射到数组索引,O(1) 查找
- 默克尔树(Merkle Tree):区块链和 Git 使用的树形哈希结构
密钥派生
从一个共享密钥派生出多个子密钥:K₁ = H(K || "enc"), K₂ = H(K || "mac")。
承诺方案
承诺 C = H(value || nonce),之后揭示 value 和 nonce 来验证。用于拍卖、投票等场景。
理想哈希函数:随机预言机
随机预言机(Random Oracle)是一个理想化的哈希函数模型:对每个新输入返回一个独立的均匀随机值,对已见过的输入返回相同值。
现实中不存在真正的随机预言机(因为哈希函数是确定性的公开算法),但它是密码学安全证明中的重要工具。任何可证明安全的哈希函数都"接近"随机预言机的行为。