第二章 杂凑函数基础:四大护法

要讲清楚 SM3 在密钥派生里怎么“守边界”,得先聊聊杂凑函数的老本行。说白了,它就是一把单向门——数据进去,指纹出来。你拿着指纹,永远变不回原来的数据。我当年刚入门时觉得这玩意很简单,直到在项目里踩了坑,才明白这几个性质有多重要。

杂凑函数四大核心性质关系图 杂凑函数核心性质 杂凑函数 H(M) 单向性 (One-way) 已知 h,求 M 不可行 抗碰撞性 (Collision) 找 M1≠M2 使 H(M1)=H(M2) 不可行 抗原像性 (Preimage) 给定 h,找不到任何 M 满足 H(M)=h 长度扩展攻击 H(M) 可预测 H(M||padding||extra) ⚠️ 长度扩展攻击仅存在于 Merkle-Damgård 结构 SM3 基于 MD 结构,使用时需特别注意

2.1 单向性:为什么不能倒着走?

单向性(One-way)是杂凑函数的立身之本。意思是:给定一段消息 M,你可以轻松算出哈希值 H(M);但给你一个哈希值 h,让你找到任意一个 M 使得 H(M)=h,那几乎不可能。

我在一次安全审计中遇到过这样的场景:团队误以为可以用哈希值的部分比特作为“加密密钥”,结果被人反推出明文结构。嗯,这里要注意——单向性不等于加密性。它只是让你没法往回走,并不保证你前向走的路径是秘密的。

单向性在实际中的应用
场景利用单向性做什么常见错误
密码存储存哈希代替明文密码未加盐导致彩虹表攻击
数字签名先对消息哈希再签名用弱哈希(如 MD5)导致伪造
文件完整性发布哈希供校验哈希值被篡改不验证来源
一个关键点:单向性是基于计算复杂度的“不可行”,不是的“不可能”。随着算力提升,曾经安全的哈希也可能变脆。业界才不断从 SHA-1 迁移到 SHA-256,再到 SM3。

2.2 抗碰撞性:名字一样,人不一样?

抗碰撞性(Collision Resistance)分两层:

  • 弱抗碰撞性:给定 M1,你找不到另一个 M2 使得 H(M1)=H(M2)。
  • 强抗碰撞性:你找不到任意两个不同的 M1 和 M2,使得它们的哈希值相同。

直觉上看,强抗碰撞性更难防。它就是要求哈希函数不能有“双胞胎”。你想想看,如果两份不同的智能合约有相同哈希,那区块链不就乱套了?

我曾经在一家金融科技公司审核过他们的交易哈希方案。他们用的是截断后的 SHA-1(只取前 120 位)。我当时就提醒:生日攻击的代价已经低于他们的安全阈值。后来他们切到了 SM3,才放心。

抗碰撞性直接关系到“数字指纹”的可靠性。如果哈希值能碰撞,那数字签名、证书吊销列表、软件包哈希验证全都会崩。所以设计派生密钥时,如果 HMAC 内部用了弱碰撞的哈希,攻击者就可能绕过认证。

2.3 抗原像性:找到原像有多难?

抗原像性(Preimage Resistance)比单向性听起来更像绕口令。其实区别很简单:

  • 单向性:从输出到输入难。
  • 抗原像性:给定输出,找任意一个输入使得哈希匹配也难。

还有一层叫“第二抗原像性”:给定 M1,你找不到不同的 M2 使 H(M1)=H(M2)。这其实就是弱抗碰撞性。所以这几个性质是互相嵌套的——抗碰撞性通常蕴涵抗原像性,反过来不一定。

我个人习惯在评估哈希函数时把这几条列出来逐个打钩。SM3 目前对这三条都扛得住,这也是国标选它做密钥派生的底气。

别混淆“抗原像性”和“不可逆性”。不可逆描述的是数学属性,抗原像性描述的是攻击难度。实际使用时,只要哈希输出充分长(SM3 的 256 位就够了),就可以认为这三条全部满足。

2.4 长度扩展攻击:Merkle-Damgård 的天生缺陷

这玩意是许多安全工程师的噩梦。长度扩展攻击(Length Extension Attack)只针对 Merkle-Damgård(MD)结构的哈希函数。SM3 正是基于 MD 结构。

攻击原理是这样:假设你有一段消息 M 和它的哈希 H(M)。攻击者不需要知道 M 的内容,就能算出 M 加上任意额外内容拼接后的哈希 H(M || padding || extra)。为什么?因为 MD 结构是状态链式的,最后一个状态就是哈希值。攻击者可以直接从那个状态继续算。

看个具体的:

已知:
  M = "my_secret"
  H(M) = SM3("my_secret")

攻击者可以计算:
  M' = "my_secret" + padding + "extra_data"
  H(M') = SM3(M')  // 不需要知道 M,只要知道 H(M) 和 M 的长度

后果:如果系统用 SM3(M) 做身份凭证,攻击者可以用 H(M||extra) 冒充合法用户。

我曾经在 PoC 里跑过这个攻击。嗯,第一次跑通的时候真的后背发凉。那只是个本地测试,但如果是生产环境呢?所以后来我复查所有涉及哈希的协议,只要疑似用裸 MD 哈希做认证或密钥派生,一律换成 HMAC。

长度扩展攻击影响与缓解
受影响的结构典型算法缓解手段
Merkle-DamgårdMD5, SHA-1, SHA-256, SM3使用 HMAC / 使用 SHA-3 / 截断输出
海绵结构SHA-3, Keccak, BLAKE天然免疫,无需额外处理
避坑指南:我曾经在生产系统里见过直接用 SM3(M) 做 API 的。攻击者只要拿到一个 ,就能伪造出对后续数据追加内容的合法 。解决办法加上密钥,变成 SM3(secret || M) 都不够,必须用 HMAC 或至少加一个独立的结构隔离步。

2.5 这一章的小结

单向性、抗碰撞性、抗原像性,这仨是哈希函数的三大基本功。长度扩展攻击则是 MD 系列特有的“暗门”。搞明白了这些,你才能理解为什么密钥派生里不能直接裸用 SM3——需要加一层“边界”。