Пример #1
0
        // Ran on server
        internal static void HandleHailResponse(ulong clientId, Stream stream)
        {
            if (!NetworkingManager.Singleton.PendingClients.ContainsKey(clientId) || NetworkingManager.Singleton.PendingClients[clientId].ConnectionState != PendingClient.State.PendingHail)
            {
                return;
            }
            if (!NetworkingManager.Singleton.NetworkConfig.EnableEncryption)
            {
                return;
            }

            using (PooledBitReader reader = PooledBitReader.Get(stream))
            {
                if (NetworkingManager.Singleton.PendingClients[clientId].KeyExchange != null)
                {
                    byte[] diffieHellmanPublic = reader.ReadByteArray();
                    NetworkingManager.Singleton.PendingClients[clientId].AesKey = NetworkingManager.Singleton.PendingClients[clientId].KeyExchange.GetSharedSecret(diffieHellmanPublic);
                    if (NetworkingManager.Singleton.NetworkConfig.SignKeyExchange)
                    {
                        byte[]                   diffieHellmanPublicSignature = reader.ReadByteArray();
                        X509Certificate2         certificate = NetworkingManager.Singleton.NetworkConfig.ServerX509Certificate;
                        RSACryptoServiceProvider rsa         = certificate.PrivateKey as RSACryptoServiceProvider;

                        if (rsa != null)
                        {
                            using (SHA256Managed sha = new SHA256Managed())
                            {
                                byte[] clientHash = rsa.Decrypt(diffieHellmanPublicSignature, false);
                                byte[] serverHash = sha.ComputeHash(diffieHellmanPublic);

                                if (!CryptographyHelper.ConstTimeArrayEqual(clientHash, serverHash))
                                {
                                    //Man in the middle.
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                    {
                                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                        {
                                            LogHelper.LogWarning("Signature doesnt match for the key exchange public part. Disconnecting");
                                        }
                                    }
                                    NetworkingManager.Singleton.DisconnectClient(clientId);
                                    return;
                                }
                            }
                        }
                        else
                        {
                            throw new CryptographicException("[MLAPI] Only RSA certificates are supported. No valid RSA key was found");
                        }
                    }
                }
            }

            NetworkingManager.Singleton.PendingClients[clientId].ConnectionState = PendingClient.State.PendingConnection;
            NetworkingManager.Singleton.PendingClients[clientId].KeyExchange     = null; // Give to GC

            // Send greetings, they have passed all the handshakes
            using (PooledBitStream outStream = PooledBitStream.Get())
            {
                using (PooledBitWriter writer = PooledBitWriter.Get(outStream))
                {
                    writer.WriteInt64Packed(DateTime.Now.Ticks); // This serves no purpose.
                }
                InternalMessageSender.Send(clientId, MLAPIConstants.MLAPI_GREETINGS, "MLAPI_INTERNAL", outStream, SecuritySendFlags.None, null, true);
            }
        }
Пример #2
0
        // This method is responsible for unwrapping a message, that is extracting the messagebody.
        // Could include decrypting and/or authentication.
        internal static BitStream UnwrapMessage(BitStream inputStream, ulong clientId, out byte messageType, out SecuritySendFlags security)
        {
            using (PooledBitReader inputHeaderReader = PooledBitReader.Get(inputStream))
            {
                try
                {
                    if (inputStream.Length < 1)
                    {
                        if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                        {
                            LogHelper.LogError("The incoming message was too small");
                        }
                        messageType = MLAPIConstants.INVALID;
                        security    = SecuritySendFlags.None;
                        return(null);
                    }

                    bool isEncrypted     = inputHeaderReader.ReadBit();
                    bool isAuthenticated = inputHeaderReader.ReadBit();

                    if (isEncrypted && isAuthenticated)
                    {
                        security = SecuritySendFlags.Encrypted | SecuritySendFlags.Authenticated;
                    }
                    else if (isEncrypted)
                    {
                        security = SecuritySendFlags.Encrypted;
                    }
                    else if (isAuthenticated)
                    {
                        security = SecuritySendFlags.Authenticated;
                    }
                    else
                    {
                        security = SecuritySendFlags.None;
                    }


#if !DISABLE_CRYPTOGRAPHY
                    if (isEncrypted || isAuthenticated)
                    {
                        if (!NetworkingManager.Singleton.NetworkConfig.EnableEncryption)
                        {
                            if (LogHelper.CurrentLogLevel <= LogLevel.Error)
                            {
                                LogHelper.LogError("Got a encrypted and/or authenticated message but key exchange (\"encryption\") was not enabled");
                            }
                            messageType = MLAPIConstants.INVALID;
                            return(null);
                        }

                        // Skip last bits in first byte
                        inputHeaderReader.SkipPadBits();

                        if (isAuthenticated)
                        {
                            long hmacStartPos = inputStream.Position;

                            int readHmacLength = inputStream.Read(HMAC_BUFFER, 0, HMAC_BUFFER.Length);

                            if (readHmacLength != HMAC_BUFFER.Length)
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Error)
                                {
                                    LogHelper.LogError("HMAC length was invalid");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            // Now we have read the HMAC, we need to set the hmac in the input to 0s to perform the HMAC.
                            inputStream.Position = hmacStartPos;
                            inputStream.Write(HMAC_PLACEHOLDER, 0, HMAC_PLACEHOLDER.Length);

                            byte[] key = NetworkingManager.Singleton.IsServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey();

                            if (key == null)
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Error)
                                {
                                    LogHelper.LogError("Failed to grab key");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            using (HMACSHA256 hmac = new HMACSHA256(key))
                            {
                                byte[] computedHmac = hmac.ComputeHash(inputStream.GetBuffer(), 0, (int)inputStream.Length);


                                if (!CryptographyHelper.ConstTimeArrayEqual(computedHmac, HMAC_BUFFER))
                                {
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Error)
                                    {
                                        LogHelper.LogError("Received HMAC did not match the computed HMAC");
                                    }
                                    messageType = MLAPIConstants.INVALID;
                                    return(null);
                                }
                            }
                        }

                        if (isEncrypted)
                        {
                            int ivRead = inputStream.Read(IV_BUFFER, 0, IV_BUFFER.Length);

                            if (ivRead != IV_BUFFER.Length)
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    LogHelper.LogError("Invalid IV size");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            PooledBitStream outputStream = PooledBitStream.Get();

                            using (RijndaelManaged rijndael = new RijndaelManaged())
                            {
                                rijndael.IV      = IV_BUFFER;
                                rijndael.Padding = PaddingMode.PKCS7;

                                byte[] key = NetworkingManager.Singleton.IsServer ? CryptographyHelper.GetClientKey(clientId) : CryptographyHelper.GetServerKey();

                                if (key == null)
                                {
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Error)
                                    {
                                        LogHelper.LogError("Failed to grab key");
                                    }
                                    messageType = MLAPIConstants.INVALID;
                                    return(null);
                                }

                                rijndael.Key = key;

                                using (CryptoStream cryptoStream = new CryptoStream(outputStream, rijndael.CreateDecryptor(), CryptoStreamMode.Write))
                                {
                                    cryptoStream.Write(inputStream.GetBuffer(), (int)inputStream.Position, (int)(inputStream.Length - inputStream.Position));
                                }

                                outputStream.Position = 0;

                                if (outputStream.Length == 0)
                                {
                                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                    {
                                        LogHelper.LogError("The incoming message was too small");
                                    }
                                    messageType = MLAPIConstants.INVALID;
                                    return(null);
                                }

                                int msgType = outputStream.ReadByte();
                                messageType = msgType == -1 ? MLAPIConstants.INVALID : (byte)msgType;
                            }

                            return(outputStream);
                        }
                        else
                        {
                            if (inputStream.Length - inputStream.Position <= 0)
                            {
                                if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                                {
                                    LogHelper.LogError("The incoming message was too small");
                                }
                                messageType = MLAPIConstants.INVALID;
                                return(null);
                            }

                            int msgType = inputStream.ReadByte();
                            messageType = msgType == -1 ? MLAPIConstants.INVALID : (byte)msgType;
                            return(inputStream);
                        }
                    }
                    else
                    {
#endif
                    messageType = inputHeaderReader.ReadByteBits(6);
                    // The input stream is now ready to be read from. It's "safe" and has the correct position
                    return(inputStream);

#if !DISABLE_CRYPTOGRAPHY
                }
#endif
                }
                catch (Exception e)
                {
                    if (LogHelper.CurrentLogLevel <= LogLevel.Normal)
                    {
                        LogHelper.LogError("Error while unwrapping headers");
                    }
                    if (LogHelper.CurrentLogLevel <= LogLevel.Error)
                    {
                        LogHelper.LogError(e.ToString());
                    }

                    security    = SecuritySendFlags.None;
                    messageType = MLAPIConstants.INVALID;
                    return(null);
                }
            }
        }