/// <summary>
        /// Encodes the specified handshake message.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns></returns>
        public byte[] Encode(ResonanceHandShakeMessage message)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (BinaryWriter writer = new BinaryWriter(ms))
                {
                    writer.Write((byte)0); //This empty byte is used to distinguish between handshake message and standard message.
                    writer.Write((byte)message.Type);
                    writer.Write(message.ClientId);
                    writer.Write(message.RequireEncryption);

                    if (message.RequireEncryption)
                    {
                        writer.Write(message.EncryptionPublicKey.ToStringOrEmpty());
                        writer.Write(message.SymmetricPassword.ToStringOrEmpty());
                    }
                }

                return(ms.ToArray());
            }
        }
Exemple #2
0
        /// <summary>
        /// Begins the hand shake.
        /// This method will block execution until the handshake has completed.
        /// </summary>
        /// <exception cref="InvalidOperationException">Must call reset before attempting to begin a handshake.</exception>
        /// <exception cref="TimeoutException">Could not initiate a handshake within the given timeout.</exception>
        public void BeginHandShake()
        {
            if (!_wasReset)
            {
                throw new InvalidOperationException("Must call reset before attempting to begin a handshake.");
            }

            if (State == ResonanceHandShakeState.Idle)
            {
                Logger.LogDebug("Starting handshake...");
                State = ResonanceHandShakeState.InProgress;
                Logger.LogDebug("Sending Handshake Request...");
                ResonanceHandShakeMessage request = new ResonanceHandShakeMessage();
                request.Type                = ResonanceHandShakeMessageType.Request;
                request.ClientId            = ClientID;
                request.RequireEncryption   = EncryptionEnabled;
                request.EncryptionPublicKey = _publicKey;

                OnWriteHandShake(HandShakeTranscoder.Encode(request));
            }

            bool cancel = false;

            TimeoutTask.StartNew(() =>
            {
                cancel = true;
            }, TimeSpan.FromSeconds(10));

            while (State != ResonanceHandShakeState.Completed && !cancel)
            {
                Thread.Sleep(10);
            }

            if (cancel)
            {
                throw new TimeoutException("Could not initiate a handshake within the given timeout.");
            }
        }
        /// <summary>
        /// Decodes the raw data to a handshake message.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns></returns>
        public ResonanceHandShakeMessage Decode(byte[] data)
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                using (BinaryReader reader = new BinaryReader(ms))
                {
                    var message = new ResonanceHandShakeMessage();

                    reader.ReadByte();  //This empty byte is used to distinguish between handshake message and standard message.
                    message.Type              = (ResonanceHandShakeMessageType)reader.ReadByte();
                    message.ClientId          = reader.ReadInt32();
                    message.RequireEncryption = reader.ReadBoolean();

                    if (message.RequireEncryption)
                    {
                        message.EncryptionPublicKey = reader.ReadString().ToNullIfEmpty();
                        message.SymmetricPassword   = reader.ReadString().ToNullIfEmpty();
                    }

                    return(message);
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// To be called when a new data is available from the other side and the handshake did not complete.
        /// </summary>
        /// <param name="data">Adapter incoming data.</param>
        /// <exception cref="InvalidOperationException">Must call reset before attempting to receive a handshake message.</exception>
        public void HandShakeMessageDataReceived(byte[] data)
        {
            if (!_wasReset)
            {
                throw new InvalidOperationException("Must call reset before attempting to receive a handshake message.");
            }

            lock (_lock)
            {
                bool shouldSendRequest = State == ResonanceHandShakeState.Idle;

                State = ResonanceHandShakeState.InProgress;

                ResonanceHandShakeMessage message = HandShakeTranscoder.Decode(data);

                if (message.Type == ResonanceHandShakeMessageType.Request)
                {
                    if (shouldSendRequest)
                    {
                        Logger.LogDebug("Sending Handshake Request...");
                        ResonanceHandShakeMessage r = new ResonanceHandShakeMessage();
                        r.Type                = ResonanceHandShakeMessageType.Request;
                        r.ClientId            = ClientID;
                        r.RequireEncryption   = EncryptionEnabled;
                        r.EncryptionPublicKey = _publicKey;

                        OnWriteHandShake(HandShakeTranscoder.Encode(r));
                        Thread.Sleep(10);
                    }
                    else if (ClientID > message.ClientId)
                    {
                        Thread.Sleep(10);
                    }

                    var request = message;

                    Logger.LogDebug("Handshake Request Received...");

                    ResonanceHandShakeMessage response = new ResonanceHandShakeMessage();
                    response.Type     = ResonanceHandShakeMessageType.Response;
                    response.ClientId = ClientID;

                    if (EncryptionEnabled && request.RequireEncryption)
                    {
                        response.EncryptionPublicKey = _publicKey;
                        response.RequireEncryption   = true;

                        if (ClientID > request.ClientId && State != ResonanceHandShakeState.Completed)
                        {
                            _symmetricPassword = Guid.NewGuid().ToString();
                            OnSymmetricPasswordAvailable(_symmetricPassword);
                            response.SymmetricPassword = _cryptographyProvider.Encrypt(_symmetricPassword, request.EncryptionPublicKey);
                            OnWriteHandShake(HandShakeTranscoder.Encode(response));
                            Logger.LogDebug("Handshake Response Sent...");
                        }
                    }
                    else
                    {
                        if (ClientID > request.ClientId && State != ResonanceHandShakeState.Completed)
                        {
                            OnWriteHandShake(HandShakeTranscoder.Encode(response));
                            Logger.LogDebug("Handshake Response Sent...");
                        }
                    }
                }
                else if (message.Type == ResonanceHandShakeMessageType.Response)
                {
                    var response = message;

                    Logger.LogDebug("Handshake Response Received...");

                    if (response.RequireEncryption && EncryptionEnabled)
                    {
                        if (response.ClientId > ClientID)
                        {
                            _symmetricPassword = _cryptographyProvider.Decrypt(response.SymmetricPassword, _privateKey);
                            OnSymmetricPasswordAvailable(_symmetricPassword);
                        }
                    }

                    if (response.ClientId > ClientID)
                    {
                        State = ResonanceHandShakeState.Completed;
                        OnWriteHandShake(HandShakeTranscoder.Encode(new ResonanceHandShakeMessage()
                        {
                            Type = ResonanceHandShakeMessageType.Complete, ClientId = ClientID
                        }));
                        Logger.LogDebug("Handshake completed.");
                        Completed?.Invoke(this, new EventArgs());
                    }
                }
                else
                {
                    State = ResonanceHandShakeState.Completed;
                    Logger.LogDebug("Handshake completed.");
                    Completed?.Invoke(this, new EventArgs());
                }
            }
        }