基于CBC模式的DES加密实现

基于CBC模式的DES加解密实现

 

 

 

 

 

 

 

     DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。 

DES是第一个广泛用于商用数据保密的密码算法,其分组长度为64位,密钥长度也为64位(其中有8位奇偶校验位,故实际密钥长度为56位)。

DES加密共有四种模式:电子密码本模式(ECB)、加密分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)。

一、程序和主要函数的流程图,及其说明:

 

通过课程学习我们知道了DES的核心原理是基于XOR数学运算。DES是基于数据块的加密。它将待加密数据以64bit为单位拆分为若干数据块。然后再进行两重迭代: 

1)内层迭代是通过Feistel网络来实现,完成内层数据块自身加密。

2)外层迭代是数据块之间的迭代,迭代的方式即加密方式,DES加密共有四种模式:电子密码本模式(ECB)、密码分组链接模式(CBC)、加密反馈模式(CFB)和输出反馈模式(OFB)。

 

其中CBC模式加解密的原理如下:

(加密与解密过程一样,箭头方向相反进行即可)

 

 

 

 

 

程序总体分为两个文件:

 

 

 

其中des.h是头文件,定义了算法中需要用到的置换表,并进行了一系列函数和变量的声明;

main.cpp文件实现了从文件读取内容,使用了基于CBC分组链接模式的加解密过程。密钥在程序中设置,密文为方便表示,以十六进制形式输出了一次。

 

     

 

 

 

 

程序总体流程图:

                 

              

 

 

 

 

主要函数功能说明:

 

 

1)(内层)迭代函数:

 内层迭代即Feistel迭代实现对单个数据块的加密。开始前将64bit数据块拆分为左右32比bit,然后进行如下图所示的迭代过程,总共迭代16次。每一次迭代的子密钥是不同的,需要单独生成子密钥。每次迭代过程都是对右半部分数据块采用轮函数进行处理(加密)。

 

 

 

 

由这个流程图可以知道,这个内层数据块迭代加密过程又会涉及到两个子问题:

  1. 子密钥如何产生   2.轮函数如何实现

所以,需要后面几个函数的功能为基础。

 

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;

}

 

 

2)获取子密钥函数

 

 

 

子密钥的生成如上图所示,用户输入的是64bit的密钥(8个字符)首先做一次ip置换将64bit的密钥置换为56bit的密钥。56bit的密钥再进行一次PC-1置换后拆分为左右28bit的密钥。进行16轮迭代,产生16个子密钥。每次迭代将左右28bit密钥做左移1位的运算,然后再进行 PC-2的置换,组合再一起后得到key。

 

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);

}

}

 

(3)“轮函数”:(包含矩阵置换和s盒函数、function函数)

轮函数的实现主要是进行了 ebox的置换处理和sbox的置换处理:

1. ebox 将32bit 的R block 通过扩展置换为48bit的R block,然后与当前迭代的子密钥Ki做XOR 运算,最后拆分为6*8的矩阵。

2. sbox 取 R block每一行的6个bit做运算,得到 sbox的坐标,取到sbox的值后做位移运算得到加密后的新的R block的行,迭代8此后得到最后的加密结果。

 

下面三个函数总和起来实现“轮函数”的功能,与获取子密钥函数一起为实现内层迭代功能服务:

 

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 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;

}

string function(string R, string K)

{//

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;

}

 

4)DES实现单块密文分组加解密函数:

在实现了获取子密钥以及轮函数的功能之后,进行16轮内层迭代函数,就实现了单块密文的加解密功能。(调用获取子密钥函数、矩矩阵转置函数和内层迭代函数)

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);

}

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;

}

 

 

5)CBC分组链接函数:

     单块(内层)加解密实现完毕之后,按照程序总体框架,进行CBC模式的加解密。(内外层迭代都需要用到异或函数)

    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;

}

 

6)异或函数:

string string_xor(string a, string b)

{//字符串异或

for (int i = 0; i < a.length(); i++)

a[i] ^= b[i];

return a;

}

 

7)字符串和比特串之间的转换函数:

     包含二进制和十六进制、实现字符串与比特串两者之间转换的函数,以十六进制输出显示密文。

     由下面四个函数组成:

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;

}

 

8)main函数:

    主要功能为:声明变量、读入文件读取字符、设置密钥、获取明文、设置分组链接初始向量,调用CBC函数。

    int main()

{

//创建个文件流对象,并打开"plaintext.txt"(ANSI编码)

ifstream datafile("C:\\Users\\ldw\\Desktop\\CBC.DES\\eg.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;

 

 

//使用分组链接模式

string init_vector("abcdefgh"); //设定分组链接的初始向量

cipher = CBC(plaintext, key, init_vector, en);

plaintext = CBC(cipher, key, init_vector, de);

 

return 0;

}

 

二、主要函数和变量说明、声明:

 

使用到的主要函数:

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);

                                   DES内部块加密函数

string CBC(string data, string key, string init_vector, MODE mode);

                                           CBC模式加解密函数

 

 

其中,主要变量含义为:

plaintxt---明文 ,cipher--密文,key--初始密钥,init_vector--分组初始向量,en、dn为mode枚举类---加密/解密密钥(判断执行操作是加密还是解密)

 

block---分块,在CBC中调用DES函数,参与异或加密过程

后面的bit_data都是字符数据

tmp---十六进制的字符

 

 

 

 

另外,   置换表和S盒初始化如下:

 

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] =

{

// S1

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,

// S2

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,

// S3

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,

// S4

 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,

// S5

 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,

// S6

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,

// S7

 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,

// S8

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

};

 

三、运行示例:

eg1

 

 

 

 

 

 

 

 eg2

 

 

 

posted @ 2020-06-07 16:29  都是好事  阅读(713)  评论(0)    收藏  举报