目前的密码算法按有无密钥可分为无密钥密码和有密钥密码,无密钥密码主要是hash函数和消息摘要等,而有密钥密码又分为对称密码和非对称密码,也称私钥密码和公钥密码,像RSA算法就属于公钥密码体制,而私钥密码中最重要的一个部分就是分组密码。
由于明文长度不确定,用一个确定的算法直接加密全部明文是不现实的,所以我们将一个任意的明文分为若干个长度为b个比特的明文块,这样就可以用一个确定的标准化算法对各个明文块进行加密进而实现对全部明文的加密。
1)扩散:使明文中的每一位影响密文中的许多位,即密文中的一位受明文的多位影响,也使密钥中的每一位影响密文的多位。基本操作是排列permutation。
2)混淆:消除统计特性,使明文密钥与密文的依赖关系变得尽可能的复杂,复杂的非线性代替变换会产生较好的混淆效果。基本操作是替换substitution。
为密码体制中的对称密码体制,明文按64位进行分组,密钥长64位,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是校验位, 使得每个密钥都有奇数个1,分组后的明文组和56位的密钥按位替代或交换的方法形成密文组的加密方法。
下图是算法整体框架图,明文采取读文件方式读入,密钥是自定义。
DES加密算法使用的是feistel结构,分组长度是64比特。
对于一个64比特的明文,首先将其进行一个IP置换,比如表中第一位58的意思是将明文的第58位挪到第1位。
这仅仅起到了一个打乱明文的作用,几乎没有提高安全性。
下图是16轮循环加密算法流程,首先要被加密的明文首先被分成左右两块,右边的块直接作为下一轮的左边输入,同时我们将右边的块使用一个有轮密钥的轮函数进行处理,将得到的结果与上一轮(若是第一轮则是明文)左边的输入进行一个异或操作,得到的结果作为下一轮的右边输入。
注:算法是可以调用OpenSSL库来完成,不过下载配置麻烦,所以des.h相当于把库文件自己写出来
本项目分为3个文件:main.cpp、des.h、des.cpp
//des.h
#ifndef DES_H_INCLUDED
#define DES_H_INCLUDED
#include
#include
using namespace std;
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
};
// 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
};
// 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 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
};
// 压缩置换表
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
};
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)
{//字符串转比特串
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 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_roundkey(string* roundkey, string key)
{//获取子密钥
string bit_key = byte2bit(key);
string transformed_key = transform(bit_key, PC1_Table, 56);//PC1是一个将64比特数据进行挑选并重新排列的过程
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]);
roundkey[i] = transform(C + D, PC2_Table, 48);//在进行左移之后将两部分数据混合起来,使用PC2的表进行一个置换,即得到了48比特的轮密钥
}
}
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);//6进4出的S盒
return C;
}
//main.cpp
#include
#include
#include
#include
#include "des.h"
#include "des.cpp"
enum MODE{encrypt,decrypt}mode;//标识是加密还是解密
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];//轮密钥
string hex_to_bit(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 bit_to_hex(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<(int)s.length();i++)
{
if(s[i]==1)
cout<<1;
else
cout<<0;
}
cout<<endl;
}
string stringxor(string a,string b)//字符串异或,将每个字符的二进制异或后再组合
{
for (int i=0;i<(int)a.length();i++)
a[i]^=b[i];
return a;
}
string enfunction(string R,string K)//f函数
{
string ER=transform(R,EXTENSION_Table,48);//E扩展,将一个32比特的数据扩展成48比特
string BS=stringxor(ER,K);//与轮密钥异或
string f;
for(int i=0;i<8;i++)
{
string B(BS.substr(i*6,6));//取6个比特位
string C=B2C(B,i);//C是4位,S盒把6位数据转换位4位了
f+=C;
}
return f;//F循环8轮,变为32位数据
}
string encryption(string L,string R,string* K)//16轮迭代
{
if(mode==encrypt)
{
for(int i=0;i<16;i++)
{
string tmp(L);//保存左边
L=R;//将右边赋值给左边
R=stringxor(tmp,enfunction(R,K[i]));//右边通过S盒加密后与左边异或
// 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置换是IP置换的逆过程
cout<<endl;
}
string des(string data,string key)//DES实现单块加解密
{
string bit_data;
if (mode==encrypt)//将信息转换为二进制字符串
bit_data=byte2bit(data);
else
bit_data=hex_to_bit(data);
// cout<<"信息-二进制:";
// output(bit_data);
bit_data =transform(bit_data,IP_Table,64);//对于一个64比特的明文,首先我们将其进行一个IP置换
// cout << "置换-二进制:";
// 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)//分组链接模式
{
string result;
string block;
string tmp;
string initvector(init_vector);
if(mode==encrypt)
{
for(int i=0;i<int(data.length()>>3);i++)//右移3位即除以8
{
block=data.substr(i*8,8);//获得字符串中从第i * 8位开始的长度为8的字符串
cout<<"第"<<i+1<<"块明文:"<<block<<"\t ";
tmp=des(stringxor(block,initvector),key);//将字符串和密钥异或
cout<<"第"<<i+1<<"块密文:"<<tmp<<endl;
initvector = bit2byte(hex_to_bit(tmp));//修改向量
result+=tmp;
}
cout<<"完整密文:";
}
else
{
for(int i=0;i<int(data.length()>>4);i++)//16个为一组
{
tmp=data.substr(i*16,16);
cout<<"第"<<i+1<<"块密文:"<<tmp<<"\t ";
block=stringxor(des(tmp,key),initvector);
cout<<"第"<<i+1<<"块明文:"<<block<<endl;
initvector=bit2byte(hex_to_bit(tmp));
result+=block;
}
cout<<"完整明文:"<<endl;
}
cout<<result<<endl<<endl;
return result;
}
int main()
{
ifstream datafile("text.txt");//创建个文件流对象
ostringstream buf;//将文件读入到ostringstream字符串流对象buf中
buf<<datafile.rdbuf();// 把文件流中的字符输入到字符串流中
string plaintext=buf.str();//返回与流对象buf关联的字符串
cout<<"明文:";
cout<<plaintext<<endl;
string key("abc10101");//设定密钥
get_roundkey(roundkey, key);//轮密钥,16个轮密钥由原始密钥生成,每个单块加密时16个轮密钥是一样的。
// for(int y=0;y<16;y++)
// {
// cout<<"roundkey "<
// output(roundkey[y]);
// }
char c=0;
while(plaintext.length()%8!=0)//明文不足8位自动补0
plaintext+=c;
string ciphertext;
string init_vector=key; //设定分组链接的初始向量
mode=encrypt;//开始加密
ciphertext=CBC(plaintext,key,init_vector);
mode=decrypt;//表示开始解密
plaintext=CBC(ciphertext,key,init_vector);
return 0;
}