📄 clientcredits.cpp
字号:
void CClientCreditsList::Process()
{
if (::GetTickCount() - m_nLastSaved > MIN2MS(13))
SaveList();
}
void CClientCredits::InitalizeIdent(){
if (m_pCredits->nKeySize == 0 ){
memset(m_abyPublicKey,0,80); // for debugging
m_nPublicKeyLen = 0;
IdentState = IS_NOTAVAILABLE;
}
else{
m_nPublicKeyLen = m_pCredits->nKeySize;
memcpy(m_abyPublicKey, m_pCredits->abySecureIdent, m_nPublicKeyLen);
IdentState = IS_IDNEEDED;
}
m_dwCryptRndChallengeFor = 0;
m_dwCryptRndChallengeFrom = 0;
m_dwIdentIP = 0;
}
void CClientCredits::Verified(uint32 dwForIP){
m_dwIdentIP = dwForIP;
// client was verified, copy the keyto store him if not done already
if (m_pCredits->nKeySize == 0){
m_pCredits->nKeySize = m_nPublicKeyLen;
memcpy(m_pCredits->abySecureIdent, m_abyPublicKey, m_nPublicKeyLen);
if (GetDownloadedTotal() > 0){
// for security reason, we have to delete all prior credits here
m_pCredits->nDownloadedHi = 0;
m_pCredits->nDownloadedLo = 1;
m_pCredits->nUploadedHi = 0;
m_pCredits->nUploadedLo = 1; // in order to safe this client, set 1 byte
if (thePrefs.GetVerbose())
DEBUG_ONLY(AddDebugLogLine(false, _T("Credits deleted due to new SecureIdent")));
}
}
IdentState = IS_IDENTIFIED;
}
bool CClientCredits::SetSecureIdent(uchar* pachIdent, uint8 nIdentLen){ // verified Public key cannot change, use only if there is not public key yet
if (MAXPUBKEYSIZE < nIdentLen || m_pCredits->nKeySize != 0 )
return false;
memcpy(m_abyPublicKey,pachIdent, nIdentLen);
m_nPublicKeyLen = nIdentLen;
IdentState = IS_IDNEEDED;
return true;
}
EIdentState CClientCredits::GetCurrentIdentState(uint32 dwForIP) const{
if (IdentState != IS_IDENTIFIED)
return IdentState;
else{
if (dwForIP == m_dwIdentIP)
return IS_IDENTIFIED;
else
return IS_IDBADGUY;
// mod note: clients which just reconnected after an IP change and have to ident yet will also have this state for 1-2 seconds
// so don't try to spam such clients with "bad guy" messages (besides: spam messages are always bad)
}
}
using namespace CryptoPP;
void CClientCreditsList::InitalizeCrypting(){
m_nMyPublicKeyLen = 0;
memset(m_abyMyPublicKey,0,80); // not really needed; better for debugging tho
m_pSignkey = NULL;
if (!thePrefs.IsSecureIdentEnabled())
return;
// check if keyfile is there
bool bCreateNewKey = false;
HANDLE hKeyFile = ::CreateFile(thePrefs.GetConfigDir() + CString("cryptkey.dat"), GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hKeyFile != INVALID_HANDLE_VALUE)
{
if (::GetFileSize(hKeyFile, NULL) == 0)
bCreateNewKey = true;
::CloseHandle(hKeyFile);
}
else
bCreateNewKey = true;
if (bCreateNewKey)
CreateKeyPair();
// load key
try{
// load private key
FileSource filesource(CStringA(thePrefs.GetConfigDir() + _T("cryptkey.dat")), true,new Base64Decoder);
m_pSignkey = new RSASSA_PKCS1v15_SHA_Signer(filesource);
// calculate and store public key
RSASSA_PKCS1v15_SHA_Verifier pubkey(*m_pSignkey);
ArraySink asink(m_abyMyPublicKey, 80);
pubkey.DEREncode(asink);
m_nMyPublicKeyLen = asink.TotalPutLength();
asink.MessageEnd();
}
catch(...)
{
if (m_pSignkey){
delete m_pSignkey;
m_pSignkey = NULL;
}
AddLogLine(false, GetResString(IDS_CRYPT_INITFAILED));
ASSERT(0);
}
//Debug_CheckCrypting();
}
bool CClientCreditsList::CreateKeyPair(){
try{
AutoSeededRandomPool rng;
InvertibleRSAFunction privkey;
privkey.Initialize(rng,RSAKEYSIZE);
Base64Encoder privkeysink(new FileSink(CStringA(thePrefs.GetConfigDir() + _T("cryptkey.dat"))));
privkey.DEREncode(privkeysink);
privkeysink.MessageEnd();
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("Created new RSA keypair"));
}
catch(...)
{
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Failed to create new RSA keypair"));
ASSERT ( false );
return false;
}
return true;
}
uint8 CClientCreditsList::CreateSignature(CClientCredits* pTarget, uchar* pachOutput, uint8 nMaxSize, uint32 ChallengeIP, uint8 byChaIPKind, CryptoPP::RSASSA_PKCS1v15_SHA_Signer* sigkey){
// sigkey param is used for debug only
if (sigkey == NULL)
sigkey = m_pSignkey;
// create a signature of the public key from pTarget
ASSERT( pTarget );
ASSERT( pachOutput );
uint8 nResult;
if ( !CryptoAvailable() )
return 0;
try{
SecByteBlock sbbSignature(sigkey->SignatureLength());
AutoSeededRandomPool rng;
byte abyBuffer[MAXPUBKEYSIZE+9];
uint32 keylen = pTarget->GetSecIDKeyLen();
memcpy(abyBuffer,pTarget->GetSecureIdent(),keylen);
// 4 additional bytes random data send from this client
uint32 challenge = pTarget->m_dwCryptRndChallengeFrom;
ASSERT ( challenge != 0 );
PokeUInt32(abyBuffer+keylen, challenge);
uint16 ChIpLen = 0;
if ( byChaIPKind != 0){
ChIpLen = 5;
PokeUInt32(abyBuffer+keylen+4, ChallengeIP);
PokeUInt8(abyBuffer+keylen+4+4, byChaIPKind);
}
sigkey->SignMessage(rng, abyBuffer ,keylen+4+ChIpLen , sbbSignature.begin());
ArraySink asink(pachOutput, nMaxSize);
asink.Put(sbbSignature.begin(), sbbSignature.size());
nResult = asink.TotalPutLength();
}
catch(...)
{
ASSERT ( false );
nResult = 0;
}
return nResult;
}
bool CClientCreditsList::VerifyIdent(CClientCredits* pTarget, uchar* pachSignature, uint8 nInputSize, uint32 dwForIP, uint8 byChaIPKind){
ASSERT( pTarget );
ASSERT( pachSignature );
if ( !CryptoAvailable() ){
pTarget->IdentState = IS_NOTAVAILABLE;
return false;
}
bool bResult;
try{
StringSource ss_Pubkey((byte*)pTarget->GetSecureIdent(),pTarget->GetSecIDKeyLen(),true,0);
RSASSA_PKCS1v15_SHA_Verifier pubkey(ss_Pubkey);
// 4 additional bytes random data send from this client +5 bytes v2
byte abyBuffer[MAXPUBKEYSIZE+9];
memcpy(abyBuffer,m_abyMyPublicKey,m_nMyPublicKeyLen);
uint32 challenge = pTarget->m_dwCryptRndChallengeFor;
ASSERT ( challenge != 0 );
PokeUInt32(abyBuffer+m_nMyPublicKeyLen, challenge);
// v2 security improvments (not supported by 29b, not used as default by 29c)
uint8 nChIpSize = 0;
if (byChaIPKind != 0){
nChIpSize = 5;
uint32 ChallengeIP = 0;
switch (byChaIPKind){
case CRYPT_CIP_LOCALCLIENT:
ChallengeIP = dwForIP;
break;
case CRYPT_CIP_REMOTECLIENT:
if (theApp.serverconnect->GetClientID() == 0 || theApp.serverconnect->IsLowID()){
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("Warning: Maybe SecureHash Ident fails because LocalIP is unknown"));
ChallengeIP = theApp.serverconnect->GetLocalIP();
}
else
ChallengeIP = theApp.serverconnect->GetClientID();
break;
case CRYPT_CIP_NONECLIENT: // maybe not supported in future versions
ChallengeIP = 0;
break;
}
PokeUInt32(abyBuffer+m_nMyPublicKeyLen+4, ChallengeIP);
PokeUInt8(abyBuffer+m_nMyPublicKeyLen+4+4, byChaIPKind);
}
//v2 end
bResult = pubkey.VerifyMessage(abyBuffer, m_nMyPublicKeyLen+4+nChIpSize, pachSignature, nInputSize);
}
catch(...)
{
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Error: Unknown exception in %hs"), __FUNCTION__);
//ASSERT(0);
bResult = false;
}
if (!bResult){
if (pTarget->IdentState == IS_IDNEEDED)
pTarget->IdentState = IS_IDFAILED;
}
else{
pTarget->Verified(dwForIP);
}
return bResult;
}
bool CClientCreditsList::CryptoAvailable(){
return (m_nMyPublicKeyLen > 0 && m_pSignkey != 0 && thePrefs.IsSecureIdentEnabled() );
}
#ifdef _DEBUG
bool CClientCreditsList::Debug_CheckCrypting(){
// create random key
AutoSeededRandomPool rng;
RSASSA_PKCS1v15_SHA_Signer priv(rng, 384);
RSASSA_PKCS1v15_SHA_Verifier pub(priv);
byte abyPublicKey[80];
ArraySink asink(abyPublicKey, 80);
pub.DEREncode(asink);
uint8 PublicKeyLen = asink.TotalPutLength();
asink.MessageEnd();
uint32 challenge = rand();
// create fake client which pretends to be this emule
CreditStruct* newcstruct = new CreditStruct;
memset(newcstruct, 0, sizeof(CreditStruct));
CClientCredits* newcredits = new CClientCredits(newcstruct);
newcredits->SetSecureIdent(m_abyMyPublicKey,m_nMyPublicKeyLen);
newcredits->m_dwCryptRndChallengeFrom = challenge;
// create signature with fake priv key
uchar pachSignature[200];
memset(pachSignature,200,0);
uint8 sigsize = CreateSignature(newcredits,pachSignature,200,0,false, &priv);
// next fake client uses the random created public key
CreditStruct* newcstruct2 = new CreditStruct;
memset(newcstruct2, 0, sizeof(CreditStruct));
CClientCredits* newcredits2 = new CClientCredits(newcstruct2);
newcredits2->m_dwCryptRndChallengeFor = challenge;
// if you uncomment one of the following lines the check has to fail
//abyPublicKey[5] = 34;
//m_abyMyPublicKey[5] = 22;
//pachSignature[5] = 232;
newcredits2->SetSecureIdent(abyPublicKey,PublicKeyLen);
//now verify this signature - if it's true everything is fine
bool bResult = VerifyIdent(newcredits2,pachSignature,sigsize,0,0);
delete newcredits;
delete newcredits2;
return bResult;
}
#endif
uint32 CClientCredits::GetSecureWaitStartTime(uint32 dwForIP){
if (m_dwUnSecureWaitTime == 0 || m_dwSecureWaitTime == 0)
SetSecWaitStartTime(dwForIP);
if (m_pCredits->nKeySize != 0){ // this client is a SecureHash Client
if (GetCurrentIdentState(dwForIP) == IS_IDENTIFIED){ // good boy
return m_dwSecureWaitTime;
}
else{ // not so good boy
if (dwForIP == m_dwWaitTimeIP){
return m_dwUnSecureWaitTime;
}
else{ // bad boy
// this can also happen if the client has not identified himself yet, but will do later - so maybe he is not a bad boy :) .
CString buffer2, buffer;
/*for (uint16 i = 0;i != 16;i++){
buffer2.Format("%02X",this->m_pCredits->abyKey[i]);
buffer+=buffer2;
}
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false,"Warning: WaitTime resetted due to Invalid Ident for Userhash %s",buffer.GetBuffer());*/
m_dwUnSecureWaitTime = ::GetTickCount();
m_dwWaitTimeIP = dwForIP;
return m_dwUnSecureWaitTime;
}
}
}
else{ // not a SecureHash Client - handle it like before for now (no security checks)
return m_dwUnSecureWaitTime;
}
}
void CClientCredits::SetSecWaitStartTime(uint32 dwForIP){
m_dwUnSecureWaitTime = ::GetTickCount()-1;
m_dwSecureWaitTime = ::GetTickCount()-1;
m_dwWaitTimeIP = dwForIP;
}
void CClientCredits::ClearWaitStartTime(){
m_dwUnSecureWaitTime = 0;
m_dwSecureWaitTime = 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -