时序攻击与常数时间实现
问题
如果密码操作的执行时间依赖于秘密数据(密钥、明文),攻击者可以通过精确测量时间来推断这些数据。
典型场景
- 字符串比较:很多实现逐字节比较 MAC/HMAC 值,遇到第一个不匹配就返回。攻击者可以逐字节猜测,每次调整猜测值,观察响应时间变化。
- RSA 中的 Montgomery 约简:条件分支可能泄露密钥比特。
- AES 查表:S 盒查表操作可能因 CPU 缓存命中/未命中而产生时间差异。
防御
- 常数时间比较:比较两个值时遍历所有字节,用位操作累积结果。如:result |= a[i] ^ b[i],最后检查 result == 0。
- 避免秘密相关的分支:if (secret_bit) 语句是危险的,用位掩码替代。
- 避免秘密相关的内存访问:不要用秘密值作为数组索引。
白盒密码学
在白盒攻击环境中,攻击者完全控制执行环境:可以观察和修改内存、设置断点、反汇编代码。这在 DRM(数字版权管理)、移动支付等场景中很常见。
白盒密码的目标:即使攻击者能观察每一步运算,也无法提取出密钥。
基本技术:
- 编码/混淆:将密钥融入查找表和网络变换中,使得密钥不以明文形式出现
- 随机化:在计算中注入随机性,使每次执行看起来不同
目前白盒密码的实用方案都已被攻破。它是密码学中一个活跃但困难的领域。
密码学库
OpenSSL
最广泛使用的密码学库,C 语言编写。提供 SSL/TLS 协议实现和大量密码算法。优点是全面、经过长期审查,缺点是 API 复杂、历史包袱重、容易误用。
Libsodium
基于 NaCl(Daniel J. Bernstein 设计)的现代密码学库。设计理念:安全的默认值、简洁的 API、难以误用。推荐用于新项目。
其他重要库
- BoringSSL:Google 维护的 OpenSSL 分支,去除了大量遗留代码
- Bouncy Castle:Java/C# 平台的密码学库
- cryptography:Python 的高层密码学库(基于 OpenSSL)
常见实现错误
- 自己实现密码算法:几乎总是不安全的。"Don't roll your own crypto"
- 使用 ECB 模式:暴露数据模式
- IV/Nonce 重复:特别是 GCM 模式中,Nonce 重复会导致密钥流重用,灾难性后果
- 使用 MD5/SHA-1:用于安全目的
- 硬编码密钥:密钥应存储在安全的密钥管理系统中
- 不做完整性检查:只加密不认证(缺少 MAC/AEAD)
- 不验证证书:TLS 连接中跳过证书验证等于没有加密