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

📄 securechatiocp.cpp

📁 提供加密的c/s 聊天程序。用到对称加密算法和非对称加密算法
💻 CPP
📖 第 1 页 / 共 3 页
字号:
	// Lock The  context. (we are going to access private members. 
	pContext->m_ContextLock.Lock();

	pContext->m_cCryptLib.BNSetEqualdw(bnG,5,_PRIVATEKEYSIZE_);
	// A= g^ a mod(p). 
	pContext->m_cCryptLib.BNModExp(bnPublicKeyAB, bnG, pContext->m_Privatekey, pContext->m_pPublickey,nPublicKeySize);
	// Hash it for Digital Signing (later on)..
	pContext->m_cCryptLib.SHA1_Hash((PBYTE)bnPublicKeyAB,_PRIVATEKEYSIZE_*4,&pContext->m_csha1Hash);
	pContext->m_ContextLock.Unlock();

	// Send the public key. 
	SendPublicKey (pContext,_keytype,bnPublicKeyAB,nPublicKeySize);
}


/*
* Compute and send Public key A. 	
*/
void SecureChatIOCP::ComputeAndSendPublicKeyA(ClientContext *pContext)
{
	ComputeAndSendPublicKey(pContext,PKG_PUBLIC_KEYA);	
}


/*
* Compute and send Public keyB. 	
*/
void SecureChatIOCP::ComputeAndSendPublicKeyB(ClientContext *pContext)
{
	ComputeAndSendPublicKey(pContext,PKG_PUBLIC_KEYB);
}

/*
* This function Build a package of type 	
*
* [obligatory headersize|Headertype (_keytype)| public key size (nPublicKeySize) | Publickey ( * obligatory headersize|Headertype (_keytype)| public key size (nPublicKeySize) | Publickey] 
*
* and sends it to client. 
*/
void SecureChatIOCP::SendPublicKey(ClientContext *pContext, BYTE _keytype, DWORD *_pPublicKey, UINT nPublicKeySize)
{

	CIOCPBuffer *pBuff=AllocateBuffer(IOWrite);
	if( !pBuff )
	{
		AppendLog("SendPublicKey FAILED pBuff=NULL");
		return;
	}

	UINT nPayLoadLen=sizeof(DWORD)+sizeof(BYTE)+nPublicKeySize*sizeof(DWORD);

	pBuff->EmptyUsed();
	// Size Header
	pBuff->AddData(nPayLoadLen);
	// Payload type 
	pBuff->AddData((BYTE)_keytype);
	// The size of nPublicKey
	pBuff->AddData(nPublicKeySize);	
	// add the public key. 
	pBuff->AddData((PBYTE)_pPublicKey,nPublicKeySize*4);
	ASend(pContext,pBuff);

}

/*
* Please see BuildAndSend(ClientContext *pContext, BYTE _pkgtype, UINT nBufferSize1, BYTE *_pBuff1, UINT nBufferSize2, BYTE *_pBuff2)
*
*
*/

void SecureChatIOCP::BuildAndSend(ClientContext *pContext, BYTE _pkgtype, CString str1, CString str2)
{
	BuildAndSend(pContext,_pkgtype,str1.GetLength(),(PBYTE)str1.GetBuffer(str1.GetLength()),str2.GetLength(),(PBYTE)str2.GetBuffer(str1.GetLength()));
}

void SecureChatIOCP::BuildAndSend(ClientContext *pContext, BYTE _pkgtype, CString str1,UINT nBufferSize2, const BYTE *_pBuff2 )
{
	BuildAndSend(pContext,_pkgtype,str1.GetLength(),(PBYTE)str1.GetBuffer(str1.GetLength()),nBufferSize2,_pBuff2);
}



/*
* This function Build a package of type 	
*
* [obligatory headersize|Headertype (_keytype)| buff1 size| buff1 |buff2 size| buff2 ]
* and sends it to client. 
*/

void SecureChatIOCP::BuildAndSend(ClientContext *pContext, BYTE _pkgtype, UINT nBufferSize1,const BYTE *_pBuff1, UINT nBufferSize2, const BYTE *_pBuff2)
{

	if ( !pContext->m_bGotSessionKey )
	{
		AppendLog("BuildAndSend FAILED, no Session key..");
		return;
	}

	UINT nPayLoadLen=sizeof(BYTE)+sizeof(UINT)+nBufferSize1+sizeof(UINT)+nBufferSize2+2; // two null termination. 

	if ( nPayLoadLen > MAXIMUMPAYLOADSIZE)
	{
		AppendLog("BuildAndSend FAILED, nPayLoadLen > MAXIMUMPAYLOADSIZE");
		return;
	}

	if ( nPayLoadLen > MaxEncyptedPayloadSize(MAXIMUMPAYLOADSIZE-1) )
	{
		AppendLog("BuildAndSend FAILED, nPayLoadLen > MaxEncyptedPayloadSize");
		return;  
	}


	CIOCPBuffer *pBuff=AllocateBuffer(IOWrite);
	if ( !pBuff )
	{
		AppendLog("BuildAndSend FAILED pBuff=NULL");
		return;
	}

	pBuff->EmptyUsed();
	// Size Header
	pBuff->AddData(nPayLoadLen);
	// Payload type 
	pBuff->AddData((BYTE)_pkgtype);
	// The size of the buffer
	pBuff->AddData(nBufferSize1);	
	// add the buffer. 
	pBuff->AddData(_pBuff1,nBufferSize1);
	pBuff->AddData((BYTE)0);
	// The size of the buffer
	pBuff->AddData(nBufferSize2);	
	// add the buffer. 
	pBuff->AddData(_pBuff2,nBufferSize2);
	pBuff->AddData((BYTE)0);
	// Encrypt the data.. 
	pBuff=EnCryptBuffer(pBuff,pContext);
	ASend(pContext,pBuff);
}



/*
* ReadPublicKeyFromBuffer(CIOCPBuffer *pBuff, UINT &nKeySize,ClientContext *pContext)
*	
* Reads public key from buffer pBuff. (Reads the packages created with SendPublicKey(..)
* 
* Output: 
* - Returns a Pointer to the public key. (if Successfull). 
* - nKeySize the size (in DWORD) of the key. 
*
*/

DWORD* SecureChatIOCP::ReadPublicKeyFromBuffer(CIOCPBuffer *pBuff, UINT &nKeySize,ClientContext *pContext)
{
	DWORD* pKey=NULL;
	nKeySize=0;
	UINT nSize=pBuff->GetUsed();
	PBYTE pPayload=pBuff->GetPayLoadBuffer()+1; // Point to the nKeySize

	if ( nSize>=MINIMUMPACKAGESIZE+4 )
	{
		memcpy(&nKeySize,pPayload,4);
	}
	else
	{
		SendErrorMessageTo(pContext->m_Socket,"Error PKG_PUBLIC_KEYX not accepted!, Size to small.");
		return NULL;
	}
	// If the keysize is reasonable size 0 < x < 4000 bits. 
	if( nKeySize>0 && nKeySize < (MAXIMUMPAYLOADSIZE-4-1)/4) 
	{
		pPayload+=sizeof(UINT);
		pKey=(DWORD*)pPayload;
	}
	else
	{
		SendErrorMessageTo(pContext->m_Socket,"Error PKG_PUBLIC_KEYX not accepted!");
	}

	return pKey;
}

/*
*	Reads a package created with BuildAndSend(..)
*
*
*/
void SecureChatIOCP::ReadPkg(CIOCPBuffer *pBuff, UINT &nSize, BYTE **_pBuff1, UINT &nSize2, BYTE **_pBuff2, ClientContext *pContext)
{


	pBuff->DUMP();

	nSize=0;
	nSize2=0;
	*_pBuff1=NULL;
	*_pBuff2=NULL;
	UINT nPkgSize=pBuff->GetUsed();
	if ( nPkgSize > MAXIMUMPACKAGESIZE )
	{

		return;
	}

	PBYTE pPayload=pBuff->GetPayLoadBuffer()+1; // Point to the nSize

	if ( nPkgSize>=MINIMUMPACKAGESIZE+sizeof(nSize))
	{
		memcpy(&nSize,pPayload,sizeof(nSize));
	}
	else
	{
		SendErrorMessageTo(pContext->m_Socket,"Error PKG not accepted!, Size to small.");
		return;
	}

	// If the nSize of the buffer is reasonable size 0 < x < 4000 bits. 
	if ( nSize>0 && nSize < (MAXIMUMPAYLOADSIZE-sizeof(nSize)-1)) 
	{
		pPayload+=sizeof(nSize);
		*_pBuff1=pPayload;
	}
	else
	{
		SendErrorMessageTo(pContext->m_Socket,"Error PKG not accepted! Username is Empty.");
		return;
	}

	pPayload+=nSize+1; // Size of the buffer and the null termination. 

	if ( nPkgSize>=MINIMUMPACKAGESIZE+sizeof(nSize)+nSize+sizeof(nSize))
	{
		memcpy(&nSize2,pPayload,sizeof(nSize2));
	}
	else
	{
		SendErrorMessageTo(pContext->m_Socket,"Error PKG not accepted!, Size to small.");
		return;
	}


	// If the nSize of the buffer is reasonable size 0 < x < 4000 bits. 
	if ( nSize2>0 && nSize2 < (MAXIMUMPAYLOADSIZE-sizeof(nSize)-1-nSize-sizeof(nSize))) 
	{
		pPayload+=sizeof(nSize2);
		*_pBuff2=pPayload;
	}
	else
	{
		SendErrorMessageTo(pContext->m_Socket,"Error PKG not accepted!");
		return; 
	}

}



/*
* The function computes the session key of size _PRIVATEKEYSIZE_ according to Diffie-Hellman algorithm, 
* given that:
*
*
* - pOverlapBuff contains the public key A or public Key B
* - The private key is already randomly generated. 
* The CRijndael is used with 256bit key and a CBC with a chain of 128bits
* 
* The function returns TRUE is successfull, FALSE if not. 
* 
*/


BOOL SecureChatIOCP::ComputeAndSetSessionKey(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{

	UINT  nKeySize=0;
	DWORD bnSessionKey[_PRIVATEKEYSIZE_];

	// read the public key from the buffer. 
	DWORD* pKey=ReadPublicKeyFromBuffer(pOverlapBuff,nKeySize,pContext);

	// if we have a key 
	if ( pKey )
	{
		pContext->m_ContextLock.Lock();

		// Hash PublicKeyA or B for Digital Signing (later on).. 
		pContext->m_cCryptLib.SHA1_Hash((PBYTE)pKey,nKeySize*4,&pContext->m_csha1Hash);
		// S= A^ b mod(p). 
		pContext->m_cCryptLib.BNModExp(bnSessionKey, pKey, pContext->m_Privatekey, pContext->m_pPublickey,nKeySize);

		// Use the Session key.. (we do not trust it until we check the signature.)
		pContext->m_cCryptor.MakeKey((const char * )bnSessionKey,(const char * )(bnSessionKey+8),32,16);

		pContext->m_ContextLock.Unlock();

		return TRUE; 
	}
	return FALSE; 
}


/*
* 
* The Function Computes The KeyB Accourding to Diffie-Hellman 
* Algorithm The Function also Adds The the Computed key into the
* Hashvalue for digital signing. 
*
*/
void SecureChatIOCP::ComputeAndSendSignature(ClientContext *pContext)
{
	// Be Safe 
	if( !pContext )
		return;
#ifndef _IOCPClientMode_

	// FIXME: Change later. 
	const UINT nSize=sizeof(m_DSAKeypubD)/4;
	DWORD S[nSize];
	int iRet=0;


	pContext->m_ContextLock.Lock();

	// Finish the Hash of public key A and key B. 
	DWORD aHashValue[_HASHSIZE_/4];

	pContext->m_cCryptLib.BNSetZero(aHashValue,_HASHSIZE_/4);
	pContext->m_cCryptLib.BNSetZero(S,nSize);


	pContext->m_cCryptLib.SHA1_Finish((unsigned char*)aHashValue,&pContext->m_csha1Hash);

	TRACE("aHashValue %s \r\n",pContext->m_cCryptLib.BNPrintC(aHashValue,_HASHSIZE_/4));

	// FIXME: REMOVE LATER: 
	/*	
	CString stmp;
	stmp.Format("aHashValue %s \r\n",pContext->m_cCryptLib.BNPrintC(aHashValue,_HASHSIZE_/4));
	AppendLog(stmp);*/

	//  Compute hash^d mod n
	iRet=pContext->m_cCryptLib.BNModExp(S,aHashValue,m_DSAKeypubD,m_DSAKeypubN,nSize);	

	pContext->m_sUsername="Sending signature.";

	AppendLog("Sending signature..");

	pContext->m_bUpdateList=TRUE;

	pContext->m_ContextLock.Unlock();

	SendPublicKey(pContext,PKG_SIGNATURE,S,nSize);
#endif

}





/*
* Handle the Signaature accourding to RSA alghorithm, 
*  
*/
inline void SecureChatIOCP::OnPKG_SIGNATURE(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{	


	// Be safe
	if ( !pContext || !pContext->m_pPublickey || !pOverlapBuff )
		return;

	// FIXME: Change later. Size of is BAD can give different answer (depends on compilation)
	const UINT nPubkeySize=sizeof(m_DSAKeypubN)/4;
	DWORD aRefHashValue[nPubkeySize];
	DWORD aPubKeyE[nPubkeySize];
	int iRet=0;


	// Finish the Hash of public key A and key B. 
	DWORD aHashValue[_HASHSIZE_/4];

	// read the signature from the buffer. 
	UINT  nKeySize=0;
	DWORD* pSig=ReadPublicKeyFromBuffer(pOverlapBuff,nKeySize,pContext);

	// If we have a signature Check it. 
	if ( pSig && nKeySize == nKeySize)
	{
		pContext->m_ContextLock.Lock();

		pContext->m_cCryptLib.BNSetZero(aRefHashValue,nPubkeySize);
		pContext->m_cCryptLib.BNSetEqualdw(aPubKeyE,m_DSAKeypubE,nPubkeySize);

		// Compute the hash value. 
		pContext->m_cCryptLib.SHA1_Finish((unsigned char*)aHashValue,&pContext->m_csha1Hash);


		TRACE("aHashValue %s \r\n",pContext->m_cCryptLib.BNPrintC(aHashValue,_HASHSIZE_/4));

		//  Compute y=(S)^e mod n ptmp2=e=3. 
		iRet=pContext->m_cCryptLib.BNModExp(aRefHashValue,pSig,aPubKeyE,m_DSAKeypubN,nPubkeySize);

		// Check if signature was correct..
		if ( iRet >= 0 && pContext->m_cCryptLib.BNIsEqual(aRefHashValue,aHashValue,_HASHSIZE_/4))
		{
			pContext->m_bGotSessionKey=TRUE;
			AppendLog("Signature verified..");
			AppendLog("Secure connection established.");

			// We have Secure Connection to the server. 

			// Send the user name and password..
			BuildAndSend(pContext,PKG_USERNAME_PASSWORD,pContext->m_sUsername,"dummy");		

		} 
		else
		{
			AppendLog("Signature verfication failed.");
			SendErrorMessageTo(pContext->m_Socket,"Error Signature not accepted!");
			pContext->m_ContextLock.Unlock();	
		}
		pContext->m_ContextLock.Unlock();

	}
	else
	{
		AppendLog("Signature verfication failed. (incorrect package)");
		SendErrorMessageTo(pContext->m_Socket,"Error Signature not accepted!");
	}

}




/*
* Handle the Public Key A according to Diffie-Hellman 
* key exchange procedure.  	
*  
* Send the respons as Public Key P. 
* 
*/
inline void SecureChatIOCP::OnPKG_PUBLIC_KEYA(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{	

	// Be safe
	if ( !pContext || !pContext->m_pPublickey || !pOverlapBuff )
		return;

	pContext->m_ContextLock.Lock();
	// Generate private key.. (just a Random nr) 
	pContext->m_cCryptLib.BNMakeRandomNr(pContext->m_Privatekey,_PRIVATEKEYSIZE_);
	pContext->m_ContextLock.Unlock();

	if ( ComputeAndSetSessionKey(pOverlapBuff,nSize,pContext) )
	{
		AppendLog("Received public key A..");
		// Compute And Send Public Key B. 
		// FIXME : Should post this part into the 
		// IOCP for fair cpu clock distribution.
		// Takes about ~40ms.. 
		ComputeAndSendPublicKeyB(pContext);

		// if USE_SIGNATURE is defined here we do not set the m_bGotSessionKey to true, even if 
		// the session key is exchanged. Because we 
		// Are not protected from "Man in middle attacks". 
#ifndef USE_SIGNATURE
		pContext->m_ContextLock.Lock();
		pContext->m_bGotSessionKey=TRUE;
		// We have Secure Connection to the server. 
		// Send the user name and password..
		BuildAndSend(pContext,PKG_USERNAME_PASSWORD,pContext->m_sUsername,"dummypwd");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -