DES加解密算法的ECB及CBC模式的C++实现

分组密码工做模式ios

DES 的工做模式:电码本模式(ECB)、密码分组连接模式(CBC)。算法

ECB 模式的加密过程:函数

Ci=E(K,Pi),i=1,2···N.编码

CBC 模式的加密过程:加密

C1=E(K,[P1⊕Ⅳ]),spa

Cj=E(K,[Pj⊕Cj-1],j=1,2···N.设计

程序分为两个文件。des.h头文件中定义了算法中须要用到的置换表,并进行了函数声明;main.cpp文件实现了从文件读取内容,使用ECB电码本与CBC分组连接两种模式的加解密。其中密钥在程序中设置,密文为方便表示,以十六进制形式输出。code

//des.h
#pragma once
#include <iostream>
using namespace std;

typedef enum { en, de } MODE;
typedef const unsigned char TABLE;

// 初始置换IP表
static TABLE IP_Table[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
};

// 逆初始置换IP1表
static TABLE IP1_Table[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
};

// 扩展置换E表
static TABLE EXTENSION_Table[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
};

// P盒置换表
static TABLE P_Table[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
};

// 密钥置换表
static TABLE KEY_Table[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
};

// 压缩置换表
static TABLE PC2_Table[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
};

// 每轮移动的位数
static TABLE SHIFT_Table[16] =
{
	1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};

// S盒设计
static TABLE S_Box[8][4][16] =
{
	// S盒1
	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盒2
	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,
	// S盒3
	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,
	// S盒4
	 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,
	// S盒5
	 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,
	// S盒6
	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,
	// S盒7
	 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,
	// S盒8
	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
};

string byte2bit(string byte);
string bit2byte(string bit);
string hex2bit(string hex);
string bit2hex(string bit);
void output(string s);
void get_subkey(string* subkey, string key);
string transform(string bit, TABLE* table, int length);
string string_xor(string a, string b);
string B2C(string B, int i);
string function(string R, string K);
string iterative(string L, string R, string* K, MODE mode);
string des(string data, string key, MODE mode);
string ECB(string data, string key, MODE mode);
string CBC(string data, string key, string init_vector, MODE mode);
//main.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "des.h"
using namespace std;

int main() 
{
	//建立个文件流对象,并打开"plaintext.txt"(ANSI编码)
	ifstream datafile("D:\\Courses\\Crypto\\Lab\\Lab3 实现DES的工做模式\\plaintext.txt");
	//将文件读入到ostringstream字符串流对象buf中
	ostringstream buf;
	buf << datafile.rdbuf(); // 把文件流中的字符输入到字符串流中
	//返回与流对象buf关联的字符串
	string plaintext = buf.str();
	cout << "plaintext: ";
	cout << plaintext << endl << endl;

	string key("abcdefgh");	//设定密钥

	char c = 0;
	while (plaintext.length() % 8 != 0)	//明文不足8位自动补0
		plaintext += c;

	string cipher;
	//使用电码本模式
	cipher = ECB(plaintext, key, en);
	plaintext = ECB(cipher, key, de);

	//使用分组连接模式
	string init_vector("abcdefgh");	//设定分组连接的初始向量
	cipher = CBC(plaintext, key, init_vector, en);
	plaintext = CBC(cipher, key, init_vector, de);

	return 0;
}

string byte2bit(string byte) 
{//字符串转比特串
	int length = byte.length();
	string bit(length * 8, 0);
	for (int i = 0; i < length; i++) {
		for (int j = 0; j < 8; j++) {
			bit[i * 8 + j] = (byte[i] >> (7 - j)) & 1;
		}
	}
	return bit;
}

string bit2byte(string bit) 
{//比特串转字符串
	int length = bit.length() / 8;
	string byte(length, 0);
	for (int i = 0; i < length; i++) 
	{
		byte[i] = 0;
		for (int j = 0; j < 8; j++)
			byte[i] = (byte[i] << 1) + bit[i * 8 + j];
	}
	return byte;
}

string hex2bit(string hex) 
{//十六进制字符串转比特串
	int length = hex.length();
	string bit(length * 4, 0);
	for (int i = 0; i < length; i++)
	{
		hex[i] -= 48;
		if (hex[i] > 9)
			hex[i] -= 7;
		for (int j = 0; j < 4; j++)
			bit[i * 4 + j] = (hex[i] >> (3 - j)) & 1;
	}
	return bit;
}

string bit2hex(string bit) 
{//比特串转十六进制字符串
	int length = bit.length() / 4;
	string hex(length, 0);
	for (int i = 0; i < length; i++) 
	{
		hex[i] = 0;
		for (int j = 0; j < 4; j++)
			hex[i] = (hex[i] << 1) + bit[i * 4 + j];
		hex[i] += 48;
		if (hex[i] > 57)
			hex[i] += 7;
	}
	return hex;
}

void output(string s) 
{//输出二进制字符串
	cout << s.length() << "\t";
	for (int i = 0; i < s.length(); i++) 
	{
		if (s[i] == 1)
			cout << 1;
		else
			cout << 0;
	}
	cout << endl;
}

string transform(string bit, TABLE* table, int length) 
{	//矩阵置换
	string tmp(length, 0);
	for (int i = 0; i < length; i++)
		tmp[i] = bit[table[i] - 1];
	return tmp;
}

void get_subkey(string* subkey, string key)
{//获取子密钥
	string bit_key = byte2bit(key);
	string transformed_key = transform(bit_key, KEY_Table, 56);
	string C(transformed_key, 0, 28);
	string D(transformed_key, 28, 28);

	for (int i = 0; i < 16; i++) 
	{
		C = C.substr(SHIFT_Table[i]) + C.substr(0, SHIFT_Table[i]);
		D = D.substr(SHIFT_Table[i]) + D.substr(0, SHIFT_Table[i]);
		subkey[i] = transform(C + D, PC2_Table, 48);
	}
}

string string_xor(string a, string b) 
{//字符串异或
	for (int i = 0; i < a.length(); i++)
		a[i] ^= b[i];
	return a;
}

string B2C(string B, int i) 
{//使用S盒
	int row = B[0] * 2 + B[5];
	int col = B[1] * 8 + B[2] * 4 + B[3] * 2 + B[4];
	int s = S_Box[i][row - 1][col - 1];
	string C;
	for (i = 3; i >= 0; i--)
		C += (int(s >> i) & 1);
	return C;
}

string function(string R, string K) 
{//f函数
	string ER = transform(R, EXTENSION_Table, 48);
	string BS = string_xor(ER, K);
	string f;
	for (int i = 0; i < 8; i++) 
	{
		string B(BS.substr(i * 6, 6));
		string C = B2C(B, i);
		f += C;
	}
	return f;
}

string iterative(string L, string R, string* K, MODE mode) 
{//16轮迭代
	if (mode == en) 
	{
		for (int i = 0; i < 16; i++) 
		{
			string tmp(L);
			L = R;
			R = string_xor(tmp, function(R, K[i]));

			/*cout << "L" << i + 1 << ":\t";
			output(L);
			cout << "R" << i + 1 << ":\t";
			output(R);*/
		}
	}
	else 
	{
		for (int i = 15; i >= 0; i--) 
		{
			string tmp(R);
			R = L;
			L = string_xor(tmp, function(L, K[i]));

			/*cout << "L" << 16 - i << ":\t";
			output(L);
			cout << "R" << 16 - i << ":\t";
			output(R);*/
		}
	}
	return transform(L + R, IP1_Table, 64);
	cout << endl;
}

string des(string data, string key, MODE mode)
{//DES实现单块加解密
	string bit_data;
	if (mode == en)
		bit_data = byte2bit(data);
	else
		bit_data = hex2bit(data);
	//cout << "bit_data: ";
	//output(bit_data);

	bit_data = transform(bit_data, IP_Table, 64);
	string L(bit_data, 0, 32);
	string R(bit_data, 32, 32);

	string subkey[16];
	get_subkey(subkey, key);

	string result = iterative(L, R, subkey, mode);
	if (mode == en) 
		return bit2hex(result);
	else 
		return bit2byte(result);
}

string ECB(string data, string key, MODE mode)
{//电码本模式
	string result;
	string block;
	if (mode == en) 
	{
		for (int i = 0; i<int(data.length() >> 3); i++) 
		{
			block = des(data.substr(i * 8, 8), key, mode);
			result += block;
			cout << "第 " << i + 1 << " 块:\t" << "cipher: " << block << endl << endl;
		}
		cout << "final cipher: " << endl;
	}
	else
	{
		for (int i = 0; i<int(data.length() >> 4); i++)
		{
			block = des(data.substr(i * 16, 16), key, mode);
			result += block;
			cout << "第 " << i + 1 << " 块:\t" << "plaintext: " << block << endl << endl;
		}
		cout << "final plaintext: " << endl;
	}
	cout << result << endl << endl;
	return result;
}

string CBC(string data, string key, string init_vector, MODE mode)
{//分组连接模式
	string result;
	string block;
	string tmp;
	string vector(init_vector);
	if (mode == en)
	{
		for (int i = 0; i<int(data.length() >> 3); i++)
		{
			block = data.substr(i * 8, 8);
			tmp = des(string_xor(block, vector), key, mode);
			cout << "第 " << i + 1 << " 块:\t" << "cipher: " << tmp << endl << endl;
			vector = bit2byte(hex2bit(tmp));
			result += tmp;
		}
		cout << "final cipher: ";
	}
	else
	{
		for (int i = 0; i<int(data.length() >> 4); i++)
		{
			tmp = data.substr(i * 16, 16);
			block = string_xor(des(tmp, key, mode), vector);
			cout << "第 " << i + 1 << " 块:\t" << "plaintext: " << block << endl << endl;
			vector =  bit2byte(hex2bit(tmp));
			result += block;
		}
		cout << "final plaintext: " << endl;
	}
	cout << result << endl << endl;
	return result;
}

加密结果:orm

······对象

encode

解密: