用AES加密实现Socket通信
2.1、设计目的
1、熟悉socket通讯原理
2、掌握AES加密算法
2.2、系统目标
实现客户服务器之间用socket进行通信;发送方传输的消息使用AES加密,接收方对消息解密获取明文。
2.3、实现步骤
2.3.1熟悉socket通讯过程
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。服务器,使用ServerSocket监听指定的端口,端口可以随意指定(由于1024以下的端口通常属于保留端口,在一些操作系统中不可以随意使用,所以建议使用大于1024的端口),等待客户连接请求,客户连接后,会话产生;在完成会话后,关闭连接。客户端,使用ClientSocke
t对网络上某一个服务器的某一个端口发出连接请求,一旦连接成功,打开会话;会话完成后,关闭Socket。客户端不需要指定打开的端口,通常临时的、动态的分配一个1024以上的端口。
2.3.2熟悉AES高级加密算法加密解密过程
AES算法是美国标准技术研究所(NIST)于2001年11月正式发布的,它是一种分组加密算法,处理的最小单元是一个分组,即把明文或密文分成固定长度的分组,进而进行加密或解密处理。AES的分组大小为128比特,可以支持的密钥长度有128、192、256三种,分别称为AES-128、AES-192、AES-256,其中又以AES-128应用最广。
AES算法定义了加密过程和解密过程,加密过程和解密过程都是一个周期迭代的过程,迭代的次数由密钥长度决定,对于AES-128迭代次数为10。由于采用了迭代过程,而且每次迭代所需要的密钥也不同,AES算法定义了密钥扩展过程,该过程也是一个迭代过程,通过10个周期产生10个不同的密钥供加密和解密使用。在加密和解密过程中128比特的分组被分解成16个字节,并依次从a0到a15命名,这16个字节又映射成一个4x4的字节矩阵。加密和解密过程中每一轮操作都基于这4x4的字节矩阵,每轮的结果又称为状态。
数据首先和128比特的原始密钥经过addroundkey运算后再进行10轮运算。10轮运算有字节替换(subbyte)、行移位(shiftrow)、列混合(mixcolumns)和轮密钥混合(addroundkey)组成,其中算法定义最
后一轮运算不进行列混合操作。
(1)字节替换
字节代换运算是一个可逆的非线性字节代换操作,该运算处理的最小单位是一个字节,也就是4x4字节矩阵中的一个元素。对字节的替换操作可以基于一个代换表(又称S盒)。字节替换表由两个独立的变换组成:有限域GF(28)中字节的乘法逆运算和有限域GF(2)中的仿射变换。
(2)行移位
加密中的行移位在状态的每行间进行,具体方法为将每一行进行循环左移位,即最高位字节移动到最低位字节。具体移位的数目与行的序号有关,第零行不进行移位,第一行循环左移一个字节,第二行循环左移两个字节,第三行循环左移三个字节…
(3)列混合
列混合主要对状态中的每一列为单位进行处理,每一列看作一个GF(28)下的4位多项式。利用该多项式和c(x)={03}x3+{01}x2+{01}x+{02}进行多项式乘法,乘法结果再进行取模运算,模的值为X4+1。
(4)轮密钥混合
轮密钥混合指对密钥中各个字节和相应的轮密钥进行逐位异或,实现数据和密钥的混合。对于加密过程,初始时刻数据和初始密钥进行异或,此后扩展出的轮密钥和状态进行异或操作。
算法描述
AES加密过程由四个不同的变换组成:
Rijnadel(State, CipherKey)
{ //初始化
KeyExpansion( CipherKey, ExpandedKey );//生成子密钥
AddRoundKey( State, ExpandedKey ); //与子密钥位与
// 前Nr-1轮
State=in;
for(i =1; i < Nr; i++)
{
SubBytes (State);// S-盒
ShiftRows(State);// 行被移位
MixColumns(State);// 列被混叠
AddRoundKey (State, ExpandedKey ); //与子密钥位与
}
//最后一轮
SubBytes(State);
ShiftRows(State);
AddRoundKeys (State, ExpandedKey );
Out=State;
}
2.3.3、代码实现
明白了socket通信过程和AES算法过程后,进行具体实现。
开发环境:Borland C++ builder 6.0
运行模式:客户端和服务器分开设计,由于本次课程设计简单实现通信,所以指定客户端与服务器通信端口为2000.
如图是开发界面:
服务器侦听:
void __fastcall TForm1::serverListenClick(TObject *Sender)
{
serverListen->Checked=!serverListen->Checked;
if(serverListen->Checked)
{
ServerSocket->Active=true;
StatusBar1->SimpleText="";
}
else
{
if(ServerSocket->Active)
ServerSocket->Active=false;
StatusBar1->SimpleText="Not listening.";
}
}
客户端建立连接:
void __fastcall TForm1::ClientConnect(TObject *Sender,
TCustomWinSocket *Socket)
{
Memo1->Lines->Clear();
clientStatusBar->SimpleText = "Connect to: " + Socket->RemoteHost;  Memo1->Lines->Add(Socket->ReceiveText());
}
服务器接受连接:
void __fastcall TForm1::ServerSocketAccept(TObject *Sender,
TCustomWinSocket *Socket)
{
StatusBar1->SimpleText="server connect to"+Socket->RemoteAddress; }
客户端加密发送:
void __fastcall TForm1::btnclientSendClick(TObject *Sender)
{
AES aes;
//读入密钥文件
const unsigned char *key = new unsigned char[16];
int keyFile=FileOpen(Edit3->Text,fmOpenRead|fmShareExclusive);  FileRead(keyFile,(char *)key,16);
//读入明文并加密
const unsigned char *plainText= new unsigned char[16];
int plainFile=FileOpen(Edit2->Text,fmOpenRead|fmShareExclusive);  const unsigned char* cipherText;
while(FileRead(plainFile,(char *)plainText,16))
{
cipherText = aes.Cipher(plainText, key, 16);
}
//发送密文
AnsiString cipher;
cipher=AnsiString((char *)cipherText);
ClientSocket->Socket->SendText(cipher);
delete []key;
delete []plainText;socket通信在哪一层
}
服务器接收解密:
void __fastcall TForm1::btnDecryptClick(TObject *Sender)
{
AES aes;
//读入解密密钥
const unsigned char *key = new unsigned char[16];
int keyFile=FileOpen(Edit1->Text,fmOpenRead|fmShareExclusive);
FileRead(keyFile,(char *)key,16);
//读入解密密文 Memo1内容作为cipherText内容,已经存入Edit2中
//解密显示到Memo1上
const unsigned char* plainText;
AnsiString memoPlain;
const unsigned char* cipherText = new unsigned char[16];
int cipherFile=FileOpen(Edit2->Text,fmOpenRead|fmShareExclusive);  while(FileRead(cipherFile,(char *)cipherText,16))
{
plainText=aes.InvCipher(cipherText,key,16);
}
memoPlain=(AnsiString)((char *)plainText);
Memo1->Lines->Add(memoPlain);
delete []key;
delete []cipherText;
}
2.4、运行结果
左边是发送的密文,右边是解密的结果
2.5、心得体会
这次实验最大的收获是学会在C++builder下开发,熟悉了一种新的开发环境。从对这个环境一无所知,到做完这个设计,自学能力得到很大提高。
为了完成c++builder下的设计,我先后从图书馆借了3本书。综合了3本书上的知识,用到什么学习什么,全部的东西都是崭新的,没有任何模板代码可以参照。过程也很艰辛,因为毕竟不是一点一点积累的学习,不知道c++builder的工程文件和设计文件不能取相同的名字,我服务器端先后重做了四次,第五次的时候偶然间想到也许不应该同名,终于解决了这个问题。期间有多郁闷,之后就有多高兴。
对于AES也是陌生的,代码是从网上下载的,但是AES的步骤比较清楚。最后把它们结合在一起。遇到的问题更多。说来无奈,整整一个上午不断的调试,最后却因为版本问题,从学生在线上下载了一个版本,运行调试没有任何错误。。。是这个问题:const unsigned char *key = new unsigned char[16];不能动态的分配。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。