“AES GCM的标签直接认证密文,可以先验证再解密。SIV认证的是明文,接收方必须先在内部解出候选。两者都遵守同一交付边界:未认证的候选不会成为成功输出。”
形式陈述
先固定参数和允许的长度
GCM用128位分组密码实现认证加密。本页固定NIST SP800-38D(2007)的AES-128、12字节IV、完整16字节标签实例。输入为秘密16字节K、公开IV、关联数据A和明文P;输出(C,T),C与P等长。解密要么返回P,要么返回FAIL。A受认证而不加密。[1, §§5,7]
全部输入按字节计。规范限制|P|≤2³⁶−32、|A|≤2⁶¹−1;本页不接受其他IV或标签长度。教学核验器进一步限制|A|+|P|≤1 MiB。每条消息能编码多长,与同一密钥累计处理多少记录、多少块和多少失败验证,是不同预算。
安全使用要求同一密钥的加密调用不重复IV,并保持密钥专用于约定用途。裸加解密算法可以计算重复IV的结果;调用者必须用nonce分配纪律兑现唯一性。后面的伪造实验故意撤掉这一前提。
计数加密只用正向AES
令
inc₃₂只把最右32位当大端整数加一,模2³²回绕,前96位不变。明文第i块(i从1起)异或E_K(inc₃₂ⁱ(J₀));不足16字节的末块只取密钥流前面的相应字节。第一块使用后缀00000002,J₀本身留给标签掩码。
长度上限使正文至多2³²−2块,计数后缀从2到2³²−1,不重用后缀0或1。空明文没有正文计数块。解密仍用相同密钥流异或,不调用AES逆运算。
GHASH的位序与认证输入
GHASH在有限域GF(2¹²⁸)里计算,模多项式是u¹²⁸+u⁷+u²+u+1。这里有一个必须固定的编码:若线上128位串从左到右为x₀…x₁₂₇,它代表x₀+x₁u+…+x₁₂₇u¹²⁷。因此乘法单位元的字节表示是80 00 … 00,不是整数表示的00 … 01。[1, §6.3]
两块相乘可执行128轮:Z初值0,V初值第二块;从第一块的最左位开始,当前位为1就令Z←Z⊕V;随后V右移一位,若原最低位为1,再异或e1000000000000000000000000000000。第i轮前V代表第二元素乘uⁱ,Z累积了已读系数的贡献;128轮后便是多项式积的余式。
将A和C分别右补最少数量零字节至16字节倍数,再接两个8字节大端整数,编码原始比特长度:
这里u、v表示所补零比特数。空串无需补一个数据块,最后的长度块仍保留。把X切成X₁,…,Xₘ,令Y₀=0、Yᵢ=(Yᵢ₋₁⊕Xᵢ)·H,最后输出
逐步展开得Yₘ=X₁Hᵐ⊕…⊕XₘH。这也说明GHASH不是整数乘加或无密钥密码哈希:H是秘密认证子密钥,线性计算要与每个IV对应的标签掩码一起分析。
解密先检查参数与长度,重新计算完整T;比较成功后才把候选明文交给调用方。因为标签只依赖IV、A和C,附件先验证再做正文异或。规范也允许先在内部算候选明文,但失败时不能释放它。[1, §7.2]
直觉
两条计算链保护不同的对象
CTR链遮住内容,却允许攻击者翻转指定明文位。GHASH链把公开A、密文C和它们的真实长度压成一块,再用E_K(J₀)遮住这块认证结果。接收方既要重建相同计数流,也要重建完全相同的认证字节。
长度块不是装饰。例如A=01与A=01 00补零后的数据块一样,原长度却分别为8和16比特。若删掉长度字段,认证输入就丢掉了这一区别。应用若把多个语义字段放在同一个A里,还要先采用无歧义编码;GCM只知道传入的一个字节串。
例子与边界
20字节AAD和60字节正文
NIST公布例AES128 #5使用离线测试密钥feffe9928665731c6d6a8f9467308308及IV=cafebabefacedbaddecaf888。[2, pp.7–8] 关联数据为
3ad77bb40d7a3660a89ecaf32466ef97f5d3d585
完整60字节明文及密文在终点和核验器中给出。可先核结构:20字节A形成两个GHASH块,60字节C形成四块,加一块长度,总共七次域乘法。最后一块为
00000000000000a0 00000000000001e0,
因为20×8=160=0xa0,60×8=480=0x1e0。得到H=b83b533708bf535d0aa6e52980d53b78、Y₇=c23b3d63d2ed95056ca342769cd13c03。与E_K(J₀)=3247184b3c4f69a44dbcd22887bbb418异或,标签为f07c2528eea2fca1211f905e1b6a881b。
正文用四个计数块,最后只消耗12字节密钥流。若把AAD长度20直接写进长度字,而非写160,标签就会不同。
重复IV怎样进一步破坏认证
取同一K、同一IV、空AAD、恰好一整块密文C。长度块固定为Λ=0⁶⁴∥[128]₆₄,因此
攻击者得到两个不同密文C₁、C₂及完整标签T₁、T₂,就能消去相同项:
C₁⊕C₂非零,在域中可逆。因此只用公开记录即可算出G=H²=(T₁⊕T₂)/(C₁⊕C₂),再选不同于旧密文的C*并计算
代回标签公式可见它必被接受。不需要知道K,也不需要先恢复H;这里的除法必须使用域乘法逆元。固定上面的公布密钥与IV,附件对两个教学明文生成:
| 记录 | 密文C | 标签T |
|---|---|---|
| 1 | 9bb22ce7d9f372c1ee2b28722b25f206 |
271dbbbc06e78d7c6be9ca74d0baba1e |
| 2 | 9ab22ce7d9f372c1ee2b28722b25f206 |
14d564575fad4efddb22cad47b6c5f19 |
计算得G=8a6ff5aca561c0d865805055eb728397。令C*=1bb22ce7d9f372c1ee2b28722b25f206,得到T*=ad724e10a3864da40e699a213bc83989,解密验证成功。攻击函数的参数只有两份公开密文/标签和C*,没有传入密钥或H。
这个闭式推导使用相同IV、相同AAD、相同一块长度及完整标签。若消息块数不同,长度项和H的次数也变了,不能沿用同一相减公式。它展示重复IV后的具体失败,不是在nonce-respecting安全游戏中破解GCM。
推论与应用
多项式根数怎样进入安全分析
先看一个局部数学结论:对两组固定且不同的(A,C),按上面规则编码后得到不同的形式多项式。若原长度不同,最后长度系数已不同;若原长度相同,分块边界相同,某个内容系数不同。设最大编码块数为m,差多项式非零、次数至多m,所以均匀H下碰撞概率至多m/2¹²⁸。
这里要求这两组固定输入不由已经获知的H来挑选。实际对手可自适应查询,还可能看到验证结果;完整GCM分析必须再处理AES的PRP假设、秘密H、标签掩码、IV唯一性和查询预算,不能把这个根数引理直接当成所有主动攻击的最终界。[1, Appendix B]
重复IV使两个标签使用同一个掩码,刚才的一块反例便暴露H²。这解释了唯一性为什么同时影响保密和认证。AES-SIV采用另一种合成IV流程,在其假设下允许重复nonce,但接受完整输入相等这一泄漏;两种构造的安全合同不同。
可复算成本与结构迁移
令a=⌈|A|/16⌉、c=⌈|P|/16⌉。预计算H需一次AES;一次加密随后需c次正文AES、一次标签AES及a+c+1次域乘法。固定128位实现中每次乘法为128轮,故总时间O(1+|A|+|P|)。附件保存拼接认证输入、输出和可选逐块轨迹,占O(1+|A|+|P|)空间;只维持GHASH链可以用常数工作空间,认证前暂存候选明文则要另算缓冲。
综合练习要求复算七块链,追加一个AAD零字节后指出哪一块发生改变;再把伪造中的第二记录扩成两块,重写相减后的多项式。标准向量彼此是独立离线测试,重复使用其公布参数不能当作真实会话的nonce使用方式。原样旧(C,T)再次验证仍会成功,是否交付第二次由重放状态决定。
参考资料
- NIST,SP800-38D,2007,§5参数;§§6.2–6.5位序和子算法;§7加解密;Appendices A/B解释重复IV和认证预算。
- NIST,GCM-AES Example Values,AES128例#1、#2、#5,PDF pp.1–8:空串、完整块和部分末块的实际中间量。本文一块认证伪造为自行推导与实现。
- NIST,FIPS197-upd1,2023,§§5.1–5.2及Appendix B:下载器AES128底层与公布向量;不由此声称Python实现具有常数时间保证。