# DES加密算法实现 **Repository Path**: Chenwzh/DES ## Basic Information - **Project Name**: DES加密算法实现 - **Description**: DES加密算法实现(C++) - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 10 - **Forks**: 2 - **Created**: 2018-11-01 - **Last Updated**: 2023-11-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 一、算法简介 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) = ${IP}^{-1}$ * W * $T_{16}$ * $T_{15} $ * ... * $T_{1}$ * $IP$ (M) * M为64位明文,C为64位密文 * IP为初始置换 * $IP^{-1}$ 为IP的逆置换 * $T_{16}$ * $T_{15} $ * ... * $T_1$ 为16轮迭代T,由密钥得出 * W为前后置换,将64位的前32位与后32位交换位置 * 解密过程 * M = DeDES(C)= ${IP}^{-1}$ * W * $T_1$ * ... * $T_{15} $ * $T_{16}$ * $IP$ (C) ### 3. 初始置换IP IP是64位的置换表,代码中表现为64位数组。其中第0位上的数为58,**表示为新得到的64位串的第0位是原来的第57位(注意是57位而不是58位,因为数组上的数只有1-64,并不是0-63,所以要相对应减1,后面的所有置换表均如此)**,新得到的64位串表示位$L_0$$R_0$,分别代表前32位(即低32位)和后32位(即高32位)。置换表在代码中给出。 ### 4. 逆置换$IP^{-1}$ 同上,置换表也在代码中给出。 ### 5. 16轮T迭代 这是最复杂的一个环节 #### (1)第k轮迭代 $L_i$ = $R_{i-1}$ , $R_i$ = $L_{i-1}$ $\bigoplus$ $f$($R_{i-1}$,$k_i$),$i$ = 1, 2, ... , 16 **注:解密过程是反过来的,即i是递减使用的** * $f$是输出32位的Feistel轮函数 * $k_i$长48位,是由密钥K生成的字密钥,共16个 #### (2)字密钥$k_i$生成 * 对K的56位非校验位进行PC-1置换,PC-1置换表共56位,得到$C_0$$D_0$,分别为前28位和后28位,$i$ = 1 * 计算$C_i$ = L$S_i$($C_{i-1}$)和$D_i$ = L$S_i$($D_{i-1}$) * 当i为1,2,9,16时,L$S_i$(A)表示将二进制串A左移一位,否则,左移两位 * 对56位的$C_i$$D_i$进行PC-2置换,得到48位的$k_i$.PC-2置换表共48位,置换表在代码中给出 * 循环得到所有字密钥 #### (3)Feistel轮函数$f$($R_{i-1}$,$k_i$) * 将长度位32位的串$R_{i-1}$进行E-扩展,成为48位的串E($R_{i-1}$),E-扩展所需要的置换表在代码中给出 * 将E($R_{i-1}$)和长度位48位的字密钥$k_i$做二进制的异或运算,$k_i$前面已算出 * 将上一步得到的48位结果分成8个分组,每个分组长度为6位 * 将8个分组分别经过8个不同的**S-盒**($S_1$$S_2$...$S_8$)进行6-4转换,得到8个长度为4位的分组,分组位越低使用的S-盒下标也小,此处是一一对应的,S-盒的转换规则稍后给出 * 将上一步得到的结果按顺序连接在一起得到长度为32位的串 * 将上一步的结果经过P-置换,得到新的32位串,作为$f$($R_{i-1}$,$k_i$) 的返回值。P置换表共32位,代码中给出 #### (4)S-盒转换 每个S-盒均为4行16列的矩阵,矩阵内数据为0-15,可变为二进制串0000-1111。输入的数有6bit,经过转化之后返回4bit。 例:S1为刚刚48位串的最低6位,为“1111001”,自然得使用$S_1$盒。令row = $(11)_{10}$ = 3,其中,高位1为$S_1$的最高位,低位1为$S_1$的最低位。令col = $(1100)_{10}$ = 12,这4个位为中间剩下的4个位。查找$S_1$盒,${[S_1]_{3,12}}$则为输出的四位。注意:3代表的是第4行,因为矩阵下标从0开始,同理12代表13列 8个S-盒的矩阵在代码中给出。 ## 三、代码实现模块及结构 此代码支持**中英文**的加密解密,具体代码请看代码文件:data.hpp存放各个置换表,des.cpp是具体实现文件 ### (1)自定义结构体代表二进制 ```C++ typedef struct data64 { bitset<64> bits; }datas_64; typedef struct data56 { bitset<56> bits; }datas_56; //还有其他不同位数的结构体 ``` ### (2)声明函数模块 ```C++ void init_secret_key(); //初始化密钥 void init_K_i(datas_64 secret_key);//初始化子密钥ki string RKCS_fill(string str); //RKCS#5补齐8个字节 vector string_to_binary(string str); //将字符串转化为二进制数 string binary_to_string(vector v); //将二进制数转化为字符串 vector encryption(vector v); //所有数据的加密算法,第二个参数为密钥 vector Decrypt(vector 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函数 ```C++ 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 v = string_to_binary(Plaintext); vector data1 = encryption(v); cout << "密文: " << binary_to_string(data1) << endl; vector data2 = Decrypt(data1); cout << "解密后明文: " << binary_to_string(data2) << endl; return 0; } ``` ## 四、实验结果 * 输入随机中文 ![image](./result_image/chinese_result.png) * 输入随机英文 ![image](./result_image/english_result.png) * 中英混合 ![image](./result_image/all_result.png)