DES代码实现(C++)

DES代码实现

DES整体思路不难,大部分都是将bit数组的每一位以交换表对应位置的数字作为下标进行重排。本文仅进行代码分析,算法原理请留意我的另一篇算法描述的博客

效果分析

本程序实现的是输入一段任意字符串(无空格,可使用中文),通过加解密,可以输出密文和解密后得到的明文

在这里插入图片描述

代码分析

使用到的数据类型

为节省内存,本程序使用了bitset数据类型,每段明文被初始分解成64bit进行操作,用于S-盒数据过多,直接使用文件I/O进行读写,使用了二进制转十进制的转换函数strtol 和任意进制转二进制的函数_itoa_s() .

ps : _itoa_s() 是visual stdio 支持的比较“安全”的itoa(),其他平台使用的是 itoa();
运行代码前,请将DES.cpp 中Intial_Sbox 的filename 改成你本地的S-盒存储路径

两个数据处理函数:

​ 1.StrToBit(string ) 将字符串转成二进制串,用于输入明文

bitset<64>  DES::StrToBit(string a)
{
	bitset<64> bits;
	for (int i = 0; i<8; ++i)
		for (int j = 0; j<8; ++j)
			bits[i * 8 + j] = ((a[i] >> j) & 1);
	return bits;
}

​ 2.BitToStr(bitset<64> a)将二进制串转成字符串,用于输出可视化的信息(如解密得到明文或者密文)

string  DES::BitToStr(bitset<64> a)
{
	bitset<8> temp;
	char **endptr = NULL;
	int num;
	string str = "";
	for (int i = 0; i < 64; i++)
	{
		temp[i % 8] = a[i];
		if (i % 8 == 7)
		{
			num = strtol(temp.to_string().c_str(), endptr, 2);
			char a = num;
			str += a;
		}

	}
	return str;
}

S-盒数据,每个S-盒共有64个数据,共8个S-盒:

14 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7 0 15 7 4 15 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 12 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

DES.cpp

#include <iostream>
#include <cstdlib>
#include <fstream>
#include "DES.hpp"
using namespace std;

DES::DES()
{
//初始化密钥
	bitset<64> ckey("1010101010110101010010101010110101110101010101001001010100010101");
	ChiperKey = ckey;
//加载S-盒数据
	Intial_Sbox();
//生成子密钥
	Generate_key();
}
void DES::initial(string str)
{
	while (str.length() < 8)
	{
		str += '0';
	}
	PlainText = StrToBit(str);
}
void DES::initialChiper(string str)
{
	ChiperText = StrToBit(str);
}
DES::~DES()
{
	SBox.clear();
}
void DES::IP(int num)
{
	int ip[64] = {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 t;
	bitset<64> temp;
	if (num == 0)
	{
		temp = PlainText;
	}
	else
	{
		temp = ChiperText;
	}

	for (int i = 0; i < 64; i++)
	{
		t = ip[i]-1;
		Temp[i] = temp[t];			
	}
}
//IP置换
string DES::IP1()
{
	int ip1[64] = { 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 };
	bitset<64> result;
	for (int i = 0; i < 64; i++)
	{
		result[i] = Temp[ip1[i] - 1];
	}

	return BitToStr(result);
}
//Feistel轮函数,包括E扩展和S-盒压缩
bitset<32> DES::Feistel(bitset<32>& R0, bitset<48>& k)
{
	//E-expend
	int index[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};
	bitset<48> E_expand;
	int t;
	for (int i = 0; i < 48; i++)
	{
		t = index[i] - 1;
		E_expand[i] = R0[t];
	}
	//XOR
	E_expand ^= k;

	//divide into 8 group
	bitset<6> group[8];
	for (int i = 0; i < 8; i++)
	{
		for (int  j = 0; j < 6; j++)
		{
			group[i][j] = E_expand[j + i * 6];
		}
	}

	// use long int strtol(const char *nptr, char **endptr, int base) 
	//to translate any base number to decimalism 
	// use char * itoa(int number , char *str,int base)
	// to translate decimalism to any base number
	bitset<6> row;
	bitset<6> col;
	bitset<6> row_and("100001");
	bitset<6> col_and("011110");
	bitset<6> temp_and("000001");
	vector<bitset<4>> bit;
	int select_row;
	int select_col;
	char **endptr = NULL;
	for (int i = 0; i < 8; i++)
	{
		row = group[i] & row_and;
		row = (row >> 5) | (row & temp_and);
		col = group[i] & col_and;
		col = col >> 1;
		select_row = strtol(row.to_string().c_str(), endptr, 2);
		select_col = strtol(col.to_string().c_str(), endptr, 2);
		int num = S_Block(i, select_row, select_col);
		char str[5] = "";
		//translate num to binary number
		_itoa_s(num, str,5, 2);//4 parameter
		bitset<4> temp(str);
		bit.push_back(temp);
	}

	bitset<32> feistel;
	t = 0;
	for (int i = 0; i < bit.size(); i++)
	{
		for (int j = 0; j < 4; j++)
		{
			feistel[t++] = bit[i][j];
		}
	}
	bit.clear();
	feistel = P_permutation(feistel);

	return feistel;
}


void DES::Generate_key()
{
	int pc[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 };
	bitset<28> C0;
	bitset<28> D0;
	int t;
	for (int i = 0; i < 28; i++)
	{
		t     = pc[i]-1;
		C0[i] = ChiperKey[t];
		t     = pc[i + 28] - 1;
		D0[i] = ChiperKey[t];
	}
	t = 1;
	int shift;
	while (t < 17)
	{
		
		switch (t)
		{
		case 1:
		case 2:
		case 9:
		case 16:shift = 1; break;
		default:
			shift = 2;
			break;
		}
		int index;
		C0 = (C0 >> (28 - shift))| (C0 << shift);
		D0 = (D0 >> (28 - shift))| (D0 << shift);
		for (int  i = 0; i < 48; i++)
		{
			index = pc2[i] - 1;
			if (index < 28)
			{
				key[t][i] = C0[index];
			}
			else
			{
				key[t][i] = D0[index - 28];
			}
		}
		t++;
	}
	

}

int DES::S_Block(int i,int row,int col)
{
	int index = i * 64 + row * 16 + col;
	return SBox[index];
}

bitset<32> DES::P_permutation(bitset<32> &feistel)
{
	int p[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 };
	bitset<32>temp;
	for (int i = 0; i < 32; i++)
	{
		temp[i] = feistel[p[i] - 1];
	}
	return temp;
}


void DES::Transfer()
{
	bitset<32> L0;
	bitset<32> R0;
	bitset<32> L1;
	bitset<32> R1;

	for (int i = 0; i < 32; i++)
	{
		L0[i] = Temp[i];
		R0[i] = Temp[i + 32];
	}
	int t = 1;
	bitset<32> feistel;
	while (t <= 16)
	{
		L1 = R0;
		feistel = Feistel(R0, key[t]);
		R1 = L0 ^ feistel;
		L0 = L1;
		R0 = R1;
		t++;
	}
	for (int i = 0; i < 32; i++)
	{
		Temp[i] = R1[i];
		Temp[i + 32] = L1[i];
	}
}

void DES::Intial_Sbox()
{
//运行前,先修改为你的S-盒存储路径
	string filename = "your absolute s-box path ";
	ifstream inSboxData;
	inSboxData.open(filename.c_str(), ios::in);
	int t = 0;
	int temp;
	vector<int> VecTemp;
	while (!inSboxData.eof())
	{	
		inSboxData >> temp;
		SBox.push_back(temp);
	}
	inSboxData.close();
}

void DES::InverseTransfer()
{
	bitset<32> A;
	bitset<32> B;
	bitset<32> G;
	bitset<32> H;
	for (int i = 0; i < 32; i++)
	{
		A[i] = Temp[i];
		B[i] = Temp[i + 32];
	}
	int t = 16;
	while (t > 0)
	{
		G = B;//G = L_t = R_t-1;
		H = A ^ Feistel(B, key[t]);//H = Li-1
		B = H;// B = Lt;
		A = G;// A = Rt;
		t--;
	}
	for (int i = 0; i < 32; i++)
	{
		Temp[i] = H[i];
		Temp[i + 32] = G[i];
	}
}
bitset<64>  DES::StrToBit(string a)
{
	bitset<64> bits;
	for (int i = 0; i<8; ++i)
		for (int j = 0; j<8; ++j)
			bits[i * 8 + j] = ((a[i] >> j) & 1);
	return bits;
}

string  DES::BitToStr(bitset<64> a)
{
	bitset<8> temp;
	char **endptr = NULL;
	int num;
	string str = "";
	for (int i = 0; i < 64; i++)
	{
		temp[i % 8] = a[i];
		if (i % 8 == 7)
		{
			num = strtol(temp.to_string().c_str(), endptr, 2);
			char a = num;
			str += a;
		}

	}
	return str;
}

DES.hpp

#ifndef DES_HPP
#define DES_HPP
#include <iostream>
#include <string>
#include <bitset>
#include <vector>
using namespace std;
class DES
{
public:
	DES();
	~DES();
	void initial(string str);
	void initialChiper(string str);
	void IP(int);
	string IP1();
	bitset<32> Feistel(bitset<32>& R0,bitset<48> &k);//轮函数
	void Generate_key();
	int S_Block(int i, int row, int col);
	bitset<32> P_permutation(bitset<32> &feistel);//P置换
	void Transfer();//加密过程的子密钥调度
	void Intial_Sbox();//从本地加载S-盒数据
	void InverseTransfer();//解密过程的子密钥调度
	bitset<64> StrToBit(string );
	string BitToStr(bitset<64> a);
private:
	std::bitset<64> PlainText;
	std::bitset<64> ChiperText;
	std::bitset<64> ChiperKey;
	std::bitset<64> Temp;
	std::bitset<48> key[17];
	vector<int> SBox;	
};
#endif

main.cpp

#include <iostream>
#include <string>
#include "DES.hpp"
using namespace std;
int main()
{
	int sign;
	cout << "input 0 to encode\ninput 1 to decode\ninput 2 to get the chiper text\n";
	string a;
	string b;
	string str = "";
	string plain = "";
	DES des;
	while (1)
	{
		cin >> sign;
		if (sign == 0)
		{
			str = "";
			cout << "please input the message" << endl;
			cin >> a;
			for (int i = 0; i < a.length(); i+= 8)
			{
				b = a.substr(i, 8);
				des.initial(b);
				des.IP(0);
				des.Transfer();
				str += des.IP1();
			}
			cerr << str << endl;
		}
		else if (sign == 1) {
			if (str.length() == 0) {
				cout << "please encode first" << endl;
				continue;
			}
			plain = "";
			for (int i = 0; i < str.length(); i += 8)
			{
				b = str.substr(i, 8);  
				des.initialChiper(b);
				des.IP(1);
				des.InverseTransfer();
				plain += des.IP1();
			}
			if (a.length() % 8 != 0)
			{
				plain = plain.substr(0, a.length());
			}
			cout << plain << endl;

		}
		else if (sign == 2) {
			if (str.length() == 0) {
				cout << "please encode first" << endl;
				continue;
			}
			cout << str << endl;
		}


	}

	return 0;
}
  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是简单的 DES 加密和解密 C++ 代码实现: ```c++ #include <iostream> #include <cstring> #include <openssl/des.h> std::string pad(std::string text) { // 用空格填充文本,使其长度为 8 的倍数 while (text.length() % 8 != 0) { text += ' '; } return text; } std::string encrypt(std::string key, std::string plaintext) { // DES 加密 DES_cblock key_des; DES_key_schedule key_schedule; std::string padded_plaintext = pad(plaintext); std::string encrypted_text; DES_string_to_key(key.c_str(), &key_des); DES_set_key_checked(&key_des, &key_schedule); for (int i = 0; i < padded_plaintext.length(); i += 8) { DES_cblock plaintext_block, ciphertext_block; memcpy(plaintext_block, padded_plaintext.c_str() + i, 8); DES_ecb_encrypt(&plaintext_block, &ciphertext_block, &key_schedule, DES_ENCRYPT); encrypted_text.append(reinterpret_cast<const char*>(&ciphertext_block), 8); } return encrypted_text; } std::string decrypt(std::string key, std::string ciphertext) { // DES 解密 DES_cblock key_des; DES_key_schedule key_schedule; std::string decrypted_text; DES_string_to_key(key.c_str(), &key_des); DES_set_key_checked(&key_des, &key_schedule); for (int i = 0; i < ciphertext.length(); i += 8) { DES_cblock ciphertext_block, decrypted_block; memcpy(ciphertext_block, ciphertext.c_str() + i, 8); DES_ecb_encrypt(&ciphertext_block, &decrypted_block, &key_schedule, DES_DECRYPT); decrypted_text.append(reinterpret_cast<const char*>(&decrypted_block), 8); } return decrypted_text; } int main() { // 测试 std::string key = "abcdefgh"; std::string plaintext = "hello, world!"; std::string encrypted_text = encrypt(key, plaintext); std::string decrypted_text = decrypt(key, encrypted_text); std::cout << "加密后的文本:" << encrypted_text << std::endl; std::cout << "解密后的文本:" << decrypted_text << std::endl; return 0; } ``` 需要安装 OpenSSL 库来使用 DES 加密和解密。以上代码中,我们使用了基本的 ECB 模式,这是不安全的,因为它容易受到 replay 攻击和其他攻击。在实际应用中,应使用更安全的加密模式,例如 CBC 或 CTR。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值