📄 ccontrolthread.cpp
字号:
authwrit = byteFifoWrite(mOriginator? &mOAuthentication : &mAAuthentication, p, e-p);
pgpAssert(authwrit == e-p);
mControlOutQ->Send(_mt_controlPacket, p, e-p);
}
void
CControlThread::SetupEncryption(short dir)
{
uchar s[256];
ulong len;
ushort keylen;
uchar *p, *e;
keylen = KeySize(mEncryptor);
if(byteFifoSize(&mSharedSecret) < keylen)
ProtocolViolation(_pv_badPrime);
else
{
for(e=s;keylen;e+=len)
{
p = byteFifoGetBytes(&mSharedSecret, &len);
len = (keylen < len ? keylen : len);
pgp_memcpy(e, p, len);
byteFifoSkipBytes(&mSharedSecret, len);
keylen -= len;
}
if(dir)
mOutHPP->ChangeTXKey(s, mEncryptor, 0, 0);
else
mInHPP->ChangeRXKey(s, mEncryptor, 0, 0);
#ifdef DEBUGCONFIG
char t[256];
short i, ks = KeySize(mEncryptor);
for(i=0,p=(uchar *)t;i<ks;i++,p+=2)
sprintf((char *)p, "%02x", s[i]);
*p=0;
if(dir)
strcat(t, "(e)");
else
strcat(t, "(d)");
mStatusPane->AddStatus(0,t);
DebugLog("%s",t);
#endif
memset(s, 0, 256); // erase key material after use
}
}
Boolean
CControlThread::ReceiveDHPublic(uchar *data, short length)
{
Boolean good = TRUE;
short plen, err;
ulong len;
uchar *e, *p, h[32];
SHA hash;
#ifdef DEBUGCONFIG
mStatusPane->AddStatus(0,"ReceiveDHPublic");
#endif
e = data;
BUFFER_TO_SHORT(e, plen);
e+=2;
if((plen == mPrime->length) && (length == mPrime->length+sizeof(short)))
{
// Make sure the public field matches the hash they sent
hash.Init();
hash.Update(e, plen);
hash.Final(h);
if(!memcmp(h, mDHHash, SHS_DIGESTSIZE))
{
// Do second half of Diffie-Hellman
// to obtain encryption keys
err = dhSecondHalf(mPrime->prime, mPrime->length,
dhGenerator, sizeof(dhGenerator),
mDHPrivate, mPrime->length,
e, mPrime->length, &mSharedSecret, NIL);
pgpAssert(err>=0);
mStatusPane->AddStatus(0,
"Completed Diffie-Hellman key agreement.");
hash.Init();
len = byteFifoSize(&mOAuthentication);
while((p = byteFifoGetBytes(&mOAuthentication, &len)) != NULL)
{
hash.Update(p, len);
byteFifoSkipBytes(&mOAuthentication, len);
}
len = byteFifoSize(&mAAuthentication);
while((p = byteFifoGetBytes(&mAAuthentication, &len)) != NULL)
{
hash.Update(p, len);
byteFifoSkipBytes(&mAAuthentication, len);
}
hash.Final(h);
pgp_memcpy(mAuthInfo, h, 4);
// all future packets are now encrypted
SetupEncryption(mOriginator);
SetupEncryption(!mOriginator);
}
else
good = FALSE;
}
else
good = FALSE;
return good;
}
void
CControlThread::SendDHPublic()
{
uchar *p, *e, alen[4];
long authwrit;
#ifdef DEBUGCONFIG
mStatusPane->AddStatus(0,"SendDHPublic");
#endif
// the following block of code sends the _ctp_DHPublic packet
// which is the result of the initial Diffie-Hellman
// calculation previously committed to by the hash we
// sent.
p = e = (uchar *)pgp_malloc(768);
pgpAssert(p);
pgpAssert(mPrime->length < 700);
*e++ = _ctp_DHPublic;
SHORT_TO_BUFFER(mPrime->length, e);
e+=2;
pgp_memcpy(e, mDHPublic, mPrime->length);
e+=mPrime->length;
SHORT_TO_BUFFER((short)(e-p), alen);
authwrit = byteFifoWrite(mOriginator? &mOAuthentication : &mAAuthentication, alen, 2);
pgpAssert(authwrit == 2);
authwrit = byteFifoWrite(mOriginator? &mOAuthentication : &mAAuthentication, p, e-p);
pgpAssert(authwrit == e-p);
mControlOutQ->Send(_mt_controlPacket, p, e-p);
}
Boolean
CControlThread::ReceiveHello(uchar *data, short length)
{
uchar *p, *e, *u, *t, *v, s[NUM_DH_PRIMES * 8], rmtSalt[8], h[32],
*foundHash=NIL, alg;
short len, num, inx, cnt, cryp, j, found, foundPrime=-1, localPrime=-1;
uchar vers;
Boolean good;
SHA hash;
#ifdef DEBUGCONFIG
mStatusPane->AddStatus(0,"ReceiveHello");
#endif
good = TRUE;
len = 0;
for(p=data,e=data+length;p<e;p+=len)
{
num = *p++;
if(p == e)
{
good = FALSE;
break;
}
len = *p++;
if(e-p < len)
{
good = FALSE;
break;
}
switch(num)
{
case _cti_Version:
vers = *p;
if(vers > pgpfMajorProtocolVersion)
{
mStatusPane->AddStatus(0, "Incompatible PGPfone versions, terminating call.");
mStatusPane->AddStatus(0, "Please get the latest PGPfone at:");
mStatusPane->AddStatus(0, "http://web.mit.edu/pgp");
good = FALSE;
}
break;
case _cti_PublicName:
if(len>0)
{
if(len>63)
len=63;
pgp_memcpy(mRemotePublicName,p,len);
mRemotePublicName[len]=0;
}
break;
case _cti_HashAlg:
if(len >= 4)
{
if(memcmp(p, "SHA1", 4)) // only SHA for now
{
mStatusPane->AddStatus(0,
"Could not negotiate a hash algorithm.");
good = FALSE;
}
}
break;
case _cti_PrimeHashList:
mPrime = NIL;
if(len >= 16)
{
pgp_memcpy(rmtSalt, p, 8);
for(u=s,inx=0;inx<mNumPrimes;inx++,u+=8)
{
hash.Init();
hash.Update(rmtSalt, 8);
alg = 2;
hash.Update(&alg, 1);
hash.Update(mPrimes[inx]->prime,
mPrimes[inx]->length);
hash.Final(h);
pgp_memcpy(u, h, 8);
}
v=p+8;
found = (len - 8) / 8;
for(u=s,inx=0;inx<mNumPrimes;inx++,u+=8)
{
for(t=v,j=0;j<found;j++,t+=8)
{
if(!memcmp(u, t, 8))
{
// Remember this prime if it's earlier
// (more preferred) in their list than
// the one we've already found.
if(!foundHash || (t<foundHash))
{
foundHash=t;
foundPrime=inx;
}
// Remember the first prime we find (in
// descending order of *our* priority)
// that's on their list.
if(localPrime<0)
localPrime = inx;
}
}
}
if(localPrime>=0 && foundPrime>=0)
{
if(mPrimes[localPrime]->length > mPrimes[foundPrime]->length)
mPrime = mPrimes[localPrime];
else if(mPrimes[localPrime]->length < mPrimes[foundPrime]->length)
mPrime = mPrimes[foundPrime];
else if(memcmp(mPrimes[localPrime]->prime,
mPrimes[foundPrime]->prime,
mPrimes[localPrime]->length) > 0)
mPrime = mPrimes[localPrime];
else
mPrime = mPrimes[foundPrime];
}
if(mPrime)
{
char str[32];
sprintf(str,"DH(%d)",mPrime->length * 8);
mPFWindow->SetKeyExchange(str);
mStatusPane->AddStatus(0,
"Agreed upon a %d bit prime.",
mPrime->length * 8);
}
}
if(!mPrime)
{
mStatusPane->AddStatus(0,
"Could not negotiate a prime.");
good = FALSE;
}
break;
case _cti_EncryptAlgorithms:
cnt = len / 4;
if(mOriginator)
{
found = -1;
for(u=p,inx=0;inx<cnt;inx++,u+=4)
if(!memcmp(sCryptorHash[gPGFOpts.popt.prefEncryptor], u, 4))
{
found = gPGFOpts.popt.prefEncryptor;
break;
}
if(found < 0)
for(cryp=0;cryp<NUMCRYPTORS && found<0;cryp++)
if((cryp != gPGFOpts.popt.prefEncryptor) &&
(gPGFOpts.popt.cryptorMask & (1<<cryp)))
{
for(u=p,inx=0;inx<cnt;inx++,u+=4)
if(!memcmp(sCryptorHash[cryp], u, 4))
{
found = cryp;
break;
}
}
}
else
{
for(u=p,inx=0;inx<cnt;inx++,u+=4)
if(gPGFOpts.popt.cryptorMask & (1<<(cryp=GetCryptorID(u))))
{
found = cryp;
break;
}
}
if(found>=0)
pgp_memcpy(mEncryptor, sCryptorHash[found], 4);
else
{
mStatusPane->AddStatus(0, "Could not negotiate encryption.");
good = FALSE;
}
break;
default:
// unknown data, so ignore it
break;
}
}
return good;
}
void
CControlThread::SendHello()
{
uchar *p, *e, *r, *u, s[128], alg, alen[4];
ulong authwrit;
short inx, cnt;
SHA hash;
static DHPrime *primes[NUM_DH_PRIMES] = {
&DH_768bitPrime, &DH_1024bitPrime,
&DH_1536bitPrime, &DH_2048bitPrime, &DH_3072bitPrime,
&DH_4096bitPrime };
#ifdef DEBUGCONFIG
mStatusPane->AddStatus(0,"SendHello");
#endif
// the following block of code sends the _ctp_Hello packet
// which is the first config packet establishing basic
// parameters such as which prime and which encryption
// algorithms to use.
p = e = (uchar *)pgp_malloc(512);
pgpAssert(p);
*e++ = _ctp_Hello;
*e++ = _cti_Version;
*e++ = 2;
*e++ = pgpfMajorProtocolVersion;
*e++ = pgpfMinorProtocolVersion;
if(gPGFOpts.popt.idUnencrypted &&
((mOriginator && gPGFOpts.popt.idOutgoing) ||
(!mOriginator && gPGFOpts.popt.idIncoming)) &&
gPGFOpts.popt.identity[0])
{
*e++ = _cti_PublicName;
*e++ = strlen(gPGFOpts.popt.identity);
strcpy((char *)e, gPGFOpts.popt.identity);
e+= strlen((char *)e);
}
*e++ = _cti_HashAlg;
*e++ = 4;
pgp_memcpy(e, "SHA1", 4);
e+=4;
*e++ = _cti_PrimeHashList;
u=e++;
// Setup internal structure of prime preferences
// Start with preferred prime upwards and then down
for(inx=gPGFOpts.popt.prefPrime;inx<NUM_DH_PRIMES;inx++)
{
if(gPGFOpts.popt.primeMask & (1 << inx))
{
mPrimes[mNumPrimes] = primes[inx];
mNumPrimes++;
}
}
for(inx=gPGFOpts.popt.prefPrime-1;inx>=0;inx--)
{
if(gPGFOpts.popt.primeMask & (1 << inx))
{
mPrimes[mNumPrimes] = primes[inx];
mNumPrimes++;
}
}
// send random salt to obscure primes
randPoolGetBytes(r=e, 8);
e+=8;
cnt = 8;
// send salted hashes of allowed primes in preferred order
for(inx=0;inx<mNumPrimes;inx++)
{
hash.Init();
hash.Update(r, 8); // Hash the salt with the prime
alg = 2; // Diffie-Hellman Algorithm Identifier
hash.Update(&alg, 1);
hash.Update(mPrimes[inx]->prime, mPrimes[inx]->length);
hash.Final(s);
pgp_memcpy(e, s, 8);
e+=8;
cnt+=8;
}
*u = cnt;
// send a list of the encryption algorithms we support preference first
*e++ = _cti_EncryptAlgorithms;
u=e++; cnt = 0;
if(mOriginator && (gPGFOpts.popt.prefEncryptor >= 0))
{
pgp_memcpy(e, sCryptorHash[gPGFOpts.popt.prefEncryptor], 4); e+=4; cnt+=4;
}
for(inx=0;inx<NUMCRYPTORS;inx++)
{
if((!mOriginator || (inx != gPGFOpts.popt.prefEncryptor)) &&
(gPGFOpts.popt.cryptorMask & (1<<inx)))
{
pgp_memcpy(e, sCryptorHash[inx], 4); e+=4; cnt+=4;
}
}
*u = cnt;
if(gPGFOpts.popt.cryptorMask & (1 << _enc_none))
mAllowNone = TRUE;
SHORT_TO_BUFFER((short)(e-p), alen);
authwrit = byteFifoWrite(mOriginator? &mOAuthentication : &mAAuthentication, alen, 2);
pgpAssert(authwrit == 2);
authwrit = byteFifoWrite(mOriginator? &mOAuthentication : &mAAuthentication, p, e-p);
pgpAssert(authwrit == e-p);
mControlOutQ->Send(_mt_controlPacket, p, e-p);
}
void
CControlThread::ProtocolViolation(enum ProtViolation id)
{
// This function is intended to receive notices from the lower
// layers about protocol violations so it can decide what to
// do about them.
switch(id)
{
case _pv_invalidSound:
// In the case of serial, we want to disconnect here. The most
// likely cause is that the remote party has disconnected
// unexpectedly and our own packets are being echoed back
// to us, decrypted by the wrong key, and attempted to be
// played.
// In the case of internet or appletalk, we'll just ignore it
// because connection shutdown is very clean on both of those.
if(mControlState != _con_Disconnecting)
{
AbortSync(FALSE, TRUE); //act like the other side hungup
mStatusPane->AddStatus(0, "Unexpected disconnection.");
}
break;
case _pv_badPrime:
// The Diffie-Hellman prime selected is not adequate for the
// encryption algorithms selected.
if(mControlState != _con_Disconnecting)
{
AbortSync(FALSE, FALSE);
mStatusPane->AddStatus(0, "Diffie-Hellman prime not large enough, terminating call.");
}
break;
case _pv_noRemote:
// The remote end has failed to respond to a reliable packet.
// We retry 10 times over 20 seconds. No response disconnects
// the call.
if(mControlState != _con_Disconnecting)
{
AbortSync(FALSE, TRUE);
mStatusPane->AddStatus(0, "Remote is not responding, terminating call.");
}
break;
}
}
void
CControlThread::GetCryptorName(short id, uchar *name)
{
switch(id)
{
case _enc_none: pgp_memcpy(name, "NONE", 4); break;
case _enc_tripleDES:pgp_memcpy(name, "TDEA", 4); break;
case _enc_blowfish: pgp_memcpy(name, "BLOW", 4); break;
case _enc_cast: pgp_memcpy(name, "CAST", 4); break;
}
}
short
CControlThread::GetCryptorID(uchar *name)
{
if(!memcmp(name, "TDEA", 4))
return _enc_tripleDES;
else if(!memcmp(name, "BLOW", 4))
return _enc_blowfish;
else if(!memcmp(name, "CAST", 4))
return _enc_cast;
else if(!memcmp(name, "NONE", 4))
return _enc_none;
return _enc_none+1; // return one higher than known for invalid
}
void
CControlThread::GetRemoteName(char *name)
{
strcpy(name, mRemotePublicName);
}
void
CControlThread::SetRemoteName(char *name)
{
strcpy(mRemotePublicName, name);
}
void
CControlThread::PlayInsecureWarning()
{
#ifdef PGP_MACINTOSH
SndListHandle respSound;
if((respSound = (SndListHandle)GetNamedResource('snd ', "\pInsecure")) != NULL)
{
HLock((Handle)respSound);
SndPlay(nil, respSound, false);
HUnlock((Handle)respSound);
}
#elif PGP_WIN32
PlaySound("INSECURE.WAV", NULL, SND_FILENAME+SND_SYNC);
#endif
}
void
CControlThread::SetXferWindow(CXferWindow *xferWindow)
{
mXferWindow = xferWindow;
}
enum SystType
CControlThread::GetRemoteSystemType()
{
return mRemoteSystemType;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -