
1. 为什么密码学基础这章绕不开DES1.1 考试定位分组密码的“母本”翻开《信息安全工程师教程》第二章密码学基础与应用算是整本书里公式最密集、最容易让人劝退的一章。我自己的学习顺序是先啃完对称密码部分再把非对称密码和哈希串起来看。其中DES算法出现的频率相当高教材不仅给了完整的算法流程还会在课后题里反复让你算初始置换、算S盒、算子密钥。刚开始我也觉得这东西又老又繁琐56位密钥现在半天就能被暴力破解学它还有什么意义但实际学下来DES的价值完全不在“还能不能用”而在于它是一把理解所有分组密码的钥匙。我建议每一位备考的朋友都把DES当作“母本”来学。原因很简单后续你接触到的许多现代对称密码设计思路几乎都能在DES身上找到影子——Feistel网络结构、轮函数、子密钥扩展、S盒非线性替换、雪崩效应这些概念在DES里理解透了再看其他算法会顺畅很多。而且考试是真会出题的我记得往年真题里就有“计算DES第一轮子密钥”“判断S盒输出”这类小题属于典型的“学的时候痛苦、考到了送分”的章节。1.2 学DES之前要铺好的底子在正式进入算法细节前有几个前置概念必须先捋清楚否则后面会越看越懵。第一个是分组密码的基本工作方式。DES一次加密一个64位的数据块用同一个密钥反复处理这种“定长输入、定长输出”的加密方式就叫分组密码。加密时把明文分成一个个64位块每个块独立经过算法变成64位密文块。这个概念看似简单但很多人后面会在工作模式上栽跟头——比如ECB模式下相同明文块会得到相同密文块这在实践里是很大的安全隐患。第二个是位运算基础。DES的整个流程基本就是置换、异或、查表这三件事。你要熟悉二进制和十六进制的转换要能快速读懂一张置换表。置换表长得很吓人其实就是“把第几个位置上的位挪到第几个位置上去”本质是一个位置映射。我见过不少同学在S盒上反复算错原因不是不会查表而是列的索引号数错了这个我们后面专门讲。第三个是密钥与奇偶校验位的关系。DES名义上是64位密钥但每个字节的最后一位是奇偶校验位真正参与运算的只有56位。教材上会写“有效密钥长度56位”这句话要记住考试爱考。密钥形如133457799BBCDFF1每一字节的二进制里1的个数都是奇数这就是有效奇偶校验。有些库在初始化时会做奇偶校验密钥校验不过会直接报错这个实操细节我们放到后面排查部分细说。2. DES的整体设计思路一个精妙的“换位加替位”机器2.1 Feistel网络加密还可以这样设计DES的核心骨架是Feistel网络这个结构在1973年由Horst Feistel提出。理解Feistel网络我建议你先放下所有置换表记住一个大框架把一个64位块切成左右两半左边32位叫L右边32位叫R每一轮做三件事——把R送进轮函数F处理把处理结果和L异或然后交换左右位置。用公式表达就是Li R(i-1) Ri L(i-1) ⊕ F(R(i-1), Ki)这个结构最妙的地方在于轮函数F可以完全不用是可逆函数解密照样能进行。解密的时候只要从第16轮往第1轮倒着走把子密钥的使用顺序反过来就行。我记得第一次看到这里时觉得特别神奇因为一般直觉会认为加密函数必须可逆才能解密。Feistel网络通过“左右交换异或”就把这个限制绕开了这让设计者可以自由选择非常复杂的非线性函数来做轮函数而不用操心怎么求它的逆。这个思想后来被广泛应用在很多密码算法里学到这里的时候值得停下来多体会一下。实际教材里DES的流程是这样的64位明文先经过初始置换IP分成L0和R0然后做16轮Feistel迭代第16轮结束后交换左右两半最后经过逆置换IP⁻¹输出64位密文。教材顺序永远是“IP→16轮→交换→IP⁻¹”这个顺序本身就是考点的重灾区很多人会忘记最后一轮之后还要交换左右。2.2 为什么是16轮雪崩效应与工程折中DES为什么要做16轮而不是8轮或32轮这背后有两个考量。一个是安全边际另一个是工程可行性。安全边际体现在雪崩效应上。雪崩效应是指明文或密钥改变一个比特密文应该有一半左右的比特发生变化。DES在经过5轮左右的时候单个比特的变化就已经能扩散到整个块16轮的设置留出了充足的冗余让差分分析和线性分析这类攻击手段在当时的计算能力下变得极其困难。你可以做一个很直观的验证手算或者用代码把同一个明文用同一把密钥加密只改动其中一个比特观察输出变化会看到扩散非常明显。工程可行性则和那个年代的计算资源有关。16轮迭代意味着要在16轮里分别完成扩展置换、子密钥异或、S盒替换、P盒置换每多一轮就是多一整轮时序电路。设计者需要在安全性和硬件实现成本之间找平衡16轮是当时综合评估下来的一个折中值。考试如果问你“DES为什么采用16轮”你就从雪崩扩散和实现成本两个角度回答答案基本不会丢分。把整个流程框起来看DES其实可以概括成三句话用IP打乱输入用16轮Feistel迭代做混淆和扩散用IP⁻¹收尾。而混淆主要靠S盒完成扩散主要靠P盒和扩展置换完成。3. 逐环节拆解从明文到密文每一步都讲透3.1 初始置换IP与逆置换IP⁻¹初始置换IP的作用是把64位明文按照一张固定的表重新排列顺序。表长这样58 50 42 34 26 18 10 2 60 52 44 36 28 20 12 4 62 54 46 38 30 22 14 6 64 56 48 40 32 24 16 8 57 49 41 33 25 17 9 1 59 51 43 35 27 19 11 3 61 53 45 37 29 21 13 5 63 55 47 39 31 23 15 7读法很简单新序列的第1位取自原序列的第58位第2位取自第50位依此类推。这张表有一个规律——前四行取的全是偶数位后四行取的全是奇数位。教材会给出IP之后的L0和R0大多是直接给结果但考试可能会让你算其中某一段所以至少要知道怎么读表。IP⁻¹是IP的逆表作用是把经过16轮迭代后的结果恢复成“正常顺序”。它并不是IP表的反向排列而是一张独立的表。很多初学者会想当然地以为把IP表倒过来读就是IP⁻¹实际操作后发现对不上原因就是没看清这是两张独立设计的表。这里有个实用的自检方法如果你手头有完整IP和IP⁻¹表可以任取一串64位数据先做IP再做IP⁻¹结果必须回到原始数据完全可以当作一道练习题来验证自己有没有读错表。3.2 轮函数F的第1步32位扩展为48位进入每一轮后右边的32位R要被扩展成48位才能和48位的子密钥做异或。扩展置换E表是这样的32 1 2 3 4 5 4 5 6 7 8 9 8 9 10 11 12 13 12 13 14 15 16 17 16 17 18 19 20 21 20 21 22 23 24 25 24 25 26 27 28 29 28 29 30 31 32 1看出规律没有每组6位中间4位来自原R中连续4位首尾两位则“借用”相邻组的边界位。第1位复制的是第32位最后1位复制的是第1位相当于把32位的圆圈首尾相接以后做了重叠采样。这种设计不是随便来的它让相邻位在后续S盒运算中产生交叉影响是扩散效应的重要来源。读表时要注意这张表输出的是48位每行6位共8行。和前面IP表一样表的数字是“取自原位置的编号”。我自己第一次做扩展置换时总犯一个毛病——先入为主地认为输出顺序是1到48结果把表给读反了。实际上你只要盯住“第1个输出位来自原第32位”这一条顺序就不会乱。3.3 轮函数F的第2步与子密钥异或扩展后的48位结果要和这一轮的48位子密钥Ki做逐位异或。异或是一种很基础的位运算规则就两条相同为0不同为1。这一步几乎没有什么理解难度唯一的坑在于子密钥顺序。DES有16轮每轮子密钥都不一样如果你在手算时把K1用成了K2无论后面算得多认真结果必然全错。所以做这一步之前先把子密钥生成流程走完整确保手里拿到的确实是第i轮的Ki。3.4 轮函数F的第3步S盒替换——算法的灵魂异或得到的48位数据会进入8个S盒每个S盒接收6位输出4位整体从48位压缩回32位。我用一个生活化的类比来理解S盒它像一本只有编号、没有公式的查询手册输入6位数字翻到对应页数、对应行列取出一个4位数字作为答案。整个DES里S盒是唯一引入非线性操作的环节安全性的根基就在这8张表里。S盒的查表规则必须死记硬背6位输入中第1位和第6位拼成2位二进制数作为行号中间4位拼成4位二进制数作为列号。举个例子输入011000第1位是0第6位是0拼接成00行号就是0中间四位是1100换算成十进制是12列号就是12。然后去S1表第0行第12列取值。S2到S8的查法完全一样。S盒表本身不用背考试通常会提供或者只考某个S盒的前一两行。但你要会查、会换算。这里我提醒一个常见低级错误行号列号都是从0开始编的不是从1开始。数第12列的时候要数到第13个数字才对很多人就是在这里差一位导致整个S盒输出全错。D盒输出的32位数据是下一步P盒置换的输入。S盒的非线性非常关键它让整个算法的输入输出关系无法用简单的线性方程描述这正是抵御线性密码分析的核心手段。3.5 轮函数F的第4步P盒置换S盒输出的32位会经过P盒置换P表如下16 7 20 21 29 12 28 17 1 15 23 26 5 18 31 10 2 8 24 14 32 27 3 9 19 13 30 6 22 11 4 25P盒的作用是把S盒的输出位重新打散让每一个S盒的输出位在下一轮能影响尽可能多的其他S盒。这就是扩散。P盒没有复杂的规则就是纯粹的位置映射照表操作即可。做完P盒置换得到的就是轮函数F的最终输出也就是前面公式里的F(R(i-1), Ki)把它和左半部分L异或再交换位置一轮就完成了。3.6 子密钥生成64位密钥如何变出16个48位子密钥子密钥生成流程在考试里出现的频率不比主流程低流程一共四步置换选择1PC-1、循环左移、置换选择2PC-2。第一步PC-1把64位密钥压缩成56位。压缩方式是丢弃8个奇偶校验位每个字节的第8位然后按PC-1表重新排列。PC-1表通常长这样只列前半段做示范57 49 41 33 25 17 9 1 58 50 42 34 26 18 10 2 59 51 43 35 27 ...经过PC-1后得到56位分成左右各28位分别叫C0和D0。16轮迭代中每一轮先把C和D各自循环左移一定位数再把拼接后的56位送入PC-2选出48位作为该轮子密钥。循环左移位数有固定规律第1、2、9、16轮左移1位其余轮次左移2位。这张“移位表”考试常考一定要背下来或者至少能现推总共左移28位后回到起点所以16轮加起来恰好移动28位。PC-2是从56位中选48位。因为丢弃的是8位密钥中的一些位置在子密钥里永远不会出现。这8个位置分别是9、18、22、25、35、38、43、54有兴趣可以对照PC-2表数一遍能帮你加深记忆。子密钥生成整体可以概括成“丢弃校验位、分组移位、压缩置换”三步而已并不复杂。4. 手算第一轮数据说话4.1 准备数据理论讲再多不手算一遍等于白看。这里我用教材里的经典示例数据走一遍第一轮让大家看到每步的中间结果是什么样。明文取0123456789ABCDEF密钥取133457799BBCDFF1。密钥133457799BBCDFF1转换成二进制是00010011 00110100 01010111 10011001 10111011 11001100 11011111 11110001这个密钥的每个字节都有奇数个1满足DES奇偶校验要求。明文0123456789ABCDEF做初始置换IP后得到L0 CC00CCFF R0 F0F0F0F04.2 IP置换如果你对这个结果有疑问可以自己拿IP表逐位核对一遍。比如原明文第1字节是01二进制00000001所以第1位是0、第2位是0……第58位落在第8字节EF的位置上这个位正好是1因此IP输出第1位是1。逐位算完全部64位之后整理成32位一组就会得到CC00CCFF和F0F0F0F0。第一次算的时候建议至少完整核对前8个输出位后面就可以信任表格直接跳着抽检。4.3 第一轮F函数完整计算先算子密钥K1。密钥经过PC-1后得到C0和D0C0 1111000011001100101010101111 D0 0101010101100110011110001111第1轮循环左移1位得到C1 1110000110011001010101011111 D1 1010101011001100111100011110C1和D1拼接成56位经过PC-2选出48位得到第一轮子密钥K1 000110 110000 001011 101111 111111 000111 000001 110010接着对R0做扩展置换。R0 F0F0F0F032位展开后11110000 11110000 11110000 11110000经过E表扩展成48位E(R0) 011110 100001 011110 100001 011110 100001 011110 100001和K1逐位异或E(R0) 011110 100001 011110 100001 011110 100001 011110 100001 K1 000110 110000 001011 101111 111111 000111 000001 110010 XOR 011000 010001 010101 001110 100001 100110 011111 010011现在把这48位分成8组每组6位依次送进S1到S8。第一组011000首位和末位是00行号0中间四位1100是12列号12。查S1表第0行第12列得到5二进制0101。其余各组照此办理最终8个S盒输出拼接为0101 1001 1100 1010 1011 0101 0110 0101把32位结果经过P盒置换得到这一轮F函数的输出f(R0, K1) 00100001 01011001 11101101 11101010最后更新左右两半L1 R0 F0F0F0F0 R1 L0 ⊕ f(R0, K1) CC00CCFF ⊕ 00100001 01011001 11101101 11101010 ED5921154.4 用自己的方式验证结果手算最怕算错了还不知道。我建议你准备两种验证手段。第一种是代码验证。用Python的加密库可以一键对拍比如from Crypto.Cipher import DES key bytes.fromhex(133457799BBCDFF1) plain bytes.fromhex(0123456789ABCDEF) cipher DES.new(key, DES.MODE_ECB) print(cipher.encrypt(plain).hex())上面这组经典数据跑完16轮之后最终密文是85e813540f0ab405。如果你的手算结果能一步一步对到第一轮再拿代码验证整个流程说明思路是对的。第二种验证方式是“反向检查”。DES解密是加密的逆过程用同一个密钥解密密文必须还原回明文。如果解不出来那肯定不是解密写错了而是加密过程的某一轮算错了。这个思路特别适合排查那种“看起来每一步都对、最终结果就是不对”的诡异问题。5. 常见错误与排查技巧5.1 手算最容易踩的坑我在手算DES第一轮的时候前前后后错了三次每次都是不同原因。整理一下最典型的三个坑。第一个是行号和列号数错。S盒的行号列号从0开始导致查表时数数字容易偏一位。保险做法是先把输入6位拆出来明确写下“行xx列yy”再动笔查表不要直接在脑子里换算。第二个是把E表和P表的位置编号理解反了。E表和P表里的数字都是“取自原输入的位置”不是“输出要放到的位置”。我知道有个同学用P表做置换时把“第16位放到输出第1位”写成了“第1位放到输出第16位”结果前两步还对后面全乱。正确理解表的第n个数字表示输出第n位来自输入的哪个位置。第三个是忘记最后一轮之后还要交换左右。DES第16轮结束后先把L16和R16交换再送进IP⁻¹。这个“交换”在教材流程图里特别显眼但手算时经常被忽略原因是你前面15轮都在反复交换最后一步反而想不起来了。把这个动作写进自己的口诀里“16轮结束先换位再逆置换。”5.2 代码验证时的常见问题用代码验证DES时最常遇到的是密钥报错。Python的pycryptodome库在创建DES对象时如果密钥奇偶校验不正确可能抛出异常或者自动忽略校验位不同版本行为还不一样。如果遇到类似的“Invalid key”提示先检查密钥是不是16个十六进制字符、每个字节是否满足奇偶校验不要一上来就怀疑算法写错了。还有一个代码层面的坑是输入长度。DES一次处理8字节ECB模式下明文长度必须是8的倍数否则要自己补位。很多初学者拿一段长度不是8倍数的文本直接加密结果到处报错或者得到莫名其妙的结果其实和算法本身没关系。CBC模式也要求输入是块长度的整数倍常见的解决方式是用PKCS7填充。5.3 考试答题的避坑清单结合我刷题和模拟考的经验整理一个简短的答题检查清单字节和位的顺序。DES教材里的位序往往是从左到右、从高位到低位和某些实现里的“低位在前”不同。考试手算时以教材的位序为准不要混用。子密钥编号。题目让算第5轮的子密钥就先把前4轮的左移位数加起来别直接拿第1轮子密钥去顶替。十六进制转二进制时每个字符要补足4位。9写成1001不能只写1001和把B写成1011时漏位这类错误特别隐蔽。IP和IP⁻¹表不要混用。两表看起来相似实际位置映射完全不同考试时如果给了附表看清楚题目让你用哪张。6. 从DES到现实安全评价与学习建议6.1 为什么今天还要学DES学完整个算法流程后有必要回头审视一个现实问题56位密钥在现代计算能力面前已经不安全了。1998年就有专用设备能在几十小时内暴力破解DES密钥如今用普通算力配合云上资源穷举56位密钥也不再是天文数字。所以现实系统里单重DES基本被淘汰取而代之的是三重DES3DES和AES。3DES的本质是“用DES算法做三次加密”常表现为加密-解密-加密EDE的结构先用K1加密再用K2解密再用K3加密。这里的“解密”不是要还原明文而是为了兼容旧的单重DES——如果K1K2K33DES就退化成了DES。这个设计非常巧妙兼顾了向后兼容性和安全性也是考试里经常延伸考察的点。但即使DES本身已被淘汰它的学习价值依然很高。理解DES的Feistel结构是理解很多现代分组密码设计思路的基础理解S盒非线性查表是理解抗攻击设计的第一步理解子密钥扩展是理解“用复杂推导从一把主密钥衍生出多把子密钥”这一通用思想的入门课。再加上信息安全工程师考试明确要求掌握DES的原理和计算流程这部分内容无论如何都不能跳过。6.2 学习顺序与资料选择如果让我重新安排一次学习顺序我会建议这样推进先花半小时把Feistel框架图看懂不纠结具体置换表再对照教材逐张表走一遍完整加密流程手算第一轮然后用代码对拍验证第一轮结果最后再回头看安全性和工作模式。千万不要一上来就背8张S盒没有任何必要考试给了表让你查你要练的是查得快、查得准。资料方面教材是主线但有些外部资源非常有帮助。比如原始标准的示例数据就是4.1节那组经典的明文和密钥很多教程和工具都基于它做演示拿来当对拍标准特别合适。另外可以找一个支持手动分步演示的DES计算小工具输入明文和密钥它会把IP、每轮L/R、每个子密钥都列出来对于排查手算错误非常有效。我自己的经验是这种工具不要拿来替代手算而是在手算完一轮之后做对照效果最好。最后再分享一个实用的小技巧把DES的16轮左移位数编成一句话——“1、1、2、2、2、2、2、2、1、2、2、2、2、2、2、1”每天默写一遍坚持三天基本就记住了。类似的IP表前四行偶数位、后四行奇数位这个规律也可以当作记忆锚点。考试时这些细节不一定考但真考到了别人还在翻表你直接写答案的感觉很爽。