📄 securechatiocp.cpp
字号:
pContext->m_ContextLock.Unlock();
AppendLog("Secure connection established.");
#endif
}
}
/*
* Handle the Public Key B according to Diffie-Hellman
* key exchange procedure.
*
* Send the respons as Public Key P.
*
*/
inline void SecureChatIOCP::OnPKG_PUBLIC_KEYB(CIOCPBuffer *pOverlapBuff, int nSize, ClientContext *pContext)
{
// Be safe
if ( !pContext || !pContext->m_pPublickey || !pOverlapBuff)
return;
if ( ComputeAndSetSessionKey(pOverlapBuff,nSize,pContext) )
{
// The Server is not Protected from "man in middle attack"
// the server should authorize the client by a password or something
// else.
pContext->m_ContextLock.Lock();
pContext->m_bGotSessionKey=TRUE;
pContext->m_ContextLock.Unlock();
// Compute and send Signature. .
// FIXME : Should post this part into the
// IOCP for fair cpu clock distribution.
// Takes about > 500ms..
#ifdef USE_SIGNATURE
ComputeAndSendSignature(pContext);
#endif
}
}
/*
* EnCryptBuffer(CIOCPBuffer *pBuff, ClientContext *pContext)
*
* Encrypts The buffer with the Rijndael, Cipher Block Chaining (CBC) cipher.
* designed by Joan Daemen and Vincent Rijmen as a candidate algorithm for the AES
* The cipher operates on 16 byte blocks and 256 bits keylength.
*
* The function also computes an CRC16 (two bytes) checksum and add it to the buffer
* to recognize incorrect decryption on the other side.
*
* If the buffer size plus the two bytes that come from the CRC16 is not a multiple of
* 16 bytes (needed for the encryption), random data is added at the end.
*
* Returns NULL if something went wrong or the encrypted buffer.
*
*/
CIOCPBuffer *SecureChatIOCP::EnCryptBuffer(CIOCPBuffer *pBuff, ClientContext *pContext)
{
if ( pBuff==NULL || pContext==NULL )
{
ReleaseBuffer(pBuff);
return NULL;
}
if ( !pContext->m_bGotSessionKey)
{
ReleaseBuffer(pBuff);
return NULL;
}
CIOCPBuffer *pCrypBuff=NULL;
//
// Allocate Buffer for the encrypted pkg.
//
pCrypBuff=AllocateBuffer(IOWrite);
if ( pCrypBuff!=NULL )
{
//
// Compute CRC16
//
unsigned short usCRC16;
pContext->m_cCryptor.crc16_init(&usCRC16);
pContext->m_cCryptor.crc16_update(&usCRC16,pBuff->GetBuffer(),pBuff->GetUsed());
pContext->m_cCryptor.crc16_final(&usCRC16);
//
// Add the CRC16 to the Buffer
//
if ( !pBuff->AddData(usCRC16) )
{
AppendLog("Error pBuff->AddData(usCRC16) in EnCryptBuffer");
DisconnectClient(pContext->m_Socket);
ReleaseBuffer(pCrypBuff);
}
//
// Check if The Buffer size is a multiple of the blocksize, if not
// add some random nr.
//
int iBlockSize=16;
int iBufferRest=0;
UINT iBufferLenght=0;
iBufferLenght=pBuff->GetUsed();
iBufferRest=iBufferLenght%iBlockSize;
// How Much is needed to make the buffersize to be a multible of the block size?
if ( iBufferRest!=0 )
{
iBufferRest=iBlockSize-iBufferRest;
}
// add random Numbers at the end so we will have an cryptable buffer.
for ( int i=0; i<iBufferRest; i++ )
{
if ( !pBuff->AddData((BYTE)(rand()%255)) )
{
AppendLog("Error pBuff->AddData((BYTE)(rand()%255) in EnCryptBuffer");
DisconnectClient(pContext->m_Socket);
ReleaseBuffer(pCrypBuff);
}
}
// We have a new length.
iBufferLenght=pBuff->GetUsed();
// For the package type.
iBufferLenght++;
//
// Configure the new package.
//
if ( iBufferLenght+MINIMUMPACKAGESIZE>MAXIMUMPACKAGESIZE )
{
AppendLog("Error package to big to fit in the buffer");
DisconnectClient(pContext->m_Socket);
ReleaseBuffer(pCrypBuff);
}
// Add the size of the buffer to the beging.We will not crypt this part.
pCrypBuff->AddData(iBufferLenght);
// Add the Type.
pCrypBuff->AddData((BYTE)PKG_ENCRYPTED);
//
// Encrypt and add to payload.
//
try
{
pContext->m_ContextLock.Lock();
pContext->m_cCryptor.ResetChain(); // Because of CBC
pContext->m_cCryptor.Encrypt((char const*)pBuff->GetBuffer(),(char*)pCrypBuff->GetBuffer()+MINIMUMPACKAGESIZE+1,iBufferLenght-1,1);
pContext->m_ContextLock.Unlock();
}
catch(exception& roException)
{
AppendLog("Error Could not encrypt in EnCryptBuffer");
DisconnectClient(pContext->m_Socket);
ReleaseBuffer(pCrypBuff);
pContext->m_ContextLock.Unlock();
pCrypBuff=NULL;
return NULL;
}
// add the payload.
pCrypBuff->Use(pBuff->GetUsed());
ReleaseBuffer(pBuff);
//
// Finished...
//
}else
{
AppendLog("Error Could not allocate memory in EnCryptBuffer");
}
return pCrypBuff;
}
/*
* DeCryptBuffer(CIOCPBuffer *pBuff, ClientContext *pContext)
*
* Decrypts the encrypted buffer. (see EnCryptBuffer(..) for more info)
*
* Returns the decrypted Buffer or return NULL if failed (or CRC16 did not mach)
*
*/
CIOCPBuffer* SecureChatIOCP::DeCryptBuffer(CIOCPBuffer *pBuff, ClientContext *pContext)
{
if ( pBuff==NULL || pContext==NULL )
return NULL;
if ( !pContext->m_bGotSessionKey )
return NULL;
CIOCPBuffer *pCrypBuff=NULL;
//
// Allocate Buffer for the encrypted pkg.
//
pCrypBuff=AllocateBuffer(IOWrite);
if ( pCrypBuff!=NULL )
{
//
// Decrypt
//
int iBufferLenght=pBuff->GetPackageSize();
try
{
pContext->m_ContextLock.Lock();
pContext->m_cCryptor.ResetChain(); // Because of CBC
pContext->m_cCryptor.Decrypt((char const*)pBuff->GetBuffer()+MINIMUMPACKAGESIZE+1,(char *)pCrypBuff->GetBuffer(),iBufferLenght-1,1);
pContext->m_ContextLock.Unlock();
}
catch(exception& roException)
{
AppendLog("Error Could not encrypt in DeCryptBuffer");
ReleaseBuffer(pCrypBuff);
pCrypBuff=NULL;
return NULL;
}
//
// Get the CRC Data from the Decrypted package and Make a package test.
//
// First we have to tell it that it have a header.
pCrypBuff->Use(MINIMUMPACKAGESIZE);
// Get the PackageSize.
iBufferLenght=pCrypBuff->GetPackageSize();
//
// Check if the size was correct
//
if ( iBufferLenght>MAXIMUMPACKAGESIZE-MINIMUMPACKAGESIZE )
{
AppendLog("Error Could not dencrypt in DeCryptBuffer. (the header size was to big)");
ReleaseBuffer(pCrypBuff);
return NULL;
}
// well we have to tell our buffer that it has the data.
pCrypBuff->Use(iBufferLenght);
unsigned short uspkgCRC16;
// We put the two byte long CRC cheksum at the end of package..
memcpy(&uspkgCRC16,pCrypBuff->GetBuffer()+MINIMUMPACKAGESIZE+iBufferLenght,sizeof(unsigned short));
//
// Compute CRC16
//
unsigned short usCRC16;
pContext->m_cCryptor.crc16_init(&usCRC16);
pContext->m_cCryptor.crc16_update(&usCRC16,pCrypBuff->GetBuffer(),pCrypBuff->GetUsed());
pContext->m_cCryptor.crc16_final(&usCRC16);
// The package is not Decrypted correctly.
if ( uspkgCRC16!=usCRC16 )
{
AppendLog("CRC16 cheksum Error. in DeCryptBuffer.");
ReleaseBuffer(pCrypBuff);
return NULL;
}
//
// Finished...
//
}else
{
AppendLog("Error Could not allocate memory in EnCryptBuffer");
//DisconnectClient(pContext->m_Socket);
}
return pCrypBuff;
}
int SecureChatIOCP::MaxEncyptedPayloadSize(int iMaxLength)
{
//
// For encryption we need some extra space. .
//
// We have to make room for another sizeheader,type header
// and also The CRC Checksum
iMaxLength-=(MINIMUMPACKAGESIZE+sizeof(unsigned short)+1);
// Furthermore we have to be sure that the maximumsize is
// a multipe of the blocksize (16).
// e.g a maximum size of 500 or 499 ot 488 results will be increased
// to 512 because of encryption algorithm.. The total size of the data
// must be a multiple of 16.
int iMaxCryptSize=MAXIMUMENCRYPSIZE-MINIMUMPACKAGESIZE-MINIMUMPACKAGESIZE-sizeof(unsigned short)-1;
//iMaxLength=(iMaxLength>iMaxCryptSize) ? iMaxCryptSize : iMaxLength;
return min(iMaxLength,iMaxCryptSize);
}
void SecureChatIOCP::SendTextMessage(CString msg)
{
// FIXME: Should post this into IOCP so it is handled by IOWORKERS.
m_ContextMapLock.Lock();
UINT nSize= m_ContextMap.GetCount();
if ( m_ContextMap.GetCount()>0 )
{
POSITION pos = m_ContextMap.GetStartPosition ();
// Here we must check if the m_ContextMap.GetCount() is > 0 because
// One or more clients can be disconnected handling SendTextMessageTo(..)
while ( pos != NULL && m_ContextMap.GetCount()>0 )
{
unsigned int iKey;
ClientContext *pContext=NULL;
m_ContextMap.GetNextAssoc (pos, iKey,pContext);
if ( pContext!=NULL )
{
SendTextMessageTo(pContext,msg);
}
}
}
m_ContextMapLock.Unlock();
}
/*
* Send Message to Client with ID iClientID
*
*/
BOOL SecureChatIOCP::SendTextMessageTo(int iClientID, CString sMsg)
{
BOOL bRet=FALSE;
m_ContextMapLock.Lock();
ClientContext* pContext = FindClient(iClientID);
if ( pContext == NULL )
{
m_ContextMapLock.Unlock();
return FALSE;
}
bRet=SendTextMessageTo(pContext,sMsg);
m_ContextMapLock.Unlock();
return bRet;
}
/*
* Returns true if we have active connections.
*
*/
BOOL SecureChatIOCP::IsConnected()
{
UINT nSizeOfConnectedClients=0;
m_ContextMapLock.Lock();
nSizeOfConnectedClients=m_ContextMap.GetCount();
m_ContextMapLock.Unlock();
return nSizeOfConnectedClients>0;
}
BOOL SecureChatIOCP::SendTextMessageTo(ClientContext* pContext, CString sMsg)
{
if ( !pContext->m_bGotSessionKey )
{
//AppendLog("Client is not authorized");
return FALSE;
}
UINT nBufLen = sMsg.GetLength();
// Add one to the size header for the null termination byte.
nBufLen++;
// Add one for the Payload type (text)
nBufLen++;
if ( nBufLen>=MaxEncyptedPayloadSize(MAXIMUMPAYLOADSIZE-2) )
{
AppendLog("SendMessageTo FAILED Message to long for encryption..");
return FALSE;
}
if ( nBufLen>=MAXIMUMPAYLOADSIZE || nBufLen<=0 )
{
AppendLog("SendMessageTo FAILED Message to long or zero..");
return FALSE;
}
CIOCPBuffer *pBuff=AllocateBuffer(IOWrite);
if ( !pBuff )
{
AppendLog("SendMessageTo FAILED pOverlapBuff=NULL");
return FALSE;
}
pBuff->EmptyUsed();
// Size Header
pBuff->AddData(nBufLen);
// Payload Header
pBuff->AddData((BYTE)PKG_TEXT_TO_ALL);
// Add the string.
int length=sMsg.GetLength();
pBuff->AddData((PBYTE) sMsg.GetBuffer(length),length);
//Extra Null Teriminate (for Strings)
pBuff->AddData((BYTE)'\0');
// Encrypt the buffer
pBuff=EnCryptBuffer(pBuff,pContext);
// Send it.
ASend(pContext,pBuff);
return TRUE;
}
BOOL SecureChatIOCP::SendErrorMessageTo(int iClientID, CString sMsg)
{
UINT nBufLen = sMsg.GetLength();
// Add one to the size header for the null termination byte.
nBufLen++;
// Add one for the message type (encrypted/SessionExchange/ERROR_MESSAGE)..
nBufLen++;
// Add one for the Payload type (text)
nBufLen++;
if ( nBufLen>=MAXIMUMPAYLOADSIZE || nBufLen<=0 )
{
AppendLog("SendMessageTo FAILED Message to long or zero..");
return FALSE;
}
CIOCPBuffer *pBuff=AllocateBuffer(IOWrite);
if ( !pBuff )
{
AppendLog("SendMessageTo FAILED pOverlapBuff=NULL");
return FALSE;
}
// Make sure that buffer is empty
pBuff->EmptyUsed();
// Size Header
pBuff->AddData(nBufLen);
// Message Header
pBuff->AddData((BYTE)PKG_ERRORMSG);
// Payload Header
pBuff->AddData((BYTE)PKG_ERRORMSG);
// Add the string.
int length=sMsg.GetLength();
pBuff->AddData((PBYTE) sMsg.GetBuffer(length),length);
//Extra Null Teriminate (for Strings)
pBuff->AddData((BYTE)'\0');
ASend(iClientID,pBuff);
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -