Protocol 1.7: Forced encryption on all connections.
This is for testing purposes only, to find bugs in the encryption. Once the encryption is deemed stable, it will be enabled only for servers with enabled Authentication.
This commit is contained in:
@@ -53,6 +53,12 @@ Implements the 1.7.x protocol classes:
|
||||
|
||||
|
||||
|
||||
const int MAX_ENC_LEN = 512; // Maximum size of the encrypted message; should be 128, but who knows...
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd: main.cpp:
|
||||
extern bool g_ShouldLogCommIn, g_ShouldLogCommOut;
|
||||
|
||||
@@ -1351,7 +1357,64 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
|
||||
|
||||
void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer)
|
||||
{
|
||||
// TODO: Add protocol encryption
|
||||
short EncKeyLength, EncNonceLength;
|
||||
a_ByteBuffer.ReadBEShort(EncKeyLength);
|
||||
AString EncKey;
|
||||
if (!a_ByteBuffer.ReadString(EncKey, EncKeyLength))
|
||||
{
|
||||
return;
|
||||
}
|
||||
a_ByteBuffer.ReadBEShort(EncNonceLength);
|
||||
AString EncNonce;
|
||||
if (!a_ByteBuffer.ReadString(EncNonce, EncNonceLength))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN))
|
||||
{
|
||||
LOGD("Too long encryption");
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decrypt EncNonce using privkey
|
||||
cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey();
|
||||
Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)];
|
||||
int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce));
|
||||
if (res != 4)
|
||||
{
|
||||
LOGD("Bad nonce length: got %d, exp %d", res, 4);
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
if (ntohl(DecryptedNonce[0]) != (unsigned)(uintptr_t)this)
|
||||
{
|
||||
LOGD("Bad nonce value");
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
|
||||
// Decrypt the symmetric encryption key using privkey:
|
||||
Byte DecryptedKey[MAX_ENC_LEN];
|
||||
res = rsaDecryptor.Decrypt((const Byte *)EncKey.data(), EncKey.size(), DecryptedKey, sizeof(DecryptedKey));
|
||||
if (res != 16)
|
||||
{
|
||||
LOGD("Bad key length");
|
||||
m_Client->Kick("Hacked client");
|
||||
return;
|
||||
}
|
||||
|
||||
StartEncryption(DecryptedKey);
|
||||
|
||||
// Send login success:
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||
Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
|
||||
Pkt.WriteString(m_Client->GetUsername());
|
||||
}
|
||||
|
||||
m_State = 3; // State = Game
|
||||
m_Client->HandleLogin(4, m_Client->GetUsername());
|
||||
}
|
||||
|
||||
|
||||
@@ -1363,14 +1426,26 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
|
||||
AString Username;
|
||||
a_ByteBuffer.ReadVarUTF8String(Username);
|
||||
|
||||
// TODO: Protocol encryption should be set up here if not localhost / auth
|
||||
|
||||
if (!m_Client->HandleHandshake(Username))
|
||||
{
|
||||
// The client is not welcome here, they have been sent a Kick packet already
|
||||
return;
|
||||
}
|
||||
|
||||
// If auth is required, then send the encryption request:
|
||||
// if (cRoot::Get()->GetServer()->ShouldAuthenticate())
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x01);
|
||||
Pkt.WriteString(cRoot::Get()->GetServer()->GetServerID());
|
||||
const AString & PubKeyDer = cRoot::Get()->GetServer()->GetPublicKeyDER();
|
||||
Pkt.WriteShort(PubKeyDer.size());
|
||||
Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size());
|
||||
Pkt.WriteShort(4);
|
||||
Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :)
|
||||
m_Client->SetUsername(Username);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send login success:
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||
@@ -1882,6 +1957,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
|
||||
|
||||
|
||||
|
||||
void cProtocol172::StartEncryption(const Byte * a_Key)
|
||||
{
|
||||
m_Encryptor.Init(a_Key, a_Key);
|
||||
m_Decryptor.Init(a_Key, a_Key);
|
||||
m_IsEncrypted = true;
|
||||
|
||||
// Prepare the m_AuthServerID:
|
||||
cSHA1Checksum Checksum;
|
||||
const AString & ServerID = cRoot::Get()->GetServer()->GetServerID();
|
||||
Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length());
|
||||
Checksum.Update(a_Key, 16);
|
||||
Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size());
|
||||
Byte Digest[20];
|
||||
Checksum.Finalize(Digest);
|
||||
cSHA1Checksum::DigestToJava(Digest, m_AuthServerID);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol172::cPacketizer:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user