DES算法实现:加密与解密实验报告

一、实验目的

本实验的目的是通过实现DES(Data Encryption Standard)算法,加密和解密给定的明文和密钥。

二、实验原理

DES算法是一种对称加密算法,其主要原理如下:

  1. 初始置换IP:将明文的64位按照一定规则进行置换。
  2. 密钥初始置换:将密钥的64位按照一定规则进行置换,生成56位的密钥。
  3. 生成16个子密钥:根据初始密钥,通过循环左移和压缩置换生成16个子密钥。
  4. 数据分组:将64位明文分为左右两个32位的数据。
  5. 16轮迭代加密:根据16个子密钥,对数据进行16轮的迭代加密,每轮包括数据扩展、异或运算、S盒置换和P盒置换。
  6. 合并数据:将左右两个32位的数据合并成64位。
  7. 逆初始置换IP-1:将加密后的64位按照逆初始置换规则进行置换,得到最终的密文。

三、代码实现

string des_StrToBitStr(string str)
{
    bitset<64> bstr;
    for (int i = 0; i < 8; i++)
    {
        bitset<8> bits = bitset<8>(str[i]);
        //a(001高位)b(002)c(003)
        for (int j = 0; j < 8; j++)
        {
            //现在是a(1高位00)b(200)c(300)
            bstr[i * 8 + j] = bits[7 - j];//将每个字符的高位,作为分组字符串的开头,重点
        }
    }
    //返回的字符串,满足,//01100001/97 高位在左,高位存放在数组的高下标,相当于翻转
    //返回的字符串是 c(003高位)b(002)a(001)
    string s = bstr.to_string();
    //添加一个翻转操作,现在是a(1高位00)b(200)c(300)
    reverse(begin(s), end(s));
    return s;
}


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;

}

//分组字符串,分两次组,第一次将字符串 以8个字符分开,然后将8个字符以一个字符分开
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) 不满len的字符串,就是直接到字符串末尾

        bool jude = false;//判断分组字符串是否满足64位
        int addchar = 0;//不满64位,需要增加的字符数量
        if (str1_temp.size() != 8) {
            jude = true;
            addchar = 8 - str1_temp.size();
        }
        int sub = str1_temp.size() * 8;//分组字符串的起始位置
        if (jude) {
            for (int i = 0; i < addchar; ++i) {
                str1_temp += 'a';//在分组末尾增加字符
            }
        }
        //返回8个字符,例如,a(1高位00)b(200)c(300)
        str1_temp = des_StrToBitStr(str1_temp);//将8个字符转换为64位二进制,//01100001/97 高位在左,高位存放在数组的高下标
        if (jude) {
            //字符数*8=位数
            for (int i = 0; i < addchar * 8; ++i) {
                str1_temp[sub + i] = '0';
            }
        }
        temp_str = temp_str + str1_temp;

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


/**
 *密钥初始置换函数 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;
}


/**
 *密钥压缩置换函数 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;
}

/**
 *子密钥生成函数
 *函数说明: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);
    }
}
/**
 *明文初始置换函数 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;
}
/**
 *数据扩展函数 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;
}

/**
 *异或运算函数
 *要求位数相同
 */
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;
}

/**
 *S盒置换函数 48位->32位
 *函数说明:s为48位数据
 *返回值为32位
 */
string S_box(string s)
{
    string rs = '';
    string s1;
    int k1, k2;//S盒的行号和列号
    int h = 1;//决定使用那个S盒
    //这里为什么是<= 
    //0、6、12、18、24、30、36、42
    for (int i = 0; i < 48; 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 = '';

        //10
        //5 0 0
        //2 1 1
        //1 0 0
        //0 1 1
        int y = 8;//1000
        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;
}

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

/**
 *封装函数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;
}
/**
 *最终置换函数 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;
}
/**
*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;
}


/**
 *DES加密函数 64位->64位
 *函数说明:str1为64位的给定明文
 *返回值为64位的密文
 */

string des_encrypt(string str1, string str2)
{
    //这一步,将明文字符a(001)b(001)c(001),变成位字符串,将密钥变为位字符串
    str1 = chardeel(str1, str2);  //明文分组和填充,返回01字符串

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


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

    string rs_temp = '';
    //对每一分组进行加密,然后相加
    for (int i = 0; i < divi_times; ++i) {
        string str1_temp = str1.substr(i * 64, 64);

        cout << '明文分组' << i + 1 << ': ' << des_G(str1_temp) << endl;
        //第一步:明文初始IP置换 64->64
        str1_temp = plaintext_initial_permutation(str1_temp);
        cout << '初始置换IP结果: ' << des_G(str1_temp) << endl;
        //第二步:数据分组
        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;
            printf('第%d轮迭代的结果为:L%d:%s;R%d:%s
', i, i, des_G(left).c_str(), i, des_G(right).c_str());
        }

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

        //结尾置换
        rs = final_permutation(rs);
        rs_temp = rs_temp + rs;
        cout << '逆初始置换IP-1结果: ' << des_G(rs) << endl;
        cout << endl;
    }

    return rs_temp;
}


/**
*解密函数
*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);
    return rs_temp;
}

int main()
{
    //    cout<<str1.substr(0,2);//不足8个就全部
    //    string str1 = 'abc';
    //    cout << str1.max_size();
    //    char ch = 'a';
    //    bitset<8> bits = bitset<8>(ch);//01100001/97 高位在左,高位存放在数组的高下标
    //    cout<<bits[0]<<endl;
    //    for (int i = 0; i < bits.size(); ++i) {
    //        cout<<bits[i];
    //    }


    string str1 = '';
    cout << '请输入明文:';
    getline(cin, str1);

    string str2 = '';
    cout << '请输入密钥(8个字符/64位):';
    getline(cin, str2);


    //加密
    string rs = des_encrypt(str1, str2);
    cout << '密文(二进制):' << rs << endl;

    //解密
    rs = des_decrypt(rs);
    cout << '明文(字符串):' << rs << endl;

    system('pause');
    return 0;
}

四、实验步骤

  1. 编写代码,实现DES算法的加密和解密函数。
  2. 运行代码,输入明文和密钥,进行加密操作。
  3. 使用加密后的密文,进行解密操作,验证解密后的明文是否与原明文一致。

五、实验结果

本实验成功地实现了DES算法的加密和解密功能。对给定的明文和密钥进行加密,并使用解密函数进行解密,解密后的明文与原明文一致,验证了算法的正确性。

六、实验总结

本实验通过实现DES算法,加深了对对称加密算法的理解,并掌握了DES算法的实现方法。实验过程中,需要仔细理解DES算法的原理,并根据原理编写代码实现加密和解密函数。此外,需要进行充分的测试,确保算法的正确性。

七、实验思考

  1. DES算法的安全性如何?
  2. DES算法的应用场景有哪些?
  3. DES算法与其他对称加密算法相比,有哪些优缺点?
  4. DES算法的未来发展趋势如何?
DES算法实现:加密与解密实验报告

原文地址: https://www.cveoy.top/t/topic/pchK 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录