目录
0 引言
1 RSA和DES原理概述
1.1 DES算法
1.2 RSA算法
2 系统架构
3 实验及结果分析
3.1 RSA加密传送密钥
3.2 DES加密通信内容
4 总结
参考文献
参考代码:
缺陷:引言总结前人观点不够精炼,还需要简述本文和前人工作的关系。另外,需要描述解决对称密钥分发的过程,使得内容更加完整。
随着通信技术的不断发展和人们需求的增加,使得通信安全问题越来越受到广泛的关注,而创造敏感信息的安全传输环境一直是学术界重要的研究内容。例如,行鸿彦[[i]]等人设计了一种特殊的保密通信系统,在使用脉冲同步技术的基础上,结合压缩检测技术,增强了通信系统的安全性;骆钊[ii]等人提供了一套基于IEC62351通信协议的身份认证机制,并提供了通过SM双密码系统安全传输目标通信消息的方案,有效解决了变电站通信报文的数据安全性和实时性要求;冷飞[iii]等人指出这种RSA融合高阶数据加密算法(AES)的新加密算法,采用了AES计算并配合了RSA加密方式,可以充分地发挥AES计算运行速率快、RSA加密方式配置性能高等的优点;Kaya和Selçuk[iv]将中国剩余定理的方法引进了门限设定密码理论中,并使用该方法建立了门限设定的RSA签名方法,极大地提高了保密性。上述加密通信方法在各自的应用领域产生了一些积极影响。本文结合DES算法和RSA算法,利用socket网络编程技术设计了一个基于C++的通信系统。
DES属于分组密码,也称为对称密码体制。它要求先对信息进行分类,然后加密和解密的组装。由内容的发出和收到方存储用以加密和解密信息的密钥。加密和解密密钥在获取其中之一时就可以利用相关数学公式互相推出。
置换IP后,将明文分为两组三十二位,接着再进行十六轮迭代的乘积变换,每次变换的结果仍然为三十二位。每次得出的结果,再与下一位密钥进行计算。通过了十六轮运算以后,再把两截内容连接起来,并进行逆置换,就可以获得最终的密文。明文和密文有效的长度均为六十四位,而密钥长度虽然也是六十四位,但有效的部分仅有五十六位。
RSA作为一种公开密钥密码体制,具有十分出色的安全性,认可度较高。因为公钥和私钥的产生是基于数学原理“可以轻易寻求两个大素数,但极难将它们的成绩分解开”,因此安全性较高。首先准备两个较大质数,分别命名为p,q,使得N=pq,N难以因式分解成原来的p和q。于是根据RSA算法的原理,令k=(q-1)(p-1)选择一个整数e,使得e与k互质且e小于k,并且令d*e1(mod k),此时,e是公钥,d是私钥。对于一份资料数据,如果使用私钥对其加密,那么我们只有使用与之匹配的公钥才能解开;而当我们使用公钥加密,那为了解开加密文本我们就需要使用私钥。
通信系统的通信框架,采用了Socket服务器和客户端的通信模型,在此基础上选择了TCP协议,如图 1所示。此外,它还结合了C++的多线程来实现通信。首先,Server建立服务器监听socket套接字,等待并接受Client创建连接socket套接字后发送到Server的请求,然后Server在接受请求后创建socket。此时,Server可以与Client进行通信。最后,Server和Client关闭套接字和相关资源,通信在此结束。
图 1:通信系统的通信框架
通讯体系所采纳的加密方式是DES和RSA的组合加密,如图 2所示。DES算法的长处是加密处理简单,且速度较快,但不足是不能保证密钥的安全转移;RSA算法的亮点在于它极高的安全性,但美中不足的是缓慢的加密速度。本文的通信系统采用公开密钥体制RSA加密传输对称密码算法密钥,对称密码体制DES加密通信的内容。服务器Server首先使用RSA算法生成公钥和私钥,公开公钥,使用私钥对DES算法密钥进行加密,然后再把加密之后的文本发送回客户端Client。客户端Client使用公钥解密密文以获取对称密码算法密钥,然后就可以利用对称密码体制对内容进行加密通信。
图 2 :混合加密通信
本文设计了一个基于C ++ 平台的安全通信系统。采用了TCP网络协议和Socket套接字,来实现通信系统的通信部分。RSA算法用于加密对称密码并将其发送到通信对象。对称密码体制采取DES加密标准,用以加密通信内容。以下实验数据都是在操作系统Ubuntu 20.04上实现的。
首先在Qt上运行程序,按照提示选择服务端,输入s,然后再输入DES算法的对称密码,可以看到加密密文和加密成功等待发送的提示,如图 3所示;此时再次运行程序,根据提示选择客户端,输入c,就可以在客户端上看到解密后的密文,如图 4所示。
图 3:Server界面截图
图 4:Client界面截图
分别在服务端和客户端上输入上文选定的DES对称密码密钥,即可开始通信,如图 5和图 6所示。最后根据提示,输入“quit”结束通信。
图 5:Server界面截图
图 6:Client界面截图
服务器Server可以正常加密DES算法的密码密钥,并将加密之后内容发送给客户端Client;客户端Client也可以正常连接到服务器Server,并向服务器Server发送请求。在通信系统中,当RSA算法满足一定条件时,可以认为它是无法破解的。同时,采取DES密码体制对通信内容实施加密,有效提升了通信过程中的数据加解密效率。实验结果显示,所设计的DES和RSA加密混合通信系统可有满足一定程度上的安全通信,对通信系统的安全设计具备一定的参考意义。
[i] 行鸿彦,冒海微,徐伟,王秋辉.基于压缩感知的脉冲同步的混沌保密通信系统[J].仪器仪表学报,2014,35(07):1510-1517.DOI:10.19650/j.cnki.cjsi.2014.07.009.
[ii] 骆钊,谢吉华,顾伟,严童,王志贺,林英俊.SM2加密体系在智能变电站站内通信中的应用[J].电力系统自动化,2015,39(13):116-123.
[iii] 冷飞, 徐进华, 栾仕喜. RSA 融合 AES 算法的网络信息安全方法[J]. 华侨大学学报: 自然科学版, 2017, 38(1): 117-120.
[iv] Kaya K and Selçuk A A. Threshold cryptography based on Asmuth-Bloom secret sharing[J]. Information Sciences, 2007, 177(19): 4148-4160.
CDes.cpp:
#include"CDes.h"
//初始置换表
const static unsigned char pc_first[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
} ;
//扩展置换,将数据从32位扩展为48位
static const unsigned char 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
} ;
//S盒子代替
const static unsigned char des_S[8][64]={
{//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
}
} ;
//P盒置换
const static unsigned char 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
} ;
//末置换
const static unsigned char pc_last[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
} ;
//密钥置换表,将64位密钥置换压缩置换为56位
const static unsigned char pctable[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
} ;
//每轮移动的位数
const static unsigned char lefttable[16] = {
1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1
} ;
//压缩置换表,56位密钥压缩位48位密钥
const static unsigned char keychoose[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
} ;
int CDes::ip(const Block & block , HBlock & left , HBlock & right)
{
for(size_t i = 0 ; i < right.size() ; i++)
right[i] = block[pc_first[i] - 1] ;//获取初始置换的右半部分
for(size_t i = 0 ; i < left.size() ; i++)
left[i] = block[pc_first[i + right.size()] - 1] ;//获取初始置换的左半部分
return 0 ;
}
int CDes::genkey(const Block & bkey)
{
//n在区间[0,15]之间取值,bkey为64位密钥
Code result ;//返回值,48位子密钥
Key key ;//56位密钥
unsigned int klen = key.size() , rlen = result.size() ;//分别为56和48
//获取56位密钥
for(size_t i = 0 ; i < key.size() ; i++)
key[i] = bkey[pctable[i] - 1] ;//密钥置换
for(size_t i = 0 ; i < SUBKEYNUM ; i++)
{//循环移位
for(size_t j = 0 ; j < lefttable[i] ; j++)
{
//将密钥循环位暂存在result中
result[rlen - lefttable[i] + j] = key[klen - lefttable[i] + j] ;
result[rlen / 2 - lefttable[i] + j] = key[klen / 2 - lefttable[i] + j] ;
}
key <<= lefttable[i] ;//移位
for(size_t j = 0 ; j < lefttable[i] ; j++)
{
//写回key中
key[klen / 2 + j] = result[rlen - lefttable[i] + j] ;
key[j] = result[rlen / 2 - lefttable[i] + j] ;
}
//压缩置换
for(size_t i = 0 ; i < result.size() ; i++)
result[i] = key[keychoose[i] - 1] ;
subkey[i] = result;
}
return 0;
}
int CDes::des_once(HBlock & left , HBlock & right , const Code & subkey)
{
Code code ;//48位数据块
HBlock pcode ;//32位数据块
//将右半部分扩展为48位
for(size_t i = 0 ; i < code.size() ; i++)
code[i] = right[des_E[i] - 1] ;//选择扩展运算
code ^= subkey ;//密钥加运算,与子密钥异或
//S盒代替
std::bitset<6> index;//用于在S盒替换的索引
for(size_t i = 0 ; i < 8 ; ++i)
{//8个盒子
index[0] = code[6 * i];
index[1] = code[6 * i+1];
index[2] = code[6 * i+2];
index[3] = code[6 * i+3];
index[4] = code[6 * i+4];
index[5] = code[6 * i+5];
std::bitset<4> temp(des_S[i][index.to_ulong()]) ;
for(size_t j = 0 ; j < temp.size() ; j++)
code[4 * i + j] = temp[j] ;//将32位暂存于48位中
}
for(size_t i = 0 ; i < pcode.size() ; i++)
pcode[i] = code[des_P[i] - 1] ;//置换运算,P盒置换
left ^= pcode ;//异或
return 0 ;
}
int CDes::exchange(HBlock & left , HBlock & right)
{
HBlock temp ;
for(size_t i = 0 ; i < temp.size() ; i++)
temp[i] = left[i] ;
for(size_t i = 0 ; i < left.size() ; i++)
left[i] = right[i] ;
for(size_t i = 0 ; i < right.size() ; i++)
right[i] = temp[i] ;
return 0 ;
}
int CDes::final_replace(const HBlock & left , const HBlock & right , Block & block)
{
for(size_t i = 0 ; i < block.size() ; i++)
{
if(pc_last[i] <= 32)
block[i] = right[pc_last[i] - 1] ;//从right部分获取数据
else
block[i] = left[pc_last[i] - 32 - 1] ;//从left部分获取数据
}
return 0 ;
}
int CDes::Encry(Block & block , Block & bkey )
{
HBlock left , right ;//左右部分
ip(block , left , right) ;//初始置换
genkey(bkey);//生成16轮子密钥
for(int i = 0 ; i < SUBKEYNUM ; i++)//十六轮迭代
{
des_once(left , right , subkey[i]) ;
if(i != (SUBKEYNUM-1)) //最后一次迭代完成后,左右俩个部分不进行交换
exchange(left , right);
}
final_replace(left , right , block) ;//末置换
return 0;
}
int CDes::Decry(Block & block , Block & bkey )
{
HBlock left , right ;//左右部分
ip(block , left , right) ;//初始置换
genkey(bkey);//生成16轮子密钥
for(int i = 15 ; i >= 0 ; i--)
{
des_once(left , right , subkey[i]) ;
if(i != 0) //最后一次迭代完成后,左右俩个部分不进行交换
exchange(left , right) ;
}
final_replace(left , right , block) ;//末置换
return 0;
}
CDes.h:
#pragma once
#include"commen.h"
#define SUBKEYNUM 16
typedef std::bitset<64> Block ;// 64 bits data block
typedef std::bitset<56> Key ;// 58 bits key
typedef std::bitset<48> Code ;// 48 bits data block
typedef std::bitset<32> HBlock ;
typedef std::bitset<28> HKey ;
typedef std::bitset<24> HCode ;
class CDes
{
private:
Code subkey[SUBKEYNUM]; //保存16轮迭代用到的子密钥
int ip(const Block & block , HBlock & left , HBlock & right) ;//初始置换 IP
int des_once(HBlock & left , HBlock & right , const Code & subkey) ;//一轮加/解密运算
int exchange(HBlock & left , HBlock & right) ;//交换左右两个部分,辅助函数
int final_replace(const HBlock & left , const HBlock & right , Block & block) ;//进行末置换 IP^-1
int genkey(const Block & bkey) ;//产生16轮迭代用到的子密钥
public:
// CDes();
// ~CDes();
int Encry(Block & block , Block & bkey );//封装一轮完整加密过程的函数
int Decry(Block & block , Block & bkey );//封装一轮完整解密过程的函数
};
commen.h:
#pragma once
//some header files will be used
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
main.cpp:
#include"commen.h"
#include"CDes.h"
#define SERVER_PORT 7274
#define SERVER_IP "127.0.0.1"
using namespace std;
const int key_length = 9;
int c[90000];
//RSA加密函数
void encrypt(int e,int n){ //自己指定指数e
//先将符号明文转换成字母所对应的ascii码。
char plaintext[100]; //符号明文
printf("Please enter the DES key:\n");
scanf("%s",plaintext);
int plain_ascii[strlen(plaintext)]; //定义符号明文
for(int i=0;i: %s\n", addr, pac.message);
}
}
}
void send_thread(int nsock, char* key)
{
char send_buf[sizeof(packet)];
Block bdata,bkey;
CDes obj;
packet pac;
pac.isquit = false;
bool isover = false;
int n = sizeof(packet)/8;//packet的大小是8的整数倍
Str2Block(bkey, key);
while(!isover)
{
cin>>pac.message;
if(strcmp(pac.message,"quit")==0)
{
isover = pac.isquit = true;
}
for(int i=0;i>choose;
if(choose == 'c')//client
{
decrypto(d,n);
char key[9];
int nConnectSocket;
struct sockaddr_in sDestAddr;
//1. 创建套接字
if ((nConnectSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("Create socket failed!");
exit(errno);
}
//2. 初始化sockaddr_in 结构体 sDestAddr
sDestAddr.sin_family = AF_INET;
sDestAddr.sin_port = htons(SERVER_PORT);
sDestAddr.sin_addr.s_addr = inet_addr(SERVER_IP);
//3. 与服务器建立连接
if (connect(nConnectSocket, (struct sockaddr *) &sDestAddr, sizeof(sDestAddr)) != 0)
{
perror("Connect failed!");
exit(errno);
}
else
{
printf("Connect Success! \nBegin to chat...\n");
//4. 开始聊天
/* blow matter */
//5. 设定密钥
cout<<"input the key:"<>key;
//6. 创建收发线程
cout<<"-----------Communication begins-----------"<> key;
//8. 开始聊天,创建收发线程
cout<<"-----------Communication begins-----------"<