DES 加密解密算法的C++实现
北京联合大学
网络管理与信息安全Introduction to Network and Security
——DES 加密解密算法的C++实现
学院:
姓名:
班级:
2011年5月22日
一、目标:学习和了解DES加密算法,设计一个基于DES加密算法的加解密软件
二、意义:锻炼团队合作能力,加强对网络安全技术的了解,学习新的编程软件的使用方法与技术
三、理论基础:DES加密算法
DES 使用一个56 位的密钥以及附加的8 位奇偶校验位,产生最大64 位的分组大小。这是一个迭代的分组密码,使用称为Feistel 的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但最后一个循环不交换。DES 使用16 个循环,使用异或,置换,代换,移位操作四种基本运算。
其入口参数有三个:key、data、mode。key为加密解密使用的密钥,data为加密,解密的数据,mode为其工作模式。当模式为加密模式时,明文按照64位进行分组,形成明文组,key用于对数据加密,当模式为解密模式时,key用于对数据解密。实际运用中,密钥只用到了64位中的56位,这样才具有高的安全性。本次里面用到计算有三种:置换,移位和异或。
算法的整体结构:有16个相同的处理过程,称为“回次”,并在首位各有一次置换。在主处理回次前,数据块被分成两个32位的半块,并被分别处理。图中的⊕符号代表异或操作。“F函数”将数据半块与某个子密钥进行处理。然后,一个F函数的输出与另一个半块异或之后,再与原本的半块组合并交换顺序,进入下一个回次的处理。在最后一个回次完成时,两个半块不必交换顺序。
扩张—用扩张置换将32位的半块扩展到48位,其输出包括8个6位的块,每块包含4位对应的输入位,加上两个邻接的块中紧邻的位。
与密钥混合—用异或操作将扩张的结果和一个子密钥进行混合。16个48位的子密钥—每个用于一个回次的F变换—是利用密钥调度从主密钥生成的。
S盒—在与子密钥混合之后,块被分成8个6位的块,然后使用“S盒”,或称“置换盒”进行处理。8个S盒的每一个都使用以查找表方式提供的非线性的变换将它的6个输入位变成4个输出位。S盒提供了DES的核心安全性—如果没有S盒,密码会是线性的,很容易破解。
P置换—最后,S盒的32个输出位利用固定的置换,“P置换”进行重组。这个设计是为了将每个S盒的4位输出在下一回次的扩张后,使用4个不同的S盒进行处理。
密钥调度右图显示了加密过程中的密钥调度—产生子密钥的算法。首先,使用选择置换1(PC-1)从64位输入密钥中选出56位的密钥—剩下的8位要么直接丢弃,要么作为奇偶校验位。然后,56位分成两个28位的半密钥;每个半密钥接下来都被分别处理。在接下来的回次中,两个半密钥都被左移1或2位(由回次数决定),然后通过选择置换2(PC-2)产生48
位的子密钥—每个半密钥24位。移位(图中由<<标示)表明每个子密钥中使用了不同的位,每个位大致在16个子密钥中的14个出现。
解密过程中,除了子密钥输出的顺序相反外,密钥调度的过程与加密完全相同。
四、详细设计:
1.头文件:DES.h
设计方法:类的共有接口只设计一个,即加密解密函数,用一个bool参数区分是加密还是解密。其他像读文件,写文件,加密变换函数等等设置为私有涉及内容:文件操作,STL向量,数制变换,位操作及函数设计等等。代码:
#include
#include
#include
#include
#include
#include
using namespace std;
/************************************************************************/
/************************************************************************/
/* DES类声明*/
class DES
{
public:
DES();/*构造函数*/
void encrypt(bool flag = true);/*加解密函数*/
private:
string plaintextFilePath_;/*明文文件路径*/
string ciphertextFilePath_;/*密文文件路径*/
string keyFilename_;/*密钥文件路径*/
string plaintext_;/*明文存储*/
string ciphertext_;/*密文存储*/
string key_;/*密钥存储*/
vector
void getsubkey_();/*计算子密钥*/
void setPlaintextFilePath_();/*设置明文路径*/
void setCiphertextFilePath_();/*设置密文路径*/
void setKeyFilePath_();/*设置密钥路径*/
string readData_(string filename);/*读取文件*/
void saveData_(string filename,string data);/*保存文件*/
vector
string bit2string_(vector
vector
vector
vector
vector
vector
vector
vector
/************************************************************************/
/* 变换矩阵*/
static const unsigned int PC_1_[56];
static const unsigned int PC_2_[48];
static const unsigned int LOOP_[16];
static const unsigned int IP_[64];
static const unsigned int IPR_[64];
static const unsigned int SBOX_[8][4][16];
static const unsigned int E_[48];
static const unsigned int P_[32];
/************************************************************************/
};
2. DES加密代码
创建基于DES加解密的函数,以备后面的代码调用。
代码:
#include "DES.h"
/************************************************************************/
/************************************************************************/
/* 静态常量放在这里*/
const unsigned int DES::IP_[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 };
const unsigned int DES::IPR_[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 };
const unsigned int DES::PC_1_[56] =
{
/*注释的部分是对应64位带奇偶校验的*/
/*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*/ 50, 43, 36, 29, 22, 15, 8, 1, 51, 44, 37, 30, 23, 16, 9, 2, 52, 45, 38, 31, 24, 17, 10, 3, 53, 46, 39, 32, 56, 49, 42, 35, 28, 21, 14, 7, 55, 48, 41, 34, 27, 20, 13, 6, 54, 47, 40, 33, 26, 19, 12, 5, 25, 18, 11, 4 };
const unsigned int DES::PC_2_[48] =
{
/*注释的部分是对应64位带奇偶校验的*/
/*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*/
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
13, 24, 3, 9, 19, 27, 2, 12, 23, 17, 5, 20,
16, 21, 11, 28, 6, 15, 18, 14, 12, 8, 1, 4
};
const unsigned int DES::LOOP_[16] =
{
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
const unsigned int DES::SBOX_[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
};
const unsigned int DES::E_[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
};
const unsigned int DES::P_[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
};
/************************************************************************/
/************************************************************************/ /* DES类实现*/
DES::DES():subkey_(16,vector
{
/*构造函数*/
}
void DES::encrypt(bool flag /* = true */)
{
/*加密函数*/
/*读取文件*/
vector
if (flag)
{
/*加密*/
setPlaintextFilePath_();
plaintext_ = readData_(plaintextFilePath_);
textBit = string2bit_(plaintext_);/*不够64bit的整数,补0,如下*/
unsigned int zeroFill = (textBit.size()%64) ? (64 - textBit.size()%64) : 0;
for (unsigned int i = 0; i < zeroFill; i++)
{
textBit.push_back(0);
}
}
else
{
/*解密*/
setCiphertextFilePath_();
ciphertext_ = readData_(ciphertextFilePath_);
textBit = string2bit_(ciphertext_);
}
/*读取密钥文件*/
getsubkey_();
/*循环读取64bit加密*/
unsigned int len = textBit.size();
unsigned int count = 0;
vector
while ( count < (len / 64) )
{
vector
for (unsigned int i = 64*count; i < 64*count+64; i++) {
textBitTmp.push_back(textBit[i]);
}
/*IP置换*/
vector
textBitTmp_IP = vecReplace_(textBitTmp,IP_);
/*划分L0和R0*/
vector
vector
for (int i = 0; i < 32; i++)
{
L[0][i] = textBitTmp_IP[i];
}
for (int i = 0; i < 32; i++)
{
R[0][i] = textBitTmp_IP[i+32];
}
/*迭代生成L1-L16,R1-R16*/
for (int i = 1; i < 17; i++)
{
L[i] = R[i-1];
if (flag)
{
R[i] = vecXor_(L[i-1], f_(R[i-1],subkey_[i-1]));
}
else
{
R[i] = vecXor_(L[i-1], f_(R[i-1],subkey_[16-i]));
}
}
vector
for (unsigned int i = 0; i < 64; i++)
{
secret.push_back(RL[IPR_[i]-1]);
}
count++;
}
if (flag)
{
ciphertext_ = bit2string_(secret);
setCiphertextFilePath_();
saveData_(ciphertextFilePath_,ciphertext_);
}
else
{
plaintext_ = bit2string_(secret);
setPlaintextFilePath_();
saveData_(plaintextFilePath_,plaintext_);
}
}
void DES::setPlaintextFilePath_()
{
/*设置明文路径*/
string plaintextFilePath;
cout << "请输入明文文件路径(例如:c://plaintext.txt):"; cin >> plaintextFilePath;
plaintextFilePath_ = plaintextFilePath;
}
void DES::setCiphertextFilePath_()
{
/*设置密文路径*/
string ciphertextFilePath;
cout << "请输入密文文件路径(例如:c://ciphertext.txt):";
cin >> ciphertextFilePath;
ciphertextFilePath_ = ciphertextFilePath;
}
void DES::setKeyFilePath_()
{
/*设置密钥路径*/
string keyFilename;
cout << "请输入密钥文件路径(例如:c://key.txt):";
cin >> keyFilename;
keyFilename_ = keyFilename;
}
string DES::readData_(string filename)
{
/*通用函数:读取文件内容到string中,包含空格和回车符等*/ ifstream in;
ostrstream os;
in.open(filename.c_str(),ios::in);
os << in.rdbuf() << ends;
in.close();
return os.str();
}
void DES::saveData_(string filename,string data)
{
/*通用函数:保存数据到文件中,包含空格和回车*/ ofstream out(filename.c_str());
out.write(data.c_str(),data.size());
out.close();
}
vector
{
/*string转为二进制*/
vector
for (unsigned int i = 0; i < str.length(); i++)
{
int mask = 128;
while (mask > 0)
{
v.push_back( ((mask&str[i]) > 0) );
mask = mask >> 1;
}
}
return v;
}
string DES::bit2string_(vector
{
/*二进制转为string*/
assert(v.size()%8 == 0);
unsigned int count = 0,len = v.size();
string str;
while ( count < (len/8) )
{
int mask = 128;
int ch = 0;
for (unsigned int i = 8*count; i < 8*count+8;i++) {
ch += (mask & (v[i]*mask));
mask = mask >> 1;
}
str += (char)ch;
count++;
}
return str;
}
vector
{
/*整形数0-15化为二进制*/
vector
for (unsigned int i = 0; i < vecInt.size(); i++)
{
int mask = 8;
while (mask > 0)
{
v.push_back( ((mask&vecInt[i]) > 0) );
mask = mask >> 1;
}
}
return v;
}
vector
{
/*向量逐位异或*/
assert(vL.size() == vR.size());
for (unsigned int i = 0; i < vL.size(); i++)
{
vL[i] ^= vR[i];
}
return vL;
}
vector
{
/*数据左移loopStep位*/
unsigned int len = movVec.size();
for (int i = 0; i < loopStep; i++)
{
movVec.push_back(movVec[i]);
}
for (unsigned int i = 0; i < len; i++)
{
movVec[i] = movVec[i+loopStep];
}
movVec.erase(movVec.end()-loopStep,movVec.end());
return movVec;
}
vector
/*通用函数:数据按照数组元素换位*/
vector
for (unsigned int i = 0; i < v.size(); i++)
{
vTmp.push_back(v[vArray[i]-1]);
}
return vTmp;
}
vector
{
/*合并两个向量*/
vector
for (unsigned int i = 0; i < vL.size(); i++)
{
vLR.push_back(vL[i]);
}
for (unsigned int i = 0; i < vR.size(); i++)
{
vLR.push_back(vR[i]);
}
return vLR;
}
vector
{
/*f函数,DES加密的核心*/
assert( (vecR.size() == 32) && (vecKey.size() == 48) );
vector
for (unsigned int i = 0; i < 48; i++)
{
vecR_E.push_back(vecR[E_[i]-1]);
}
vecR_E = S_(vecXor_(vecR_E,vecKey));
vecR_E_P = vecReplace_(vecR_E,P_);
return vecR_E_P;
}
vector
{
/*S函数,6bit入4bit出*/
assert(vecRKey.size() == 48);
vector
vector
for (unsigned int i = 0; i < 8; i++)
{
for (unsigned int j = 0; j < 6; j++)
{
S_out[i][j] = vecRKey[6*i+j];
}
int a = 2 * S_out[i][0] + S_out[i][5];
int b = 8 * S_out[i][1] + 4 * S_out[i][2] + 2 * S_out[i][3] + S_out[i][4];
tmp.push_back(SBOX_[i][a][b]);
}
return int2bit_(tmp);
}
void DES::getsubkey_()
{
/*函数功能:获得子密钥*/
/*读取密钥文件*/
setKeyFilePath_();
key_ = readData_(keyFilename_);
vector
/*生成子密钥*/
/*1 - keybit通过PC_1*/
vector
vector
vector
for (int i = 0; i < 28; i++)
{
C[0][i] = keyBit_PC_1[i];
}
for (int i = 0; i < 28; i++)
{
D[0][i] = keyBit_PC_1[i+28];
}
/*3循环移位得到C1-C16,D1-D16*/
for (int i = 1; i <17; i++)
{
C[i] = leftIterMove_(C[i-1],LOOP_[i-1]);
D[i] = leftIterMove_(D[i-1],LOOP_[i-1]);
}
/*4子密钥*/
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 24; j++)
{
subkey_[i][j] = C[i+1][PC_2_[j]-1];
}
}
for (int i = 0; i < 16; i++)
{
for (int j = 24; j < 48; j++)
{
subkey_[i][j] = D[i+1][PC_2_[j]-1];
}
}
}
3. 测试文件test.cpp
调用我们编写的程序中的函数,即基于DES的加解密函数
菜单设计:由于我们的DES加解密软件是在命令提示符中运行的,所以菜单的主要输入输出是由关键字实现的,如:cout
代码:
#include "DES.h"
int main()
{
DES de;
int choice;
do
{
system("cls");
cout << "\t" <<"**************************************************" << endl;
cout << "\t" <<"********************* DES ************************" << endl;
cout << "\t" <<"** *1、加密**" << endl;
cout << "\t" <<"** *2、解密**" << endl;
cout << "\t" <<"** *3、退出**" << endl;
cout << "\t" <<"**************************************************" << endl;
cout << "\t" <<"**************************************************" << endl;
cout << "请输入您的选择(1-3):";
cin >> choice;
switch(choice)
{
case 1:
de.encrypt();
break;
case 2:
de.encrypt(false);
break;
default:
break;
}
} while(choice != 3);
return 0;
}
五、项目的实施:
1.收集关于DES加密算法的资料
2.研究DES加密算法
3.搜索关于DES代码
4.修改程序代码
5.编译代码,生成可执行文件
6.运行可执行文件,测试程序是否能完成DES加解密过程
7.打包程序
六、项目总结:
通过这次大作业的学习,我们对于密码学有了大致的了解。了解密码学的起源及分类等知识知道了数据加密技术的种类以及方法,尤其是在加密知识方面有了很大的提高。
在对称加密算法中,我们主要研究了DES加密算法,学习了DES加密的过程,其中我们重点研究了S盒,压缩置换以及拓展置换等,这些都很好地锻炼了我们的动手能力以及解决问题的能力。
这次大作业我们小组成员每一个都很努力,我们了解到更多的知识面,我们也不会荒废这方面的学习,也许这些会在给我们将来的工作奠定基础。