1977年1月,美国政府颁布:采纳IBM公司设计的方案作为非机密数据的正式数据加密标准(Data Encryption Standard)。上周帮leojay看3DES算法,讲讲这个算法是如何进行的:)

先来讲讲DES加密:
首先,这个算法全程是按位运算的,每次计算64位的内容,也就是8个字节。密钥Key,为64位。
我们把内容经过一个初始置换,就是每位按如下表格进行位置交换:

Initial Permutation 
 
 58,50,12,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,



然后把换好的东西经过16轮叫做DES的算法



每一轮这个算法是这样的:



我们先来生成子密钥:


把密钥Key的每个字节的最后一位扔掉,经过第1次缩小换位:


Permuted Choice One 
 
 左: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


这样就从64位减少到56位了,把这56位分为左28位和右28位,分别称为Ci和Di。




将Ci和Di分别进行左移,左移的位数由第几论来决定:


Schedule of Left Shifts: 
 
 Round number: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 
 
 Bits rotated:      1 1 2 2 2 2 2 2 1  2   2   2   2   2   2  1



把左移好的Ci和Di,通过第2次缩小换位:


Permuted Choice Two 
 
 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



这样生成了一组48位的子密钥Ki。


而刚刚左移好的Ci和Di将等待着下一轮的计算。



下面处理加密的内容:


把加密的内容分为左32位和右32位,分别称为Li和Ri,


Li先放着不管,先来看Ri,把这个Ri经过一个F函数的变化:


先通过放大换位表:


Expansion Permutation 
 
   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,


将这32位变成48位,然后和刚刚生成的子密钥Ki进行一次异或运算,再经过S-box这样一个选择运算将这48位变为32位。



S-box的过程如下:


将输入的48位分为8组,每组对应一个S-box表,每个表里有4行16列。


这样每组有6位,取2、3、4、5位为列数,1、6位为行数,在所对应的表中寻找这个数字,将找到的数字转换为4位二进制数输出。这样一共8组,就将48位转换为32位了。


Definition of DES S-boxes: 
 
 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, 
 
 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, 
 
 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, 
 
 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, 
 
 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, 
 
 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, 
 
 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, 
 
 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,




然后通过置换函数P的变化:


Permutation Function 
 
   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,



将这32位的转换后的Ri与Li进行一次异或运算后放入Ri,


而将没有经过转换的那个Ri放入Li,这样就进行完一轮DES算法。


整个DES算法过程如下图所示:




连续进行16轮后,再进行一次逆置换:


Inverse initial permutation: 
 
   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,



这样就完成了一次DES加密过程,解密过程刚好与其相反:)



下面说说3DES:


共有两个密钥key1和key2:


加密过程:用key1加密,用key2解密再用key1加密


解密过程:用key1解密,用key2加密再用key1解密



下面是算法的实现程序:


//3DES加密解密算法 - SJW 
 
 #include <iostream> 
 
 #include <cstdlib> 
 
 #include <cstring> 
 
 #include <memory.h> 
 
 using namespace std; 
 

 typedef bool 
 
 (*PSubKey)[16][48]; 
 

 // 初始置换 
 
 const static char Table_IP[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 
 
 }; 
 

 // 末置换 
 
 const static char Table_InverseIP[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 
 
 }; 
 

 // 扩展置换 
 
 static const char Table_E[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 
 
 }; 
 

 // 密钥初始置换 
 
 const static char Table_PC1[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 
 
 }; 
 

 // 左移运算 
 
 const static char Table_Moveleft[16] = 
 
 { 
 
 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 
 
 }; 
 

 // 密钥压缩置换 
 
 const static char Table_PC2[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 
 
 }; 
 

 // S盒 
 
 const static char Box_S[8][4][16] = 
 
 { 
 
 // 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, 
 
 // 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, 
 
 // 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, 
 
 // 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, 
 
 // 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, 
 
 // 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, 
 
 // 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, 
 
 // 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 
 
 }; 
 

 // P盒置换 
 
 const static char Table_P[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 
 
 }; 
 

 static bool SubKey[2][16][48];//两个密钥的16轮子密钥 
 
 static char Tmp[256], deskey[16]; 
 

 #define ENCRYPT 0 
 
 #define DECRYPT 1 
 

 //通用置换函数 
 
 void Transform(bool *Out, bool *In, const char *Table, int len) 
 
 { 
 
 for(int i = 0; i < len; ++ i) 
 
 Tmp[i] = In[ Table[i] - 1 ]; 
 
 memcpy(Out, Tmp, len); 
 
 } 
 

 //异或运算 
 
 void Xor(bool *InA, const bool *InB, int len) 
 
 { 
 
 for(int i = 0; i < len; ++ i) 
 
 InA[i] ^= InB[i]; 
 
 } 
 

 //循环左移 
 
 void MoveLeft(bool *In, int len, int loop) 
 
 { 
 
 memcpy(Tmp, In, loop); 
 
 memcpy(In, In + loop, len - loop); 
 
 memcpy(In + len - loop, Tmp, loop); 
 
 } 
 

 //字节转换成位 
 
 void Byte2Bit(bool *Out, const char *In, int bits) 
 
 { 
 
 for(int i = 0; i < bits; ++ i) 
 
 Out[i] = (In[i >> 3] >> (i & 7)) & 1; 
 
 } 
 

 //位转换字节 
 
 void Bit2Byte(char *Out, const bool *In, int bits) 
 
 { 
 
 memset(Out, 0, bits >> 3); 
 
 for(int i = 0; i < bits; ++ i) 
 
 Out[i >> 3] |= In[i] << (i & 7); 
 
 } 
 

 //S 盒置换 
 
 void funS(bool Out[32], const bool In[48]) 
 
 { 
 
 for(char i = 0, j, k; i < 8; ++ i, In += 6, Out += 4) 
 
 { 
 
 j = (In[0] << 1) + In[5]; 
 
 k = (In[1] << 3) + (In[2] << 2) + (In[3] << 1) + In[4]; 
 
 Byte2Bit(Out, &Box_S[i][j][k], 4); 
 
 } 
 
 } 
 

 //F 函数 
 
 void funF(bool In[32], const bool Ki[48]) 
 
 { 
 
 static bool MR[48]; 
 
 Transform(MR, In, Table_E, 48); 
 
 Xor(MR, Ki, 48); 
 
 funS(In, MR); 
 
 Transform(In, In, Table_P, 32); 
 
 } 
 

 //生成子密钥 
 
 void MakeSubKey(PSubKey pSubKey, const char Key[8]) 
 
 { 
 
 static bool K[64], *KL = &K[0], *KR = &K[28]; 
 
 Byte2Bit(K, Key, 64); 
 
 Transform(K, K, Table_PC1, 56); 
 
 for(int i = 0; i < 16; ++ i) 
 
 { 
 
 MoveLeft(KL, 28, Table_Moveleft[i]); 
 
 MoveLeft(KR, 28, Table_Moveleft[i]); 
 
 Transform((*pSubKey)[i], K, Table_PC2, 48); 
 
 } 
 
 } 
 

 //生成密钥 
 
 void MakeKey(const char* Key, int len) 
 
 { 
 
 memset(deskey, 0, 16); 
 
 memcpy(deskey, Key, len > 16 ? 16 : len); 
 
 MakeSubKey(&SubKey[1], &deskey[8]); 
 
 } 
 

 //一重DES加/解密 
 
 void DES(char Out[8], char In[8], const PSubKey pSubKey, bool Type) 
 
 { 
 
 static bool M[64], tmp[32], *Li = &M[0], *Ri = &M[32]; 
 
 Byte2Bit(M, In, 64); 
 
 Transform(M, M, Table_IP, 64); 
 
 if( Type == ENCRYPT ){ //加密 
 

 for(int i = 0; i < 16; ++ i) 
 
 { 
 
 memcpy(tmp, Ri, 32); 
 
 funF(Ri, (*pSubKey)[i]); 
 
 Xor(Ri, Li, 32); 
 
 memcpy(Li, tmp, 32); 
 
 } 
 
 } 
 
 else //解密 
 
 { 
 
 for(int i = 15; i >= 0; -- i) 
 
 { 
 
 memcpy(tmp, Li, 32); 
 
 funF(Li, (*pSubKey)[i]); 
 
 Xor(Li, Ri, 32); 
 
 memcpy(Ri, tmp, 32); 
 
 } 
 
 } 
 
 Transform(M, M, Table_InverseIP, 64); 
 
 Bit2Byte(Out, M, 64); 
 
 } 
 

 bool DoDES(char *Out, char *In, long datalen, const char *Key, int keylen, bool Type) 
 
 { 
 
 if( !( Out && In && Key && (datalen=(datalen+7)&0xfffffff8) ) ) 
 
 return false; 
 

 MakeKey(Key, keylen); 
 
 // 3次DES 加密:加(key0)-解(key1)-加(key0) 解密:解(key0)-加(key1)-解(key0) 
 
 for(long i = 0, j = datalen >> 3; i < j; ++ i, Out += 8, In += 8) 
 
 { 
 
 DES(Out, In,  &SubKey[0], Type); 
 
 DES(Out, Out, &SubKey[1], !Type); 
 
 DES(Out, Out, &SubKey[0], Type); 
 
 } 
 
 return true; 
 
 } 
 

 int main(int argc,char *argv[]) 
 
 { 
 
 int i; 
 
 char key[255]; 
 
 char buf[255]; 
 
 char str[255]; 
 
 char key1[15]; 
 
 char key2[8]; 
 

 cout<<"Please input The string before encrypting: /n"; 
 
 cin.getline(str, 255, '/n'); 
 
 do 
 
 { 
 
 cout<<"Please input Key1(8 chars): /n"; 
 
 cin>>key1; 
 
 } while (strlen(key1) != 8); //key1为8个字符 
 

 cout<<"Please input Key2: /n"; 
 
 cin>>key2; 
 

 memset(key, 0, sizeof(key)); 
 
 for (i = 0; i < 8; i ++) 
 
 { 
 
 key[i] = key1[i]; 
 
 key[i + 8] = key2[i]; 
 
 } 
 

 memset(buf, 0, sizeof(buf)); 
 
 strcpy(buf, str); 
 
 cout<<"/nBefore encrypting/n"; 
 
 cout<<buf<<endl; 
 

 DoDES(buf, buf, sizeof(str), key, sizeof(key), ENCRYPT); 
 
 cout<<"/nAfter encrypting/n"; 
 
 cout<<buf<<endl; 
 

 DoDES(buf, buf, sizeof(str), key, sizeof(key), DECRYPT); 
 
 cout<<"/nAfter decrypting/n"; 
 
 cout<<buf<<endl; 
 

 return 0; 
 
 }