实验4 DES密码算法
一、基于OBE模式的实验目的和要求
1、了解分组密码的起源与涵义。 2、掌握DES密码的加解密原理。 3、编程设计DES密码算法。
二、实验仪器和设备 Visual C/C++ 三、实验过程
1、DES是美国联邦信息处理标准(FIPS)于1977年公开的分组密码算法,它的设计基于Feistel对称网络以及精心设计的S盒,在提出前已经进行了大量的密码分析,足以保证在当时计算条件下的安全性。不过,随着计算能力的飞速发展,现如今DES已经能用密钥穷举方式破解。虽然现在主流的分组密码是AES,但DES的设计原理仍有重要参考价值。在本实验中,为简便起见,就限定DES密码的明文、密文、密钥均为bit,具体描述如下:
明文m是bit序列。
初始密钥K是 bit序列(含8个奇偶校验bit)。 子密钥K1, K2…K16均是48 bit序列。
轮变换函数f (A,J):输入A(32 bit序列), J(48 bit序列),输出32 bit序列。 密文c是 bit序列。 1) 子密钥生成:
输入初始密钥,生成16轮子密钥K1, K2…K16。
初始密钥(bit)经过置换PC-1,去掉了8个奇偶校验位,留下56 bit,接着分成两个28 bit的分组C0与D0,再分别经过一个循环左移函数LS1,得到C1与D1,连成56 bit数据,然后经过置换PC-2,输出子密钥K1,以此类推产生K2至K16。
注意:置换PC-1、PC-2在下文中会具体给出; 函数LSi为向左循环移动 1个位置(i=1,2,9,16)
2个位置(i=3,4,5,6,7,8,10,11,12,13,14,15)。详见下图:
初始密钥(bit) 置换PC-1 C0(28bit) LS1 C1 LS2 D0(28bit) LS1 D1 LS2 置换PC-2 K1 … LS1C16 LS16 D16 置换PC-2 K16
2) 轮变换函数f:
f是DES加解密中每一轮的核心运算,输入A(32 bit), J(48 bit),输出32 bit。 将A做一个扩展运算E,变成48 bit,记为E(A)。计算B=E(A)⊕J,将B分为8组B1…B8,每组Bi为6 bit,通过相应的S盒Si,输出Ci为4 bit,将所有Ci连成C(32 bit),再通过置换P,得到最后的输出f(A,J),为32 bit。在加密或解密的第i轮,A = Ri-1,J = Ki。
注意:每个S盒Si是4×16的矩阵,输入b0b1b2b3b4b5 (6 bit),令L是b0b5对应的十进制数,n是b1b2b3b4对应的十进制数,输出矩阵中第L行n列所对应数的二进制表示。 详见下图:
A (32bit) E J (48bit) E(A) (48bit) B1 B2 B3 B4 B5 B6 B7 B8 6 bit 4 bit C1 C2 C3 C4 C5 C6 C7 C8 P f(A,J) (32bit) S1 S2 S3 S4 S5 S6 S7 S8
3) 加/解密:
DES的加密和解密几乎一样,不同之处在于加密时输入是明文,子密钥使 用顺序为K1K2…K16;解密时输入是密文,子密钥使用顺序为K16K15…K1。 以加密为例,输入明文分组 bit,先进行一次初始置换IP,对置换后的数据X0分成左右两半L0与R0,根据第一个子密钥K1对R0实行轮变换f(R0, K1),将结果与L0作逐位异或运算,得到的结果成为下一轮的R1,R0则成为下一轮的L1。如此循环16次,最后得到L16与R16。可用下列公式简洁地表示:
RiLi1f(Ri1,Ki)LiRi1,i1,2,,16
最后对 bit数据R16, L16实行IP的逆置换IP-1,即得密文分组。
注意:第16轮变换后并未交换L16与R16,而直接将R16, L16作为IP-1的输入。 详见下图:
输入 初始置换IP L0 f R0 K1 L1=R0 f R1=L0⊕f(R0,K1) Ki L15=R14 f R16=L15⊕f(R15,K16) R15=L14⊕f(R14,K15) K16 L16=R15 逆初始置换IP-1 输出
3、编写程序,实现DES密码。 主要步骤:
1) 使用模块化编程,将算法实现的功能写成子函数后供上一层函数调用。 2) 所使用参数的初始定义       #include static bool SubKey[16][48];     //定义子密钥,使得所有函数都能调用  static const unsigned char IP_Table[] = {              //定义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,,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}; static const unsigned char IPInv_Table[] = {         //定义IP逆置换表  40,8,48,16,56,24,,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 unsigned char E_Table[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}; static const unsigned char P_Table[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 const unsigned char PC1_Table[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}; static const unsigned char PC2_Table[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}; static const unsigned char LS_Table[16] = {         1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1}; static unsigned char S_Box[8][4][16] = {             //定义E扩展表  //定义P置换表 //定义PC1置换表 //定义PC2置换表 //定义左移位数表 //S盒 //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}; 3) 编写各个模块函数,例如: void ByteToBit(bool* Out, const unsigned char* In, int bits); //将字符数组In转化为bool数组Out,bits控制转换bit数 void BitToByte(unsigned char* Out, const bool* In, int bits); //将bool数组In转化为字符数组Out void Transform(bool* Out, bool* In, const unsigned char* Table, int len); //利用置换表Table将bool数组In转换成长度为len的bool数组Out void RotateL(bool* In, int len, int loop); //对长度为len的bool数组In循环左移loop位 void Des_SetSubKey(unsigned char Key[8]); //利用初始密钥Key生成16轮子密钥SubKey,  注意前文已定义static bool SubKey[16][48];  void Xor(bool* InA, bool* InB, int len); //将bool数组InB与InA逐位做异或,结果存入InA void S_Func(bool Out[32], bool In[48]); //利用S盒S_Box将bool数组In转换为bool数组Out void f_Func(bool In[32], bool Ki[48]); //利用子密钥Ki对bool数组In做轮变换函数,结果仍存入In void Des_Run(unsigned char Out[8], unsigned char In[8], bool flag); //Des加解密:输入字符数组In,输出字符数组Out, flag=1时代表加密,flag=0时代表解密。 4) 编写主函数,主要步骤有        输入明文字符序列(8个字符);        输入密钥字符序列(8个字符);        生成16轮子密钥;        加密并输出密文;        解密并输出解密后的明文。 提示点: 1) 编写函数时多输出中间变量查看结果。 2) 函数memcpy(void *dest, const void *src, size_t n) 用于将源地址src处n        个单位数据拷贝至目的地址dest处, 适用于bool数组的拷贝。 3) 部分函数参考代码 void Transform(bool* Out, bool* In, const unsigned char* Table, int len) // 置换,输入为置换前的位,输出为置换后的位,具体的置换由参数Table控制,置换后的长度由参数len输入 { } void ByteToBit(bool* Out, const char* In, int bits)   //字符转换为比特,输入为字符In, 输出的二进制位存放在Out {    } for (int i = 0; i < bits; i++) Out[i] = (In[i / 8] >> (i % 8)) & 1; bool Temp[256]; //临时数组长度定义成足够大的即可 for(int i=0;i memcpy(Out, Temp, len); //In[i]的第N位右移N位并和0x01按位与运算 void BitToByte(char* Out, const bool* In, int bits)    //比特转换为字符,输入二进制为In, 输出的字符存放在Out {     } void Xor(bool *InA,bool *InB, int len)     //异或 { for(int i = 0; i void RotateL(bool *In, int len, int loop)    //循环左移 { static int Tmp[256];     memcpy(Tmp, In, loop);     memcpy(In, In+loop, len-loop);     memcpy(In+len-loop, Tmp, loop); } void S_func(bool Out[32],bool In[48])   // S 盒,输入6位,输出4位,将第一六位对应的十进制数作为行,第二三四五为的对应十进制数作为列 { for(char i=0,j,k; i<8; i++,In+=6,Out+=4) int i; memset(Out, 0, (bits + 7) / 8); for (i = 0; i < bits; i++) Out[i / 8] |= In[i] << (i % 8); { j = (In[0]<<1) + In[5]; k = (In[1]<<3) + (In[2]<<2) + (In[3]<<1) + In[4];         ByteToBit(Out, &S_Box[i][j][k], 4);     } } void F_func(bool In[32],bool Ki[48])    // f 轮函数 { static bool MR[48]; Transform(MR, In, E_Table, 48);    // 置换     Xor(MR, Ki, 48);      // 异或     S_func(In, MR);       //  S 盒 Transform(In, In, P_Table, 32);     // 置换 } 测试示例:利用DES加密算法,实现“Hi, this is chapter 2!”字符串的加密,并同时解密,例如,加密密钥取为:12345678(字符形式,也可自选)。 4、程序代码: #include const static char 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,  , 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 EP1[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 LOOP[16] =// 左移 { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; const static char EP2[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 }; static const char EC[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 SBox[8][4][16] =//8 个 S 盒 {  {  // 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 }  } }; const static char PP[32] =//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, }; const static char LP[] =// 末置换 { 40, 8, 48, 16, 56, 24, , 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 bool M[], tmp[32], *Li = &M[0], *Ri = &M[32]; static bool SubKey[16][48];//16 个子密钥 class CDES// 定义 DES 类 {  public: //void Mode();// 模式 void Encryption(char out[8],char In[8]);// 加密函数  void Decryption(char out[8],char In[8]);// 解密函数 }; void ByteToBit(bool *Out, const char *In, int bits)// 字符转换成字节 {  int i; for(i=0;i void BitToByte(char *Out,const bool *In,int bits)// 字节转换成字符 {  int i; memset(Out,0,(bits+7)/8);  for(i=0;i void RotateL(bool*In,int len,int loop)// 循环左移 { static bool tmp[256];   memcpy(tmp,In,loop); memcpy(In,In+loop,len-loop);   memcpy(In+len-loop,tmp,loop);  } void Xor(bool*InA,const bool*InB,int len)// 异或 {  int i; for(i=0;i void Transform(bool*Out,bool*In,const char*Table,int len)// 各个置换转换 {  int i; static bool tmp[256];  for(i=0;i memcpy(Out,tmp,len); } void S_func(bool Out[32],const bool In[48])// 将 48 位转换成 32 位 { int j,m,n; // 膨胀后的比特串分为 8 组,每组 6 比特。    for(j=0;j<8;j++,In+=6,Out+=4)  { m = (In[0]*2)+In[5]; n = (In[1]*8)+(In[2]*4)+(In[3]*2)+In[4];  ByteToBit(Out,&SBox[j][m][n],4);  } } void F_func(bool In[32],const bool Ki[48]) { static bool MR[48];  Transform(MR,In,EC,48);   Xor(MR, Ki, 48); // 膨胀后的比特串分为 8 组,每组 6 比特。各组经过各自的 S 盒后,又变为 4 比特,合并后又成为 32 比特。  S_func(In, MR); // 该 32 比特经过 P 变换后,输出的比特串才是 32 比特的 f(Ri-1,Ki) 。  Transform(In, In, PP, 32); } void SetKey(char key[8])// 生成子密钥 {  int i; static bool K[], *KL = &K[0], *KR = &K[28];  ByteToBit(K,key,); // 转换为二进制 Transform(K,K,EP1,56); // 比特的密钥 K ,经过 EP1 后,生成 56 比特的串。  // 生成 16 个子密钥  for(i=0;i<16;i++)  { // 循环左移,合并    RotateL(KL,28,LOOP[i]);  RotateL(KR,28,LOOP[i]);  Transform(SubKey[i],K,EP2,48);  } } void CDES::Encryption(char out[8],char In[8])// 加密函数 { ByteToBit(M,In,); // 转换为二进制  Transform(M,M,IP,);   for(int i=0;i<16;i++)  { memcpy(tmp,Ri,32);  F_func(Ri,SubKey[i]); Xor(Ri,Li,32);// 将所得结果与明文的左 32 位进行异或  memcpy(Li,tmp,32);// 将明文的左右 32 位交换  } Transform(M, M, LP, ); BitToByte(out, M, );  // return(out); } void CDES::Decryption(char out[8],char In[8])// 解密函数 ( 加密的逆过程 ) { ByteToBit(M,In,); // 转换为二进制  Transform(M,M,IP,);     for(int i=15;i>=0;i--)  { memcpy(tmp,Li,32);  F_func(Li,SubKey[i]);  Xor(Li,Ri,32);  memcpy(Ri,tmp,32);  } Transform(M, M, LP, );  BitToByte(out, M, );  // return(out); } int main() { char key[10];  char str[10];  char str1[10]; cout<<\" 请输入要加密的字符 ( 只限字符类 ):\";  cin>>str; cout<<\" 请设置密码 ( 不多于 8 位 ):\";  cin>>key;  SetKey(key); memset(str1,0,sizeof(str1));  CDES des; des.Encryption(str1,str);  cout<<\" 加密后为: \"< while(1)    { cout<<\" 请输入密码: \";      char sec[10]; cin>>sec; if(strcmp(sec,key)==0)      { memset(str,0,sizeof(str));  des.Decryption(str,str1);  cout<<\" 解密后为: \"< 五、基于OBE模式的学生自我评价与体会 这次的实验跟我们以前做的实验不同,因为我觉得这次我是真真正正的自己亲自去完成。所以是我觉得这次实验最宝贵,最深刻的。就是实验的过程全是我们学生自己动手来完成的,这样,我们就必须要弄懂实验的原理。在这里我深深体会到哲学上理论对实践的指导作用:弄懂实验原理,而且体会到了实验的操作能力是靠自己亲自动手,亲自开动脑筋,亲自去请教别人才能得到提高的。              
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- 91gzw.com 版权所有 湘ICP备2023023988号-2
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务
