📄 securechatiocp.cpp
字号:
// SecureChatIOCP.cpp: implementation of the SecureChatIOCP class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SecureChat.h"
#include "iocps.h"
#include "SecureChatIOCP.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
const DWORD SecureChatIOCP::m_DSAKeypubN[64] = {
0xf99223fb, 0x625e88c9, 0x1fa77dc9, 0x3c6361c3, 0xe9a92919, 0xf4bfa25b,
0x4247b58c, 0xbdc1cec1, 0x25b0b4fd, 0x88ea361d, 0xb1909686, 0xf59c6edc,
0x0a99bffa, 0x33c2b433, 0xfe66ce05, 0xc01e773a, 0x5ad01646, 0x787a48ce,
0x5b95cc4a, 0xcd63c5b8, 0x9432cc06, 0xa830a077, 0x8e80cc90, 0x8cd27948,
0x8bd1c5a6, 0x635f7a31, 0xd7e1d3f0, 0x3987eea5, 0x2c20433d, 0x5f7e5927,
0xca9f9c36, 0xb8d903f8, 0x6467e423, 0xe9a7d14f, 0x058d0a7c, 0x7efb3413,
0x373851ad, 0xa801a2b3, 0x383c337f, 0xf6d967b6, 0x91e2194a, 0x877c1fca,
0x722d981a, 0x73563cf6, 0x527c7db2, 0xc63f5829, 0x59780705, 0x26440988,
0x1ae803bc, 0x612ac808, 0xed5217e2, 0xb6fde648, 0xd9425a87, 0x5a9cadf5,
0x6010b36d, 0x42934058, 0x16d6c677, 0xea80ed00, 0x23299845, 0x73ca6dfe,
0x5b9697e8, 0xeb0e49a3, 0x9266b8d1, 0x8820e5ed, };
// The private Key is only existing in Server.
#ifndef _IOCPClientMode_
const DWORD SecureChatIOCP::m_DSAKeypubD[64] = {
0xfd52a66b, 0x52ca6690, 0xf265a0f1, 0x08ba2a83, 0x7341150b, 0x06452c7d,
0x9fe3f0e2, 0x733d56c7, 0xbdc9ab4d, 0xaf91094e, 0xc3c97caf, 0x36b126a1,
0x28072f0b, 0x9eaddf59, 0x2f36a3e9, 0x465dccb9, 0x8a6cf32a, 0x105da5fa,
0x961d488a, 0x225371f4, 0x9e786282, 0xe9e86eb3, 0xb73d6a77, 0x61570378,
0x38961f7f, 0x7de9e518, 0x898a709e, 0x351f0f62, 0xbf61f92e, 0x4a40940a,
0xc04e03ae, 0xd796d66f, 0xed9a9816, 0x9bc53634, 0x5908b1a8, 0xff5222b7,
0x7a258bc8, 0xc5566c77, 0x7ad2ccff, 0x4f3b9a79, 0xb696bb87, 0xafa81531,
0xf6c91011, 0xf78ed34e, 0x8c52fe76, 0xd97f901b, 0x3ba55a03, 0xc42d5bb0,
0x674557d2, 0x40c73005, 0xf38c0fec, 0x79fe9985, 0xe62c3c5a, 0xe7131ea3,
0x400b2248, 0xd70cd590, 0x0f39d9a4, 0x47009e00, 0xc21bbad9, 0xa286f3fe,
0x92646545, 0x9cb43117, 0x0c447b36, 0x5ac09949,
};
#endif
const DWORD SecureChatIOCP::m_DSAKeypubE = 3;
SecureChatIOCP::SecureChatIOCP()
{
#ifdef _IOCPClientMode_
m_pPublicKeyP=NULL;
m_nSizePublicKey=0;
m_sUserName="";
#endif
}
SecureChatIOCP::~SecureChatIOCP()
{
#ifdef _IOCPClientMode_
m_StatusLock.Lock();
if ( m_pPublicKeyP!=NULL )
{
delete [] m_pPublicKeyP;
m_pPublicKeyP=NULL;
}
m_StatusLock.Unlock();
#endif
}
void SecureChatIOCP::AppendLog(CString msg)
{
TRACE("%s\r\n",msg);
int nLen = msg.GetLength();
if ( nLen>=0 && m_hWnd!=NULL )
{
char *pBuffer = new char[nLen+1];
strcpy(pBuffer,(const char*)msg);
pBuffer[nLen]='\0';
BOOL bRet=FALSE;
bRet=::PostMessage(m_hWnd, WM_LOGG_APPEND, 0, (LPARAM) pBuffer);
if(!bRet)
delete[] pBuffer;
}
}
/*
* This functions defines what should be done when A job from the work queue is arrived.
* (not used).
*/
void SecureChatIOCP::ProcessJob(JobItem *pJob,IOCPS* pServer)
{
//SecureChatIOCP* pthis= reinterpret_cast<SecureChatIOCP*>(pServer);
}
void SecureChatIOCP::NotifyNewConnection(ClientContext *pcontext)
{
unsigned int *pBuffer= new unsigned int;
if(pBuffer!=NULL)
{
*pBuffer=pcontext->m_Socket;
::PostMessage(m_hWnd, WM_NEW_CONNECTION, 0, (LPARAM) pBuffer);
}
#ifdef _IOCPClientMode_
m_StatusLock.Lock();
pcontext->m_ContextLock.Lock();
pcontext->m_pPublickey=m_pPublicKeyP;
pcontext->m_nPublicKeySize=m_nSizePublicKey;
pcontext->m_sUsername=m_sUserName;
pcontext->m_ContextLock.Unlock();
m_StatusLock.Unlock();
AppendLog("Sending public key P..");
m_StatusLock.Lock();
SendPublicKey(pcontext,PKG_PUBLIC_KEYP,m_pPublicKeyP,m_nSizePublicKey);
m_StatusLock.Unlock();
#endif
}
void SecureChatIOCP::NotifyWriteCompleted(ClientContext *pContext, DWORD dwIoSize, CIOCPBuffer *pOverlapBuff)
{
// The pOverlapBuff Buffer are Successfully sended.
// If we sended an error message Kill the connection
if ( pContext && pOverlapBuff->GetPackageType()== PKG_ERRORMSG )
{
DisconnectClient(pContext->m_Socket);
}
}
void SecureChatIOCP::NotifyDisconnectedClient(ClientContext *pContext)
{
if ( pContext!=NULL && pContext->m_Socket!=INVALID_SOCKET )
{
pContext->m_ContextLock.Lock();
pContext->m_bGotSessionKey=FALSE;
unsigned int *pBuffer= new unsigned int;
if(pBuffer!=NULL&&m_hWnd!=NULL)
{
*pBuffer=pContext->m_Socket;
::PostMessage(m_hWnd, WM_DISCONNECT_CLIENT, 0, (LPARAM) pBuffer);
}else
{
delete pBuffer;
pBuffer=NULL;
}
CString msg;
CTime tm= CTime::GetCurrentTime();
msg.Format("[%s] %s Disconnected. (%s)",tm.Format("%H:%M:%S"),pContext->m_sUsername,GetHostAddress(pContext->m_Socket));
AppendLog(msg);
TRACE("Client %i is disconnected\r\n",pContext->m_ID);
pContext->m_ContextLock.Unlock();
// We can not Lock m_ContextMapLock inside pContext->m_ContextLock lock -> leads do deadlock..
#ifndef _IOCPClientMode_
SendTextMessage(msg);
#endif
// Clean The memory.
NotifyNewClientContext(pContext);
}
}
void SecureChatIOCP::NotifyNewClientContext(ClientContext *pContext)
{
pContext->m_ContextLock.Lock();
pContext->m_sUsername="";
pContext->m_sUsername.FreeExtra();
pContext->m_nPublicKeySize=0;
pContext->m_pPublickey=NULL;
pContext->m_bUpdateList=FALSE;
pContext->m_bGotSessionKey=FALSE;
// Init the hash struct used for digital signing.
memset(&(pContext->m_csha1Hash),0,sizeof(pContext->m_csha1Hash));
pContext->m_cCryptLib.SHA1_Start(&(pContext->m_csha1Hash));
pContext->m_ContextLock.Unlock();
}
void SecureChatIOCP::NotifyContextRelease(ClientContext *pContext)
{
//
// Remove the Public key if we are in server mode.
//
#ifndef _IOCPClientMode_
pContext->m_ContextLock.Lock();
if ( pContext->m_pPublickey!=NULL )
{
delete[] pContext->m_pPublickey;
pContext->m_pPublickey=NULL;
}
pContext->m_ContextLock.Unlock();
#endif
}
inline void SecureChatIOCP::ProcessPayload(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{
BYTE PackageType=pOverlapBuff->GetPackageType();
switch ( PackageType)
{
case PKG_TEXT_TO_ALL:
OnPKG_TEXT_TO_ALL(pOverlapBuff,nSize,pContext);
break;
case PKG_USERNAME_PASSWORD:
OnPKG_USERNAME_PASSWORD(pOverlapBuff,nSize,pContext);
break;
}
}
void SecureChatIOCP::NotifyReceivedPackage(CIOCPBuffer *pOverlapBuff,int nSize,ClientContext *pContext)
{
// No Context? Why do the work ?
if ( pContext==NULL )
{
AppendLog("pContext==NULL) in NotifyReceivedPackage");
return;
}
// No Connection ?? Why do the work ?
if ( pContext->m_Socket==INVALID_SOCKET )
{
//AppendLog("pContext->m_Socket==INVALID_SOCKET in NotifyReceivedPackage");
return;
}
BYTE PackageType=pOverlapBuff->GetPackageType();
switch (PackageType)
{
case PKG_ERRORMSG:
OnPKG_ERRORMSG(pOverlapBuff,nSize,pContext);
break;
case PKG_ENCRYPTED:
{
//pContext->m_bGotSessionKey=FALSE;
if(! pContext->m_bGotSessionKey )
{
SendErrorMessageTo(pContext->m_Socket,"Server> Session key Not available, you are not authorized");
CString msg;
msg.Format("Client %x (%s) not Authorized",pContext->m_Socket,GetHostAddress(pContext->m_Socket));
AppendLog(msg);
break;
}
CIOCPBuffer *pDecryptedPKG=DeCryptBuffer(pOverlapBuff,pContext);
if ( !pDecryptedPKG )
{
AppendLog("SECURITY RISK: Warning could not decrypt the clients message.. The remote client may be try to hack your system.");
DisconnectClient(pContext->m_Socket);
}else
{
// Process it
ProcessPayload(pDecryptedPKG,pDecryptedPKG->GetUsed(),pContext);
}
if ( pDecryptedPKG )
ReleaseBuffer(pDecryptedPKG);
break;
}
#ifdef _IOCPClientMode_ // Handle the package sent from server
case PKG_PUBLIC_KEYA:
OnPKG_PUBLIC_KEYA(pOverlapBuff,nSize,pContext);
break;
case PKG_SIGNATURE:
OnPKG_SIGNATURE(pOverlapBuff,nSize,pContext);
break;
#else // Handle the package sent from clients.
case PKG_PUBLIC_KEYP:
OnPKG_PUBLIC_KEYP(pOverlapBuff,nSize,pContext);
break;
case PKG_PUBLIC_KEYB:
OnPKG_PUBLIC_KEYB(pOverlapBuff,nSize,pContext);
break;
#endif
};
}
/*
* Called when a package with user data have arrived..
*
*
*/
inline void SecureChatIOCP::OnPKG_ERRORMSG(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{
BYTE PayloadType= 255;
CString sTxtErr;
PBYTE pPayload=pOverlapBuff->GetPayLoadBuffer();
pPayload++;
if( nSize>=MINIMUMPACKAGESIZE+2)
memcpy(&PayloadType,pPayload,1);
pPayload++;
// Assumes that we already have a null termination.
if( nSize >=MINIMUMPACKAGESIZE+2 )
sTxtErr=pPayload;
pContext->m_sUsername=sTxtErr;
pContext->m_bUpdateList=TRUE;
AppendLog(sTxtErr);
}
inline void SecureChatIOCP::OnPKG_TEXT_TO_ALL(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{
CString sTxt;
nSize=pOverlapBuff->GetPackageSize();
PBYTE pPayload=pOverlapBuff->GetPayLoadBuffer();
pPayload++;
// Assumes that we already have a null termination.
if( nSize >=0 )
sTxt=pPayload;
#ifndef _IOCPClientMode_
AppendLog(pContext->m_sUsername+">"+sTxt);
SendTextMessage(pContext->m_sUsername+" >"+sTxt);
#else
AppendLog(sTxt);
#endif
}
inline void SecureChatIOCP::OnPKG_USERNAME_PASSWORD(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{
BYTE PayloadType= 255;
PBYTE pBuff1=NULL;
PBYTE pBuff2=NULL;
UINT nBuffSize=0;
UINT nBuffSize2=0;
// Read the Package
ReadPkg(pOverlapBuff,nBuffSize,&pBuff1,nBuffSize2,&pBuff2,pContext);
if ( pBuff1!=NULL )
{
pContext->m_sUsername=pBuff1;
pContext->m_bUpdateList=TRUE;
//FIXME: Send Notification to all Users and send
// User list to Client.
AppendLog("Secure connection established.");
AppendLog(pContext->m_sUsername+ ", joined Channel..");
SendTextMessage(pContext->m_sUsername+ ", joined Channel..");
}
}
/*
* Handle the Public Key P according to Diffie-Hellman
* key exchange procedure.
*
* Send the respons as Public Key P.
*
*/
inline void SecureChatIOCP::OnPKG_PUBLIC_KEYP(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{
UINT nKeySize=0;
// read the public key from the buffer.
DWORD* pKey=ReadPublicKeyFromBuffer(pOverlapBuff,nKeySize,pContext);
if ( pKey )
{
pContext->m_ContextLock.Lock();
// Make sure that the Public key P is accepted for year 2005, _MINPUBLICKEYPSIZE_ = 1024 bits.
// FIXME: What if the public key P is not prime ? is the security broken ?
UINT nPubKeyBitLength= pContext->m_cCryptLib.BNBitLength(pKey,nKeySize);
if ( nPubKeyBitLength < _MINPUBLICKEYPSIZE_)
{
SendErrorMessageTo(pContext->m_Socket,"Error PKG_PUBLIC_KEYP not accepted!, Size to small Minimum 1024 bits. ");
pContext->m_ContextLock.Unlock();
return;
}
// We must make a copy of the public key P.
// FIXME: allocate data on the heap is bad (hmm change later)
DWORD* pPublicKeyP=NULL;
pPublicKeyP= new DWORD[nKeySize];
if ( pPublicKeyP )
{
memcpy(pPublicKeyP,pKey,nKeySize*sizeof(DWORD));
}else
{
AppendLog("Error pPublicKeyP=NULL, not enough memory");
DisconnectClient(pContext->m_Socket);
pContext->m_ContextLock.Unlock();
}
// allocate data on the heap is bad (hmm change later)
if ( pContext->m_pPublickey )
delete[] pContext->m_pPublickey;
pContext->m_pPublickey = pPublicKeyP;
// Generate private key.. (just a Random nr)
pContext->m_cCryptLib.BNMakeRandomNr(pContext->m_Privatekey,_PRIVATEKEYSIZE_);
pContext->m_bGotSessionKey=FALSE;
pContext->m_nPublicKeySize=nKeySize;
pContext->m_sUsername="Public key Accepted.";
// Compute And Send Public Key A.
// FIXME : Should post this part into the
// IOCP for fair cpu clock distribution.
// Takes about ~40ms..
ComputeAndSendPublicKeyA(pContext);
pContext->m_ContextLock.Unlock();
} else
{
AppendLog("OnPKG_PUBLIC_KEYP Failed Package error");
}
}
/*
* ComputeAndSendPublicKey(ClientContext *pContext, BYTE _keytype)
*
* The Function computes the punlic key according to Diffie-Hellman algorithm
* The Function also hash the Computed key for digital signing later on..
*
* _keytype is PKG_PUBLIC_KEYA or PKG_PUBLIC_KEYB
*
* Observe that the function assumes that private random key a is
* already Initialized.
*
*/
void SecureChatIOCP::ComputeAndSendPublicKey(ClientContext *pContext, BYTE _keytype)
{
// Be safe or no need to do the work
if ( !pContext || !pContext->m_pPublickey || pContext->m_Socket==INVALID_SOCKET)
return;
DWORD bnPublicKeyAB[_PRIVATEKEYSIZE_];
DWORD bnG[_PRIVATEKEYSIZE_];
UINT nPublicKeySize=_PRIVATEKEYSIZE_;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -