CBC模式的DES加解密
一、实验内容
学习并完成对称加解密中的DES加解密以及CBC模式的DEC加解密。
二、实验原理
2.1 DES加解密原理
DES算法是一种最通用的对称密钥算法,因为算法本身是公开的,所以其安全性在于密钥的安全性。基于密钥的算法通常有两类:对称算法和公开密钥算法。对称算法的对称性体现在加密密钥能够从解密密钥推算出来,反之亦然。在大多数对称算法中,加解密的密钥是相同的,DES就是这样。对称密钥算法的加解密密钥都是保密的。
Des流程图
Des加密主要可以分为四个步骤:1.初始置换。2.密钥的运算。3.密码函数的运算。4.逆置换。
初始置换和为逆置换都是根据置换表进行的,复杂的地方在于密码的获得和函数f的运算。
初始置换表:
逆置换表:
密码获得:
1.我们在读入64位原密码后首先会根据置换表一进行第一次压缩置换,将64位密码中的标志位去除,得到56位的原密码。
2.下一步我们将剩余的56位原密码左边28位标为C0,右边28位标为D0,根据左移规则进行循环左移后得到C1和D1,将C1,D1合起来进行压缩置换2,得到48位的密钥k1。
3.接下来的步骤就可以进行循环处理,将第二步得到的C1,D1再次按规则进行循环左移得到C2和D2,再次进行压缩置换2得到48位的密钥k2,之后的k3–k16依次如此获得。
**轮函数的运转:**轮函数为{Li=Ri-1;Ri=Li-1^f(ki,Ri-1),i=1,2,16}。这里R0指64位明文的后32位,L0指64位明文的前32位,我们可以看到Li是可以很方便得到的,但是轮函数F很复杂,我们可以分为以下步骤进行。
1.我们将输入进来的32位Ri-1进行扩展置换,得到48位的一组数。
2.将这个48位的数与对应的48位密钥进行异或运算之后得到新48位的数。再将这48位分成8组,每组6位,放入对应的S盒进行6–>4位的转换(第一位和第六位组合起来是行数,中间四位组合起来是列数),得到32位数据,将这32位数据进行p盒置换之后,就得到轮函数结果。
3.再和Li-1进行异或即可得到Ri。
2.2 3DES加解密原理
我们在得到des加密模块之后,就可以很方便的进行3des加密,3des加密不是指加密三次,而是指第一次调用加密des函数进行运算,第二次调用解密des函数进行运算,第三次在进行加密des,三次的密钥都不一样的,我们可以单独在主函数调用三次这个模块。
3DES加密过程为:C=Ek3(Dk2(Ek1§))
3DES解密过程为:P=Dk1((EK2(Dk3©))
3DES:trip DES(3级DES,是DES的升级版,主要是为了应对快速发展的计算机能力,能够在24小时内暴力破解传统的56位长度密钥的DES,而3DES相当于对统一数据块采用3次DES,3次DES使用的密钥如果完全不同,则密钥长度可以达到168位,大大延长了被暴力破解的时间)
2.3 分组密码CBC加解密模式原理
CBC模式是指:大部分的加解密流程和EBC电子密码本一样,不同的是每个明文组在加密前与前一组密文按位异或运算后,再进行加密变换。第一组加密时有一个初始向量IV,第一组和这个初始向量IV异或运算。采用CBC方式加密时,双方不仅要共享加解密密钥,还要共享初始向量IV,解密时每组密文先进行解密,再与前一组密文进行异或运算,还原出明文。
使用CBC模式加解密时,初始换向量IV和密钥一样重要,在加密时由于引入反馈机制,所以不能进行并行运算处理,同时,相同的明文在相同的密钥下,也会得到不同的密文分组,CBC模式隐藏了明文的统计特性,且如果密文分组里的一个比特错误,就会影响到本组和其后的每一个分组的解密。
CBC模式加密流程图:
CBC模式解密流程图:
2.4 填充原理
对称加密中的分组加解密都有一个问题,就是在分组的时候最后的那一组可能不会刚好为一组,所以我们需要进行填充处理,填充处理分为两种情况,第一种是刚好分为完整的一组,第二种为不满一组的情况,一般第二种较多。策略如下:
1.刚好分为一组的时候:刚好分为一组时,我们单独加一个分组,全部设为0。
2.当一个分组不够时,我们补齐8个,最后一个为补充的个数,比如@@@,差5个我们就补充为@@@00005。
三、实验过程
3.1 变量说明
3.1.1 主函数变量说明
Int y//几DES加密选择
Int X//主函数加解密选择
String mingwenfile//明文的文件地址
String miyaofile//密钥的文件地址
String miwenfile//密文的文件地址
String jmmingwenfile//解密后的明文文件地址
3.1.2 其他重要变量说明
- encrypt // 函数中加密选择
- decrypt//函数中解密选择
- Pad//填充,数据长度不足8byte的倍数时,以0x00补足,如果是8byte的倍数,补8个0x00。
- const char IP_Table[64] //初始置换ip,将读入的明文串进行特定顺序重排,之后将前32位和后32位分别记为L0和R0。
- const char IPR_Table[64]// 初始置换ip-1,将最终得到的R16,I16进行初始置换的逆置换后得到。
- const char E_Table[48]//扩展置换,在计算轮函数时将32位输入扩展位48位,在与子密钥进行安位模2加运算。
- const char P_Table[32]//p盒置换。
- const char PC1_Table[56]//置换选择一,去掉标识位。
- const char PC2_Table[48]//置换选择二,将循环左移之后的56位进行置换选择二得到48位,即为密钥Ki。
- const char LOOP_Table[16]//生成子密钥时,生成Ci/Di时进行循环左移的位数。
- const char S_Box[8][4][16]//s盒,轮函数里生成s1到s8后再进行P盒置换就成轮函数f(Ri-1,Ki)。
3.2 函数功能说明
3.2.1主函数说明
主函数起到调用的作用,调用加解密模块以及选择几DES加密的功能。加解密的功能都在模块函数中实现。
3.2.2 其他重要函数说明(以下为举例)
1)char * CDES::HexToStr(string s)
作用:十六进制字符串转化为ASCII字符串 每2位十六进制字符 = 8 bit = 1 ASCII字符。
参数:需要转换成ASCLL字符串的十六进制字符串。
返回:转换后的字符串。
2)string CDES::StrToHex(char* bytes, int bytelength)
作用:字符串转化为十六进制 一个字符 = 一个ASCII码 = 两位十六进制数 。
参数:字符串,以及其长度。
返回:转换后的字符串。
3)static void zuoyi(bool *In, int len, int loop)
作用:按规则循环左移。
参数:需要读入的字符串,字符串长度,移动规则表。
返回:左移后的字符串。
4)static void Xor(bool *InA, const bool *InB, int len)
作用:两个bit流进行异或。
参数:bit流A和B,长度。
返回:异或后得到的串。
5)static void zhihuan(bool *Out, bool *In, const char *Table, int len)
作用: 把Bit流按表进行位转化。
参数:读入的bit流和输出的bit流,长度,需要置换的表。
返回:置换后的表。
6)void CDES::SetSubKey(PSubKey pSubKey, const unsigned char Key[8])
作用:计算密码并填充到pSubKey中。
参数:数组pSubKey,读入的8字节16进制数。
返回:将计算得到的结果存入密码数组中。
7)static void Sbox(bool Out[32], const bool In[48])
作用:s盒模块。
参数:读入的48位串,经过6–>4的处理的串。
返回:处理后的串。
8)static void lunhs(bool In[32], const bool Ki[48])
作用:轮函数模块。
参数:读入的32位Ri,48位密钥。
返回:处理好的串。
9)bool RunDES(bool bType, bool bMode, int PaddingMode, const unsigned char* In,unsigned char* Out, unsigned datalen, const unsigned char* Key, unsigned keylen)
作用:执行DES对算法进行加解密。
参数:bType:加解密类型;bMove:默认为1;in:待加密串指针;out:待传输串指针;datalen:待加密串长度;key:密钥。Keylen:密钥长度。
返回:成功或失败(true/false)。
10)bool RunPad(bool bType, int nType, const unsigned char* In, unsigned datalen, unsigned char* Out, unsigned& padlen)
作用:填充函数。
参数:nType:pad类型;in:数据串指针;out:填充输出串指针;datalen:数据长度;padlen:填充后的长度。
返回:返回处理成功或失败(true/false)。
11)bool CDES::EnCode(string mingwenfile,string miyaofile,string miwenfile)
作用:加密入口。
参数:文明、密钥、密文文件的地址。
返回:返回处理成功或失败(true/false)。
12)bool CDES::DeCode(string miyaofile,string miwenfile,string jmhmingwenfile)
作用:解密入口。
参数:密钥、密文、解密后明文的文件地址。
返回:返回处理成功或失败(true/false)。
3.3 流程图
3.3.1 主函数流程图
3.3.2 其他重要函数流程图
1.子密钥流程图:
2.轮函数流程图:
3.加密入口模块的流程图:
4.解密入口流程图:
5.选择界面流程图:
四、实验结果与截图
1.选择界面:
2.一次DES加解密:
3.3DES加密:
**4.CBC模式加密:**在这里插入图片描述
5.CBC模式解密:
代码奉上
#include <bits/stdc++.h>
#include<fstream>
using namespace std;
class CDES {
public:
CDES();
virtual ~CDES();
/*十六进制字符串转化为ASCII字符串 每2位十六进制字符 = 8 bit = 1 ASCII字符*/
static char* HexToStr(string s);
/*字符串转化为十六进制 一个字符 = 一个ASCII码 = 两位十六进制数 */
static string StrToHex(char* bytes, int bytelength);
//进行加密
static bool EnCode(string q,string w,string e);
static bool DeCode(string w,string e,string r);
protected:
typedef bool(*PSubKey)[16][48];
static bool RunDES(bool bType, bool bMode, int PaddingMode, const unsigned char* IV, const unsigned char* In,
unsigned char* Out, unsigned datalen, const unsigned char* Key, unsigned keylen);
static void DES(unsigned char Out[8], const unsigned char In[8], const PSubKey pSubKey, bool Type);
//计算并填充子密钥到SubKey数据中
static void SetSubKey(PSubKey pSubKey, const unsigned char Key[8]);
static bool RunPad(bool bType, int nType, const unsigned char* In, unsigned datalen,
unsigned char* Out, unsigned& padlen);
private:
enum {
encrypt = 0, // 加密
decrypt,
};
enum {
pad = 0,
};
enum {
ECB = 0, // ECB模式
CBC=1, // CBC模式
};
};
//初始置换ip,将读入的明文串进行特定顺序重排,之后将前32位和后32位分别记为L0和R0
const char 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
};
// 初始置换ip-1,将最终得到的R16,I16进行初始置换的逆置换后得到
const char IPR_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
};
//扩展置换,在计算轮函数时将32位输入扩展位48位,在与子密钥进行安位模2加运算
const char E_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盒置换
const char 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
};
//置换选择一,去掉标识位
const char 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
};
//置换选择二,将循环左移之后的56位进行置换选择二得到48位,即为密钥Ki
const char 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
};
//生成子密钥时,生成Ci/Di时进行循环左移的位数
const char LOOP_Table[16] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };
//s盒,轮函数里生成s1到s8后再进行P盒置换就成轮函数f(Ri-1,Ki)
const char 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
};
CDES::CDES() {}
CDES::~CDES() {}
/*加密入口*/
/*十六进制字符串转化为ASCII字符串 每2位十六进制字符 = 8 bit = 1 ASCII字符*/
char * CDES::HexToStr(string s) {
int temp = 0;
int len = s.length();
char * result = new char[len / 2 + 1];
/*例如十六进制字符串为ACBDC
ABCD的ascll码分别为:0100 0001
0100 0010
0100 0011
0100 0100
则是(s[i + j] - 'A' + 10)=0000 1010 ,因为这是第一轮,i=0,j=0,所以(4 * (1 - j))=4,需要左移四位,即s[0]=1010 0000
同理,C转化后为00001100;j第一轮for循环结束,两个16进制数加起来成为一个temp,存放在result[0]中*/
for (int i = 0; i < len; i += 2) {
for (int j = 0; j < 2; j++) {
if (s[i + j] >= '0' && s[i + j] <= '9') {
temp += (s[i + j] - '0') << (4 * (1 - j));
}
else if (s[i + j] >= 'A' && s[i + j] <= 'F') {
temp += (s[i + j] - 'A' + 10) << (4 * (1 - j));
}
else if (s[i + j] >= 'a'&& s[i + j] <= 'f') {
temp += (s[i + j] - 'a' + 10) << (4 * (1 - j));
}
}
result[i / 2] = (char)temp;
temp = 0;
}
result[len / 2] = '\0';
return result;
}
/*字符串转化为十六进制 一个字符 = 一个ASCII码 = 两位十六进制数 */
string CDES::StrToHex(char* bytes, int bytelength) {
string str("");
string str2("0123456789ABCDEF");
for (int i = 0; i < bytelength; i++) {
int b;
b = 0x0f & (bytes[i] >> 4);
str.append(1, str2.at(b));
b = 0x0f & bytes[i];
str.append(1, str2.at(b));
}
return str;
}
/*
把BYTE转化为Bit流
bits: Bit流的长度[in]
*/
static void ByteToBit(bool *Out, const unsigned char *In, int bits) {
for (int i = 0; i < bits; ++i)
Out[i] = (In[i >> 3] >> (7 - i & 7)) & 1;
}
/*
把Bit转化为Byte流
lens: Bit流的长度
*/
static void BitToByte(unsigned char *Out, const bool *In, int lens) {
memset(Out, 0, lens >> 3);
for (int i = 0; i < lens; ++i)
Out[i >> 3] |= In[i] << (7 - i & 7);
}
/* 把BIT流按位向左循环移动
*/
static void zuoyi(bool *In, int len, int loop) {
bool Tmp[256];
memcpy(Tmp, In, loop);
memcpy(In, In + loop, len - loop);
memcpy(In + len - loop, Tmp, loop);
}
/*
把两个Bit流进行异或
*/
static void Xor(bool *InA, const bool *InB, int len) {
for (int i = 0; i < len; ++i)
InA[i] ^= InB[i];
}
/*
把两个Bit流按表进行位转化
Table: 转化需要的表指针
*/
static void zhihuan(bool *Out, bool *In, const char *Table, int len) {
bool Tmp[256];
for (int i = 0; i < len; ++i)
Tmp[i] = In[Table[i] - 1];
memcpy(Out, Tmp, len);
}
//计算子密钥并且填充到pSubKey中
void CDES::SetSubKey(PSubKey pSubKey, const unsigned char Key[8]) {
bool K[64], *KL = &K[0], *KR = &K[28];
ByteToBit(K, Key, 64);
zhihuan(K, K, PC1_Table, 56);
for (int i = 0; i < 16; ++i) {
zuoyi(KL, 28, LOOP_Table[i]);
zuoyi(KR, 28, LOOP_Table[i]);
zhihuan((*pSubKey)[i], K, PC2_Table, 48);
}
}
/*
S盒模块
*/
static void Sbox(bool Out[32], const bool In[48]) {
for (char i = 0, j, k; i < 8; ++i, In+= 6, Out += 4)
{
j = (In[0] << 1) + In[5];
k = (In[1] << 3) + (In[2] << 2) + (In[3] << 1) + In[4];
for (int l = 0; l < 4; ++l)
Out[l] = (S_Box[i][j][k] >> (3 - l)) & 1;
}
}
//轮函数模块
static void lunhs(bool In[32], const bool Ki[48]) {
bool MR[48];
zhihuan(MR, In, E_Table, 48);
Xor(MR, Ki, 48);
Sbox(In, MR);
zhihuan(In, In, P_Table, 32);
}
bool CDES::RunDES(bool bType, bool bMode, int PaddingMode, const unsigned char* Iv, const unsigned char* In,
unsigned char* Out, unsigned datalen, const unsigned char* Key, unsigned keylen)
{
memset(Out, 0x00, strlen((const char*)Out));
unsigned char* outbuf = Out;
/*判断输入合法性*/
if (!(outbuf && Key && keylen >= 8)) // 空字符串加密的时候In和datalen都为0,应该去掉此判断
return false;
unsigned char* inbuf = new unsigned char[datalen + 8]{ 0 };
memcpy(inbuf, In, datalen);
unsigned padlen = datalen;
/* 根据填充模式填充 */
if (!RunPad(bType, PaddingMode, In, datalen, inbuf, padlen)) {
delete[]inbuf;
inbuf = NULL;
return false;
}
unsigned char* tempBuf = inbuf;
bool m_SubKey[3][16][48]; //密钥
/*构造并生成SubKeys */
unsigned char nKey = (keylen >> 3) >= 3 ? 3 : (keylen >> 3);
for (int i = 0; i < nKey; i++) {
SetSubKey(&m_SubKey[i], &Key[i << 3]);
}
/*ECB模式*/
if (bMode == ECB) {
if (nKey == 1) {
int j = padlen >> 3;
for (int i = 0, j = padlen >> 3; i < j; ++i, outbuf += 8, tempBuf += 8)
DES(outbuf, tempBuf, &m_SubKey[0], bType);
}
else if (nKey == 2) {
for (int i = 0, j = padlen >> 3; i < j; ++i, outbuf += 8, tempBuf += 8) {
DES(outbuf, tempBuf, &m_SubKey[0], bType);
DES(outbuf, outbuf, &m_SubKey[1], !bType);
DES(outbuf, outbuf, &m_SubKey[0], bType);
}
}
else {
for (int i = 0, j = padlen >> 3; i < j; ++i, outbuf += 8, tempBuf += 8) {
DES(outbuf, tempBuf, &m_SubKey[bType ? 2 : 0], bType);
DES(outbuf, outbuf, &m_SubKey[1], !bType);
DES(outbuf, outbuf, &m_SubKey[bType ? 0 : 2], bType);
}
}
}
/*CBC模式*/
else {
unsigned char cvec[8] = "";
unsigned char cvin[8] = "";
memcpy(cvec, Iv, 8);
for (int i = 0, j = padlen >> 3; i < j; ++i, outbuf += 8, tempBuf += 8) {
if (bType == CDES::encrypt) {
for (int j = 0; j < 8; ++j)
cvin[j] = tempBuf[j] ^ cvec[j];
}
else {
memcpy(cvin, tempBuf, 8);
}
DES(outbuf, cvin, &m_SubKey[0], bType);
if (bType == CDES::encrypt) {
memcpy(cvec, outbuf, 8);
}
else {
for (int j = 0; j < 8; ++j)
outbuf[j] = outbuf[j] ^ cvec[j];
memcpy(cvec, cvin, 8);
}
}
}
if (inbuf) {
delete[]inbuf;
inbuf = NULL;
}
if (bType == CDES::decrypt) {
if (PaddingMode == pad) {
//待补充
}
}
return true;
}
/* DES单元运算 */
void CDES::DES(unsigned char Out[8], const unsigned char In[8], const PSubKey pSubKey, bool Type) {
bool M[64], tmp[32], *Li = &M[0], *Ri = &M[32];
ByteToBit(M, In, 64);
zhihuan(M, M, IP_Table, 64);
if (Type == encrypt) {
for (int i = 0; i < 16; ++i) {
memcpy(tmp, Ri, 32);
lunhs(Ri, (*pSubKey)[i]);
Xor(Ri, Li, 32);
memcpy(Li, tmp, 32);
}
}
else {
for (int i = 15; i >= 0; --i) {
memcpy(tmp, Ri, 32);
lunhs(Ri, (*pSubKey)[i]);
Xor(Ri, Li, 32);
memcpy(Li, tmp, 32);
}
}
zuoyi(M, 64, 32);
zhihuan(M, M, IPR_Table, 64);
BitToByte(Out, M, 64);
}
bool CDES::RunPad(bool bType, int nType, const unsigned char* In, unsigned datalen, unsigned char* Out, unsigned& padlen) {
if (nType < pad) //|| nType > pad
return false;
if (In == NULL || datalen < 0 || Out == NULL)
return false;
int res = (datalen & 0x07); //得到datalen的低三位 也就是对8取余
if (bType == CDES::decrypt) {
// padlen = datalen;
padlen = datalen / 2;
memcpy(Out, In, datalen);
return true;
}
memcpy(Out, In, datalen);
padlen = datalen;
if (res != 0) {
padlen += (8 - res);//使成为8的倍数
if (nType == pad) {
memset(Out + datalen, 0x00, 8 - res);
}
}
return true;
}
/*加密入口*/
bool CDES::EnCode(string mingwenfile,string miyaofile,string miwenfile) {
string msg, sKey,IV = "",ivfile;
int mode;
cout<<"请输入明文地址:"<<endl;
cin>>mingwenfile;
//读入明文并打印
ifstream msgFile(mingwenfile);
if (!msgFile.is_open()) {
cout << "加密时无法打开明文文件!" << endl;
return false;
}
getline(msgFile, msg);
cout << "明文: " << msg << endl;
msgFile.close();
//读入密钥并打印
cout<<"请输入密钥地址:"<<endl;
cin>>miyaofile;
ifstream keyFile(miyaofile);
if (!keyFile.is_open()) {
cout << "加密时无法打开密钥文件!" << endl;
return false;
}
keyFile >> sKey;
cout << "密钥: " << sKey << endl;
sKey = HexToStr(sKey);
keyFile.close();
cout<<"选择加密模式,ECB模式为0,CBC模式为1"<<endl;
cin>>mode;
if (mode == CBC) {
//读入IV并打印
cout << "读入IV文件地址:" << endl;
cin >> ivfile;
ifstream IVFile(ivfile);
if (!IVFile.is_open()) {
cout << "不能打开IV文件!" << endl;
return false;
}
IVFile >> IV;
cout << "IV: " << IV << endl;
IV = HexToStr(IV);
IVFile.close();
}
unsigned char buff[1024] = { 0 };
CDES::RunDES(CDES::encrypt, mode, CDES::pad, (const unsigned char*)IV.c_str(), (const unsigned char*)msg.c_str(), buff, strlen(msg.c_str()), (const unsigned char*)sKey.c_str(), strlen(sKey.c_str()));
string restr = StrToHex((char*)buff, strlen((char*)buff));
cout<<"请输入密文地址:"<<endl;
cin>>miwenfile;
cout<<"密文:"<<restr<<endl;
ofstream cipherFile(miwenfile);
if (!cin || !cipherFile.is_open())
return false;
cipherFile << restr;
cout <<"加密时写入密文成功!" << endl;
cipherFile.close();
return true;
}
/*解密入口*/
bool CDES::DeCode(string miyaofile,string miwenfile,string jmhmingwenfile) {
string miwen, sKey,IV = "",ivfile;
int mode;
//读入密文并打印
cout<<"请输入密文地址:"<<endl;
cin>>miwenfile;
ifstream ciphFile(miwenfile);
if (!ciphFile.is_open()) {
cout << "无法打开密文文件!";
return false;
}
ciphFile >> miwen;
cout << "密文: "<< miwen << endl;
ciphFile.close();
cout<<"请输入要读入的密钥文件名:"<<endl;
cin>>miyaofile;
ifstream keyFile(miyaofile);
if (!keyFile.is_open()) {
cout << "无法打开密钥文件!" << endl;
return false;
}
keyFile >> sKey;
cout << "密钥: " << sKey << endl;
sKey = HexToStr(sKey);
keyFile.close();
cout<<"选择解密模式,ECB为0,CBC为1:"<<endl;
cin>>mode;
if(mode==CBC)
{
//读入IV并打印
cout << "请输入iv文件地址:" << endl;
cin >> ivfile;
ifstream IVFile(ivfile);
if (!IVFile.is_open()) {
cout << "不能打开iv文件!" << endl;
return false;
}
IVFile >> IV;
cout << "IV: " << IV << endl;
IV = HexToStr(IV);
IVFile.close();
}
unsigned char ch[1024] = { 0 };
char* c = HexToStr(miwen);
char Out[1024] = { 0 };
CDES::RunDES(CDES::decrypt, mode, CDES::pad, (const unsigned char*)IV.c_str(), (const unsigned char*)c, (unsigned char*)Out, strlen(miwen.c_str()), (const unsigned char*)sKey.c_str(), strlen(sKey.c_str()));
string dmingwen = Out;
cout<<"请输入要读入的解密后明文文件名:"<<endl;
cin>>jmhmingwenfile;
cout << "解密后明文: " << dmingwen << endl;
ofstream decryptedFile(jmhmingwenfile);
if (!cin || !decryptedFile.is_open())
return false;
decryptedFile << dmingwen;
cout << "解密且保存成功!" << endl;
decryptedFile.close();
return true;
}
int main()
{
CDES cdes;
string mingwenfile,miyaofile, miwenfile,jmhmingwenfile;
cout<<"请输入是要进行几加密(仅限于1,2,3)"<<endl;
int y,x;
part:
cin>>y;
if(y<1||y>3)
{
cout<<"错误,请重新输入:"<<endl;
goto part;
}
else{
if(y==1)
{
cout<<"请输入要进行加密还是解密"<<endl;
cout<<"加密为0,解密为1"<<endl;
cin>>x;
if(x==0)
{
cdes.EnCode(mingwenfile,miwenfile,miyaofile);
}
else if(x==1)
{
cdes.DeCode(miwenfile,miyaofile,jmhmingwenfile);
}
}
else if(y==2)
{
cout<<"二次加解密未写"<<endl;
cout<<"请重新输入加密次数:";
goto part;
}
else if(y==3)
{
cout<<"请输入要进行加密还是解密"<<endl;
cout<<"加密为0,解密为1"<<endl;
cin>>x;
if(x==0)
{
cdes.EnCode(mingwenfile,miwenfile,miyaofile);
cout<<"第一次加密结束!"<<endl;
cout<<"第二次加密开始!"<<endl;
cdes.DeCode(miwenfile,miyaofile,jmhmingwenfile);
cout<<"第二次加密结束!"<<endl;
cout<<"第三次加密开始!"<<endl;
cdes.EnCode(mingwenfile,miwenfile,miyaofile);
cout<<"第三次加密结束!"<<endl;
}
else if(x==1)
{
cdes.DeCode(miwenfile,miyaofile,jmhmingwenfile);
cout<<"第一次解密结束!"<<endl;
cout<<"第二次解密开始!"<<endl;
cdes.EnCode(mingwenfile,miwenfile,miyaofile);
cout<<"第二次解密结束!"<<endl;
cout<<"第三次解密开始!"<<endl;
cdes.DeCode(miwenfile,miyaofile,jmhmingwenfile);
cout<<"第三次解密结束!"<<endl;
}
}
}
return 0;
}
部分代码学习与csdn,希望大家能相互学习,完善自己。