最近好几个正在啃《应用密码学第三版》的朋友不约而同跑来问我第六章的习题怎么做尤其是那几道AES计算题个个一脸苦相。这一章在整本书里的地位很特殊前面几章讲古典密码、信息论还能靠背定义混过去到了第六章分组密码的框架、AES的结构、密钥扩展再加上ECB、CBC、CFB、OFB、CTR五种工作模式概念密度一下子顶上来习题也从默写变成了动手算。我当年做题时也栽过不少跟头所以这次把第六章习题拆成几个典型类型逐个说清楚题目背后的考点、计算过程和自查方法你看完以后能自己把答案推出来而不是只能翻到书末对着答案抄。1. 先搞清楚第六章在考什么题目背后的知识地图1.1 这章在整本书里的位置我手头这本第三版的第六章主题是AES与分组密码的工作模式。从章节脉络来看前面讲的扩散、混淆这些理论到这一章才真正落地成具体算法后面要讲的公钥密码又完全建立在对称分组密码已经没问题这个前提上。所以第六章是一个承上启下的枢纽章节习题的目的也很明确验证你有没有真正吃透分组密码的内部结构而不只是知道AES很安全这句话。习题覆盖的知识点拆开看其实就三大块算法结构AES的轮函数、S盒、密钥扩展、工作模式五种模式的加密链结构与特性、应用相关填充、错误传播、并行性。绝大多数做不出来的题都不是因为计算复杂而是因为这三块之间的关联没打通。比如问你为什么CTR模式可以并行加密如果你只背了CTR能并行但没理解它每一块用的是独立的计数器值加密结果做异或那题目稍微换个问法比如如果两个分组用了相同的计数器值会发生什么照样答不上来。1.2 做习题前必须掌握的七个核心概念我把这章习题涉及的核心概念整理成了一张对照表做任何一道题之前先确认自己能不能不看笔记说出每一项的关键参数概念关键参数习题常见考法AES-128 / 192 / 256分组长度固定128位密钥长度分别128/192/256位轮数10/12/14给密钥长度问轮数或者反过来SPN结构每轮包含替代、置换、混淆、加轮密钥与Feistel结构对比S盒SubBytes基于GF(2^8)的乘法逆与仿射变换16x16查找表手算给定字节的S盒输出或验证生成过程密钥扩展初始密钥生成44个32位字AES-128用到RotWord、SubWord、Rcon推算某轮轮密钥工作模式ECB、CBC、CFB、OFB、CTR给场景选模式、分析错误传播PKCS#7填充缺n字节就填n个0x0n明文恰好整数块时填充一整块计算填充后长度、填充值错误传播不同模式下密文损坏影响哪些明文分组判断某个密文块出错会破坏几个明文块这个概念表我建议你贴在笔记本扉页上。第六章的习题尤其是计算题几乎每一道都绕不开这张表里的内容。你对照着它去读题通常一眼就能看出题目在考哪个概念、需要用哪条性质解题。1.3 三类典型命题风格从习题类型看这章题目基本可以分成三类第一类是概念辨析题。典型问法是比较Feistel结构与SPN结构为什么AES的S盒是可逆的ECB模式下重复明文会产生什么后果。这类题看似简单但得分率并不高原因是很多人只写结论不写过程或者说不到点子上。第二类是计算推导题。比如给定输入字节0x01计算经过AES S盒后的输出以某个初始密钥推算出第一轮轮密钥在CBC模式下加密给定的明文分组。这类题考的是对算法步骤的真实理解每一步都有固定操作错一步后面全错但恰恰说明过程比结果重要。第三类是应用设计题。通常是给一个通信场景让你选工作模式、分析错误传播、设计填充方案。这类题没有唯一答案但必须把你的选择理由写清楚用的是结构、效率、安全性、适用场景这四个维度去论证。2. 概念题怎么答才能拿稳分数2.1 Feistel结构与SPN结构的对比这几乎是第六章必考的一道题。答题的关键不是背Feistel是左右两半交叉处理SPN是整体替换置换而是要说清楚两者在设计哲学上的区别以及这种区别带来的实际后果。Feistel结构每一轮只处理一半数据另一半原样保留轮函数甚至可以不可逆解密时只要把轮密钥顺序倒过来就能还原。这种加解密同构的特性直接导致DES这类算法实现起来非常方便。代价是每轮只有一半数据被更新扩散速度偏慢需要更多轮数才能达到充分的混淆效果。SPN结构则是一整块数据在每轮中同时经历代换和线性变换扩散更直接所以AES用10轮128位密钥就能达到很好的混淆程度。但SPN的S盒必须可逆否则解密时无法从输出还原输入这也就是为什么AES的S盒要通过GF(2^8)乘法逆加仿射变换构造而不是随便填一张随机表。答题模板我建议按这个顺序写先一句话点明各自的结构逻辑再指出加解密是否同构这个关键差异最后落到扩散速度与轮数的关系上。这样逻辑闭环评卷老师一眼就能看出你真懂了。2.2 五种工作模式横向对比另一类高概率概念题是让你比较ECB、CBC、CFB、OFB、CTR这五种模式。我给一个通用的四维答题框架结构、并行性、错误传播、适用场景。对照着写基本不会漏得分点。模式加密结构能否并行错误传播特点典型场景ECB各分组独立加密加密可并行解密可并行密文块出错只影响对应明文块但重复明文暴露模式加密随机数、密钥材料等短数据CBC前一个密文块参与当前块异或加密不可并行解密可并行第i块密文出错影响第i块与第i1块明文通用文件加密、磁盘加密CFB把分组密码当流密码用密文反馈加密不可并行解密可并行第i块出错影响第i块和第i1块出错位按密文位对应传递流式数据加密OFB密钥流与明文无关只反馈加密输出加密、解密都需要先生成密钥流预计算后可并行密文块出错只影响对应块但密钥流重复会导致灾难卫星、无线链路CTR计数器值加密后与明文异或加密、解密均可并行密文块出错只影响对应块无传播高性能并行加密、自选序号场景2.3 概念题最容易丢分的三个细节第一只写能并行不写前提。比如CBC加密不可并行是因为每个密文块依赖于前一个密文块CTR加密可并行是因为每个分组独立使用计数器的加密输出。你必须说清楚为什么。第二术语不规范。Feistel、SPN、S盒、轮函数这些词写错或用混会直接让老师怀疑你概念没记牢。第三不提安全性边界。比如ECB的不安全不是算法被攻破而是模式在重复明文下泄露统计规律这个边界不写清楚概念题就拿不到满分。3. 计算题实操演示三道典型题从读题到验算3.1 S盒生成以输入0x01为例的手算全流程先说明一下AES的S盒不是随机生成的表而是按严格数学规则构造的。规则是两条在GF(2^8)上求乘法逆然后做一次仿射变换。习题里如果让你验证S盒中某个值的来源本质上考的就是这两步。以输入字节0x01为例。第一步求0x01在GF(2^8)中的乘法逆。GF(2^8)的乘单位元是0x01任何非零元素乘上自己的逆都要等于0x01而0x01乘以0x01显然等于0x01所以它的逆就是它自己。第二步对0x01做仿射变换。先把字节写成比特序列从低位到高位记为b0到b70x01的二进制是00000001也就是b01b1到b7全为0。AES仿射变换的公式是bi bi ⊕ b(i4) mod 8 ⊕ b(i5) mod 8 ⊕ b(i6) mod 8 ⊕ b(i7) mod 8 ⊕ ci其中常量c取0x63二进制01100011c0到c7依次为1, 1, 0, 0, 0, 1, 1, 0。逐位代入i0b0 b0⊕b4⊕b5⊕b6⊕b7⊕c0 1⊕0⊕0⊕0⊕0⊕1 0i1b1 b1⊕b5⊕b6⊕b7⊕b0⊕c1 0⊕0⊕0⊕0⊕1⊕1 0i2b2 b2⊕b6⊕b7⊕b0⊕b1⊕c2 0⊕0⊕0⊕1⊕0⊕0 1i3b3 b3⊕b7⊕b0⊕b1⊕b2⊕c3 0⊕0⊕1⊕0⊕0⊕0 1i4b4 b4⊕b0⊕b1⊕b2⊕b3⊕c4 0⊕1⊕0⊕0⊕0⊕0 1i5b5 b5⊕b1⊕b2⊕b3⊕b4⊕c5 0⊕0⊕0⊕0⊕0⊕1 1i6b6 b6⊕b2⊕b3⊕b4⊕b5⊕c6 0⊕0⊕0⊕0⊕0⊕1 1i7b7 b7⊕b3⊕b4⊕b5⊕b6⊕c7 0⊕0⊕0⊕0⊕0⊕0 0从高到低排列这8位得到01111100也就是0x7C。翻看AES标准S盒表S盒[0x01]的值确实是0x7C。整个过程和查表结果完全对得上。提示考试时遇到计算S盒输出的题通常不会让你求复杂的乘法逆而是选0x01这类逆元好求的输入重点考察你会不会做仿射变换。如果真遇到0x00规则是0x00的乘法逆定义为0x00再做同样的仿射变换结果是0x63这也是S盒的第一个值。3.2 密钥扩展推算出第一轮轮密钥密钥扩展是另一道高频计算题。AES-128需要把16字节初始密钥扩展成11个轮密钥共44个32位字。习题通常只让你推第一轮甚至只推第一个新字目的是考察你对RotWord、SubWord、Rcon以及异或操作的掌握。我以一个在NIST标准文档里常见的测试密钥为例2B7E151628AED2A6ABF7158809CF4F3C。先把16字节拆成4个32位字w0 2B7E1516w1 28AED2A6w2 ABF71588w3 09CF4F3C求w4时规则是当索引i不是4的倍数时w4 w0 ⊕ w3当i是4的倍数时要先对w3做三步操作。i4是4的倍数所以走完整流程。第一步RotWord把w3循环左移一个字节09CF4F3C变成CF4F3C09。第二步SubWord对这四个字节逐字节查S盒。0xCF换成0x8A0x4F换成0x840x3C换成0xEB0x09换成0x01结果得到字8A84EB01。第三步异或轮常量Rcon[1]010000008A84EB01 ⊕ 01000000 8B84EB01。最后把这个结果和w0异或w4 8B84EB01 ⊕ 2B7E1516 A0FAFE17算出来的这个A0FAFE17正是NIST标准文档里第一个轮密钥的第一个字。你可以在很多公开资料里查到这一致结果这也是我拿它当示例的原因——手算完可以立刻对照标准答案。做这类题最容易出错的点有三个RotWord的移位方向搞反是循环左移不是右移SubWord的字节顺序搞乱必须保持RotWord之后的顺序以及忘了只有在i为4的倍数时才需要Rcon。我建议你做题时把每一步的中间结果都写在旁边最后用代码验证出错时一眼就能定位。3.3 CBC模式加密与错误传播分析CBC也是必考计算点。加密过程一句话C_i E_K(P_i ⊕ C_{i-1})其中C_0就是初始向量IV。解密过程对应P_i D_K(C_i) ⊕ C_{i-1}。很多同学记混的地方在于解密时是先解密再异或前一个密文块而不是反过来。这个顺序直接决定错误传播的性质。假设你是接收方正在CBC解密收到的一条密文块C_i在传输中发生了一位翻转。解密C_i时D_K(C_i)的输出完全随机会变所以P_i对应位置以及更多位都会受影响同时C_i还要参与下一块的解密也就是P_{i1} D_K(C_{i1}) ⊕ C_i但D_K(C_{i1})本身是正常的只不过异或的对象C_i变了所以P_{i1}中恰好与出错位相同位置的那一位也会翻转。结论是CBC模式下第i块密文出错会破坏第i块和第i1块明文且第i块损坏严重、第i1块只损坏对应位。CFB模式类似OFB和CTR则只影响当前块。习题如果让你判断某个密文块出错会破坏哪些明文块先把该模式的链式依赖画出来答案基本就出来了。我强烈建议你用纸笔画出CBC的加密和解密两条链这比背结论可靠得多。3.4 用Python快速验算手算结果手算这类题最怕自己算错还不知道。我的习惯是算完立刻用一小段代码核对。比如验证上面的密钥扩展我可以直接实现AES-128密钥扩展的前几步或者更简单直接用现成的加密库验证对错。from Crypto.Cipher import AES key bytes.fromhex(2B7E151628AED2A6ABF7158809CF4F3C) plaintext bytes.fromhex(6BC1BEE22E409F96E93D7E117393172A) cipher AES.new(key, AES.MODE_ECB) ciphertext cipher.encrypt(plaintext) print(ciphertext.hex()) # 3AD77BB40D7A3660A89ECAF32466EF97如果你手算某个加密结果拿这个代码一跑就知道对不对。这里的明文分组是NIST测试向量里的第一组结果可以直接在标准文档里核到。再看一下S盒生成验证。你不需要自己实现GF(2^8)乘法逆直接用库或查表来反推# 验证 S盒[0x01] 0x7C sbox [ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, # ... 此处省略完整表查资料补全后运行 ] print(hex(sbox[0x01])) # 0x7c核验时要特别注意字节顺序和大小端。AES所有内部操作都以字节为单位十六进制字符串从左到右依次对应字节顺序不要当成整数来算。这是手算题里非常隐蔽的一个坑。4. 作业和考试里出现频率最高的五个坑4.1 高频错误对照表我把自己做题以及帮朋友改作业时看到的错误按出现频率排了个序错误现象根本原因正确做法S盒输入输出方向看反没搞清S盒是16x16二维表输入字节高四位作行、低四位作列先拆高四位和低四位再查表RotWord方向写反把循环左移位当成右移记住左移第1字节放到最后CBC解密顺序搞错先异或前一块再解密写成了解密后异或解密函数输出再与C_{i-1}异或CBC错误传播结论记混只背结论不理解链式结构画加密链逐块推导PKCS#7填充值写错明文长度是16的倍数时不知道该填什么缺n字节填n个0x0n缺0字节时也要补16个0x10其中最后一条是出题人的最爱。很多人以为明文恰好是整块就不用填充但PKCS#7的规则是必须填充否则解密端无法区分最后一个块里原本就有16个0x10和最后一块是填充块两种情况。所以明文是16字节时填充后变成32字节最后一个块全是0x10。4.2 用好反向验证法自查计算题做完怎么自查最实用的一招是反向验证。加密算出来的密文你当作已知密文去做一次解密看能不能还原出原明文。很多习题的明文密文都是成对给出的你甚至可以完全不看标准答案自己形成一个闭环。第二招是使用公开测试向量。这章涉及AES的地方NIST在SP 800-38A里发布了完整的测试向量密钥、明文、IV、密文全都有固定值。你手里的题目只要注明AES-128且没有改参数算出来的结果就能直接和测试向量对照。如果不一致先检查密钥和明文有没有转成正确的字节序列再检查工作模式是不是选对了。第三招是单位思维检查。AES分组固定16字节如果你算出来某个中间结果是17字节或15字节肯定哪里出了问题。小到单独一个字节的异或结果大到整条消息的长度都可以用这种量纲感快速排除低级错误。5. 光有答案不够把习题转化成真本事的学习方法5.1 三类工具按需选择工具只是辅助关键是你用它来验证思路而不是替代思考。第一类是Python密码库我常用的是PyCryptodome。它适合验证整个AES加密、解密的结果以及测试各种工作模式。第二类是CrypTool这类图形化工具适合看分组密码模式的结构演示对理解CBC、CFB的链式反馈特别有帮助我当年就是靠它把OFB和CTR的区别彻底弄明白的。第三类是在线十六进制计算器适合快速做异或运算。密钥扩展的计算过程中有大量异或用计算器能省不少时间但注意别用它算S盒输出那种还是要靠查表或自己写代码。5.2 别让答案变成拐杖说句实在话习题答案的真正用法不是对答案而是验思路。我建议做题时遵循这样一个流程先对着1.2节的概念表判断题目考什么再独立完成计算中间不翻任何资料算完用工具验证结果最后如果结果错了再翻开答案重点看你是在哪一步偏离的而不是直接把答案抄一遍。另外建议你按题型做总结。同一道题按照考点是什么、用到哪些性质、关键计算步骤、易错点四个维度整理成自己的笔记。这样复习的时候只看笔记效率比重新刷题高得多。我个人做题做了两轮第一轮被S盒和密钥扩展的繁琐计算折磨得不轻第二轮把每种模式的错误传播画成图之后整个思路就顺了。这章习题里最值钱的不是最终答案而是你推演过程中建立起来的密码学直觉。看懂别人的答案和自己亲手算出来差别真的非常大——当你独立推出一个轮密钥并且验证它与标准向量一致的那一刻AES才真正从教材里的一个章节变成你自己手里的工具。
阅读完成 · 觉得有帮助?