⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 securechatiocp.cpp

📁 提供加密的c/s 聊天程序。用到对称加密算法和非对称加密算法
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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 + -