项目GitHub地址:https://github.com/joliph/DES_File
TIPS:
1.选择 项目 属性,字符集哪里选择使用多字节字符集,不要用UNICODE字符集
2.项目在Windows 10 + VS2017 + X64 +Release下编译测试通过,非X64版本部分API接口可能不一样
3.肯定有BUG,后续有机会就修,暂时没发现
4.DES算法接口和上篇的算法部分有些许改动
5.CBC模式为外部实现,即DES算法部分只能做ECB模式,确实有点难受,但是能用
6.消息响应函数哪里确实代码风格有些杂乱…
7.加解密过后文件的MD5值可能会发生变化但是不影响使用,因为只是后面被我多加了几个0使其8字节对齐而已
8.CBC模式的初始秘钥为64位的1
界面确实有点丑…
算法测试:
秘钥:“security”
明文:“computercomputer”
ECB加密后的密码:“3B6C72B2710EB5133B6C72B2710EB513”
CBC加密后的密码:“3B6C72B2710EB51339283610A256F03E”
加密算法效率分析:
测试1:23兆字节文件:ECB:4.484秒 CBC:4.971秒
测试2:230兆字节文件:ECB:22.271秒 CBC:24.718秒
ECB效率高于CBC,因为CBC有额外的异或操作,而且后期可以做多线程ECB模式加密,因为ECB可以可以多线程同步运算,而CBC不行
关键函数作用及简要说明
1. DES_Key类的构造函数设计
接收参数:char Char_Key[8]
作用:生成16轮密钥
步骤:
1.调用CharToBit将8个字节的密钥转换成64位
2.调用Transform进行置换选择
3.左右分组
4.16轮循环左移
5.每轮再进行置换选择生成16轮密钥
DES_Key::DES_Key(char Char_Key[8]) {
CharToBit(Bit_Key, Char_Key);
Transform(Bit_Key, Bit_Key, PC1_Table, 56);
bool *C0 = &Bit_Key[0];
bool *D0 = &Bit_Key[28];
for (int i = 0; i < 16; i++) {
RotateL(C0, LOOP_Table[i]);
RotateL(D0, LOOP_Table[i]);
Transform(Round_Key[i], Bit_Key, PC2_Table, 48);
}
}
********************************************************************************
2. Xor矩阵异或函数设计:
接收参数:位矩阵A ,位矩阵B,矩阵位个数
作用:将A矩阵和B矩阵逐位异或,结果更新A矩阵
void Xor(bool *InputA, const bool *InputB, int len) {
for (int i = 0; i < len; i++) {
InputA[i] = InputA[i] ^ InputB[i];
}
}
********************************************************************************
3. CharToBit字符转位矩阵函数设计
接收参数:位矩阵指针 ,字符串指针
作用:将8位字符串转换成64个位矩阵
关键:位测试运算
void CharToBit(bool *Output, const char *Input) {
for (int i = 0; i<64; i++) {
Output[i] = (Input[i / 8] << (i % 8)) & 0x80;
}
}
********************************************************************************
4. Transform置换选择函数设计
接受参数:输出位矩阵指针,输入位矩阵指针,置换表,置换个数
作用:DES加密中的置换选择操作
void Transform(bool *Output, bool *Input, const int *Table, int Tablelen) {
bool temp[256];
for (int i = 0; i < Tablelen; i++) {
temp[i] = Input[Table[i] - 1];
}
memcpy(Output, temp, Tablelen);
}
********************************************************************************
5. RotateL左移函数设计
接受参数:输入位矩阵,左移长度
作用:DES轮秘钥生成中的左移操作,将位矩阵整体循环左移len长度
void RotateL(bool *Input, int len) {
bool temp[28];
memcpy(temp, &Input[len], 28 - len);
memcpy(&temp[28 - len], Input, len);
memcpy(Input, temp, 28);
}
********************************************************************************
6. S_func S盒代换函数设计
接受参数:输出位矩阵,输入位矩阵
作用:DES加密中的S盒替换的函数实现,将48位矩阵压缩成32位
void S_func(bool *Output, bool *Input) {
for (int i = 0; i < 8; i++) {
int row = 2 * Input[6 * i] + 1 * Input[6 * i + 5];
int col = 8 * Input[6 * i + 1] + 4 * Input[6 * i + 2] + 2 * Input[6 * i + 3] + 1 * Input[6 * i + 4];
int s_result = S_Box[i][row][col];
for (int j = 0; j < 4; j++) {
Output[4 * i + j] = (s_result << j) & 0x8;
}
}
}
********************************************************************************
7. F_func F函数设计
接受参数:输入R0矩阵,输入密钥位矩阵
作用:DES加密中的F函数实现,将密钥和密文进行混合加密
步骤:
1. 调用Transform置换选择
2. 调用Xor函数进行矩阵异或
3. 调用S盒函数进行S盒代换
4. 调用Transform置换选择
void F_func(bool *R, bool *Key) {
bool Ex_R[48];
Transform(Ex_R, R, E_Table, 48);
Xor(Ex_R, Key, 48);
S_func(R, Ex_R);
Transform(R, R, P_Table, 32);
}
********************************************************************************
8. Des_Run DES加密函数设计
接受参数:输入明文位矩阵,输入密钥实例,输入加密后的密文存放指针
作用:输入明文进行DES加密,结果写入密文存放矩阵
步骤:
1. 调用Transform置换选择
2. 左右明文分离
3. 16轮加密循环
1. F函数混合密钥加密
2. 矩阵异或
3. S函数代换压缩
4. 调用Transform置换选择
void Des_Run(bool *Bit_Mingwen, DES_Key DES_Key,char *pNewFileBuf) {
Transform(Bit_Mingwen, Bit_Mingwen, IP_Table, 64);
bool *L0 = &Bit_Mingwen[0];
bool *R0 = &Bit_Mingwen[32];
for (int i = 0; i < 16; i++) {
bool temp[32];
memcpy(temp, R0, 32);
F_func(R0, DES_Key.Round_Key[i]);
Xor(R0, L0, 32);
memcpy(L0, temp, 32);
}
bool temp[32];
memcpy(temp, R0, 32);
memcpy(R0, L0, 32);
memcpy(L0, temp, 32);
Transform(Bit_Mingwen, Bit_Mingwen, IPR_Table, 64);
ShowResult(Bit_Mingwen, pNewFileBuf);
}
********************************************************************************
9. Re_Des_Run DES解密函数设计
接受参数:输入密文位矩阵,输入密钥实例,输入加密后的明文存放指针
作用:输入明文进行DES解密,结果写入明文存放矩阵
步骤:
5. 调用Transform置换选择
6. 左右明文分离
7. 16轮解密循环
4. F函数混合密钥解密
5. 矩阵异或
6. S函数代换压缩
8. 调用Transform置换选择
void Re_Des_Run(bool *Bit_Mingwen, DES_Key DES_Key, char *pNewFileBuf) {
Transform(Bit_Mingwen, Bit_Mingwen, IP_Table, 64);
bool *L0 = &Bit_Mingwen[0];
bool *R0 = &Bit_Mingwen[32];
for (int i = 0; i < 16; i++) {
bool temp[32];
memcpy(temp, R0, 32);
F_func(R0, DES_Key.Round_Key[15-i]);
Xor(R0, L0, 32);
memcpy(L0, temp, 32);
}
bool temp[32];
memcpy(temp, R0, 32);
memcpy(R0, L0, 32);
memcpy(L0, temp, 32);
Transform(Bit_Mingwen, Bit_Mingwen, IPR_Table, 64);
ShowResult(Bit_Mingwen, pNewFileBuf);
}
********************************************************************************
10. ShowResult结果显示函数设计
接受参数:输入64位密文位矩阵,输入加密后的明文存放指针
作用:将64位位矩阵转换成16进制存储在指针指向的内存中
void ShowResult(const bool Input[64],char *pNewFileBuf) {
int Character[8];
for (int i = 0; i<8; i++) {
pNewFileBuf[i] = char(128 * Input[0 + i * 8] + 64 * Input[1 + i * 8] + 32 * Input[2 + i * 8] + 16 * Input[3 + i * 8] +8 * Input[4 + i * 8] + 4 * Input[5 + i * 8] + 2 * Input[6 + i * 8] + 1 * Input[7 + i * 8]);
}
}
********************************************************************************
11. OnBnClickedChose文件选择消息响应按钮
作用:响应文件选择按钮,将文件读入内存,使文件按8位对齐
void CDESFileDlg::OnBnClickedChose(){
CFileDialog dlg(TRUE, NULL, NULL,
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
(LPCTSTR)_TEXT("All Files (*.*)|*.*||"), NULL);
if (dlg.DoModal() == IDOK)
FilePath = dlg.GetPathName();
else
return;
UpdateData(FALSE);
File_Handle = CreateFile(FilePath,
GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (File_Handle == INVALID_HANDLE_VALUE) {
MessageBoxA("加载文件失败!","Error", MB_OK);
File_Handle = NULL;
return;
}
FileSize = GetFileSize(File_Handle, NULL);
int need_add = 0;
if(FileSize % 8 != 0){
need_add = 8 - (FileSize % 8);
}
pFileBuf = new char[FileSize+ need_add];
DWORD ReadSize = 0;
ReadFile(File_Handle, pFileBuf, FileSize, &ReadSize, NULL);
memset(pFileBuf + FileSize, 0, need_add * sizeof(char));
FileSize += need_add;
CloseHandle(File_Handle);
File_Handle = NULL;
}
********************************************************************************
12. OnBnClickedEncrypt加密消息响应按钮
作用:响应加密按钮,调用DES加密函数对文件进行加密,将新文件写入磁盘
分支:ECB加密+CBC加密
void CDESFileDlg::OnBnClickedEncrypt(){
UpdateData(TRUE);
if (!Check()) {
return;
}
char *Char_Key= (char*)CString_Key.GetBuffer(0);
DES_Key Input_Key(Char_Key);
int count = FileSize / 8;
pNewFileBuf = new char[FileSize];
for(int i=0;i<count;i++){
bool Bit_Mingwen[64];
CharToBit(Bit_Mingwen, pFileBuf);
if (Ls_CBC && i != 0) {
CBC_Xor(Bit_Mingwen,pFileBuf, pNewFileBuf-8);
}
Des_Run(Bit_Mingwen, Input_Key, pNewFileBuf);
pFileBuf += 8;
pNewFileBuf += 8;
}
pNewFileBuf -= count * 8;
int n=FilePath.ReverseFind('.');
CString NewFilePath = FilePath.Left(n+1);
NewFilePath+="encrypted";
HANDLE NewFile_Handle=CreateFile(NewFilePath,
GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD WriteSize = 0;
WriteFile(NewFile_Handle, pNewFileBuf, FileSize, &WriteSize, NULL);
CloseHandle(NewFile_Handle);
NewFile_Handle = NULL;
MessageBoxA("加密完成", "Nice", NULL);
}
********************************************************************************
13. OnBnClickedDecrypt解密消息响应按钮
作用:响应解密按钮,调用DES解密函数对文件进行解密,将新文件写入磁盘
分支:ECB解密+CBC解密
void CDESFileDlg::OnBnClickedDecrypt(){
UpdateData(TRUE);
if (!Check()) {
return;
}
char *Char_Key = (char*)CString_Key.GetBuffer(0);
DES_Key Input_Key(Char_Key);
int count = FileSize / 8;
pNewFileBuf = new char[FileSize];
for (int i = 0; i<count; i++) {
bool Bit_Mingwen[64];
CharToBit(Bit_Mingwen, pFileBuf);
Re_Des_Run(Bit_Mingwen, Input_Key, pNewFileBuf);
if (Ls_CBC && i != 0) {
CBC_Xor(Bit_Mingwen, pNewFileBuf, pFileBuf-8);
ShowResult(Bit_Mingwen, pNewFileBuf);
}
pFileBuf += 8;
pNewFileBuf += 8;
}
pNewFileBuf -= count * 8;
int n = FilePath.ReverseFind('.');
CString NewFilePath = FilePath.Left(n + 1);
NewFilePath += "decrypted";
HANDLE NewFile_Handle = CreateFile(NewFilePath,
GENERIC_READ | GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD WriteSize = 0;
WriteFile(NewFile_Handle, pNewFileBuf, FileSize, &WriteSize, NULL);
CloseHandle(NewFile_Handle);
NewFile_Handle = NULL;
MessageBoxA("解密完成", "Nice", NULL);
}
********************************************************************************
14. Check信息完整性检测按钮
作用:响应解密按钮,检测信息是否完整
BOOL CDESFileDlg::Check() {
if (CString_Key.GetLength() != 8) {
MessageBoxA("密钥应为8位","Error",MB_ICONWARNING);
return FALSE;
}
return TRUE;
}