3.4 流密码:从 RC4 兴衰看设计教训


3.4 流密码:从 RC4 兴衰看设计教训

本节摘要:流密码把分组密码的"整块变换"换成"逐位掩码":密钥驱动伪随机数发生器吐出密钥流,与明文逐位异或。它曾经是无线通信与网页加密的主角——RC4 统治了 WEP 与 SSL 长达十五年,又在十年内被统计偏差攻破、被标准除名。本节沿这条兴衰线讲透流密码的结构、LFSR 的线性陷阱、RC4 的败因,以及继任者 ChaCha20 的设计要点。

密钥流的生意:一次一位的加密

2.3 节已经见过一次一密的形态:密钥流与明文逐位异或。流密码保留这个形状,但把"与明文等长的真随机密钥"换成"由短密钥驱动的伪随机密钥流"——密钥播种给一个发生器,发生器连续吐出与明文等长的伪随机字节,加密就是一次异或。与分组密码相比,它天生逐字节处理、无填充、时延极低,尤其适合语音、无线帧这类字节即到即发的场景;香农的告诫也随之而来:密钥流的统计质量就是一切——它离随机多远,破译者就能从密文里挤出多少信息。

早期流密码偏爱线性反馈移位寄存器(LFSR):一排寄存器位,按抽头位异或后反馈回队头,硬件上只是几级触发器,输出周期可长至 2ⁿ−1。 GSM 语音加密的 A5/1 就是三只 LFSR 的组合。但线性是它的原罪:任何纯 LFSR 序列都能由 Berlekamp-Massey 算法从一小段输出反推出结构,2ⁿ 的周期挡不住 2n 比特的反演。于是工业流密码普遍采用"非线性组合"——多只 LFSR 经非线性函数滤波,或像 RC4、ChaCha20 那样完全用字节运算混合状态。

图:流密码结构与 LFSR 的线性陷阱

图:流密码结构与 LFSR 的线性陷阱

二、RC4 的十五年统治与十年崩塌

1987 年,RSA 公司的罗纳德·李维斯特设计了 RC4(Rivest Cipher 4),作为商业机密保守了七年——1994 年有人把源码匿名贴上互联网,大家惊讶地发现这位主角只有区区几十行:一个 256 字节的状态表 S,先用密钥打乱(KSA),再每步交换两个表项、输出一个字节(PRGA)。如此简单的结构配上不差的统计表现,让它在保密协议与无线标准里无处不在:Wi-Fi 早期的 WEP 用它,SSL/TLS 从 v3 到 1.2 用它,IEEE 802.11、Skype 早期版本同样如此。

崩塌从两头同时发生。WEP 那边是协议层的愚蠢:把 24 位 IV 拼在 RC4 密钥前面,而 IV 以明文随帧广播,24 位空间意味着几千帧后必然重用——密钥流重用加上 RC4 自身的密钥调度偏差,FMS 攻击(2001)把破解 WEP 的时间压到几分钟,Wi-Fi 保护标准 WPA 随即诞生。TLS 这边是统计层的腐蚀:曼廷与沙米尔 2002 年发现输出第二个字节的偏差;2013 年,两组独立研究证明在 TLS 场景下积累约 2²⁶ 个会话即可可靠恢复认证 Cookie;攻击随持续改进逐年降价。2015 年,RFC 7465 正式禁止 RC4 出现在任何 TLS 套件中——从"流量半壁"到"全网禁用",前后不到二十五年。

用十几行 Python 复刻这位陨落主角的完整实现:

def rc4(key: bytes, data: bytes) -> bytes: """RC4:KSA 打乱状态表,PRGA 逐字节输出(仅供理解其简单性与危险性)""" S = list(range(256)) j = 0 for i in range(256): # KSA:密钥打乱状态表 j = (j + S[i] + key[i % len(key)]) % 256 S[i], S[j] = S[j], S[i] out, i, j = bytearray(), 0, 0 for ch in data: # PRGA:交换并输出 i = (i + 1) % 256 j = (j + S[i]) % 256 S[i], S[j] = S[j], S[i] out.append(ch ^ S[(S[i] + S[j]) % 256]) return bytes(out) ct = rc4(b"secret", b"ATTACK AT DAWN") print(ct.hex()) print(rc4(b"secret", ct)) # 对称:同一函数即解密

三、继任者 ChaCha20:用算术重新证明简单不是罪

RC4 的退场没有连累流密码这门手艺——eSTREAM 工程与丹·伯恩斯坦的 ChaCha 家族接过了接力棒。ChaCha20(2008)围绕"四分之一轮"函数展开:对四个 32 位字做"加法、循环移位、异或"各若干次(业内称 ARX 运算),全状态 16 个字、20 轮迭代,密钥 256 位,nonce 96 位。它的每一行都在回应 RC4 的教训:8→32 位字的运算让统计偏差无处藏身,恒定时间实现天然抗时序侧信道(见 7.2 节),软件效率还高得惊人。2015 年后它以 ChaCha20-Poly1305 的 AEAD 组合进入 TLS 套件,与 AES-GCM 平分数据面:没有 AES 硬件指令的手机与路由器上,ChaCha20 反而更快,WireGuard、QUIC 部分实现均默认采用。

流密码百年演化收敛出三条铁律,值得单独成行:

  • 密钥流绝不重用:重用即两份密文的异或等于两份明文的异或(3.3 节实验原样适用);
  • 发生器必须非线性:线性结构(纯 LFSR)扛不住代数反演,输出统计必须有可证明的偏差下界;
  • nonce 纪律写入协议:IV/nonce 的生成与校验必须由协议强制,不能依赖实现者自觉——WEP 的 24 位 IV 就是反例。

💡 关键直觉:流密码是把一次一密的"等长真随机密钥"折算成"短密钥 + 伪随机发生器"的经济学。折算的利差,就是破译者攻击的全部空间——发生器每暴露一分非随机性,利差就被吃掉一分。

本节要点回顾

  • 流密码结构:密钥播种发生器、密钥流异或明文,逐字节低时延,适合语音与无线;
  • LFSR 陷阱:纯线性寄存器可由 Berlekamp-Massey 从约 2n 位输出重建,必须非线性化;
  • RC4 教训:WEP 的短 IV 重用加 RC4 输出偏差使它在 2001 与 2013 两轮攻击后于 2015 年被 RFC 7465 禁用;
  • ChaCha20 接棒:256 位密钥、96 位 nonce、ARX 结构,抗偏差、抗侧信道、无硬件也快,与 AES-GCM 平分 TLS 数据面。

至此"加密"这条线讲完,但只加密的消息仍可能被人调包。下一节回答"怎么确认没人动过手脚",并处理对称密码最后的工程命题——密钥的一生。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U