mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 14:37:41 +00:00
if the N value is zero, send an empty seed to the server and expect an empty seed back. Don't use encryption.
This commit is contained in:
@ -341,9 +341,9 @@ void NetMsgChannelGetDhConstants (
|
|||||||
const BigNum ** dh_xa,
|
const BigNum ** dh_xa,
|
||||||
const BigNum ** dh_n
|
const BigNum ** dh_n
|
||||||
) {
|
) {
|
||||||
*dh_g = channel->m_dh_g;
|
if (dh_g) *dh_g = channel->m_dh_g;
|
||||||
*dh_xa = &channel->m_dh_xa;
|
if (dh_xa) *dh_xa = &channel->m_dh_xa;
|
||||||
*dh_n = &channel->m_dh_n;
|
if (dh_n) *dh_n = &channel->m_dh_n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,8 +40,6 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|||||||
# define NCCLI_LOG NULL_STMT
|
# define NCCLI_LOG NULL_STMT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define NO_ENCRYPTION
|
|
||||||
|
|
||||||
#ifndef PLASMA_EXTERNAL_RELEASE
|
#ifndef PLASMA_EXTERNAL_RELEASE
|
||||||
|
|
||||||
struct NetLogMessage_Header
|
struct NetLogMessage_Header
|
||||||
@ -120,8 +118,8 @@ struct NetCli : THashKeyVal<Uuid> {
|
|||||||
ENetCliMode mode;
|
ENetCliMode mode;
|
||||||
FNetCliEncrypt encryptFcn;
|
FNetCliEncrypt encryptFcn;
|
||||||
byte seed[kNetMaxSymmetricSeedBytes];
|
byte seed[kNetMaxSymmetricSeedBytes];
|
||||||
CryptKey * cryptIn;
|
CryptKey * cryptIn; // nil if encrytpion is disabled
|
||||||
CryptKey * cryptOut;
|
CryptKey * cryptOut; // nil if encrytpion is disabled
|
||||||
void * encryptParam;
|
void * encryptParam;
|
||||||
|
|
||||||
// Message buffers
|
// Message buffers
|
||||||
@ -174,9 +172,8 @@ static void PutBufferOnWire (NetCli * cli, void * data, unsigned bytes) {
|
|||||||
}
|
}
|
||||||
#endif // PLASMA_EXTERNAL_RELEASE
|
#endif // PLASMA_EXTERNAL_RELEASE
|
||||||
|
|
||||||
if (cli->mode == kNetCliModeEncrypted) {
|
if (cli->mode == kNetCliModeEncrypted && cli->cryptOut) {
|
||||||
// Encrypt data...
|
// Encrypt data...
|
||||||
#ifndef NO_ENCRYPTION
|
|
||||||
if (bytes <= 2048)
|
if (bytes <= 2048)
|
||||||
// byte count is small, use stack-based buffer
|
// byte count is small, use stack-based buffer
|
||||||
temp = ALLOCA(byte, bytes);
|
temp = ALLOCA(byte, bytes);
|
||||||
@ -187,7 +184,6 @@ static void PutBufferOnWire (NetCli * cli, void * data, unsigned bytes) {
|
|||||||
MemCopy(temp, data, bytes);
|
MemCopy(temp, data, bytes);
|
||||||
CryptEncrypt(cli->cryptOut, bytes, temp);
|
CryptEncrypt(cli->cryptOut, bytes, temp);
|
||||||
data = temp;
|
data = temp;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (cli->sock)
|
if (cli->sock)
|
||||||
AsyncSocketSend(cli->sock, data, bytes);
|
AsyncSocketSend(cli->sock, data, bytes);
|
||||||
@ -644,7 +640,7 @@ static void ClientConnect (NetCli * cli) {
|
|||||||
if (cli->sock) {
|
if (cli->sock) {
|
||||||
unsigned bytes;
|
unsigned bytes;
|
||||||
NetCli_Cli2Srv_Connect msg;
|
NetCli_Cli2Srv_Connect msg;
|
||||||
unsigned char * data = serverSeed.GetData_LE(&bytes);
|
unsigned char * data = serverSeed.GetData_LE(&bytes); // will be 0 if encryption is disabled, and thereby send an empty seed
|
||||||
ASSERTMSG(bytes <= sizeof(msg.dh_y_data), "4");
|
ASSERTMSG(bytes <= sizeof(msg.dh_y_data), "4");
|
||||||
msg.message = kNetCliCli2SrvConnect;
|
msg.message = kNetCliCli2SrvConnect;
|
||||||
msg.length = (byte) (sizeof(msg) - sizeof(msg.dh_y_data) + bytes);
|
msg.length = (byte) (sizeof(msg) - sizeof(msg.dh_y_data) + bytes);
|
||||||
@ -668,48 +664,55 @@ static bool ServerRecvConnect (
|
|||||||
* (const NetCli_Cli2Srv_Connect *) &pkt;
|
* (const NetCli_Cli2Srv_Connect *) &pkt;
|
||||||
if (pkt.length < sizeof(msg))
|
if (pkt.length < sizeof(msg))
|
||||||
return false;
|
return false;
|
||||||
|
int seedLength = msg.length - sizeof(pkt);
|
||||||
|
|
||||||
// Send the server seed to the client (unencrypted)
|
// Send the server seed to the client (unencrypted)
|
||||||
if (cli->sock) {
|
if (cli->sock) {
|
||||||
NetCli_Srv2Cli_Encrypt reply;
|
NetCli_Srv2Cli_Encrypt reply;
|
||||||
reply.message = kNetCliSrv2CliEncrypt;
|
reply.message = kNetCliSrv2CliEncrypt;
|
||||||
reply.length = sizeof(reply);
|
reply.length = seedLength == 0 ? 0 : sizeof(reply); // reply with empty seed if we got empty seed (this means: no encryption)
|
||||||
MemCopy(reply.serverSeed, cli->seed, sizeof(reply.serverSeed));
|
MemCopy(reply.serverSeed, cli->seed, sizeof(reply.serverSeed));
|
||||||
AsyncSocketSend(cli->sock, &reply, sizeof(reply));
|
AsyncSocketSend(cli->sock, &reply, reply.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute client seed
|
if (seedLength == 0) { // client wishes no encryption (that's okay, nobody else can "fake" us as nobody has the private key, so if the client actually wants encryption it will only work with the correct peer)
|
||||||
byte clientSeed[kNetMaxSymmetricSeedBytes];
|
cli->cryptIn = nil;
|
||||||
{
|
cli->cryptOut = nil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Compute client seed
|
||||||
|
byte clientSeed[kNetMaxSymmetricSeedBytes];
|
||||||
BigNum clientSeedValue;
|
BigNum clientSeedValue;
|
||||||
NetMsgCryptServerConnect(
|
{
|
||||||
cli->channel,
|
NetMsgCryptServerConnect(
|
||||||
msg.length - sizeof(pkt),
|
cli->channel,
|
||||||
msg.dh_y_data,
|
seedLength,
|
||||||
&clientSeedValue
|
msg.dh_y_data,
|
||||||
|
&clientSeedValue
|
||||||
|
);
|
||||||
|
|
||||||
|
ZERO(clientSeed);
|
||||||
|
unsigned bytes;
|
||||||
|
unsigned char * data = clientSeedValue.GetData_LE(&bytes);
|
||||||
|
MemCopy(clientSeed, data, min(bytes, sizeof(clientSeed)));
|
||||||
|
delete [] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the symmetric key from a combination
|
||||||
|
// of the client seed and the server seed
|
||||||
|
byte sharedSeed[kNetMaxSymmetricSeedBytes];
|
||||||
|
CreateSymmetricKey(
|
||||||
|
sizeof(cli->seed), cli->seed, // server seed
|
||||||
|
sizeof(clientSeed), clientSeed, // client seed
|
||||||
|
sizeof(sharedSeed), sharedSeed // combined seed
|
||||||
);
|
);
|
||||||
|
|
||||||
ZERO(clientSeed);
|
// Switch to encrypted mode
|
||||||
unsigned bytes;
|
cli->cryptIn = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
||||||
unsigned char * data = clientSeedValue.GetData_LE(&bytes);
|
cli->cryptOut = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
||||||
MemCopy(clientSeed, data, min(bytes, sizeof(clientSeed)));
|
|
||||||
delete [] data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the symmetric key from a combination
|
cli->mode = kNetCliModeEncrypted; // should rather be called "established", but whatever
|
||||||
// of the client seed and the server seed
|
|
||||||
byte sharedSeed[kNetMaxSymmetricSeedBytes];
|
|
||||||
CreateSymmetricKey(
|
|
||||||
sizeof(cli->seed), cli->seed, // server seed
|
|
||||||
sizeof(clientSeed), clientSeed, // client seed
|
|
||||||
sizeof(sharedSeed), sharedSeed // combined seed
|
|
||||||
);
|
|
||||||
|
|
||||||
// Switch to encrypted mode
|
|
||||||
cli->mode = kNetCliModeEncrypted;
|
|
||||||
cli->cryptIn = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
|
||||||
cli->cryptOut = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
|
||||||
|
|
||||||
return cli->encryptFcn(kNetSuccess, cli->encryptParam);
|
return cli->encryptFcn(kNetSuccess, cli->encryptParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -722,26 +725,39 @@ static bool ClientRecvEncrypt (
|
|||||||
if (cli->mode != kNetCliModeClientStart)
|
if (cli->mode != kNetCliModeClientStart)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Validate message size
|
// find out if we want encryption
|
||||||
|
const BigNum * DH_N;
|
||||||
|
NetMsgChannelGetDhConstants(cli->channel, nil, nil, &DH_N);
|
||||||
|
bool encrypt = !DH_N->isZero();
|
||||||
|
|
||||||
|
// Process message
|
||||||
const NetCli_Srv2Cli_Encrypt & msg =
|
const NetCli_Srv2Cli_Encrypt & msg =
|
||||||
* (const NetCli_Srv2Cli_Encrypt *) &pkt;
|
* (const NetCli_Srv2Cli_Encrypt *) &pkt;
|
||||||
if (pkt.length != sizeof(msg))
|
if (encrypt) { // we insist on encryption, don't let some MitM decide for us!
|
||||||
return false;
|
if (pkt.length != sizeof(msg))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Create the symmetric key from a combination
|
// Create the symmetric key from a combination
|
||||||
// of the client seed and the server seed
|
// of the client seed and the server seed
|
||||||
byte sharedSeed[kNetMaxSymmetricSeedBytes];
|
byte sharedSeed[kNetMaxSymmetricSeedBytes];
|
||||||
CreateSymmetricKey(
|
CreateSymmetricKey(
|
||||||
sizeof(msg.serverSeed), msg.serverSeed, // server seed
|
sizeof(msg.serverSeed), msg.serverSeed, // server seed
|
||||||
sizeof(cli->seed), cli->seed, // client seed
|
sizeof(cli->seed), cli->seed, // client seed
|
||||||
sizeof(sharedSeed), sharedSeed // combined seed
|
sizeof(sharedSeed), sharedSeed // combined seed
|
||||||
);
|
);
|
||||||
|
|
||||||
// Switch to encrypted mode
|
// Switch to encrypted mode
|
||||||
cli->mode = kNetCliModeEncrypted;
|
cli->cryptIn = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
||||||
cli->cryptIn = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
cli->cryptOut = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
||||||
cli->cryptOut = CryptKeyCreate(kCryptRc4, sizeof(sharedSeed), sharedSeed);
|
}
|
||||||
|
else { // honestly we do not care what the other side sends, we will send plaintext
|
||||||
|
if (pkt.length != sizeof(pkt))
|
||||||
|
return false;
|
||||||
|
cli->cryptIn = nil;
|
||||||
|
cli->cryptOut = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli->mode = kNetCliModeEncrypted; // should rather be called "established", but whatever
|
||||||
return cli->encryptFcn(kNetSuccess, cli->encryptParam);
|
return cli->encryptFcn(kNetSuccess, cli->encryptParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1061,18 +1077,18 @@ bool NetCliDispatch (
|
|||||||
// Decrypt data...
|
// Decrypt data...
|
||||||
byte * temp, * heap = NULL;
|
byte * temp, * heap = NULL;
|
||||||
|
|
||||||
#ifndef NO_ENCRYPTION
|
if (cli->cryptIn) {
|
||||||
if (bytes <= 2048)
|
if (bytes <= 2048)
|
||||||
// byte count is small, use stack-based buffer
|
// byte count is small, use stack-based buffer
|
||||||
temp = ALLOCA(byte, bytes);
|
temp = ALLOCA(byte, bytes);
|
||||||
else
|
else
|
||||||
// byte count is large, use heap-based buffer
|
// byte count is large, use heap-based buffer
|
||||||
temp = heap = (byte *)ALLOC(bytes);
|
temp = heap = (byte *)ALLOC(bytes);
|
||||||
|
|
||||||
MemCopy(temp, data, bytes);
|
MemCopy(temp, data, bytes);
|
||||||
CryptDecrypt(cli->cryptIn, bytes, temp);
|
CryptDecrypt(cli->cryptIn, bytes, temp);
|
||||||
data = temp;
|
data = temp;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
// Add data to accumulator and dispatch
|
// Add data to accumulator and dispatch
|
||||||
cli->input.Add(bytes, data);
|
cli->input.Add(bytes, data);
|
||||||
|
@ -83,6 +83,7 @@ static void GetCachedServerKey (
|
|||||||
const BigNum * DH_A;
|
const BigNum * DH_A;
|
||||||
const BigNum * DH_N;
|
const BigNum * DH_N;
|
||||||
NetMsgChannelGetDhConstants(channel, &DH_G, &DH_A, &DH_N);
|
NetMsgChannelGetDhConstants(channel, &DH_G, &DH_A, &DH_N);
|
||||||
|
hsAssert(!DH_N->isZero(), "DH_N must not be zero in encrypted mode");
|
||||||
|
|
||||||
// Compute the result
|
// Compute the result
|
||||||
ka->PowMod(dh_y, *DH_A, *DH_N);
|
ka->PowMod(dh_y, *DH_A, *DH_N);
|
||||||
@ -107,17 +108,22 @@ void NetMsgCryptClientStart (
|
|||||||
const BigNum * DH_X;
|
const BigNum * DH_X;
|
||||||
const BigNum * DH_N;
|
const BigNum * DH_N;
|
||||||
NetMsgChannelGetDhConstants(channel, &DH_G, &DH_X, &DH_N);
|
NetMsgChannelGetDhConstants(channel, &DH_G, &DH_X, &DH_N);
|
||||||
|
if (DH_N->isZero()) { // no actual encryption, but the caller expects a seed
|
||||||
|
clientSeed->SetZero();
|
||||||
|
serverSeed->SetZero();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Client chooses b and y on connect
|
||||||
|
BigNum g(DH_G);
|
||||||
|
BigNum seed(seedBytes, seedData);
|
||||||
|
BigNum b; b.Rand(kNetDiffieHellmanKeyBits, &seed);
|
||||||
|
|
||||||
// Client chooses b and y on connect
|
// Client computes key: kb = x^b mod n
|
||||||
BigNum g(DH_G);
|
clientSeed->PowMod(*DH_X, b, *DH_N);
|
||||||
BigNum seed(seedBytes, seedData);
|
|
||||||
BigNum b; b.Rand(kNetDiffieHellmanKeyBits, &seed);
|
|
||||||
|
|
||||||
// Client computes key: kb = x^b mod n
|
// Client sends y to server
|
||||||
clientSeed->PowMod(*DH_X, b, *DH_N);
|
serverSeed->PowMod(g, b, *DH_N);
|
||||||
|
}
|
||||||
// Client sends y to server
|
|
||||||
serverSeed->PowMod(g, b, *DH_N);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
@ -89,6 +89,10 @@ public:
|
|||||||
{
|
{
|
||||||
return BN_cmp(&m_number, &a.m_number);
|
return BN_cmp(&m_number, &a.m_number);
|
||||||
}
|
}
|
||||||
|
bool isZero() const
|
||||||
|
{
|
||||||
|
return BN_is_zero(&m_number);
|
||||||
|
}
|
||||||
|
|
||||||
void Div (const BigNum & a, dword b, dword * remainder)
|
void Div (const BigNum & a, dword b, dword * remainder)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user