密码学 E08:安全定义与协议审查——IND-CPA、IND-CCA、EUF-CMA
一次“改密文被拒绝”的测试能证明加密方案满足 IND-CCA 吗?不能。你观察的是某个密钥、某条消息、某次篡改;安全定义讲的是指定攻击者可以查询什么、在什么假设下对所有足够大的安全参数成功概率受到何种限制。把“有限测试通过”写成“一般证明”会让协议审查虚假完结。但安全游戏并非只给数学家看的缩写:工程师可以用它们倒推自己是否给攻击者开放了过强的接口。
三种攻击接口是三种问题
在 IND-CPA 游戏里,攻击者可查询加密 oracle,自选两个等长消息 m0,m1,得到其中一个的挑战密文,目标是猜被加密的是哪条。若同一密钥下加密确定性,攻击者提前问 oracle 加密 m0,再比较挑战密文是否相同,往往立刻赢。相反,随机化或 nonce 管理正确的加密还须具体证明安全假设,不能只因两次密文不同就断言 IND-CPA。
IND-CCA 比上述更强,允许攻击者再做受限制的解密查询(不能直接要求解挑战密文本身),让它探查畸形密文和错误处理;认证加密的必要性及错误消息边界在此更清楚。EUF-CMA 是签名的伪造游戏:攻击者可选择消息请求合法签名,之后却要给出一条未曾被授权的新消息及其可验签名。若应用把“订单 A 的合法签名”直接当作“订单 B 的合法授权”,那可能是消息编码/域验证错误,即使签名原语满足 EUF-CMA 也不能救。HMAC 的密钥在双方,服务接收者也能生成合法 MAC;不能用它替换可公开验证且不希望验证者造签名的场景。
1 | |
examples/cryptography/E08_security_games.py 用成熟密码库执行一条具体 IND-CPA 反例:AES-ECB 对两个各为 16 字节的合成订单块做确定性加密,攻击者先查询 synthetic-order0 的加密值,再拿挑战输出与之比较,实验中的每次挑战都能猜中。程序的本地随机挑战 bit 和密钥不会打印,也不手写 AES。另一实验用 AES-GCM 真 AEAD,改密文字节后 InvalidTag;它只验证此例中标签检查确实拦住篡改,绝不通过“一个畸形密文拒绝”就证明整个库及应用达到 IND-CCA。
先按仓库内 examples/cryptography/README.md 完成环境准备;以下命令从仓库根目录执行。
1 | |
一项测试通过,输出 aes_gcm_ind_cca_proved=false、finite_experiment_proves_security_definition=false。它是对弱用法的具体攻击,不是对安全用法的形式证明;未实现 EUF-CMA 的签名伪造游戏和任何参数渐近证明,均 NOT_RUN。审查实际协议还须对照密码学原语的威胁假设、真实序列化、错误处理、密钥生命周期、客户端已信公钥及服务端消费状态。即使原语安全,验签通过仍无法说明这笔交易已执行、在共同历史确认或现实订单已交付。
练习及答案
推导题: 已知在同一密钥下 ECB 加密同一个块永远产生同一块,攻击者如何利用一次 Encrypt(m0) 询问识别后来的等长挑战加密 m0 还是 m1?如果把数据库里同一订单的密文做随机 nonce 的 AEAD 加密,再次密文不同是否足以证明 IND-CCA?
答案: 提前保存 oracle 返回的 c0,挑战密文等于 c0 就猜 m0,否则猜 m1;对两个不同完整块且加密是排列的模型中,每次正确。AEAD 两次不同是预期现象,但不等于已经证明在允许解密查询的 IND-CCA 游戏中没有任何有效攻击;必须说明 nonce 约束、对手接口和算法假设。
实验变更题: 把 E08_security_games.py 中的两个明文改成同一条消息,实验的挑战 bit 还能被有意义地区分吗?将 GCM 改后密文的标签也替换为另一份合法消息的标签,而服务端不核对订单 ID 的 AAD,会暴露什么协议风险?
答案: m0=m1 时两种世界给出的密文分布相同,用任何比较也不能从密文本身确定挑战 bit;实验应坚持等长不同消息。另一合法消息连同合法 tag 若被移植到错误订单上下文,而上下文不在 AAD 或应用未检查,密码学标签仍可能对其原本的字节有效,业务却处理了错误对象;这是协议绑定问题,不是标签伪造。




