C++-DES
实验目的
通过用DES算法对实际的数据进行加密和解密来深刻了解DES的运行原理。
实验原理
DES算法将明文分成64位大小的众多数据块,即分组长度为64位。同时用56位密钥对64位明文信息加密,最终形成64位的密文。如果明文长度不足64位,即将其扩展为64位(如补零等方法)。具体加密过程首先是将输入的数据进行初始置换(IP),即将明文M中数据的排列顺序按一定的规则重新排列,生成新的数据序列,以打乱原来的次序。然后将变换后的数据平分成左右两部分,左边记为\(L_{0}\),右边记为\(R_{0}\),然后对\(R_{0}\)实行在子密钥(由加密密钥产生)控制下的变换f,结果记为f(\(R_{0}\),\(K_{1}\)),再与\(L_{0}\)做逐位异或运算,其结果记为\(R_{1}\),\(R_{0}\)则作为下一轮的\(L_{1}\)。如此循环16轮,最后得到\(L_{16}\)、\(R_{16}\),再对\(L_{16}\)、\(R_{16}\)实行逆初始置换\(IP^{-1}\),即可得到加密数据。解密过程与此类似,不同之处仅在于子密钥的使用顺序正好相反。
实验过程
本实验用string类型记录明文、密钥、密文等信息,用全局变量keys[16]记录所有密钥。
DES加密
程序流程图
相关函数
输入检查
如果输入的密钥、明文、密文不足64位,会自动补零。
1 | //输入64bit数据检查 |
二进制转十六进制
1 | //二进制转十六进制 |
十六进制转二进制
1 | //十六进制转二进制 |
密钥生成
1 | void Getkeys(string key) { |
行pc-1置换
输入的初始密钥值为64位,但DES算法规定,其中第8、16、...、64位为奇偶校验位,不参予DES的运算。所以,实际可用位数只有56位,经过缩小选择即密钥置换PC-1的变换后,初始密钥的位数由64位变成了56位,将其平分位两部分\(C_{0}\),\(D_{0}\)。
1 | //密钥选择置换1 64->56 |
左循环移位
得到\(C_{0}\),\(D_{0}\)之后分别进行第一次循环左移,得到\(C_{1}\),\(D_{1}\),将\(C_{1}\)(28位)、\(D_{1}\)(28位)合并后得到56位的输出结果.
1 | //左移位数 |
pc-2置换
得到的56位的输出结果,再经过压缩置换PC-2,从而得到了密钥\(K_{1}\)(48位)。依次类推,便可得到\(K_{2}\)、...、\(K_{16}\)
1 | //密钥选择置换2 56->48 |
明文加密
1 | string DES_lock(string c, string a) { |
初始置换IP
它的作用是把输入的64位数据块的排列顺序打乱,每位数据按照下面的置 换规则重新排列,即将第58位换到第一位,第50位换打第2位,...,依次类推。置换后的64位输出分为\(L_{0}\) 、\(R_{0}\)(左、右)两部分,每部分分别为32位。
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 | //初始置换IP |
\(R_{0}\)和\(K_{1}\)经过f(\(R_{0}\),\(K_{1}\))变换后的输出结果,再和\(L_{0}\)进行异或运算,输出结果位\(R_{1}\),\(R_{0}\)则赋给\(L_{1}\)。\(L_{1}\)和\(R_{1}\)同样再做类似运算生成\(L_{2}\)和\(R_{2}\),...,经过16次运算后生成\(L_{16}\)和\(R_{16}\)。
f函数
f 函数是多个置换函数和替代函数的组合函数,它将32位比特的输入变换为32位的输出,原理图如下图:
\(R_{i}\)经过扩展运算E变换后扩展为48位的E(\(R_{i}\)),与 进行异或运算后输出的结果分成8组,每组6比特。每一组再经过一个S盒(共8个S盒)运算转换为4位,8个4位合并为32位后再经过P变换输出为32位的 。其中,扩展运算E与置换P主要作用是增加算法的扩散效果。
1 | string F(string ming_r,int i) { |
E扩展运算
将\(R_{i-1}\)(即输入A)扩展从32位扩展为48位,32位->48位 通过扩展置换E,数据的右半部分\(R_{i-1}\)从32位扩展到48位。扩展置换改变了位的次序,重复了某些位。
作用:产生与秘钥相同长度的数据以进行异或运算,\(R_{0}\)是32位,子秘钥是48位,所以\(R_{0}\)要先进行扩展置换之后与子秘钥进行异或运算;提供更长的结果,使得在替代运算时能够进行压缩。
1 | //E盒扩展 |
异或运算
48位中间结果与48位子密钥按位异或,引入密钥.
1 | //异或 |
S盒选择
8个S盒,每个6位输入,4位输出,混淆作用,48位->32位.
\(R_{n}\)扩展置换之后与子秘钥Kn异或以后的结果作为输入块,功能是把48位数据压缩为32位数据,由8个不同的代替盒(S盒)完成。每个S盒有6位输入,4位输出。48位的输入块被分成8个6位的分组,每一个分组对应一个S盒代替操作。经过S盒代替,得到8个4位分组结果---32位。
1 | //S盒 |
P置换
将S盒输出的32位数据打乱重排,扩散作用,32位->32位;结果为一轮f函数输出.
1 | //P置换 |
逆初始置换\(IP^{-1}\)
它将\(L_{16}\)和\(R_{16}\)作为输入,进行逆初始置换得到密文输出。逆初始置换是初始置换的逆运算:
1 | //逆置换 |
实验结果
PS:第一次输入的明文虽然只有0,但是程序会用0补齐至明文为64位。
DES解密
实验流程
DES加密和解密使用相同的算法,唯一的不同是密钥的次序相反。如果各轮加密密钥分别是\(K_{1}\),\(K_{2}\),\(K_{3}\)...\(K_{16}\),那么解密密钥就是\(K_{16}\),\(K_{15}\),\(K_{14}\)...\(K_{1}\)。
1 | //解密 |
实验结果
雪崩效应
对DES的密文进行雪崩效应检验。即固定密钥, 仅改变明文中的一位,统计密文改变的位数;固定明文,仅改变密钥中的一位,统计密文改变的位数。
实验流程
固定密钥,改变明文一位
1 | cout << "---------------------------雪崩效应-改变明文---------------------------" << endl; |
固定明文,改变密钥一位
1 | cout << "---------------------------雪崩效应-改变密钥---------------------------" << endl; |
实验结果
固定密钥,改变明文一位:
可以看到平均改变位数为32.1719位。
固定明文,改变密钥一位:
可以看到平均改变位数为 28.9844位,并且,改变奇偶校验位不会对最后结果产生影响。
