实现 DES 的工作模式

一、 实验目的

  1. 掌握 DES 算法的工作原理;

  2. 熟悉分组加密算法的工作模式。

二、 实验原理

  1. DES 的基本原理

ppop 其入口参数有三个:key、data、mode。 Key 为加密解密使用的密钥,data 为加密解密的数据,mode 为其工作模式。当模式为加密模式时,明文按照 64 位进行分组,形成明文组, key 用于对数据加密,当模式为解密模式时,key 用于对数据解密。实际运用中,密钥只用到了 64 位中的 56 位,这样才具有高的安全性。

  1. 分组密码工作模式

电码本模式(ECB)的加密过程:

Ci=E(K,Pi),i=1,2,⋅⋅⋅N\begin{aligned} C_i = E(K,P_i),i=1,2,···N \end{aligned}Ci​=E(K,Pi​),i=1,2,⋅⋅⋅N​

密码分组链接模式(CBC)的加密过程:

C1=E(K,[P1⨁IV]),Cj=E(K,[P1⨁Cj−1]),j=2,3,⋅⋅⋅NC_1=E(K,[P_1\bigoplus IV]),\\ C_j =E(K,[P_1\bigoplus C_ {j-1}]),j=2,3,···N C1​=E(K,[P1​⨁IV]),Cj​=E(K,[P1​⨁Cj−1​]),j=2,3,⋅⋅⋅N

DES 是原型块密码— 一种算法,它采用固定长度的明文位字符串,并通过一系列复杂的操作将其转换为另一个相同长度的密文位字符串。对于 DES,块大小为 64 位。DES还使用密钥来自定义转换,因此解密只能由那些知道用于加密的特定密钥的人执行。密钥表面上由64位组成;但是,算法实际使用了其中的56个。KEY的每个 8 位字节中的一个位可用于密钥生成、分发和存储中的错误检测。位 8、16,…, 64 用于确保每个字节具有奇偶校验。第八位仅用于检查奇偶校验,然后被丢弃。因此,有效密钥长度为 56 位。

该算法的整体结构如图 1 所示:有 16 个相同的处理阶段,称为轮次。还有一个初始和最终排列,称为IP和FP,它们是逆的(IP"撤消"FP的作用,反之亦然)。IP 和 FP 没有加密意义,但包括在内是为了便于在 20 世纪 70 年代中期基于 8 位的硬件中加载块。

在主回合之前,块被分成两个32位的半部分并交替处理;这种纵横交错被称为Feistel方案。Feistel 结构可确保解密和加密是非常相似的过程 — 唯一的区别是解密时子密钥以相反的顺序应用。算法的其余部分是相同的。这大大简化了实现,特别是在硬件中,因为不需要单独的加密和解密算法。

⊕符号表示抑或(XOR) 操作。F 函数将半个块与一些键一起打乱。然后,F函数的输出与块的另一半组合,并在下一轮之前交换一半。在最后一轮之后,交换一半;这是Feistel结构的一个特征,它使加密和解密过程相似。

DES 的 Feistel 函数(F 函数)

轮函数的作用是根据“右侧”和子密钥生成对“左侧”进行加密的比特序列,它是密码系统的核心。将轮函数的输出与“左侧”进行XOR运算,其结果就是“加密后的左侧”。也就是说,我们用XOR将轮函数的输出与“左侧”进行了合并。而输人的“右侧”则会直接成为输出的“右侧”。

总结一下,一轮的具体计算步骤如下:

  1. 将输人的数据等分为左右两部分
  2. 将输人的右侧直接发送到输出的右侧
  3. 将输人的右侧发送到轮函数
  4. 轮函数根据右侧数据和子密钥,计算出一串看上去是随机的比特序列
  5. 将上一步得到的比特序列与左侧数据进行XOR运算,并将结果作为加密后的左侧。

但是,这样一来“右侧”根本就没有被加密,因此我们需要用不同的子密钥对一轮的处理重复若干次,并在每两轮处理之间将左侧和右侧的数据对调。

Feistel具体的轮函数一次在半个块(32 位)上运行,由四个阶段组成:

  • 扩展:32位半块使用扩展排列(在图中表示为E)通过复制一半的位来扩展到48位。输出由 8 个 6 位(8 × 6 = 48 位)片段组成,每个片段包含 4 个相应输入位的副本,以及从每个输入片段到任一侧的紧邻位的副本。
  • 抑或:使用 XOR 操作将结果与子密码(subkey)组合在一起。16 个 48 位子密钥(每轮一个)使用从主密钥派生(如下所述)。
  • S盒替换:在子键中混合后,块被分成八个6位片段,然后由或替换框处理。八个 S-box 中的每一个都根据非线性变换将其六个输入位替换为四个输出位,该变换以查找表的形式提供。S-box提供了DES安全性的核心 - 没有它们,密码将是线性的,并且很容易损坏。
  • P盒排列:最后,来自S盒的32个输出根据固定排列重新排列,即P盒。这样做是为了在排列之后,本轮中每个 S 盒输出的位在下一轮中分布在四个不同的 S 盒中。

三、 实验要求

1.编写一个 DES 算法,输出其每一轮的加密结果并显示在屏幕上;

2.编程实现对文件的加密,加密模式:电码本、分组链接模式。

四、 实验内容

1. 编程实现 DES 算法;

java实现

先定义一个BOX类用于存放各种盒子
package com.des.demo;public class Box {// E 扩展置换public static int[] 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};//P置换表public static int[] 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, 25};// 置换选择1,PC_1将64位密钥减至56位public static int[] PC_1 = {57, 49, 41, 33, 25, 17, 9,1, 58, 50, 42, 34, 26, 18,10, 2, 59, 51, 43, 35, 27,19, 11, 3, 60, 52, 44, 36,63, 55, 47, 39, 31, 23, 15,7, 62, 54, 46, 38, 30, 22,14, 6, 61, 53, 45, 37, 29,21, 13, 5, 28, 20, 12, 4};//置换选择2,PC_2 用于将循环左移和右移后的56bit密钥压缩为48bitpublic static int[] PC_2 = {14, 17, 11, 24, 1, 5,3, 28, 15, 6, 21, 10,23, 19, 12, 4, 26, 8,16, 7, 27, 20, 13, 2,41, 52, 31, 37, 47, 55,30, 40, 51, 45, 33, 48,44, 49, 39, 56, 34, 53,46, 42, 50, 36, 29, 32};// IP FP置换表public static int[] IP = {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};public static int[] FP = {40, 8, 48, 16, 56, 24, 64, 32,39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30,37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28,35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26,33, 1, 41, 9, 49, 17, 57, 25};// 8个S盒public static int[] S1 = {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13};public static int[] S2 = {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9};public static int[] S3 = {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12};public static int[] S4 = {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14};public static int[] S5 = {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3};public static int[] S6 = {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13};public static int[] S7 = {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12};public static int[] S8 = {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11};// 总S盒public static int[][] S = {S1, S2, S3, S4, S5, S6, S7, S8};}
再定义DES类继承BOX
package com.des.demo;public class DES extends Box {//DES密钥扩展算法public static String[] creatSubKeys(String key) {// 创建编码类对象 并将密钥转为64位长的二进制字符串Ecode k1 = new Ecode(key);k1.s2n();StringBuilder key64 = k1.getSb();StringBuilder key56 = new StringBuilder();// 64位变56位 使用PC_1表格进行操作for (int i = 0; i < 56; i++) {key56.append(key64.charAt(PC_1[i] - 1));}// 子密钥列表 16个子密钥String[] subKeys = new String[16];//初始化 C DString C = key56.substring(0, 28);String D = key56.substring(28, 56);// 移位次数 16个项中12个都是2,初始化为2for (int i = 0; i < 16; i++) {int shiftStep = 2;if (i == 0 || i == 1 || i == 8 || i == 15) {//1 2 9 16 轮仅位移1shiftStep = 1;}// C D 左移2或1位 调用自定义的位移方法C = leftMove(C, shiftStep);D = leftMove(D, shiftStep);// CD 字符串合并String CD;CD = C + D;// 通过PC_2置换,将56位变成48位StringBuilder key48 = new StringBuilder();for (int j = 0; j < 48; j++) {key48.append(CD.charAt(PC_2[j] - 1));}subKeys[i] = key48.toString();}return subKeys;}//自定义字符串左移n位方法private static String leftMove(String str, int position) {String str1 = str.substring(position);String str2 = str.substring(0, position);return str1 + str2;}// 初始 IP 置换public static String iPReplace(String binStr64) {StringBuilder ipStr = new StringBuilder();for (int i = 0; i < 64; i++) {ipStr.append(binStr64.charAt(IP[i] - 1));}return ipStr.toString();}// 逆初始 FP 置换public static String fPReplace(String binStr64) {StringBuilder fpStr = new StringBuilder();for (int i = 0; i < 64; i++) {fpStr.append(binStr64.charAt(FP[i] - 1));}return fpStr.toString();}// 拓展置换E 32 -> 48public static String replE(String binStr32) {StringBuilder eStr48 = new StringBuilder();for (int i = 0; i < 48; i++) {eStr48.append(binStr32.charAt(E[i] - 1));}return eStr48.toString();}// S盒代换 48 -> 32public static String replS(String binStr48) {int si = 0;StringBuilder binStr32 = new StringBuilder();// 48 个字符每组6个,共8组,for (int i = 0; i < 8; i++) {// 截取出6长度的一组 隔6个截取一次String binStr6 = binStr48.substring(i * 6, i * 6 + 6);// 总字符串中截取出 首尾作为行号 中间部分作为列号String row = String.valueOf(binStr6.charAt(0)) + binStr6.charAt(5);String col = binStr6.substring(1, 5);// 将字符作为二进制解析出数字int rown = Integer.parseInt(row, 2);int coln = Integer.parseInt(col, 2);// 根据S盒 4行16列的排布算出在一维状态下的索引int index = 16 * rown + coln;// 找到对应的S盒的对应位置进行代换 si++ 在执行一次后自动加一int bitn4 = S[i][index];//讲格式定为4个,不足补空位,后续替换为0String binStr4 = String.format("%4s", Integer.toBinaryString(bitn4)).replace(' ', '0');// binStr4逐个添加binStr32.append(binStr4);}return binStr32.toString();}// 取得S盒变换的结果后再进行一次P置换public static String replP(String binStr32) {StringBuilder sb32 = new StringBuilder();for (int i = 0; i < 32; i++) {sb32.append(binStr32.charAt(P[i] - 1));}return sb32.toString();}// 字符形式的二进制异或运算public static String xor(String s1, String s2) {// 二进制字符串转为数字 截取出钱30 后2或者18自行判断int len = s2.length();int sn1l = Integer.parseInt(s1.substring(0, 30), 2);int sn1r = Integer.parseInt(s1.substring(30), 2);int sn2l = Integer.parseInt(s2.substring(0, 30), 2);int sn2r = Integer.parseInt(s2.substring(30), 2);// 异或运算int snl = sn1l ^ sn2l;int snr = sn1r ^ sn2r;// 格式化字符串String left = String.format("%30s", Integer.toBinaryString(snl)).replace(' ', '0');String rlenfm = "%" + (len - 30) + "s";String right = String.format(rlenfm, Integer.toBinaryString(snr)).replace(' ', '0');// 生成format字符串格式参数return left + right;}public static String feistel(String binStr32, String subKey48) {// 扩展置换 E 32->48String binE48 = replE(binStr32);// 异或运算String binXor48 = xor(binE48, subKey48);// S盒代换 48->32String binS32 = replS(binXor48);// P 盒置换String binP32 = replP(binS32);return binP32;}// 加密过程public static String encryption(String binPlain64, String[] binKeys48) {// 初始IP置换String binIP = iPReplace(binPlain64);// 分割成左右两部分 Li RiString left = binIP.substring(0, 32);String right = binIP.substring(32);// 定义 Li-1  Ri-1String beforeLeft;String beforeRight;// 16轮 Feistel 转换// Li=Ri-1    Ri=Li-1 ^ F(Ri-1, Ki)for (int i = 0; i < 16; i++) {beforeLeft = left;beforeRight = right;left = beforeRight;right = xor(beforeLeft, feistel(beforeRight, binKeys48[i]));
//            System.out.println("第" + (i + 1) + "轮的加密结果为" + left + right);}// 最后一轮交换后得到结果String encryptionText = right + left;return fPReplace(encryptionText);}public static String decryption(String binPlain64, String[] binKeys48) {// 初始IP置换String binIP = iPReplace(binPlain64);// 分割成左右两部分 Li RiString left = binIP.substring(0, 32);String right = binIP.substring(32);// 定义 Li-1  Ri-1String beforeLeft;String beforeRight;// 16轮 Feistel 转换// Li=Ri-1    Ri=Li-1 ^ F(Ri-1, Ki)for (int i = 0; i < 16; i++) {beforeLeft = left;beforeRight = right;left = beforeRight;right = xor(beforeLeft, feistel(beforeRight, binKeys48[15 - i]));
//            System.out.println("第" + (i + 1) + "轮的解密结果为" + left + right);}// 最后一轮交换后得到结果String decryptionText = right + left;return fPReplace(decryptionText);}
}
Ecb电码本模式
package com.des.demo;public class Ecb extends DES {public static String encryption(String binPlain, String binKey) {// 生成子密钥串String[] binKeys48 = creatSubKeys(binKey);// 64个一组分组int group = binPlain.length() / 64;StringBuilder cipher = new StringBuilder();for (int i = 0; i < group; i++) {//            System.out.println("开始第" + (i + 1) + "组加密");String binPlain64 = binPlain.substring(i * 64, (i + 1) * 64);cipher.append(encryption(binPlain64, binKeys48));}return cipher.toString();}public static String decryption(String binCipher, String binKey) {// 生成子密钥串String[] binKeys48 = creatSubKeys(binKey);// 64个一组分组int group = binCipher.length() / 64;StringBuilder plain = new StringBuilder();for (int i = 0; i < group; i++) {String binCipher64 = binCipher.substring(i * 64, (i + 1) * 64);plain.append(decryption(binCipher64, binKeys48));}return plain.toString();}
}
Cbc密码分组链接模式
package com.des.demo;public class Cbc extends DES {public static String encryption(String binStr, String binKey, String strIV) {// 生成子密钥串String[] binKeys48 = creatSubKeys(binKey);int group = binStr.length() / 64;// 将IV 编码成二进制Ecode si = new Ecode(strIV);si.s2n();String binIV = si.getBinString();
//        System.out.println("binIV" + binIV);StringBuilder cipher = new StringBuilder();// 进行第一轮的加密String binCbc1 = xor(binStr.substring(0, 64), binIV);String binCbcBefore = encryption(binCbc1, binKeys48);cipher.append(binCbcBefore);// 进行其余组的加密for (int i = 1; i < group; i++) {// 取余第i+1组String binCbcStri = binStr.substring(i * 64, i * 64 + 64);String binCbci = xor(binCbcStri, binCbcBefore);binCbcBefore = encryption(binCbci, binKeys48);cipher.append(binCbcBefore);}return cipher.toString();}public static String decryption(String binStr, String binKey, String strIV) {// 生成子密钥串String[] binKeys48 = creatSubKeys(binKey);int group = binStr.length() / 64;// 将IV 编码成二进制Ecode si = new Ecode(strIV);si.s2n();String binIV = si.getBinString();StringBuilder plaint = new StringBuilder();// 进行第一轮的加密String binCbcBefore = decryption(binStr.substring(0, 64), binKeys48);String binCbc1 = xor(binCbcBefore, binIV);plaint.append(binCbc1);// 进行其余组的加密for (int i = 1; i < group; i++) {// 取余第i+1组String binCbcStri = binStr.substring(i * 64, i * 64 + 64);binCbcBefore = decryption(binCbcStri, binKeys48);String binCbci = xor(binCbcBefore, binStr.substring(i * 64 - 64, i * 64));plaint.append(binCbci);}return plaint.toString();}// 字符形式的二进制异或运算 重写父类的方法 专为此处64位异或设计public static String xor(String s1, String s2) {// 二进制字符串转为数字 截取出钱30 后2或者18自行判断int len = s2.length();int sn1l = Integer.parseInt(s1.substring(0, 30), 2);int sn1c = Integer.parseInt(s1.substring(30, 60), 2);int sn1r = Integer.parseInt(s1.substring(60), 2);int sn2l = Integer.parseInt(s2.substring(0, 30), 2);int sn2c = Integer.parseInt(s2.substring(30, 60), 2);int sn2r = Integer.parseInt(s2.substring(60), 2);// 异或运算int snl = sn1l ^ sn2l;int snc = sn1c ^ sn2c;int snr = sn1r ^ sn2r;String left = String.format("%30s", Integer.toBinaryString(snl)).replace(' ', '0');String center = String.format("%30s", Integer.toBinaryString(snc)).replace(' ', '0');String rlenfm = "%" + (len - 60) + "s";String right = String.format(rlenfm, Integer.toBinaryString(snr)).replace(' ', '0');// 生成format字符串格式参数return left + center + right;}
}
Ecode二进制编码类
package com.des.demo;public class Ecode {public String str;public int len;private char[] array;private String[] binarray;private StringBuilder sb = new StringBuilder();private StringBuilder stringChar = new StringBuilder();// 规定所有组创建时必须有字符public Ecode(String str) {this.str = str;}// 编码时得到可变二进制字符串public StringBuilder getSb() {return sb;}// 编码时得到二进制字符串public String getBinString() {return sb.toString();}// 解码时得到字符串public String getStringChar() {return stringChar.toString();}// String to Number 编码public void s2n() {this.array = str.toCharArray();this.len = str.length();this.binarray = new String[len];for (int i = 0; i < len; i++) {// 逐个读取出字符char ch = array[i];// 转为二进制形式,以字符串存储// 如下是将字符定为8位,不足补零的两种方式,调用format或者做if elsString binch = String.format("%8s", Integer.toBinaryString(ch)).replace(' ', '0');/*            String binch = Integer.toBinaryString(ch);int binlen = binch.length();if (binlen == 6) {binch = "00" + binch;} else if (binlen == 7 || binlen == 15) {binch = "0" + binch;} else if (binlen != 8) {System.out.println("该字符符有问题");}*/binarray[i] = binch;sb.append(binch);}}// Number to String 解码 将二进制字符转为字符public void n2s() {// 获得字符长度 并分组this.len = str.length();for (int i = 0; i < len / 8; i++) {String item = str.substring(i * 8, i * 8 + 8);int ass = Integer.parseInt(item, 2);stringChar.append((char) ass);}}
}
测试类
package com.des.demo;public class Test {public static void main(String[] args) {String str = "skpriminE1914168";String key="12345678";System.out.println("将要加密的内容为"+str);System.out.println("密钥为"+key);Ecode gin = new Ecode(str);gin.s2n();String plaint = gin.getBinString();System.out.println("\n欢迎来到ECB模式");String ciphere = Ecb.encryption(plaint, key);System.out.println("密文为"+ciphere);String plaintoute = Ecb.decryption(ciphere, key);System.out.println("明文为"+plaintoute);Ecode goute = new Ecode(plaintoute);goute.n2s();String plaintoutchare = goute.getStringChar();System.out.println("ECB解密"+plaintoutchare);System.out.println("\n欢迎来到CBC模式");String iV = "11112222";System.out.println("IV为"+iV);String cipherc = Cbc.encryption(plaint, key,iV);System.out.println("加密得到的密文为"+cipherc);String plaintoutc = Cbc.decryption(cipherc, key,iV);System.out.println("解密得到的明文为"+plaintoutc);Ecode goutc = new Ecode(plaintoutc);goutc.n2s();String plaintoutcharc = goutc.getStringChar();System.out.println("CBC解密"+plaintoutcharc);}
}
文件输入输出类
package com.des.demo;import java.io.*;public class FileRW {public static void main(String[] args) {//1.1有一个源文件File f1 = new File("Cryptology/src/com/des/demo/testin.txt");//1.2有一个目标文件:File f2 = new File("Cryptology/src/com/des/demo/output.txt");//2.1搞输入的管和输出的管,并分别接到源文件和目标文件上try (FileReader fr = new FileReader(f1);FileWriter fw = new FileWriter(f2);) {//3利用缓冲字符数组,将数组转为String写出char[] ch = new char[8];int len = fr.read(ch);while (len != -1) {String str = new String(ch, 0, len);String key = "12345678";System.out.println("将要加密的内容为" + str);System.out.println("密钥为" + key);// 进行字符编码Ecode gin = new Ecode(str);gin.s2n();String plaint = gin.getBinString();// ECB  模式System.out.println("\n欢迎来到ECB模式");String ciphere = Ecb.encryption(plaint, key);System.out.println("密文为" + ciphere);String plaintoute = Ecb.decryption(ciphere, key);System.out.println("明文为" + plaintoute);Ecode goute = new Ecode(plaintoute);goute.n2s();String plaintoutchare = goute.getStringChar();System.out.println("ECB解密" + plaintoutchare);// 写入文件fw.write("ECB模式\n 密文:" + ciphere + "\n明文:" + plaintoute + "\n解码:" + plaintoutchare);// CBC  模式System.out.println("\n欢迎来到CBC模式");String iv = "11112222";System.out.println("iv为" + iv);String cipherc = Cbc.encryption(plaint, key, iv);System.out.println("加密得到的密文为" + cipherc);String plaintoutc = Cbc.decryption(cipherc, key, iv);System.out.println("解密得到的明文为" + plaintoutc);Ecode goutc = new Ecode(plaintoutc);goutc.n2s();String plaintoutcharc = goutc.getStringChar();System.out.println("CBC解密" + plaintoutcharc);// 写入文件fw.write("\nCBC模式\n 密文:" + cipherc + "\n明文:" + plaintoutc + "\n解码" + plaintoutcharc);len = fr.read(ch);}} catch (IOException e) {e.printStackTrace();}}
}

输出效果

ECB模式

加密

解密

CBC模式

加密

解密

控制台自行输入内容

文件输入输出

2. 改变 1 位明文观察输出 DES 算法的 16 轮输出,几轮后密文变化达到 32位以上;

想要通过肉眼比较出不同的位数是困难的,可以使用python写一写这种简单的工具

即使是给字符串格式化也可以使用技巧,通过替换换行符实现

随后编写脚本运行,发现在第五轮时变化就达到32位以上,由于一轮加密的结果是01组成的64位字符,想保持32位以上的差异概率较低,其后一直反复,但大体在32左右。

skprimin = ["第1轮的加密结果为0000000011111111111100101000101101101100111100111111100111101001", "第2轮的加密结果为0110110011110011111110011110100100000101010110011111010001100110", ...]skprimio = ["第1轮的加密结果为0000000011111111011100101000101111101101011100110110100111101001", "第2轮的加密结果为1110110101110011011010011110100110000001111101011010111001001110", ...]for i in range(16):s1 = skprimin[i][-64:]s2 = skprimio[i][-64:]change = 0for index,j in enumerate(s1):if j != s2[index]:change += 1print(f"第{i+1}轮有{change}位不同")

3. 改变 1 位密钥观察输出 DES 算法的 16 轮输出,几轮后密文变化达到 32位以上;

依靠人眼依然不现实

  • 通过脚本比较,发现在第5轮差异就达到了32以上

4. 在电码本模式和分组链接模式中,在最少 64 个分组的明文中,观察当一个密文分组错误时,还原的明文有几个分组错误。

首先生成了一段长达8*64=512长度的字符串,可分为64组。ECb,CBC模式下均得到了4096个字符的密文,这里我们在解密是替换掉一部分密文,替换第二组的密文。

package com.des.demo;public class Test {public static void main(String[] args) {// 直接定义明文密钥String str = "11112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222111122221111222211112222";String key = "12345678";System.out.println("将要加密的内容为" + str);System.out.println("密钥为" + key);// 进行字符编码Ecode gin = new Ecode(str);gin.s2n();String plaint = gin.getBinString();// ECB  模式System.out.println("\n欢迎来到ECB模式");String ciphere = Ecb.encryption(plaint, key);System.out.println("密文为" + ciphere);// 截取替换String replace = String.format("%64s", "0").replace(' ', '0');ciphere = ciphere.substring(0, 64) + replace + ciphere.substring(128);System.out.println("修改后的密文为" + ciphere);String plaintoute = Ecb.decryption(ciphere, key);System.out.println("明文为" + plaintoute);Ecode goute = new Ecode(plaintoute);goute.n2s();String plaintoutchare = goute.getStringChar();System.out.println("ECB解密" + plaintoutchare);// CBC  模式System.out.println("\n欢迎来到CBC模式");String iv = "11112222";System.out.println("iv为" + iv);String cipherc = Cbc.encryption(plaint, key, iv);System.out.println("加密得到的密文为" + cipherc);// 截取替换cipherc = cipherc.substring(0, 64) + replace + cipherc.substring(128);System.out.println("修改后的密文为" + cipherc);String plaintoutc = Cbc.decryption(cipherc, key, iv);System.out.println("解密得到的明文为" + plaintoutc);Ecode goutc = new Ecode(plaintoutc);goutc.n2s();String plaintoutcharc = goutc.getStringChar();System.out.println("CBC解密" + plaintoutcharc);}
}

由图可以轻而易举的看出 ECB一组出错只会影响本组,而CBC模式出错会影响本组以及下一组。

密码学 实现 DES 的工作模式 电码本模式ECB 密码分组链接模式CBC java 实现相关推荐

  1. 基于C++的DES的EBC电子密码本加解密,CBC密码分组链接思想,以及相关流程图

    CBC模式的DES加解密 一.实验内容 学习并完成对称加解密中的DES加解密以及CBC模式的DEC加解密. 二.实验原理 2.1 DES加解密原理 DES算法是一种最通用的对称密钥算法,因为算法本身是 ...

  2. 分组加密模式 ECB、CBC、PCBC、CFB、OFB、CTR

    在分组加密算法中,有几种不同的工作模式,分别是ECB(Electronic CodeBook,电子密码本模式).CBC(Cipher-block chaining,密码块连接模式).PCBC(Prop ...

  3. 【密码学三】分组密码是如何迭代的、ECB、CBC、CFB、OFB、CTR的异同以及应如何选择

    分组密码的模式 "分组密码的模式 -- 分组密码是如何迭代的" 本章中我们将探讨一下分组密码的模式 DES和AES都属于分组密码,它们只能加密固定长度的明文.如果需要加密任意长度的 ...

  4. 【密码学】DES 介绍

    文章目录 一.DES 简介 二.DES 算法入口参数 三.DES 算法框架 1. 子密钥生成 2. 迭代加密 3. 轮函数 F 四.DES 设计的基本原则:混淆和扩散 五.安全性 参考链接 一.DES ...

  5. 密码学之DES/AES算法

    本文示例代码详见:https://github.com/52fhy/cryp... DES DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1 ...

  6. 用python实现DES加解密,并附带EBC和CBC两种分组加密模式

    之前在网上看了好多关于DES加解密的文章,很多都是直接贴代码,然而大多数都不能运行.花了一天写了个能运行的程序,其中有参考网上的一些好的代码.希望入了密码学坑的同学能得到帮助.python刚上手,代码 ...

  7. 计算机应用工作技能与经验,关于计算机应用技能人才培养模式的思考

    [摘 要]本文针对当前职业院校计算机应用专业人才培养模式中存在的人才培养与市场脱节.课程体系陈旧不适应企业和社会需求.缺乏办学特色等问题,提出了改革人才培养模式的思路,即:以职业能力为核心.以工作过程 ...

  8. (68)SPI工作模式有哪些?分为几种极性模式。

    1.1 SPI工作模式有哪些?分为几种极性模式. 1.1.1 本节目录 1)本节目录: 2)本节引言: 3)FPGA简介: 4)SPI工作模式有哪些?分为几种极性模式.: 5)结束语. 1.1.2 本 ...

  9. 苹果手机夜间模式怎么设置_微信怎么设置夜间模式?iPhone夜间模式设置教程 省电又护眼!...

    最近有小伙伴后台留言问了这样一个问题,微信怎么设置夜间模式?首先微信APP目前本身并没有加入夜间模式,如果觉得夜间看手机刺眼的话,可以开启手机自动的夜间模式,大多数安卓和iOS手机都支持,开启后不仅更 ...

最新文章

  1. ASP:关于生成HTML文件的新闻系统
  2. 使用Powerdesigner的逆向工程生成PDM(主要是注释可以放进去)
  3. android 特色输入输出
  4. 超简单方法: Intellij Idea 把 java 工程打成可运行的 jar
  5. 刘朋:程序员如何练就领导力
  6. Cloudflare泄露客户数据,IT部门可从中吸取什么教训?
  7. mock of python
  8. Elpscrk:功能强大的智能字典生成器
  9. 机器人开发--NDC方案
  10. 计算机未来的发展英语作文,关于科技发展英语作文(通用10篇)
  11. duilib库combo box提供输入字符模糊查询
  12. 线性代数 --- 用条件数(condition number)来判断矩阵是否可逆
  13. 别错过,教你如何用电脑玩手机
  14. 俄罗斯方块、贪吃蛇、心形表白 | 好玩的C语言源码
  15. Occupancy Flow: 4D Reconstruction by Learning Particle Dynamics(2)
  16. android 旋转屏幕 不重走生命周期,屏幕旋转后Activity生命周期
  17. OCX控件全屏、恢复
  18. 杭电计算机学院宿舍,走进杭电 | 不得不说的杭电寝室
  19. 永辉超市第三季营收222亿:净亏7.8亿 卖金龙鱼股权套现1.7亿
  20. SaaS普及引发SaaS用户对数据集成的需求

热门文章

  1. 麻省理工MIT计算机课程表
  2. 电子邮件发错了怎么撤回?原来邮件误发也有“后悔药”
  3. Visual Studio 匹配花括号的背景颜色
  4. 计算机为啥启用不了网络发现,Win7系统网络发现打不开怎么办 win7不能启用网络发现如何解决...
  5. 解决caffe编译时//usr/lib/x86_64-linux-gnu/libSM.so.6: undefined reference to `uuid_unparse_lower@UUI
  6. warning:In file included from...
  7. 深度学习中的对抗损失怎么使用
  8. 2020年终总结!新的起航,新的征程
  9. 企业微信打卡怎么防止作弊?看看其他企业是怎么做的
  10. shared_ptr的引用计数原理