CQU密码学实验三

二、实验项目内容

1.编写DES子密钥的生成算法,并根据自己设定的种子密钥运行程序产生并显示出16轮的子密钥,同时完成DES算法弱秘钥和半弱秘钥对的验证;

2.应用DES算法程序实现对一个文件进行加密和解密,提交程序代码和执行结果。

3.用DES算法对输入的十六进制数加密,比较输入和输出,当改变一个位时比较输出的变化,并说明原因。

三、实验过程或算法(源程序)

以下程序的运行环境都是window10 + CLion, 编程语言为c++。

1.

#include <iostream>
#include<string>

using namespace std;

int 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};
int 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};
int lshift[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

//十六进制转二进制
string trans16to2(string hexDigit) {
    string binaryDigit;
    for (int i = 0; i < hexDigit.length(); ++i) {
        char e = hexDigit[i];
        if (e >= 'A' && e <= 'F') {
            int a = static_cast<int>(e - 'A' + 10);
            switch (a) {
                case 10:
                    binaryDigit += "1010";
                    break;
                case 11:
                    binaryDigit += "1011";
                    break;
                case 12:
                    binaryDigit += "1100";
                    break;
                case 13:
                    binaryDigit += "1101";
                    break;
                case 14:
                    binaryDigit += "1110";
                    break;
                case 15:
                    binaryDigit += "1111";
                    break;
            }
        } else if (isdigit(e)) {
            int b = static_cast<int>(e - '0');
            switch (b) {
                case 0:
                    binaryDigit += "0000";
                    break;
                case 1:
                    binaryDigit += "0001";
                    break;
                case 2:
                    binaryDigit += "0010";
                    break;
                case 3:
                    binaryDigit += "0011";
                    break;
                case 4:
                    binaryDigit += "0100";
                    break;
                case 5:
                    binaryDigit += "0101";
                    break;
                case 6:
                    binaryDigit += "0110";
                    break;
                case 7:
                    binaryDigit += "0111";
                    break;
                case 8:
                    binaryDigit += "1000";
                    break;
                case 9:
                    binaryDigit += "1001";
                    break;
            }
        }
    }
    return binaryDigit;
};

//循环左移一位
string strol(string ss) {
    int len = ss.length();
    string ss1;
    char temp = ss[0];
    for (int i = 1; i < len; i++) {
        ss1 += ss[i];
    }
    ss1 += temp;
    return ss1;
};

bool isHexDigit(char c) {
    return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
}
int main() {
    system("chcp 65001");
    //方便打印四个弱密钥
    int n = 4;
    while (n--){
        string hexDigit_key;
        cout << "请输入64位的秘钥,以16进制的方式输入:" << endl;
        getline(cin,hexDigit_key);
        string key;
        for (char c : hexDigit_key) {
            if (isHexDigit(c)) {
                key+=c;
            }
        }
        //转换成二进制
        string binaryDigit = trans16to2(key);
        cout << "秘钥转换成二进制之后:" << endl;
        cout << binaryDigit << endl << endl;

        string sPC1;
        string K[16];
        // 秘钥转换,转换成56位 64-->56
        for (int i = 0; i < 56; i++) {
            sPC1 += binaryDigit[PC1[i] - 1];
        }
        cout << "秘钥转换之后(64-->56): " << endl <<sPC1 << endl << endl;

        string temp = sPC1;
        string left = temp.substr(0, 28);
        string right = temp.substr(28, 55);
        for (int i = 0; i < 16; i++) {
            int numlshift = lshift[i];
            if (numlshift == 1) {
                left = strol(left);
                right = strol(right);
            }
            if (numlshift == 2) {
                left = strol(left);
                right = strol(right);
                left = strol(left);
                right = strol(right);
            }

            string ss;
            ss += left;
            ss += right;
            for (int j = 0; j < 48; j++) {
                K[i] += ss[PC2[j] - 1];
            }
        }
        for (int k = 0; k < 16; k++) {
            cout << "第" << k+1 << "轮的子密钥为:" << K[k] << endl;
        }
        cout << endl;
    }

}

2.

#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
#include<fstream>

using namespace std;


string desKeys[20];
/**
 *数据初始置换表
 */
int T1[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 T2[8][7] = {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,
                3, 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};

/**
 *密钥循环左移位数表
 */
int T3[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

/**
 *密钥压缩置换表
 */
int T4[8][6] = {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};

/**
 *数据扩展表
 */
int T5[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, 1};

/**
 *S盒置换表
 */
int S[8][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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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盒置换表
 */
int P[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,
               19, 13, 30, 6,
               22, 11, 4, 25};


/**

 *最终置换表

 */
int T6[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};

/**

 *最终置换函数 64位->64位

 *函数说明:s为完成最后一轮循环得到的64为数据

 *返回值为密文或明文

 */
string final_permutation(string s) {
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            rs += s[T6[i][j] - 1];
        }
    }
    return rs;
}

/**

 *P盒置换函数 32位->32位

 *函数说明:s为S盒的输出

 */
string P_box(string s) {
    string rs = "";
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 8; j++) {
            rs += (s[P[i][j] - 1]);
        }
    }
    return rs;
}

/**

 *S盒置换函数 48位->32位

 *函数说明:s为48位数据

 *返回值为32位

 */
string S_box(string s) {
    string rs = "";
    string s1;
    int k1, k2;//S盒的行号和列号
    int h = 1;//决定使用那个S盒
    for (int i = 0; i <= 42; i = i + 6, h++) {
        k1 = (s[i] - '0') * 2 + (s[i + 5] - '0') * 1;
        k2 = (s[i + 1] - '0') * 8 + (s[i + 2] - '0') * 4 + (s[i + 3] - '0') * 2 + (s[i + 4] - '0') * 1;
        int x = S[h - 1][k1][k2];
        s1 = "";
        int y = 8;
        for (int j = 1; j <= 4; j++) {
            if (x < y) {
                s1 += "0";
                y /= 2;
            } else {
                s1 += "1";
                x = x % y;
                y /= 2;
            }
        }
        rs += s1;
    }
    return rs;
}

/**

 *异或运算函数

 *要求位数相同

 */
string desXOR(string s1, string s2) {
    string rs = "";
    for (int i = 0; i < s1.length() && i < s2.length(); i++) {
        rs += ((s1[i] - '0') ^ (s2[i] - '0')) + '0';
    }
    return rs;
}

/**

 *数据扩展函数 32->48

 *函数说明:s为数据的右半部分 32位

 *扩展成48位的输出

 */
string plaintext_righthalf_extended_permutation(string s) {
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 6; j++) {
            rs += s[T5[i][j] - 1];
        }
    }
    return rs;
}

/**

 *密钥压缩置换函数 56位->48位

 *函数说明:s为56为的密钥

 *输出为48位的子密钥

 */
string secret_key_compression_replacement(string s) {
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 6; j++) {
            rs += s[T4[i][j] - 1];
        }
    }
    return rs;
}

/**

 *密钥循环左移函数 56位->56位

 *函数说明:k为左移位数 s为密钥

 *返回值位数不变

 */
string secret_ket_left_move(int k, string s)//密钥循环左移k位
{
    string s1 = s.substr(0, 28);
    string s2 = s.substr(28, 28);
    string rs = s1.substr(k, 28 - k) + s1.substr(0, k) + s2.substr(k, 28 - k) + s2.substr(0, k);
    return rs;
}

/**

 *密钥初始置换函数 64位->56位

 *函数说明:s为64位的初始密钥

 *返回值为56位

 */
string secret_key_initial_permutation(string s) {

    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 7; j++) {
            rs += s[T2[i][j] - 1];
        }
    }

    return rs;
}

/**

 *明文初始置换函数 64位->64位

 *函数说明:s为初始明文 64位

 *返回值为6位

 */
string plaintext_initial_permutation(string s)//明文初始置换
{
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            rs += s[T1[i][j] - 1];
        }
    }
    return rs;
}

/**

 *16进制转2进制函数

 *函数说明:s为16进制字符串

 *返回为2进制字符串

 */
string des_H(string s) {
    string s1;
    string rs = "";
    for (int i = 0; i < s.length(); i++) {
        int x;
        if (s[i] >= '0' && s[i] <= '9') {
            x = s[i] - '0';
        } else {
            x = s[i] - 'A' + 10;
        }
        s1 = "";
        int y = 8;
        for (int j = 1; j <= 4; j++) {
            if (x < y) {
                y /= 2;
                s1 += "0";
            } else {
                s1 += "1";
                x = x % y;
                y = y / 2;
            }
        }
        rs += s1;
    }
    return rs;
}

/**

*2进制转16进制函数

*str为2进制字符串

*返回值为16进制字符串

*/
string des_G(string str) {
    string rs = "";
    char temp;
    for (int i = 0; i <= str.length() - 4; i = i + 4) {
        int x = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + str[i + 3] - '0';

        if (x >= 10) {
            temp = (char) (x - 10 + 'A');
        } else {
            temp = (char) (x + '0');
        }
        rs += temp;
    }
    return rs;
}

/**

 *封装函数f

 *函数说明:接收32位数据和48位的子密钥 产生一个32位的输出

 *str1:32位数据  str2:48位的子密钥

 *返回值32位

 */

string des_f(string str1, string str2) {
    string expendR = plaintext_righthalf_extended_permutation(str1);
    //cout<<"32位数据扩展为48位结果:"<<expendR<<endl;

    string rs = desXOR(expendR, str2);
    //cout<<"密钥和扩展数据异或结果:"<<rs<<endl;

    rs = S_box(rs);
    //cout<<"S盒替代结果(48->32):"<<rs<<endl;

    rs = P_box(rs);
    //cout<<"P盒替代结果(32->32):"<<rs<<endl;

    return rs;
}

/**

 *子密钥生成函数

 *函数说明:s为给定的密钥

 *生成16个子密钥

 */


void des_generateKeys(string s) {

    s = secret_key_initial_permutation(s);

    for (int i = 1; i <= 16; i++) {
        s = secret_ket_left_move(T3[i - 1], s);
        desKeys[i] = secret_key_compression_replacement(s);
    }
}

/*
* 明文字符串转换成0/1字符串
*/
string des_StrToBitStr(string str) {
    bitset<64> bstr;
    for (int i = 0; i < 8; i++) {
        bitset<8> bits = bitset<8>(str[i]);
        for (int j = 0; j < 8; j++) {
            bstr[i * 8 + j] = bits[7 - j];
        }
    }
    string s = bstr.to_string();
    //添加一个翻转操作
    reverse(begin(s), end(s));
    return s;
}

/*
* 0/1字符串装换为字符形式的字符串
*/
string des_BitStrToStr(string bstr) {
    string str = "";
    //每八位转化成十进制,然后将数字结果转化成字符
    int sum;
    for (int i = 0; i < bstr.size(); i += 8) {
        sum = 0;
        for (int j = 0; j < 8; j++)
            if (bstr[i + j] == '1')
                sum = sum * 2 + 1;
            else
                sum = sum * 2;
        str = str + char(sum);
    }
    return str;

}

string chardeel(string &str1, string &str2) {
    string temp_str = "";
    int divi_times = (str1.size() % 8 ? str1.size() / 8 + 1 : str1.size() / 8);        //计算分组个数
    for (int i = 0; i < divi_times; ++i) {                                        //每个分组单独转换成二进制串
        string str1_temp = str1.substr(8 * i, 8);  //substr(start,len) 

        bool jude = false;
        int addchar = 0;
        if (str1_temp.size() % 8) {
            jude = true;
            addchar = 8 - str1_temp.size() % 8;
        }
        int sub = str1_temp.size() * 8;
        if (jude) {
            for (int i = 0; i < addchar; ++i) {
                str1_temp += 'a';
            }
        }
        str1_temp = des_StrToBitStr(str1_temp);
        if (jude) {
            for (int i = 0; i < addchar * 8; ++i) {
                str1_temp[sub + i] = '0';
            }
        }
        temp_str = temp_str + str1_temp;

    }
    str2 = des_H(str2);
    return temp_str;
}

/**

 *DES加密函数 64位->64位

 *函数说明:str1为64位的给定明文

 *返回值为64位的密文

 */

string des_encrypt(string str1, string str2) {
    //str1是要明文,str2是密文
    str1 = chardeel(str1, str2);  //明文分组和填充,返回01字符串 

    des_generateKeys(str2);  //生成16个子密钥

    int divi_times = str1.size() / 64;  //分成多少组去进行des
    string rs_final = "";

    for (int i = 0; i < divi_times; ++i) {
        string str1_temp = str1.substr(i * 64, 64);

        //第一步:明文初始置换 64->64
        str1_temp = plaintext_initial_permutation(str1_temp);

        //第二步:数据分组
        string left = str1_temp.substr(0, 32);
        string right = str1_temp.substr(32, 32);
        string newleft;

        //第三步:16轮迭代
        for (int i = 1; i <= 16; i++) {
            newleft = right;
            right = desXOR(left, des_f(right, desKeys[i]));
            left = newleft;
        }

        //第四步:合并数据 注意位R16L16
        string rs = right + left;

        //结尾置换,最后一次置换
        rs = final_permutation(rs);
        rs_final = rs_final + rs;
    }

    return rs_final;

}

/**

*解密函数

*str为密文

*输出明文

*/
string des_decrypt(string str) {
    int divi_times = str.size() / 64;  //分成多少组去进行des
    string rs_temp = "";

    for (int i = 0; i < divi_times; ++i) {
        string str_temp = str.substr(i * 64, 64);
        //把密文当作明文进行初始明文置换
        str_temp = plaintext_initial_permutation(str_temp);

        //左右分组
        string left = str_temp.substr(0, 32);
        string right = str_temp.substr(32, 32);

        string newleft;

        //逆序的子密钥使用 16轮迭代
        for (int i = 16; i >= 1; i--) {
            newleft = right;
            right = desXOR(left, des_f(right, desKeys[i]));
            left = newleft;
        }

        //合并
        string rs = right + left;

        //最后置换
        rs = final_permutation(rs);
        rs_temp = rs_temp + rs;
    }
    rs_temp = des_BitStrToStr(rs_temp);
//    cout << " 11111 " << endl;
    return rs_temp;
}

//将二进制密文转换为16进制显示
std::string binaryToString(const std::string& binary_str) {
    std::string result;

    // 将二进制字符串按照8位一组进行分割,并将每组转换为对应的字符
    for (size_t i = 0; i < binary_str.size(); i += 8) {
        std::string sub_str = binary_str.substr(i, 8);
        std::bitset<8> bits(sub_str);
        int decimal = bits.to_ulong();
        char ch = static_cast<char>(decimal);
        result += ch;
    }

    return result;
}
int main() {
    //用于控制台打印中文字符
    system("chcp 65001");

    string str2 = "";
    cout << "请输入密钥:(秘钥格式为16为的字符,然后用代码转换为2进制)" << endl;
    getline(cin, str2);

    ifstream ifs;
    // 3打开文件并判断是否打开成功
    ifs.open("C:\\Users\\ASUS\\Desktop\\3434\\111.txt", ios::in);
    if (!ifs.is_open()) {
        cout << "打开失败" << endl;

    }
    //读数据
    char buf[1024] = {0};
    string rs;
    while (ifs >> buf) {
        string str1 = buf;
        rs += buf;
        rs += " ";
    }
    cout << "****************明文***************" << endl;
    cout << "获取到的明文信息:"  << endl << rs << endl << endl;
    //加密
    rs = des_encrypt(rs, str2);

    cout << "****************加密***************" << endl;
    cout << "加密后的密文:"  << endl << rs << endl;

    std::string result = binaryToString(rs);
    std::cout << "加密后的密文(字符形式): " << result << std::endl << endl;
    //解密
    rs = des_decrypt(rs);
    cout << "****************解密***************" << endl;
    cout << "解密后的明文:" << rs << endl;


    return 0;
}

3.

#include <iostream>
#include <string>
#include <algorithm>
#include <bitset>
#include<fstream>

using namespace std;


string desKeys[20];
/**
 *数据初始置换表
 */
int T1[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 T2[8][7] = {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,
                3, 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};

/**
 *密钥循环左移位数表
 */
int T3[16] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};

/**
 *密钥压缩置换表
 */
int T4[8][6] = {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};

/**
 *数据扩展表
 */
int T5[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, 1};

/**
 *S盒置换表
 */
int S[8][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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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}},
                   {{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盒置换表
 */
int P[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,
               19, 13, 30, 6,
               22, 11, 4, 25};


/**

 *最终置换表

 */
int T6[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};

/**

 *最终置换函数 64位->64位

 *函数说明:s为完成最后一轮循环得到的64为数据

 *返回值为密文或明文

 */
string final_permutation(string s) {
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            rs += s[T6[i][j] - 1];
        }
    }
    return rs;
}

/**

 *P盒置换函数 32位->32位

 *函数说明:s为S盒的输出

 */
string P_box(string s) {
    string rs = "";
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 8; j++) {
            rs += (s[P[i][j] - 1]);
        }
    }
    return rs;
}

/**

 *S盒置换函数 48位->32位

 *函数说明:s为48位数据

 *返回值为32位

 */
string S_box(string s) {
    string rs = "";
    string s1;
    int k1, k2;//S盒的行号和列号
    int h = 1;//决定使用那个S盒
    for (int i = 0; i <= 42; i = i + 6, h++) {
        k1 = (s[i] - '0') * 2 + (s[i + 5] - '0') * 1;
        k2 = (s[i + 1] - '0') * 8 + (s[i + 2] - '0') * 4 + (s[i + 3] - '0') * 2 + (s[i + 4] - '0') * 1;
        int x = S[h - 1][k1][k2];
        s1 = "";
        int y = 8;
        for (int j = 1; j <= 4; j++) {
            if (x < y) {
                s1 += "0";
                y /= 2;
            } else {
                s1 += "1";
                x = x % y;
                y /= 2;
            }
        }
        rs += s1;
    }
    return rs;
}

/**

 *异或运算函数

 *要求位数相同

 */
string desXOR(string s1, string s2) {
    string rs = "";
    for (int i = 0; i < s1.length() && i < s2.length(); i++) {
        rs += ((s1[i] - '0') ^ (s2[i] - '0')) + '0';
    }
    return rs;
}

/**

 *数据扩展函数 32->48

 *函数说明:s为数据的右半部分 32位

 *扩展成48位的输出

 */
string plaintext_righthalf_extended_permutation(string s) {
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 6; j++) {
            rs += s[T5[i][j] - 1];
        }
    }
    return rs;
}

/**

 *密钥压缩置换函数 56位->48位

 *函数说明:s为56为的密钥

 *输出为48位的子密钥

 */
string secret_key_compression_replacement(string s) {
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 6; j++) {
            rs += s[T4[i][j] - 1];
        }
    }
    return rs;
}

/**

 *密钥循环左移函数 56位->56位

 *函数说明:k为左移位数 s为密钥

 *返回值位数不变

 */
string secret_ket_left_move(int k, string s)//密钥循环左移k位
{
    string s1 = s.substr(0, 28);
    string s2 = s.substr(28, 28);
    string rs = s1.substr(k, 28 - k) + s1.substr(0, k) + s2.substr(k, 28 - k) + s2.substr(0, k);
    return rs;
}

/**

 *密钥初始置换函数 64位->56位

 *函数说明:s为64位的初始密钥

 *返回值为56位

 */
string secret_key_initial_permutation(string s) {

    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 7; j++) {
            rs += s[T2[i][j] - 1];
        }
    }

    return rs;
}

/**

 *明文初始置换函数 64位->64位

 *函数说明:s为初始明文 64位

 *返回值为6位

 */
string plaintext_initial_permutation(string s)//明文初始置换
{
    string rs = "";
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            rs += s[T1[i][j] - 1];
        }
    }
    return rs;
}

/**

 *16进制转2进制函数

 *函数说明:s为16进制字符串

 *返回为2进制字符串

 */
string des_H(string s) {
    string s1;
    string rs = "";
    for (int i = 0; i < s.length(); i++) {
        int x;
        if (s[i] >= '0' && s[i] <= '9') {
            x = s[i] - '0';
        } else {
            x = s[i] - 'A' + 10;
        }
        s1 = "";
        int y = 8;
        for (int j = 1; j <= 4; j++) {
            if (x < y) {
                y /= 2;
                s1 += "0";
            } else {
                s1 += "1";
                x = x % y;
                y = y / 2;
            }
        }
        rs += s1;
    }
    return rs;
}

/**

*2进制转16进制函数

*str为2进制字符串

*返回值为16进制字符串

*/
string des_G(string str) {
    string rs = "";
    char temp;
    for (int i = 0; i <= str.length() - 4; i = i + 4) {
        int x = (str[i] - '0') * 8 + (str[i + 1] - '0') * 4 + (str[i + 2] - '0') * 2 + str[i + 3] - '0';

        if (x >= 10) {
            temp = (char) (x - 10 + 'A');
        } else {
            temp = (char) (x + '0');
        }
        rs += temp;
    }
    return rs;
}

/**

 *封装函数f

 *函数说明:接收32位数据和48位的子密钥 产生一个32位的输出

 *str1:32位数据  str2:48位的子密钥

 *返回值32位

 */

string des_f(string str1, string str2) {
    string expendR = plaintext_righthalf_extended_permutation(str1);
    //cout<<"32位数据扩展为48位结果:"<<expendR<<endl;

    string rs = desXOR(expendR, str2);
    //cout<<"密钥和扩展数据异或结果:"<<rs<<endl;

    rs = S_box(rs);
    //cout<<"S盒替代结果(48->32):"<<rs<<endl;

    rs = P_box(rs);
    //cout<<"P盒替代结果(32->32):"<<rs<<endl;

    return rs;
}

/**

 *子密钥生成函数

 *函数说明:s为给定的密钥

 *生成16个子密钥

 */


void des_generateKeys(string s) {

    s = secret_key_initial_permutation(s);

    for (int i = 1; i <= 16; i++) {
        s = secret_ket_left_move(T3[i - 1], s);
        desKeys[i] = secret_key_compression_replacement(s);
    }
}

/*
* 明文字符串转换成0/1字符串
*/
string des_StrToBitStr(string str) {
    bitset<64> bstr;
    for (int i = 0; i < 8; i++) {
        bitset<8> bits = bitset<8>(str[i]);
        for (int j = 0; j < 8; j++) {
            bstr[i * 8 + j] = bits[7 - j];
        }
    }
    string s = bstr.to_string();
    //添加一个翻转操作
    reverse(begin(s), end(s));
    return s;
}

/*
* 0/1字符串装换为字符形式的字符串
*/
string des_BitStrToStr(string bstr) {
    string str = "";
    //每八位转化成十进制,然后将数字结果转化成字符
    int sum;
    for (int i = 0; i < bstr.size(); i += 8) {
        sum = 0;
        for (int j = 0; j < 8; j++)
            if (bstr[i + j] == '1')
                sum = sum * 2 + 1;
            else
                sum = sum * 2;
        str = str + char(sum);
    }
    return str;

}

string chardeel(string &str1, string &str2) {
    string temp_str = "";
    int divi_times = (str1.size() % 8 ? str1.size() / 8 + 1 : str1.size() / 8);        //计算分组个数
    for (int i = 0; i < divi_times; ++i) {                                        //每个分组单独转换成二进制串
        string str1_temp = str1.substr(8 * i, 8);  //substr(start,len)

        bool jude = false;
        int addchar = 0;
        if (str1_temp.size() % 8) {
            jude = true;
            addchar = 8 - str1_temp.size() % 8;
        }
        int sub = str1_temp.size() * 8;
        if (jude) {
            for (int i = 0; i < addchar; ++i) {
                str1_temp += 'a';
            }
        }
        str1_temp = des_StrToBitStr(str1_temp);
        if (jude) {
            for (int i = 0; i < addchar * 8; ++i) {
                str1_temp[sub + i] = '0';
            }
        }
        temp_str = temp_str + str1_temp;

    }
    str2 = des_H(str2);
    return temp_str;
}

/**

 *DES加密函数 64位->64位

 *函数说明:str1为64位的给定明文

 *返回值为64位的密文

 */

string des_encrypt(string str1, string str2) {
    //str1是要明文,str2是密文
    str1 = chardeel(str1, str2);  //明文分组和填充,返回01字符串

    des_generateKeys(str2);  //生成16个子密钥


    int divi_times = str1.size() / 64;  //分成多少组去进行des
    string rs_final = "";

    for (int i = 0; i < divi_times; ++i) {
        string str1_temp = str1.substr(i * 64, 64);

        //第一步:明文初始置换 64->64
        str1_temp = plaintext_initial_permutation(str1_temp);

        //第二步:数据分组
        string left = str1_temp.substr(0, 32);
        string right = str1_temp.substr(32, 32);
        string newleft;

        //第三步:16轮迭代
        for (int i = 1; i <= 16; i++) {
            newleft = right;
            right = desXOR(left, des_f(right, desKeys[i]));
            left = newleft;
        }

        //第四步:合并数据 注意位R16L16
        string rs = right + left;

        //结尾置换,最后一次置换
        rs = final_permutation(rs);
        rs_final = rs_final + rs;
    }

    return rs_final;

}

/**

*解密函数

*str为密文

*输出明文

*/
string des_decrypt(string str) {
    int divi_times = str.size() / 64;  //分成多少组去进行des
    string rs_temp = "";

    for (int i = 0; i < divi_times; ++i) {
        string str_temp = str.substr(i * 64, 64);
        //把密文当作明文进行初始明文置换
        str_temp = plaintext_initial_permutation(str_temp);

        //左右分组
        string left = str_temp.substr(0, 32);
        string right = str_temp.substr(32, 32);

        string newleft;

        //逆序的子密钥使用 16轮迭代
        for (int i = 16; i >= 1; i--) {
            newleft = right;
            right = desXOR(left, des_f(right, desKeys[i]));
            left = newleft;
        }

        //合并
        string rs = right + left;

        //最后置换
        rs = final_permutation(rs);
        rs_temp = rs_temp + rs;
    }
    rs_temp = des_BitStrToStr(rs_temp);
//    cout << " 11111 " << endl;
    return rs_temp;
}


std::string binaryToString(const string binary_str) {
    std::string result = "";

    // 将二进制字符串按照8位一组进行分割,并将每组转换为对应的字符
    for (int i = 0; i < binary_str.size(); i += 8) {
        std::string sub_str = binary_str.substr(i, 8);
        std::bitset<8> bits(sub_str);
        int decimal = bits.to_ulong();
        char ch = static_cast<char>(decimal);
        result += ch;
    }
//    cout << "?";
//    cout << binary_str << endl;
//    cout << "result: "  << result;
    return result;
}
int main() {
    //用于控制台打印中文字符
    system("chcp 65001");
    cout << "****************DES加密***************" << endl;
    string str2 = "";
    cout << "请输入密钥:(秘钥格式为16为的字符,然后用代码转换为2进制)" << endl;
    getline(cin, str2);

    string plaintext;
    cout << "****************明文***************" << endl;
    cout << "请输入明文:"  ;
    getline(cin, plaintext);
    //加密
    plaintext = des_encrypt(plaintext, str2);

    cout << "****************加密***************" << endl;
    cout << "加密后的密文:"  << endl << plaintext << endl;
    string temp_re = plaintext;
    string result = binaryToString(temp_re);
    cout << "密文(字符形式): " << result << endl << endl;
    //解密
    plaintext = des_decrypt(plaintext);
    cout << "****************解密***************" << endl;
    cout << "解密后的明文:" << plaintext << endl;
    return 0;
}

四、实验结果

1.

2.

3.

由于是分组密码,所以秘钥不变,相应的分组加密之后不会变.

参考

数据加密算法--详解DES加密算法原理与实现 - DreamGo - 博客园 (cnblogs.com)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值