原创:岐山凤鸣
引用需注明本站域名。
总述
先直接看一遍加密性质:
- 分组密码:明文密文都是64位
- 字符都变成二进制,即每一位都是一个二进制,0或者1
- 密钥长度56位(64-8),生命周期短,运算速度慢
然后是加密的过程,分为两步,第一步是密钥生成,第二步才是加密。
总概述过程如下:
- 密钥生成
- Step1:输入64位密钥,各分为8个8字节的段,然后去掉每个8字节的第八位(奇偶校验位),再合起来形成56位
- Step2:将这个56位按照下表打乱顺序,表的顺序是先行后列,表中的数字指的是原来的那个位的数字。
- Step3:然后将这个56位中间分段,分成两个28位,前28位叫做C0,后28位叫做D0
- Step4:C0和D0合起来的56位,即打乱顺序后的那个56位是我们得到的第一个子密钥,叫做K0,我们一共需要16个子密钥,即K0-k15,下面就是要生成这剩下的15个子密钥
- Step5:将C0和D0按照下面的表进行循环左移,因为我们现在是要得到C1,所以只需要看表的第一列,即1,所以两个都只需循环左移1位,得到C1和D1
- Step6:将C1和D1合并,形成新的56位,然后按照下表打乱顺序,得到K1
- Step7: 重复Step5和Step6,15次,得到K1到K15,结束
- 加密
- Step1:输入64位数据块,进行初始置换,输出32位R0和L0
- Step2:将L0和R0进行16次f函数运算,每一次要用到相应的密钥K_i(f函数在下面会详细说道),输出最后的32位R0和32位L0
- Step3:将最后的R0和L0进行逆置换,输出64位密文,结束,总过程如下图
加密过程详细
密钥生成不再叙述,这里从头详细说一遍加密过程
开始之前:我们有64位明文数据块,16个子密钥K0-K15
Step1、初始置换
将64位数据块按照下面的表打乱顺序
打乱后从中切开,左32位提出叫做L0,后32位提出叫做R0,【只输入R0】进入下个步骤
Step2、f函数
f函数分为三个步骤
第一步、扩展32位R0数据块
按照下面的表进行扩展,将32位R0扩展成48位
32 | 01 02 03 04 | 05 |
04 | 05 06 07 08 | 09 |
08 | 09 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 | 01 |
第二步、与子密钥模二相加
将这个48位和对应的子密钥(第一次运算f函数就是K0,第十六次就是K15)模二相加,得到新的48位。
第三步、S盒替代
将这个新的48位按照每6位分成8个块,每个块是6位。
对每个块来说,将第一位和第六位合在一起的两位,计算出一个0-3的数字,叫做行,再将剩余的四位合在一起计算出一个0-15的数字,叫做列,一共得到8对行和列,然后在下面8个表S1-S8中,分别按照行列,找出8个十进制数字。这个过程叫做S盒替代。
将得到的8个十进制数字全部转成四位二进制合成,得到32位。
第四步、P盒置换
将这个32位再按照下面的表打乱顺序
第五步、得到R1
这样得到了最终的32位,现在,我们将这个32位叫做新的R0,即R1,将R1与之前一直没有改动的L0模二相加,得到新的R1。
第六步、得到新的L1和R1,回到第一步,重复f函数
将之前的没有变动的32位R0改成L1,现在我们有了新的L1和R1,可以重复这六步,得到L2和R2,重复16次,得到L15和R15
Step3、合并L15和R15,逆置换
合并L15和R15,得到64位数据,按照下表进行逆置换打乱顺序
结束,得到64位密文
代码实现
类的设计:
#ifndef DESENCRYPTOR_H
#define DESENCRYPTOR_H
#include <iostream>
using namespace std;
class DESEncryptor
{
public:
DESEncryptor(){keys = new string[16];}
~DESEncryptor(){}
string* keys; // 包含16个48位子密钥
string encrypt(string sourceText, string *keys); // 加密算法,输入64位数据块,和16个子密钥
void getKey(string sourceKey); // 得到16个48位子密钥,输入64位原始密钥
//private:
int initialPermutationTable[8][8] = {
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
}; // 初始置换矩阵
int inverseInitialPermutationTable[8][8] = {
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
}; // 逆置换矩阵
int expandTable[8][6] = {
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, 01
}; // 32位扩展到48位矩阵
int s1[4][16] = {
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
}; // S盒的第一个矩阵,下面7个都是S盒替代的
int s2[4][16] = {
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
};
int s3[4][16] = {
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
};
int s4[4][16] = {
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
};
int s5[4][16] = {
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,
};
int s6[4][16] = {
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
};
int s7[4][16] = {
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
};
int s8[4][16] = {
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
};
int pTable[4][8] = {
16, 7, 20, 21, 29, 12, 28, 17,
1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9,
9, 13, 30, 6, 22, 11, 4, 25
}; // P置换矩阵
int C0D0[8][7] = {
57, 49, 41, 33, 25, 17, 9,
10, 2, 59, 51, 43, 35, 27,
63, 55, 47, 39, 31, 23, 15,
14, 6, 61, 53, 45, 37, 29,
1, 58, 50, 42, 34, 26, 18,
19, 11, 3, 60, 52, 44, 36,
7, 62, 54, 46, 38, 30, 22,
21, 13, 5, 28, 20, 12, 4
}; // C0置换矩阵,D0置换矩阵
int iterTimes[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
// 循环左移次数
int keyPermutationTable[4][12] = {
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
}; // 密钥置换
string initialPermutation(string); // 初始置换
string inverseInitialPermutation(string); // 逆置换
string pPermutaion(string); // P置换,输入32位数据,输出32位数据
string expansionPermutation(string); // 扩展置换,输入32位数据,输出48位扩展数据
string c0d0Permutation(string); // c0d0置换,输入56位,输出56位
string keyPermutation(string); // 密钥置换,输入56位,输出48位子密钥
string sBox(string); // s盒置换,输入了48位数据,经过8个S盒的替代后,输出32位数据
string feistelCipher(string, string); // 一次f函数,包含了上述的各种步骤,运用了本类中的各种函数
string str2bit(string sourceText); // 字符串到二进制,输入字符串,输出其二进制串
string bit2str(string bitText); // 二进制到字符串,输入二进制串,输出字符串
string num2bit(int num, int bit); // 数字到二进制,只支持0-15的数字,输入数字字符串,和2位还是4位,输出转换后的2位或者4位数据
string bit2num(string bit); // 二进制到数字,上面的翻转
string myXor(string str1, string str2); // 模二相加,输入的两个串必须大小相同
string leftShift(string); // 循环左移,输入一个二进制串和左移位数
};
#endif // DESENCRYPTOR_H
具体设计细节待定,cpp代码:
#include "desencryptor.h"
#include <cmath>
#include <exception>
#include <map>
#include <sstream>
string DESEncryptor::str2bit(string sourceText){
string ans;
for(string::iterator it = sourceText.begin(); it != sourceText.end(); ++it){
unsigned char k = 0x80;
for(int i = 0; i < 8; ++i, k >>= 1){
if((*it) & k){
ans = ans + "1";
}else{
ans = ans + "0";
}
}
}
return ans;
}
string DESEncryptor::bit2str(string bitText){
string ans;
int times = (bitText.size() / 8);
for(int i = 0; i < times; ++i){
string tmp = bitText.substr(i * 8, 8);
unsigned char k = 0;
for(int j = 0; j < 8; ++j){
k = k + (tmp.at(j) - '0') * (int)(pow(2, 7 - j));
}
stringstream stream;
stream<<k;
ans = ans + stream.str();
}
return ans;
}
string DESEncryptor::initialPermutation(string sourceText){
string ans = sourceText + "";
for(int i = 0; i < 8; ++i){
for(int j = 0; j < 8; ++j){
ans[8 * i + j] = sourceText[initialPermutationTable[i][j] - 1];
}
}
return ans;
}
string DESEncryptor::inverseInitialPermutation(string sourceText){
string ans = sourceText + "";
for(int i = 0; i < 8; ++i){
for(int j = 0; j < 8; ++j){
ans[8 * i + j] = sourceText[inverseInitialPermutationTable[i][j] - 1];
}
}
return ans;
}
string DESEncryptor::pPermutaion(string sourceText){
string ans = sourceText + "";
for(int i = 0; i < 4; ++i){
for(int j = 0; j < 8; ++j){
ans[8 * i + j] = sourceText[pTable[i][j] - 1];
}
}
return ans;
}
string DESEncryptor::expansionPermutation(string sourceText){
string ans;
for(int i = 0; i < 48; ++i)
ans = ans + "1";
for(int i = 0; i < 8; ++i){
for(int j = 0; j < 6; ++j){
ans[6 * i + j] = sourceText[expandTable[i][j] - 1];
}
}
return ans;
}
string DESEncryptor::myXor(string str1, string str2){
if(str1.size() != str2.size()){
cout<<"***Error when myXor"<<endl;
return "";
}
string ans = str1 + "";
for(int i = 0; i < str1.size(); ++i){
if(str1.at(i) == str2.at(i)){
ans[i] = '0';
}else{
ans[i] = '1';
}
}
return ans;
}
string DESEncryptor::feistelCipher(string sourceText, string key){
string expand = expansionPermutation(sourceText);
expand = myXor(expand, key);
string afterSBox = sBox(expand);
string afterPBox = pPermutaion(afterSBox);
return afterPBox;
}
string DESEncryptor::num2bit(int num, int bit){
if(bit == 2){
map<int, string> table;
table[0] = "00";
table[1] = "01";
table[2] = "10";
table[3] = "11";
try{
return table[num];
}catch (exception& e){
cout<<"***num2bit Error"<<endl;
}
}else if(bit == 4){
map<int, string> table;
table[0] = "0000";
table[1] = "0001";
table[2] = "0010";
table[3] = "0011";
table[4] = "0100";
table[5] = "0101";
table[6] = "0110";
table[7] = "0111";
table[8] = "1000";
table[9] = "1001";
table[10]= "1010";
table[11]= "1011";
table[12]= "1100";
table[13]= "1101";
table[14]= "1110";
table[15]= "1111";
try{
return table[num];
}catch (exception& e){
cout<<"***num2bit Error"<<endl;
}
}else{
cout<<"***num2bit Error, expected int bit"<<endl;
}
}
string DESEncryptor::bit2num(string bit){
map<string, string> table;
table["0000"] = "0";
table["0001"] = "1";
table["0010"] = "2";
table["0011"] = "3";
table["0100"] = "4";
table["0101"] = "5";
table["0110"] = "6";
table["0111"] = "7";
table["1000"] = "8";
table["1001"] = "9";
table["1010"]= "10";
table["1011"]= "11";
table["1100"]= "12";
table["1101"]= "13";
table["1110"]= "14";
table["1111"]= "15";
table["00"] = "0";
table["01"] = "1";
table["10"] = "2";
table["11"] = "3";
table["0"] = "0";
table["1"] = "1";
try{
return table[bit];
}catch (exception& e){
cout<<"***bit2num Error"<<endl;
}
}
string DESEncryptor::sBox(string sourceText){
// input 48bits, output 32bits
string ans;
// divided into 8 parts
// sourceText[0 - 5]
int row = stoi(bit2num(sourceText.substr(0, 1) + sourceText.substr(5, 1)));
int col = stoi(bit2num(sourceText.substr(1, 4)));
ans = ans + num2bit(s1[row][col], 4);
// sourceText[6 - 11]
row = stoi(bit2num(sourceText.substr(6, 1) + sourceText.substr(11, 1)));
col = stoi(bit2num(sourceText.substr(7, 4)));
ans = ans + num2bit(s2[row][col], 4);
// sourceText[12 - 17]
row = stoi(bit2num(sourceText.substr(12, 1) + sourceText.substr(17, 1)));
col = stoi(bit2num(sourceText.substr(13, 4)));
ans = ans + num2bit(s3[row][col], 4);
// sourceText[18 - 23]
row = stoi(bit2num(sourceText.substr(18, 1) + sourceText.substr(23, 1)));
col = stoi(bit2num(sourceText.substr(19, 4)));
ans = ans + num2bit(s4[row][col], 4);
// sourceText[24 - 29]
row = stoi(bit2num(sourceText.substr(24, 1) + sourceText.substr(29, 1)));
col = stoi(bit2num(sourceText.substr(25, 4)));
ans = ans + num2bit(s5[row][col], 4);
// sourceText[30 - 35]
row = stoi(bit2num(sourceText.substr(30, 1) + sourceText.substr(35, 1)));
col = stoi(bit2num(sourceText.substr(31, 4)));
ans = ans + num2bit(s6[row][col], 4);
// sourceText[36 - 41]
row = stoi(bit2num(sourceText.substr(36, 1) + sourceText.substr(41, 1)));
col = stoi(bit2num(sourceText.substr(37, 4)));
ans = ans + num2bit(s7[row][col], 4);
// sourceText[42 - 47]
row = stoi(bit2num(sourceText.substr(42, 1) + sourceText.substr(47, 1)));
col = stoi(bit2num(sourceText.substr(43, 4)));
ans = ans + num2bit(s8[row][col], 4);
return ans;
}
string DESEncryptor::encrypt(string sourceText, string *key){
sourceText = str2bit(sourceText);
sourceText = initialPermutation(sourceText);
string L = sourceText.substr(0, 32);
string R = sourceText.substr(32, 32);
for(int i = 0; i < 16; ++i){
R = feistelCipher(R, key[i]);
R = myXor(L, R);
string tmp = L;
L = R;
R = tmp;
}
sourceText = L + R;
return inverseInitialPermutation(sourceText);
}
string DESEncryptor::c0d0Permutation(string sourceText){
string ans;
for(int i = 0; i < 8; ++i){
for(int j = 0; j < 7; ++j){
ans = ans + sourceText[C0D0[i][j] - 1];
}
}
return ans;
}
string DESEncryptor::keyPermutation(string sourceKey){
string ans;
for(int i = 0; i < 48; ++i)
ans = ans + "0";
for(int i = 0; i < 4; ++i){
for(int j = 0; j < 12; ++j){
ans[12 * i + j] = sourceKey[keyPermutationTable[i][j] - 1];
}
}
return ans;
}
void DESEncryptor::getKey(string sourceKey){
string sourceText = c0d0Permutation(sourceKey);
keys[0] = keyPermutation(sourceText);
string c0 = sourceText.substr(0, 28);
string d0 = sourceText.substr(28, 28);
for(int i = 0; i < 15; ++i){
if(iterTimes[i + 1] == 1){
c0 = leftShift(c0);
d0 = leftShift(d0);
}else if(iterTimes[i + 1] == 2){
c0 = leftShift(c0);
d0 = leftShift(d0);
c0 = leftShift(c0);
d0 = leftShift(d0);
}
keys[i + 1] = keyPermutation(c0 + d0);
}
}
string DESEncryptor::leftShift(string sourceText){
string ans = sourceText + "";
for(int j = 0; j < sourceText.size() - 1; ++j){
ans[j] = sourceText[j + 1];
}
ans[sourceText.size() - 1] = sourceText[0];
return ans;
}