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

被折叠的 条评论
为什么被折叠?



