高级 #crypto#hash

哈希函数(SHA, MD)

密码学哈希函数把任意长度输入映射为固定长度输出——抗碰撞、单向。SHA-256 是当前标准,MD5 和 SHA-1 已被破解

🆔 给数据”算个指纹”

你去公安局办身份证——警察量你的身高、拍你的照片、录你的指纹。按了手印,你就和这份档案”绑定”了。以后只要按个指纹,就能确认”这是你”。

哈希函数就是给数据”按个指纹”——把任意长度的数据(比如一个文件、一条消息),压缩成固定长度的”摘要”(哈希值)。

📐 哈希函数(Hash Function)hash(任意长度输入) → 固定长度输出

一个简单的哈希例子——Mod 10 哈希:

hash("Hello") = 842842 % 10 = 2
hash("World") = 568568 % 10 = 8

🔐 密码学哈希的三个性质

普通哈希(如 Python 的 hash())只要求”分布均匀”——但密码学哈希有三个更强的性质:

性质含义为什么重要
抗碰撞(Collision Resistance)找不到两个不同的输入,使哈希值相同没人能伪造和你一样的”指纹”
单向性(Preimage Resistance)从哈希值反推输入不可行密码哈希存储——数据库被拖了也得不到密码
雪崩效应(Avalanche Effect)输入改一比特,输出约一半比特翻转改一个字符,哈希值完全不同
import hashlib

def sha256(text):
    return hashlib.sha256(text.encode()).hexdigest()

print(sha256("Hello"))
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

print(sha256("Hello "))  # 只多了一个空格
# 5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03
# ↑ 完全不同!

print(sha256("hello"))   # 首字母小写
# 2cf24dba... ← 和 "Hello" 不同!

🧪 常见的哈希算法

算法输出长度安全性推荐使用?
MD5128 位❌ 已破解(可制造碰撞)不用于安全场景
SHA-1160 位❌ 已破解(Google 演示过碰撞)不再推荐
SHA-256256 位✅ 安全✅ 当前推荐
SHA-3可变✅ 安全✅ 新一代标准

⚠️ MD5 的破解:2004 年,中国学者王小云团队发现了 MD5 的碰撞攻击——可以在几分钟内生成两个不同的文件,使 MD5 哈希完全相同。这直接宣告了 MD5 在安全场景中的死亡。


🏢 哈希函数的四个关键应用

① 密码存储

# ❌ 错误做法:数据库存明文密码
# 如果数据库被拖——所有用户密码暴露

# ✅ 正确做法:存哈希值
import hashlib

def store_password(password):
    # 加盐——防止彩虹表攻击
    salt = os.urandom(16)
    hashed = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    return salt + hashed  # 存 salt + 哈希

def verify_password(password, stored):
    salt = stored[:16]
    hashed = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
    return hashed == stored[16:]

🔑 加盐(Salt):即使两个用户设置相同的密码,由于加盐不同,存储的哈希值也不同——攻击者无法用一个”常见密码哈希表”(彩虹表)批量破解。

② 文件完整性验证

# 下载大文件时——验证文件有没有被篡改
# 官方网站提供 SHA-256 校验码
sha256sum ubuntu-24.04-desktop.iso
# 输出:a1b2c3...(64 位十六进制数)
# 和官网对比——一致说明文件没有被修改

③ 数字签名

哈希函数是数字签名的关键——你不是对整个文件签名(太慢),而是先对文件的哈希值签名:

签名:hash(文件) → 签名算法(hash) → 签名
验证:签名算法验证(hash) → 对比 hash(下载的文件)

④ 区块链中的 Merkle Tree

比特币的区块不是直接存所有交易——而是用 Merkle Tree(哈希树)把所有交易的哈希值层层归约为一个根哈希。改任何一笔交易都会导致根哈希变化——保证了区块链数据的不可篡改性。

         Root Hash
       /          \
   Hash(AB)     Hash(CD)
   /     \       /    \
Hash(A) Hash(B) Hash(C) Hash(D)
  ↑       ↑       ↑       ↑
交易A   交易B   交易C   交易D

🆚 密码学哈希 vs 普通哈希

对比密码学哈希(SHA-256)普通哈希(Python hash())
安全性抗碰撞、单向不保证安全
速度相对慢(故意慢一点防暴力)快(用于哈希表)
确定性完全确定每次运行可能不同(Python 加随机种子)
用途安全场景数据结构

📝 小结

概念一句话
哈希函数任意输入 → 固定输出(数据”指纹”)
抗碰撞找不到两个不同输入产生相同哈希值
单向性从哈希值反推输入不可行
雪崩效应改一比特输入 → 一半输出比特翻转
SHA-256当前推荐的密码学哈希(256 位输出)
MD5/SHA-1已破解——不用于安全场景
加盐(Salt)哈希前加随机串——防彩虹表攻击

🎯 思考题:为什么密码学哈希要”故意慢一点”?如果验证用户密码需要 0.1 秒而不是 0.0001 秒——对用户来说几乎无感,但对攻击者来说影响有多大?(提示:尝试 1 亿次暴力破解需要的时间)

为什么先学这个? 哈希函数是数字签名与证书的基础——先把消息”浓缩”成哈希值,再对哈希值签名。