📄 securechatiocp.cpp
字号:
// 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 + -