一、算法简介
DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国国家标准局(NBS)确定为联邦信息处理标准(FIPS),并授权在非密级政府通信中使用,随后该算法在国际上广泛流传开来。
DES是基于56位密钥的对称算法,由于它使用的56位密钥过短,目前已经不被视为一种安全的加密算法。当然你也可以使用DES的派生算法3DES来进行加密,提高破解的难度。
2001年,DES被高级加密标准(AES)所取代。另外,DES已经不作为NIST的标准。
二、算法原理概述
1. 算法基本概念
明文以字节为基本单位,将明文分成每8字节一组,即64位,如果明文最后的分组不够64位,按照PKCS#5规范进行填充,如最后一组只有2字节,那么在末尾补上6个字节,每个字节取值均为06,如果刚刚分组完全,则在末尾添加8个字节,字节取值均为08。
密钥K以位为基本单位,密钥长64位,与明文分组一样长,但密钥因为存在8位奇偶校验位,实际起作用的只有56位,密钥需要加密解密双方均知道才可以进行加密解密。
2. 算法总体结构
以下明文、密文长均为64位,加密或解密后需手动组装起来
- 加密过程
- C = DES(M) = * W * * * … * * (M)
- M为64位明文,C为64位密文
- IP为初始置换
- * $T_{15} $ * … *
- W为前后置换,将64位的前32位与后32位交换位置
- 解密过程
- M = DeDES(C)= * W * * … * * *
3. 初始置换IP
IP是64位的置换表,代码中表现为64位数组。其中第0位上的数为58,表示为新得到的64位串的第0位是原来的第57位(注意是57位而不是58位,因为数组上的数只有1-64,并不是0-63,所以要相对应减1,后面的所有置换表均如此),新得到的64位串表示位,分别代表前32位(即低32位)和后32位(即高32位)。置换表在代码中给出。
4. 逆置换
同上,置换表也在代码中给出。
5. 16轮T迭代
这是最复杂的一个环节
(1)第k轮迭代
= , = (,),
注:解密过程是反过来的,即i是递减使用的
- 是输出32位的Feistel轮函数
- 长48位,是由密钥K生成的字密钥,共16个
(2)字密钥生成
- 对K的56位非校验位进行PC-1置换,PC-1置换表共56位,得到,分别为前28位和后28位,
- 计算 = L()和 = L()
- 当i为1,2,9,16时,L(A)表示将二进制串A左移一位,否则,左移两位
- 对56位的进行PC-2置换,得到48位的.PC-2置换表共48位,置换表在代码中给出
- 循环得到所有字密钥
(3)Feistel轮函数(,)
- 将长度位32位的串进行E-扩展,成为48位的串E(),E-扩展所需要的置换表在代码中给出
- 将E()和长度位48位的字密钥做二进制的异或运算,前面已算出
- 将上一步得到的48位结果分成8个分组,每个分组长度为6位
- 将8个分组分别经过8个不同的S-盒(…)进行6-4转换,得到8个长度为4位的分组,分组位越低使用的S-盒下标也小,此处是一一对应的,S-盒的转换规则稍后给出
- 将上一步得到的结果按顺序连接在一起得到长度为32位的串
- 将上一步的结果经过P-置换,得到新的32位串,作为(,) 的返回值。P置换表共32位,代码中给出
(4)S-盒转换
每个S-盒均为4行16列的矩阵,矩阵内数据为0-15,可变为二进制串0000-1111。输入的数有6bit,经过转化之后返回4bit。
例:S1为刚刚48位串的最低6位,为“1111001”,自然得使用盒。令row = = 3,其中,高位1为的最高位,低位1为的最低位。令col = = 12,这4个位为中间剩下的4个位。查找盒,则为输出的四位。注意:3代表的是第4行,因为矩阵下标从0开始,同理12代表13列
8个S-盒的矩阵在代码中给出。
三、代码实现模块及结构
此代码支持中英文的加密解密,具体代码请看代码文件:data.hpp存放各个置换表,des.cpp是具体实现文件
(1)自定义结构体代表二进制
typedef struct data64
{
bitset<64> bits;
}datas_64;
typedef struct data56
{
bitset<56> bits;
}datas_56;
//还有其他不同位数的结构体
(2)声明函数模块
void init_secret_key(); //初始化密钥
void init_K_i(datas_64 secret_key);//初始化子密钥ki
string RKCS_fill(string str); //RKCS#5补齐8个字节
vector<datas_64> string_to_binary(string str); //将字符串转化为二进制数
string binary_to_string(vector<datas_64> v); //将二进制数转化为字符串
vector<datas_64> encryption(vector<datas_64> v); //所有数据的加密算法,第二个参数为密钥
vector<datas_64> Decrypt(vector<datas_64> v); //所有数据的解密算法,第二个参数为密钥
datas_64 byte_encryption(datas_64 v); //64位的加密算法
datas_64 byte_Decrypt(datas_64 v); //64位的解密算法
datas_64 IP(datas_64 v); //IP置换
datas_64 IP_inverse(datas_64 v); //IP的逆置换
datas_64 W(datas_64 v); //W操作
datas_64 T_iteration(datas_64 v, datas_48* K); //16次T迭代,注意,算法最后的左右交换输出就是W操作,在这里不写,不要重复!!
datas_64 T_iteration_inverse(datas_64 v, datas_48* K); //16次T的逆迭代,算法最后的左右交换输出就是W操作,在这里不写,不要重复!!
datas_32 Feistel(datas_32 R, datas_48 K); //Feistel轮函数
datas_48 E_extend(datas_32 v); //E-扩展
datas_32 S_box_change(datas_48 v); //s盒6-4转化,48位转位32位
//6-4转化,输入一个6位,输出一个4位,index位第index个S-BOX
datas_4 find_in_Sbox(int index, datas_6 v);
datas_32 P(datas_32 v); //Feistel轮函数中的P置换
(3)main函数
int main(){
init_secret_key();
init_K_i(secret_key);
string Plaintext = "";
char c;
cout << "输入明文: ";
while((c = cin.get()) != '\n'){
Plaintext += c;
}
Plaintext = RKCS_fill(Plaintext);
vector<datas_64> v = string_to_binary(Plaintext);
vector<datas_64> data1 = encryption(v);
cout << "密文: " << binary_to_string(data1) << endl;
vector<datas_64> data2 = Decrypt(data1);
cout << "解密后明文: " << binary_to_string(data2) << endl;
return 0;
}
四、实验结果
- 输入随机中文
- 输入随机英文
- 中英混合