DES算法
2019-04-14 20:40:19
一、概要设计
这个程序主要是 DES算法部分的 加密和解密,还有后面对文件的操作。
程序主要流程图如下:

图-1 程序流程图
这个程序的关键在DES算法的操作,主要有下的主要步骤:
1.初始置换 IP;
2.子密钥 Ki 的获取;
3.密码函数 f ;
4.尾置换 IP-1 ;
下面是具体的几个过程:
1) 初始置换IP
这一部分很简单,IP(initial permutation)是一个 8x8 的置换表:
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 };
根据表中的规定,将输入的 64 位明文重新进行排序,即将第 58 位放到第 1 位,第 50 位放到第 2 位……以此类推。初始置换以后得到的是一个 64 位的输出。
2) 子密钥 Ki 的获取
用户输出的密钥是 64 位的,根据密钥置换表PC-1,将 64 位变成 56 位密钥。(去掉了奇偶校验位)将 PC-1 置换得到的 56 位密钥,分为前28位 C0 和后28位 D0,分别对它们进行循环左移,C0左移得到 C1,D0 左移得到 D1。将 C1 和 D1 合并成 56 位,然后通过PC-2表进行压缩置换,得到当前这一轮的 48 位子密钥 K1 。然后对 C1 和 D1 进行左移和压缩置换,获取下一轮的子密钥……一共进行16轮,得到 16 个 48 位的子密钥。
3) 密码函数 f
l 密码函数f(R, K)接受两个输入:32 位的数据和 48 位的子密钥。然后:
l 通过表 E 进行扩展置换,将输入的 32 位数据扩展为 48 位;
l 将扩展后的 48 位数据与 48 位的子密钥进行异或运算;
l 将异或得到的 48 位数据分成 8 个 6 位的块,每一个块通过对应的一个 S 表产生一个 4 位的输出。
其中,每个 S 表都是 4 行 16 列。具体的置换过程如下:把 6 位输入中的第 1 位和第 6 位取出来行成一个两位的二进制数 x ,作为 Si 表中的行数(0~3);把 6 位输入的中间 4 位构成另外一个二进制数 y,作为 Si 表的列数(0~15);查出 Si 表中 x 行 y 列所对应的整数,将该整数转换为一个 4 位的二进制数。
把通过 S 表置换得到的 8 个 4 位连在一起,形成一个 32 位的数据。然后将该 32 位数据通过表 P 进行置换(称为P-置换),置换后得到一个仍然是 32 位的结果数据,这就是f(R, K)函数的输出。
4) 尾置换IP-1
合并 L16 和 R16 得到一个 64 位的数据,再经过尾置换后得到的就是 64 位的密文。注意:要将 L16和 R16 合并成 R16L16(即左右互换)。尾置换表IP-1如下:
int IP_1[] = {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算法代码:
1 #include<iostream> 2 #include<bitset> 3 #include <fstream> 4 #include<cstring> 5 using namespace std; 6 /* 7 在打开文件时,如果要指定文件名,可以用C风格的字符串。 8 如果用到string类型的字符串作为文件名时,就必须调用c_str()方法将其转换为一个C风格字符串 9 */ 10 bitset<64> key; // 64位密钥 11 bitset<48> subKey[16]; // 存放16轮子密钥 12 13 // 初始置换表 14 int IP[] = { 58, 50, 42, 34, 26, 18, 10, 2, 15 60, 52, 44, 36, 28, 20, 12, 4, 16 62, 54, 46, 38, 30, 22, 14, 6, 17 64, 56, 48, 40, 32, 24, 16, 8, 18 57, 49, 41, 33, 25, 17, 9, 1, 19 59, 51, 43, 35, 27, 19, 11, 3, 20 61, 53, 45, 37, 29, 21, 13, 5, 21 63, 55, 47, 39, 31, 23, 15, 7 }; 22 23 // 结尾置换表 24 int IP_1[] = { 40, 8, 48, 16, 56, 24, 64, 32, 25 39, 7, 47, 15, 55, 23, 63, 31, 26 38, 6, 46, 14, 54, 22, 62, 30, 27 37, 5, 45, 13, 53, 21, 61, 29, 28 36, 4, 44, 12, 52, 20, 60, 28, 29 35, 3, 43, 11, 51, 19, 59, 27, 30 34, 2, 42, 10, 50, 18, 58, 26, 31 33, 1, 41, 9, 49, 17, 57, 25 }; 32 33 /*------------------下面是生成密钥所用表-----------------*/ 34 35 // 密钥置换表,将64位密钥变成56位 36 int PC_1[] = { 57, 49, 41, 33, 25, 17, 9, 37 1, 58, 50, 42, 34, 26, 18, 38 10, 2, 59, 51, 43, 35, 27, 39 19, 11, 3, 60, 52, 44, 36, 40 63, 55, 47, 39, 31, 23, 15, 41 7, 62, 54, 46, 38, 30, 22, 42 14, 6, 61, 53, 45, 37, 29, 43 21, 13, 5, 28, 20, 12, 4 }; 44 45 // 压缩置换,将56位密钥压缩成48位子密钥 46 int PC_2[] = { 14, 17, 11, 24, 1, 5, 47 3, 28, 15, 6, 21, 10, 48 23, 19, 12, 4, 26, 8, 49 16, 7, 27, 20, 13, 2, 50 41, 52, 31, 37, 47, 55, 51 30, 40, 51, 45, 33, 48, 52 44, 49, 39, 56, 34, 53, 53 46, 42, 50, 36, 29, 32 }; 54 55 // 每轮左移的位数 56 int shiftBits[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 }; 57 58 /*------------------下面是密码函数 f 所用表-----------------*/ 59 60 // 扩展置换表,将 32位 扩展至 48位 61 int E[] = { 32, 1, 2, 3, 4, 5, 62 4, 5, 6, 7, 8, 9, 63 8, 9, 10, 11, 12, 13, 64 12, 13, 14, 15, 16, 17, 65 16, 17, 18, 19, 20, 21, 66 20, 21, 22, 23, 24, 25, 67 24, 25, 26, 27, 28, 29, 68 28, 29, 30, 31, 32, 1 }; 69 70 // S盒,每个S盒是4x16的置换表,6位 -> 4位 71 int S_BOX[8][4][16] = { 72 { 73 { 14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7 }, 74 { 0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8 }, 75 { 4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0 }, 76 { 15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13 } 77 }, 78 { 79 { 15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10 }, 80 { 3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5 }, 81 { 0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15 }, 82 { 13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9 } 83 }, 84 { 85 { 10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8 }, 86 { 13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1 }, 87 { 13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7 }, 88 { 1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12 } 89 }, 90 { 91 { 7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15 }, 92 { 13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9 }, 93 { 10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4 }, 94 { 3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14 } 95 }, 96 { 97 { 2,12,4,1,7,10,11,6,8,5,3,15,13,0,14,9 }, 98 { 14,11,2,12,4,7,13,1,5,0,15,10,3,9,8,6 }, 99 { 4,2,1,11,10,13,7,8,15,9,12,5,6,3,0,14 }, 100 { 11,8,12,7,1,14,2,13,6,15,0,9,10,4,5,3 } 101 }, 102 { 103 { 12,1,10,15,9,2,6,8,0,13,3,4,14,7,5,11 }, 104 { 10,15,4,2,7,12,9,5,6,1,13,14,0,11,3,8 }, 105 { 9,14,15,5,2,8,12,3,7,0,4,10,1,13,11,6 }, 106 { 4,3,2,12,9,5,15,10,11,14,1,7,6,0,8,13 } 107 }, 108 { 109 { 4,11,2,14,15,0,8,13,3,12,9,7,5,10,6,1 }, 110 { 13,0,11,7,4,9,1,10,14,3,5,12,2,15,8,6 }, 111 { 1,4,11,13,12,3,7,14,10,15,6,8,0,5,9,2 }, 112 { 6,11,13,8,1,4,10,7,9,5,0,15,14,2,3,12 } 113 }, 114 { 115 { 13,2,8,4,6,15,11,1,10,9,3,14,5,0,12,7 }, 116 { 1,15,13,8,10,3,7,4,12,5,6,11,0,14,9,2 }, 117 { 7,11,4,1,9,12,14,2,0,6,10,13,15,3,5,8 }, 118 { 2,1,14,7,4,10,8,13,15,12,9,0,3,5,6,11 } 119 } 120 }; 121 122 // P置换,32位 -> 32位 123 int P[] = { 16, 7, 20, 21, 124 29, 12, 28, 17, 125 1, 15, 23, 26, 126 5, 18, 31, 10, 127 2, 8, 24, 14, 128 32, 27, 3, 9, 129 19, 13, 30, 6, 130 22, 11, 4, 25 }; 131 132 /**********************************************************************/ 133 /* */ 134 /* 下面是DES算法实现 */ 135 /* */ 136 /**********************************************************************/ 137 138 /** 139 * 密码函数f,接收32位数据和48位子密钥,产生一个32位的输出 140 */ 141 bitset<32> f(bitset<32> R, bitset<48> k) 142 { 143 bitset<48> expandR; 144 // 第一步:扩展置换,32 -> 48 145 for (int i = 0; i<48; ++i) 146 expandR[47 - i] = R[32 - E[i]]; 147 // 第二步:异或 148 expandR = expandR ^ k; 149 // 第三步:查找S_BOX置换表 150 bitset<32> output; 151 int x = 0; 152 for (int i = 0; i<48; i = i + 6) 153 { 154 int row = expandR[47 - i] * 2 + expandR[47 - i - 5]; 155 int col = expandR[47 - i - 1] * 8 + expandR[47 - i - 2] * 4 + expandR[47 - i - 3] * 2 + expandR[47 - i - 4]; 156 int num = S_BOX[i / 6][row][col]; 157 bitset<4> binary(num); 158 output[31 - x] = binary[3]; 159 output[31 - x - 1] = binary[2]; 160 output[31 - x - 2] = binary[1]; 161 output[31 - x - 3] = binary[0]; 162 x += 4; 163 } 164 // 第四步:P-置换,32 -> 32 165 bitset<32> tmp = output; 166 for (int i = 0; i<32; ++i) 167 output[31 - i] = tmp[32 - P[i]]; 168 return output; 169 } 170 171 /** 172 * 对56位密钥的前后部分进行左移 173 */ 174 bitset<28> leftShift(bitset<28> k, int shift) 175 { 176 bitset<28> tmp = k; 177 for (int i = 27; i >= 0; --i) 178 { 179 if (i - shift<0) 180 k[i] = tmp[i - shift + 28]; 181 else 182 k[i] = tmp[i - shift]; 183 } 184 return k; 185 } 186 187 /** 188 * 生成16个48位的子密钥 189 */ 190 void generateKeys() 191 { 192 bitset<56> realKey; 193 bitset<28> left; 194 bitset<28> right; 195 bitset<48> compressKey; 196 // 去掉奇偶标记位,将64位密钥变成56位 197 for (int i = 0; i<56; ++i) 198 realKey[55 - i] = key[64 - PC_1[i]]; 199 // 生成子密钥,保存在 subKeys[16] 中 200 for (int round = 0; round<16; ++round) 201 { 202 // 前28位与后28位 203 for (int i = 28; i<56; ++i) 204 left[i - 28] = realKey[i]; 205 for (int i = 0; i<28; ++i) 206 right[i] = realKey[i]; 207 // 左移 208 left = leftShift(left, shiftBits[round]); 209 right = leftShift(right, shiftBits[round]); 210 // 压缩置换,由56位得到48位子密钥 211 for (int i = 28; i<56; ++i) 212 realKey[i] = left[i - 28]; 213 for (int i = 0; i<28; ++i) 214 realKey[i] = right[i]; 215 for (int i = 0; i<48; ++i) 216 compressKey[47 - i] = realKey[56 - PC_2[i]]; 217 subKey[round] = compressKey; 218 } 219 } 220 221 /** 222 * 工具函数:将char字符数组转为二进制 223 */ 224 bitset<64> charToBitset(const char s[8]) 225 { 226 bitset<64> bits; 227 for (int i = 0; i<8; ++i) 228 for (int j = 0; j<8; ++j) 229 bits[i * 8 + j] = ((s[i] >> j) & 1); 230 return bits; 231 } 232 233 /** 234 * DES加密 235 */ 236 bitset<64> encrypt(bitset<64>& plain) 237 { 238 bitset<64> cipher; 239 bitset<64> currentBits; 240 bitset<32> left; 241 bitset<32> right; 242 bitset<32> newLeft; 243 // 第一步:初始置换IP 244 for (int i = 0; i<64; ++i) 245 currentBits[63 - i] = plain[64 - IP[i]]; 246 // 第二步:获取 Li 和 Ri 247 for (int i = 32; i<64; ++i) 248 left[i - 32] = currentBits[i]; 249 for (int i = 0; i<32; ++i) 250 right[i] = currentBits[i]; 251 // 第三步:共16轮迭代 252 for (int round = 0; round<16; ++round) 253 { 254 newLeft = right; 255 right = left ^ f(right, subKey[round]); 256 left = newLeft; 257 } 258 // 第四步:合并L16和R16,注意合并为 R16L16 259 for (int i = 0; i<32; ++i) 260 cipher[i] = left[i]; 261 for (int i = 32; i<64; ++i) 262 cipher[i] = right[i - 32]; 263 // 第五步:结尾置换IP-1 264 currentBits = cipher; 265 for (int i = 0; i<64; ++i) 266 cipher[63 - i] = currentBits[64 - IP_1[i]]; 267 // 返回密文 268 return cipher; 269 } 270 271 /** 272 * DES解密 273 */ 274 bitset<64> decrypt(bitset<64>& cipher) 275 { 276 bitset<64> plain; 277 bitset<64> currentBits; 278 bitset<32> left; 279 bitset<32> right; 280 bitset<32> newLeft; 281 // 第一步:初始置换IP 282 for (int i = 0; i<64; ++i) 283 currentBits[63 - i] = cipher[64 - IP[i]]; 284 // 第二步:获取 Li 和 Ri 285 for (int i = 32; i<64; ++i) 286 left[i - 32] = currentBits[i]; 287 for (int i = 0; i<32; ++i) 288 right[i] = currentBits[i]; 289 // 第三步:共16轮迭代(子密钥逆序应用) 290 for (int round = 0; round<16; ++round) 291 { 292 newLeft = right; 293 right = left ^ f(right, subKey[15 - round]); 294 left = newLeft; 295 } 296 // 第四步:合并L16和R16,注意合并为 R16L16 297 for (int i = 0; i<32; ++i) 298 plain[i] = left[i]; 299 for (int i = 32; i<64; ++i) 300 plain[i] = right[i - 32]; 301 // 第五步:结尾置换IP-1 302 currentBits = plain; 303 for (int i = 0; i<64; ++i) 304 plain[63 - i] = currentBits[64 - IP_1[i]]; 305 // 返回明文 306 return plain; 307 } 308 309 void encryptfile() 310 { 311 string a, b, k; 312 // char filename[20]; 313 cout << "请输入待加密文件名(完整路径):" << endl; 314 cin >> a; 315 cout << "请输入密钥:" << endl; 316 cin >> k; 317 cout << "请输入密文文件名(完整路径):" << endl; 318 cin >> b; 319 key = charToBitset(k.c_str()); 320 generateKeys(); // 生成16个子密钥 321 ifstream in; 322 ofstream out; 323 // strcpy(filename,a); 324 in.open(a.c_str(), std::ios::binary); 325 326 out.open(b.c_str(), ios::binary); 327 bitset<64> plain; 328 while (in.read((char*)&plain, sizeof(plain))) 329 { 330 bitset<64> cipher = encrypt(plain); 331 out.write((char*)&cipher, sizeof(cipher)); 332 plain.reset(); // 置0 333 } 334 in.close(); 335 out.close(); 336 cout << "加密成功,密文文件在" << b << endl; 337 } 338 339 void decodefile() 340 { 341 string a, b, k; 342 cout << "请输入密文文件名(完整路径):" << endl; 343 cin >> a; 344 cout << "请输入密钥:" << endl; 345 cin >> k; 346 cout << "请输入解密后文件名(完整路径):" << endl; 347 cin >> b; 348 key = charToBitset(k.c_str()); 349 generateKeys(); // 生成16个子密钥 350 ifstream in; 351 ofstream out; 352 in.open(a.c_str(), ios::binary); 353 out.open(b.c_str(), ios::binary); 354 bitset<64> plain; 355 while (in.read((char*)&plain, sizeof(plain))) 356 { 357 bitset<64> temp = decrypt(plain); 358 out.write((char*)&temp, sizeof(temp)); 359 plain.reset(); // 置0 360 } 361 in.close(); 362 out.close(); 363 cout << "解密成功,明文文件在" << b << endl; 364 } 365 int main(){ 366 int cycle=0; 367 while(cycle!=(-1)){ 368 cout<<"****************DES加密解密文件工具****************"<<endl; 369 cout<<"****************1、加密文件****************"<<endl; 370 cout<<"****************2、解密文件****************"<<endl; 371 cout<<"****************0、退出********************"<<endl; 372 cout<<"请选择功能(1-2):"<<endl; 373 374 375 int n; 376 cin>>n; 377 switch(n){ 378 case 1: 379 encryptfile(); 380 printf("\n\nPress Enter Contiue!\n"); 381 getchar(); 382 while(getchar()!='\n'); 383 break; 384 385 case 2: 386 decodefile(); 387 printf("\n\nPress Enter Contiue!\n"); 388 getchar(); 389 while(getchar()!='\n'); 390 break; 391 392 case 0: 393 cycle=(-1); 394 395 break; 396 default: 397 398 cout<<"你的输入有误!"<<endl; 399 cout<<"\nPress Enter Contiue!\n"; 400 getchar(); 401 402 while(getchar()!='\n'); 403 break; 404 405 } 406 407 } 408 }