DES算法

DES算法是一种使用56位密钥的加密算法,通过一系列复杂运算将64位明文转化为密文。主要包括初始IP置换、16次迭代循环运算(每次循环包括E扩展、异或、S盒和P盒操作)、逆置换IP-1得到密文。解密过程与加密过程类似,只是子密钥使用顺序相反。DES算法分为IP置换、子密钥生成、迭代循环和IP逆置换四个模块,数据结构涉及数组、矩阵和struct。
部署运行你感兴趣的模型镜像

一、DES算法原理概述

DES算法是这样的一个算法:它使用密钥和明文作为参数,经过一系列复杂的运算过程,输出明文对应的密文。首先要指出的是,明文是按照每64位一个分组来进行输入的。输出的对应密文也是64位。而密钥虽说也是64位,但是其中8位用来做奇偶校验位,故真正有用的只有56位。DES通过其巧妙的设计,使得加密和解密可以使用同一套密钥和同一个算法。
DES算法具体实现过程如下:
1、首先将输入的64位明文进行一个初始的IP置换。所谓的置换就是根据已经规定好的顺序将所有位数重新排序。如下图所示,“58”出现在第一位,说明第一位将在新64位数的第58位,以此类推。
这里写图片描述
本算法中将多次用到“置换”这种方法,其意思都是一样的,区别的是每次这个所谓的“规定好的顺序”不同而已。置换之后得到的64位数,我们将它叫做afterFirstIPChange,将这个afterFirstIPChange的64位从中间分成两半,分别叫做L0、R0,顾名思义。这个L0、R0将和密钥K作为算法下一个模块的初始化数据 (如果将算法的下一个模块实现成一个独立的函数的话,那么L0、R0和K就是这个独立函数的输入参数)。

2、在这一步,我们将做一个16次的循环 (分别称为循环1、循环2……循环16)。
每次循环操作都需要用到密钥K的一个子密钥Ki。所以我们先说清楚Ki是怎么来的:前面说过,K虽然有64位,但是其中只有56位会被我们利用(被排除的位数分别是:第8、16、24、32、40、48、56、64位)。之后,我们对K的剩下的位数进行PC-1置换,置换表如下:
这里写图片描述

之后我们将得到一个数:afterPC1,我们也将它从中间分成两半,分别叫做C0、D0。然后,根据C0、D0,我们做16个循环,循环i生成Ki。每次循环执行以下步骤:计算 Ci = LSi(Ci-1) 和 Di = LSi(Di-1)。其中,LSi函数表示左移函数:当 i =1, 2, 9, 16 时,LSi (string) 表示将二进制串 string 循环左移一个位置; 否则循环左移两个位置。这样子得到 Ci和Di之后将它们合并成CiDi (56位),将这个56位的CiDi执行PC-2压缩置换,得到的就是48位的Ki。16次循环后得到一个序列:K1,…, K16 。
所谓的压缩置换,就是从56位的CiDi中去掉第9,18,22,25,35,38,43, 54位,将剩下的48位按照 PC-2置换表作置换:
这里写图片描述
说完Ki是怎么来的之后,我们说回原来的循环,每次循环的参数都有:Li-1、Ri-1和Ki。每次循环的具体内容为:先将32位的Ri-1进行E扩展得到48位的结果,我们可以称它为afterEChangei。
这里先说一下什么是E扩展。其实跟置换表的原理是一样的。见:
这里写图片描述

然后将afterEChangei和对应的子密钥Ki进行异或运算得到一个数afterXORi(48位)。将这个afterXORi从左到右分成8组,每组6位,分别通过8个S盒S1、S2、S3、S4、S5、S6、S7、S8。
这里也先介绍一下S盒:S盒是这样一个函数:输入6个位,通过这8个位的值来决定其输出,输出4个位。其决定规则是这样的:将6位中的首位和尾位取出来组成一个新的数,该数对应的10进制数作为行号,中间4个位对应的十进制数作为列号,在S盒对应的表中查找对应行列的数,这个数的二进制数就是我们要的结果。如下图S1盒,举个例子,若输入是000100,则行数是(00)10 = 0,列数是(0010)10=2,对应的数是13,其二进制数是11012。就是我们所要的第一组的输出。
这里写图片描述
这里写图片描述

所有S盒如下所示:
这样所有位通过之后再将结果整合起来就是32位。然后再将这个32位数做一个P盒置换,得到afterPBoxChangei 。
这里写图片描述
最后将这个afterPBoxChangei同Li-1进行异或运算得到的结果就是Ri。而Li的值就是Ri-1。
就这样,循环16次之后得到了L16、R16。将它们交换之后组合成R16L16 (64位)这个数,便是下一阶段需要操作的数。
3、这一步将第二步得到的R16L16作为输入,进行一个“逆置换IP-1”。得到的结果就是我们想要的结果,即“密文”。
这里写图片描述
4、解密过程。因为DES置换表的巧妙设计,使得DES 的加密和解密过程可以使用同一套密钥和同一个算法。区别只是中间子密钥的使用顺序:加密过程是K1-K16的顺序使用,解密过程使用的顺序相反,从K16到K1。其余过程一样,故不赘述。

二、总体结构

这里写图片描述

三、模块分解

根据第一部分的描述可以将该算法分成4个模块。
第一个模块是64位明文输入后的IP置换,这个模块的输入是64位明文,输出置换运算后的64位数的左半部分和右半部分。
第二个模块是子密钥的产生。这个模块的输入是64位的密钥,这个模块将进行16次迭代循环,每一次循环后输出一个数,这个数便是这一轮循环产生的子密钥。16次循环之后产生一个子密钥序列K1,…, K16 ,这个子密钥序列将参与另一个模块的运算。
第三个模块是16次复杂的迭代循环运算,第i次迭代使用的参数是Li-1、Ri-1和Ki。Ki是第二个模块的第i次迭代循环产生的子密钥。该模块第i次迭代生成Li和Ri。 第16次迭代循环之后生成L16和R16是这个模块的输出。
最后一个模块是IP逆置换模块。它的输入是前一个模块产生的R16和L16合并成的64位数R16L16;输出是密文,也就是整个算法的最终结果。
由于加密和解密使用的是同一套密钥和算法,只是中间有一点细微的不同,故解谜过程不单独设置一个模块,只需要直接使用上面所说的模块即可。

四、数据结构

第一个模块可使用的数据结构是数组和矩阵。需要使用两个64位的布尔数组和一个8X8的整型矩阵。
第二个模块也是可以直接使用数组和矩阵。需要用到的是两个28位的数组、一个56位的数组、一个48位的数组、一个7X8整型矩阵和一个6X8整型矩阵。
第三个模块需要使用数组、整型矩阵以及struct结构体。需要用到多个32位、多个48位的布尔数组和两个struct结构体,其中一个包含8个6位大小的布尔数组,另一个包含8个4位大小的布尔数组。此外,还需要一个6x8的整型矩阵和8个16x4的整型矩阵。
第四个模块需要使用的是数组和整型矩阵。需要两个64位的布尔数组和一个8x8的整型矩阵。

五、类-C语言算法过程

以下是使用C++语言 + 一些伪代码实现的DES算法。其中,因为S1盒到S8盒的算法基本完全一致,故只写出了S1盒作为代表。其他的一些教繁琐的运算直接使用了伪代码来说明。如异或运算:afterEChange XOR subKey[i],以及二进制和十进制的互相转换。

bool* IPChange(bool inputText[]) {
  bool result[64];
  int IPBox[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};
  for (int i = 0; i < 64; i++) {
    result[IPBox[i]] = inputText[i];
  }
  return result;
}


vector<vector<bool> > getSubKey(bool key[]) {
  bool trueKey[56];
  for (int i = 0, j = 0; i < 64; ++i, j++) {
    trueKey[j] = key[i];
    if (i == 6 || i == 14 || i == 22 || i == 30 || i == 38 || i == 46 || i == 54 || i == 62)
      i++;
  }
  bool afterPC1[56];
  int PC1Box[56] = {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 };
  for (int i = 0; i < 56; i++) {
    afterPC1[PC1Box[i]] = trueKey[i];
  }
  bool C0[28], D0[28];
  for (int i = 0; i < 28; ++i)
    C0[i] = afterPC1[i];
  for (int i = 0; i < 28; ++i)
    D0[i] = afterPC1[i+28];
  vector<vector<bool> > result;
  bool lastC[28] = C0, lastD[28] = D0;
  for (int i = 0; i < 16; i++) {
    bool nextC[28], nextD[28];
     //当 i =1, 2, 9, 16 时,LSi (string) 表示将二进制串 string 循环左移一个位置,否则循环左移两个位置
    if (i == 0 || i == 1 || i == 8 || i == 15) {
      nextC[27] = lastC[0];
      nextD[27] = lastD[0];
      for (int j = 1; j < 28; j++) {
        nextC[j - 1] = lastC[j];
        nextD[j - 1] = lastD[j];
      }
    } else {
      nextC[27] = lastC[1];
      nextC[26] = lastC[0];
      nextD[27] = lastD[1];
      nextD[26] = lastD[0];
      for (int j = 2; j < 28; j++) {
        nextC[j - 2] = lastC[j];
        nextD[j - 2] = lastD[j];
      }
    }
    bool connectNewCD[56];
    for (int j = 0; j < 28; ++j) {
      connectNewCD[j] = nextC[j];
      connectNewCD[j+28] = nextD[j];
    }
    bool temp[48];
    for (int j = 0, k = 0; j < 56; ++j, ++k) {
      temp[k] = connectNewCD[j];
      if (j == 7 || j == 16 || j == 20 || j == 23 || j == 33 || j == 36 || j == 41 || j == 52)
        j++;
    }
    bool afterPC2[48];
    int PC2Box[48] = { 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 };
    for (int i = 0; i < 48; i++) {
      afterPC2[PC2Box[i]] = temp[i];
    }
    vector<bool> newSubKey;
    for (int j = 0; j < 48; ++j)
      newSubKey.push_back(afterPC2[i]);

    result.push_back(newSubKey);
    lastC = nextC;
    lastD = nextD;
  }
  return result;
}


bool* throughSBox1(bool afterXOR[], int begin, int end) {
  bool row[2];
  row[0] = afterXOR[begin], row[1] = afterXOR[end];
  int r = bToD(row);  //二进制转十进制
  bool col[4];
  for (int i = 0; i < 4; i++)
    col[i] = afterXOR[begin+1+i];
  int c = bToD(col);  //二进制转十进制
  int SBox1[4][16] = { {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},
                      {0,15,7,4,15,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} }
  int temp = SBox1[r][c];
  return temp.toBinary();  //十进制转二进制
}


bool* sixteenLoop(bool L0[], bool R0[], vector<vector<bool> > & subKey, bool type) {
  bool lastL[32] = L0, lastR[32] = R0;
  for (int i = 0; i < 16; ++i) {
    bool afterEChange[48];
    int EChange[48] = {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};
    for (int j = 0; j < 48; ++j) {
      afterEChange[EChange[i]] = lastR[i];
    }
    if (type == 0) {
      bool afterXOR[48] = afterEChange XOR subKey[i]; // 伪代码
    } else {
      bool afterXOR[48] = afterEChange XOR subKey[15-i]; // 伪代码
    }
    bool afterAllSBox[32];
    afterAllSBox[0,3] = throughSBox1(afterXOR, 0, 5);
    afterAllSBox[4,7] = throughSBox2(afterXOR, 6, 11);
    afterAllSBox[8,11] = throughSBox3(afterXOR, 12, 17);
    afterAllSBox[12,15] = throughSBox4(afterXOR, 18, 23);
    afterAllSBox[16,19] = throughSBox5(afterXOR, 24, 29);
    afterAllSBox[20,23] = throughSBox6(afterXOR, 30, 35);
    afterAllSBox[24,27] = throughSBox7(afterXOR, 36, 41);
    afterAllSBox[28,31] = throughSBox8(afterXOR, 42, 47);
    bool afterPBoxChange[32];
    int PBox[32] = {
      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
    }
    for (int j = 0; j < 48; ++j) {
      afterPBoxChange[PBox[i]] = afterAllSBox[i];
    }
    bool nextL[32], nextR[32];
    nextL = lastR;
    nextR = afterPBoxChange XOR lastL; // 伪代码
    lastL = nextL;
    lastR = nextR;
  }
  bool result[64];
  for (int i = 0; i < 64; i++) {
    result[i] = lastR[i];
    result[i+32] = lastL[i];
  }
  return result;
}


bool* inverseIPChange(bool after16Loop[]) {
  bool result[64];
  int inverseIPBox[64] = {
    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 };
  for (int i = 0; i < 64; i++) {
    result[inverseIPBox[i]] = after16Loop[i];
  }
  return result;
}


//type: 0代表加密,1代表解密
bool* DES(bool *inputText, bool *key, bool type) {
    bool* afterFirstIPChange = IPChange(inputText);
    bool L0[32], R0[32];
    for (int i = 0; i < 32; ++i)
      L0[i] = afterFirstIPChange[i];
    for (int i = 0; i < 32; ++i)
      R0[i] = afterFirstIPChange[i+32];
    vector<vector<bool> > subKey = getSubKey(key);
    bool* after16Loop = sixteenLoop(L0, R0, subKey, type);
    bool* outputText = inverseIPChange(after16Loop);
    return outputText;
}

您可能感兴趣的与本文相关的镜像

ComfyUI

ComfyUI

AI应用
ComfyUI

ComfyUI是一款易于上手的工作流设计工具,具有以下特点:基于工作流节点设计,可视化工作流搭建,快速切换工作流,对显存占用小,速度快,支持多种插件,如ADetailer、Controlnet和AnimateDIFF等

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值