基于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次。每一次迭代的子密钥是不同的,需要单独生成子密钥。每次迭代过程都是对右半部分数据块采用轮函数进行处理(加密)。

由这个流程图可以知道,这个内层数据块迭代加密过程又会涉及到两个子问题:
- 子密钥如何产生 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] =
{
// 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
};
三、运行示例:
eg1



eg2


浙公网安备 33010602011771号