Encryption and decryption process based on CBC and DES

1, Introduction

1. Password classification:

According to whether there is a key or not, the current cipher algorithms can be divided into keyless cipher and keyless cipher. Keyless cipher mainly includes hash function and message digest, while keyed cipher can be divided into symmetric cipher and asymmetric cipher, also known as private key cipher and public key cipher. For example, RSA algorithm belongs to public key cryptosystem, and the most important part of private key cipher is block cipher.

2. Group password:

Because the length of plaintext is uncertain, it is unrealistic to encrypt all plaintext directly with a certain algorithm, so we divide an arbitrary plaintext into several plaintext blocks with length of b bits, so we can encrypt each plaintext block with a certain standardized algorithm and then realize the encryption of all plaintext.

3. Design principle of block cipher:

**1) Diffusion: * * make each bit in the plaintext affect many bits in the ciphertext, that is, one bit in the ciphertext is affected by many bits in the plaintext, and each bit in the key affects many bits in the ciphertext. The basic operation is permutation.
**2) Obfuscation: * * eliminate statistical characteristics, so that the dependence between plaintext key and ciphertext becomes as complex as possible, and complex nonlinear substitution transformation will produce better obfuscation effect. The basic operation is to replace substitution.

4. DES encryption algorithm:

As a symmetric cryptosystem, the plaintext is grouped by 64 bits, and the key is 64 bits long. In fact, the key is 56 bits participating in DES operation (the 8th, 16th, 24th, 32nd, 40th, 48th, 56th and 64th bits are check bits, so that each key has an odd number of 1s. After grouping, the plaintext group and the 56 bit key are replaced or exchanged by bits to form a ciphertext group encryption method.

2, Algorithm flow chart

The figure below shows the overall framework of the algorithm. The plaintext is read in as a file, and the key is user-defined.
DES encryption algorithm uses the feistel structure, and the packet length is 64 bits.
For a 64 bit plaintext, an IP permutation is performed first. For example, the first 58 in the table means to move the 58th bit of plaintext to the first.
This only plays a role in disrupting the plaintext, and hardly improves the security.

The following figure shows the 16 round cyclic encryption algorithm flow. First, the plaintext to be encrypted is divided into left and right blocks, and the block on the right is directly used as the left input of the next round. At the same time, we use a round function with round key to process the block on the right, and perform an exclusive or operation between the result obtained and the input on the left of the previous round (if the first round is plaintext). The result is obtained As input to the right of the next round.

3, Source code

The project is divided into three documents: main.cpp ,des.h, des.cpp

//des.h
#ifndef DES_H_INCLUDED
#define DES_H_INCLUDED
#include <iostream>
#include <string>
using namespace std;
typedef const unsigned char TABLE;

// Initial replacement IP table
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
};

// Table of inverse initial displacement 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
};

// Extended permutation table 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
};

// S box design
static TABLE S_Box[8][4][16] =
{
	// S box 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 box 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 box 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,
	// Box 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 box 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 box 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 box 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,
	// Box 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
};

// P box replacement table
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
};

// Key replacement table
static TABLE PC1_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
};

// Compression replacement table
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
};

// Number of bits moved per round
static TABLE SHIFT_Table[16] =
{
	1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1
};

string byte2bit(string byte);
string bit2byte(string bit);
void get_roundkey(string* roundkey, string key);
string transform(string bit, TABLE* table, int length);
string B2C(string B, int i);

#endif // DES_H_INCLUDED

//des.cpp
#include "des.h"

string byte2bit(string byte)
{//String to bit string
	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)
{//Bit string to string
	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 transform(string bit, TABLE* table, int length)
{	//Matrix permutation
	string tmp(length, 0);
	for (int i = 0; i < length; i++)
		tmp[i] = bit[table[i] - 1];
	return tmp;
}

void get_roundkey(string* roundkey, string key)
{//Get subkey
	string bit_key = byte2bit(key);
	string transformed_key = transform(bit_key, PC1_Table, 56);//PC1 is a process of selecting and rearranging 64 bit data
	string C(transformed_key, 0, 28);
	string D(transformed_key, 28, 28);

	for (int i = 0; i < 16; i++)//Rotate the data to the left. The specific shift is related to the number of encryption rounds
	{
		C = C.substr(SHIFT_Table[i]) + C.substr(0, SHIFT_Table[i]);
		D = D.substr(SHIFT_Table[i]) + D.substr(0, SHIFT_Table[i]);
		roundkey[i] = transform(C + D, PC2_Table, 48);//After the left shift, we mix the two parts of data, and use PC2's table to make a replacement, that is, we get 48 bit round key
	}
}

string B2C(string B,int i)//Use S box
{
	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);//6 in 4 out S box
	return C;
}

//main.cpp
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "des.h"
#include "des.cpp"
enum MODE{encrypt,decrypt}mode;//Identify whether to encrypt or decrypt
using namespace std;

string enfunction(string R,string K);
string encryption(string L,string R,string* K);
string des(string data,string key);
string CBC(string data,string key,string init_vector);
string stringxor(string a,string b);
string hex_to_bit(string hex);
string bit_to_hex(string bit);
void output(string s);
string roundkey[16];//Round key

string hex_to_bit(string hex)//Hexadecimal string to bit string
{
	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 bit_to_hex(string bit)//Bit string to sixteen base string
{
	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)//Output binary string
{
	cout<<s.length()<<"\t";
	for(int i=0;i<(int)s.length();i++)
	{
		if(s[i]==1)
			cout<<1;
		else
			cout<<0;
	}
	cout<<endl;
}

string stringxor(string a,string b)//String exclusive or, combining the binary exclusive or of each character
{
	for (int i=0;i<(int)a.length();i++)
		a[i]^=b[i];
	return a;
}

string enfunction(string R,string K)//f function
{
	string ER=transform(R,EXTENSION_Table,48);//E-expansion, expanding a 32-bit data to 48 bits
	string BS=stringxor(ER,K);//Exclusive or with round key
	string f;
	for(int i=0;i<8;i++)
	{
		string B(BS.substr(i*6,6));//Take 6 bits
		string C=B2C(B,i);//C is 4 bits. S box converts 6 bits of data into 4 bits
		f+=C;
	}
	return f;//F cycle 8 rounds, change to 32-bit data
}

string encryption(string L,string R,string* K)//16 iterations
{
	if(mode==encrypt)
	{
		for(int i=0;i<16;i++)
		{
			string tmp(L);//Save left
			L=R;//Assign right to left
			R=stringxor(tmp,enfunction(R,K[i]));//Right side is exclusive or with left side after encryption through S box

//			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=stringxor(tmp,enfunction(L,K[i]));

//			cout << "L" << 16 - i << ":\t";
//			output(L);
//			cout << "R" << 16 - i << ":\t";
//			output(R);
		}
	}
	return transform(L+R,IP1_Table,64);//IP1 replacement is the reverse process of IP replacement
	cout<<endl;
}

string des(string data,string key)//DES implementation of single block encryption and decryption
{
	string bit_data;
	if (mode==encrypt)//Convert information to binary strings
		bit_data=byte2bit(data);
	else
		bit_data=hex_to_bit(data);
//	Cout < < information binary:;
//	output(bit_data);

	bit_data =transform(bit_data,IP_Table,64);//For a 64 bit plaintext, we first perform an IP permutation
//	Cout < < displacement binary:;
//	output(bit_data);

	string L(bit_data,0,32);
	string R(bit_data,32,32);
	string result=encryption(L,R,roundkey);
	if (mode==encrypt)
		return bit_to_hex(result);
	else
		return bit2byte(result);
}

string CBC(string data,string key,string init_vector)//Group link mode
{
	string result;
	string block;
	string tmp;
	string initvector(init_vector);

	if(mode==encrypt)
	{
		for(int i=0;i<int(data.length()>>3);i++)//Move 3 bits to the right, i.e. divide by 8
		{
			block=data.substr(i*8,8);//Get the 8-length string starting from the i * 8 bit in the string
			cout<<"The first"<<i+1<<"Block plaintext:"<<block<<"\t                    ";
			tmp=des(stringxor(block,initvector),key);//XOR string and key
			cout<<"The first"<<i+1<<"Block ciphertext:"<<tmp<<endl;
			initvector = bit2byte(hex_to_bit(tmp));//Modify vector
			result+=tmp;
		}
		cout<<"Complete ciphertext:";
	}
	else
	{
		for(int i=0;i<int(data.length()>>4);i++)//16 in a group
		{
			tmp=data.substr(i*16,16);
			cout<<"The first"<<i+1<<"Block ciphertext:"<<tmp<<"\t            ";
			block=stringxor(des(tmp,key),initvector);
			cout<<"The first"<<i+1<<"Block plaintext:"<<block<<endl;
			initvector=bit2byte(hex_to_bit(tmp));
			result+=block;
		}
		cout<<"Complete clear text:"<<endl;
	}
	cout<<result<<endl<<endl;
	return result;
}

int main()
{
	ifstream datafile("text.txt");//Create FileStream objects
	ostringstream buf;//Read the file into the ostringstream character stream object buf
	buf<<datafile.rdbuf();// Enter characters from the file stream into the string stream
	string plaintext=buf.str();//Returns the string associated with the stream object buf
	cout<<"Clear text:";
	cout<<plaintext<<endl;
	string key("abc10101");//Set key
	get_roundkey(roundkey, key);//Round key, 16 round keys are generated from the original key, and 16 round keys are the same when each single block is encrypted.
//    for(int y=0;y<16;y++)
//    {
//        cout<<"roundkey "<<y+1<<": ";
//        output(roundkey[y]);
//    }
	char c=0;
	while(plaintext.length()%8!=0)//Auto fill 0 if the plaintext is less than 8 bits
		plaintext+=c;
	string ciphertext;
	string init_vector=key;	//Set initial vector for grouping links
	mode=encrypt;//Start encryption
	ciphertext=CBC(plaintext,key,init_vector);
	mode=decrypt;//Indicates start decryption
	plaintext=CBC(ciphertext,key,init_vector);

	return 0;
}

4, Test of experimental results

Tags: less

Posted on Thu, 18 Jun 2020 07:04:27 -0400 by austinderrick2