1、xx 工程大学实验报告( 2015-2016 学年第一学期)报告题目: DES 加密算法 课程名称: 密码学 B 任课教员: 专 业: 学 号: 姓 名: 二 O 一六年一月十八日一、课程概述目的:培养学员的编程能力,理解算法原理。要求:给出 DES 算法的软件实现,测试 DES 的加密速度。二、设计思路使用 C+语言进行编程,简化了输入输出语句。 预处理时加入了 iostream 包。使用了 std 名字空 间。加密时程序输入的明文是 8 个 ascii 码,生成一个 16 个 16 进制数的密文。脱密时程序输入的密文是 16 个 16 进制数,生成一个 8 个 ascii 码的明文。加脱密
2、所用密钥均由 16 个 16 进制数组成。其中 16 进制数全部使用大写字母。程序中大量使用了的布尔数组,一个 bool 型变量只占用一位存 储空间,比 int 型、char 型 变量要小的多。 这降低了程序的空间复杂度。三、采取的方案本程序是将一个由 8 个 ascii 码组成的明文分组加密,生成一个由 16 个 16 进制数组成的密文。或将一个由 16 个 16 进制数组成的密文进行脱密,生成一个由 8 个 ascii 码组成的明文。所用密钥由 16 个 16 进制数组成。本实验按照输入数据及初始置换、16 圈迭代、子密钥生成和逆初始置换及输出数据四个步骤实现加密算法设计。1、输入数据及初
3、始置换 本程序首先会提示用户输入加密脱密识别码,加密输入 1,脱密输入 0,将此 识别码存入整形变量 o。根据 o 的不同值,提示用 户输入 8 个字符(加密)或 16 个 16 进制数(脱密)。输入的明文或密文转化为二进制数后储存到布尔型数组 m65中。初始置换通过函数 IP 完成,函数输入为原始明文 m,函数将输出结果保存到布尔型数组 mip65中。函数思想 为查表,含有一个整形 变 量数组 ip64,保存初始变换表 IP。将 mip 的第 i 位赋值为 m 的第 ipi位。2、子密钥生成输入 16 个 16 进制数的密钥后,将密钥保存在一个 16 位字符数组 c 中,通过ToEr 函数将
4、之变为二进制数。ToEr 函数输入为字符数组,通过 switch 语句逐个检查字符数组的每一位,将对应的四位二进制数存在 64 位布尔数组 k 中。64 bit 密钥去掉每个字节的最高位得到 56 bit 密钥输入,通过置换选择 1 变换得到0C和 D各 28 bit,通过 Zhihuan_1 函数实现置换选择 一。 Zhihuan_1 函数输入为二进制密钥数组 k64,输出为 C0 和 D0,将 C0、D0 分别储 存在 28 位布尔数组 C、D 中。函数采用查表方式生成 C0 和 D0。根据迭代的轮数确定 C 和 D 移位循环的位数,主程序中利用一个 16 位整形数组来存放每一次循环左移的
5、位数。循环左移通过 XunHuan 函数实现,函数输入为循环位数和长度为 28 的布尔数组(C 或者 D),函数运行一次只能改变一个布尔数组的值。为了减低编程复杂度,程序使用串行方法,分两次进行 C、D 的移位。每完成一次 C 和 D 的移位,进行一次置换选择二。置换选择二利用 zhihuan_2 函数完成。思想和 Zhihuan_1 函数类似。zhihuan_2 函数输入为移位后的 C、D,zhihuan_2 函数将圈子密钥存放在 16*48 的二维布尔数组 kk1749 中。kki48表示第 i 圈的圈子密钥。原理 图如图 1 所示。脱密(o=0 时)需要将圈子密钥交换,此时可利用 kk0
6、49充当中间变量,无需定义新的变量减少了系统开销。5628281置 换 选 择密 钥 0C0D移 位 循 环112置 换 选 择 1k2C2置 换 选 择 2 481616D2置 换 选 择 16k48移 位 循 环移 位 循 环 移 位 循 环移 位 循 环 移 位 循 环图 1 圈子密钥生成算法3、16 圈迭代DES 的每一圈迭代采用的是 Feistel 模型,先将初始置换后的明文 mip 数组分成 L和 R 两部分,先将 R 的内容放在等 长的布尔数组 T 中,最后时需要将 L 的值赋为 T。之后进入 F 函数,F 函数原理如图 2。P R=a1 a2 a32 S1 S8 S2 S7 S
7、6 S4 S3 S5 E a1 a2 a48 K=k1 k2 k48 图 2 F 函数原理图程序中的 F 函数 输入有初始置 换结果的右半部分 R、圈子密钥 kk、迭代圈数 i。输出保存在 R 中。先将 输入的 R 通过查表的方法进行 E 拓展,结果保存在 48 位布尔数组 a中。再将 a 与圈子密钥 k 按位模二加。结果保存在 a 中。接下来将 a 分成 8 组,分别进入 8 个 S 盒。用 for 控制循环 8 次,每次操作选用 6 位二进制代码的开头一位和最后一位转化成十进制数,控制 S 盒的行数,再将 6 位二进制代码的中间四位转化成十进制数,控制 S 盒的列数。进入第几个 S 盒有迭
8、代圈数 i 确定。取到 S 盒中的十 进制数后,将它转化成二进制数,储存在 32 位布尔数组 T 中,在使用 查表法完成 P 盒置 换,最 终结 果保存在 R 中。最后将 L 与 R 按位模二加,得到新的 R,完成一次迭代。4、逆初始置换16 次迭代后,先将 L16 和 R16 连接起来,保存到 64 位布尔数组 m 中, m 之前用于保存明文,这样减小了程序占用的空间。另外,为了保 证加脱密算法的一致性,迭代时最后一圈不需要交换 L 与 R,但程序中 为了简化编程复 杂度,在迭代时仍然交换了 L 与R。所以在 连接时需要再次交 换 L 与 R。所以 m 的高 32 位应储存 R,低 32 位
9、应储存 L。逆初始置换原理同初始置换步骤,不再赘述。四、取得的成果利用密钥 201601211438FBCA 对明文 81623317 加密,密文 为6B217C871EAE79D2H 结果如图 3 所示。图 3 DES 加密结果 图利用密钥 201601211438FBCA 对密文 6B217C871EAE79D2 脱密,明文为81623317。结果如图 4 所示。图 4 DES 脱密结果 图变换不同明文及密钥,均可以正常加脱密。在报告中不再罗列。五、心得体会DES 算法是一种分组密码算法,本人通过对一个明文分组的加脱密进行编程,耗时近一个月,独立完成了次算法的 C+实现。本人的程序不同于网
10、上找的 DES 算法程序,网上的大多数程序的密文都是以 ASCII 码来输出的。但是,这样输出的结果有很多乱码出现。因 为 ASCII 码只有在小范围内输出的结果是正常的字母、数字或者符号(从 33 至127),如果按 ASCII 输出乱 码密文,脱密者就很 难键 入这些密文,只能通 过复制粘贴进行。而 VC6.0 的环境在控制台中很难进行复制操作,这样如果不借助文件,就很难完成密文的脱密。而密文按 16 进制输出就不存在这个问题。二进制串与 ASCII 码、 16 进制数之间的转化也是实验的难点之一。C 语言的课上没有 讲过位运算的相关知识,本人只能通过除以二取余、查表等笨 办法进行转化。同
11、 样,密 钥选用 16 进制也是一个道理,如果只用字符输入密钥,密钥 的每八位就会局限在 00100001(33)至 01111111(127)范围之内,超过 范围就无法用键盘进 行输入密钥, 这样破译 者如果看到了加密程序源代码,相应的穷尽时间会减少。通过本次编程,我发现我对 C/C+语言的掌握还是不够,尤其是涉及到位运算。我也会找机会自学这一部分内容。六、附录程序代码:#include using namespace std;void ToEr(char c,bool k)int i,j;j=0;for(i=1;io;coutci;ToEr(c,k);if(o=1)coutasci;Mto
12、Er(asc,m);else coutci;ToEr(c,m);for(i=64;i0;i-) mi=mi-1;IP(m,mip);Zhihuan_1(k,C,D);for (i=0;i16;i+) /用 for 控制循环 16 次XunHuan(zi,C); XunHuan(zi,D);/ for(j=1;j=28;j+) coutCj;/ coutendl;zhihuan_2(C,D,kk,i);if(o=0)for(i=1;i=8;i+)for(j=1;j=48;j+) kk0j = kkij;kkij = kk17-ij;kk17-ij = kk0j;for(i=1;i=65;i+)
13、if(i=32) Li = mip i;else Ri-32 = mip i;for(i=1;i=16;i+)for (j=1;j=32;j+) Tj = Rj; F(R,kk,i);for (j=1;j=32;j+) Rj = Lj;for (j=1;j=32;j+) Lj = Tj;for(i=1;i=64;i+) if(i=32) mi = Ri;else mi = Li-32;IP2(m,mip);/ for (j=1;j=64;j+) coutmipj;/ coutendl;if(o=1) cout“密文是:“;for(i=1;i=16;i+) j = 4*(i-1);mouti = mipj+1 * 8 + mipj+2 * 4 + mipj+3 * 2 + mipj+4;coutuppercasehexmouti;cout“H“endl;elsecout“明文是:“;for(j=1;j=8;j+) i = 8 * (j-1);cj = mipi+2*64 + mipi+3*32 + mipi+4*16 + mipi+5*8 + mipi+6*4 + mipi+7*2 + mipi+8;for(j=1;j=8;j+) coutcj;coutendl;