/// <summary>
        /// Creates a new wire message.
        /// </summary>
        /// <param name="messageType">Message type name</param>
        /// <param name="serializedMessage">Serialized message</param>
        /// <param name="serializer">Serializer used to serialize the signed content</param>
        /// <param name="keyPair">RSA key pair to be used for creating a RSA signature for the message data</param>
        /// <param name="sharedSecret">Shared secret (wire message will be not encrypted, if null)</param>
        /// <param name="error">Species whether the wire message is in error state</param>
        /// <param name="uniqueCallKey">Unique key to correlate RPC call</param>
        /// <returns>The created wire message</returns>
        /// <exception cref="ArgumentException">Thrown if the message type is left empty.</exception>
        public WireMessage CreateWireMessage(
            string messageType,
            byte[] serializedMessage,
            ISerializerAdapter serializer,
            RsaKeyPair keyPair   = null,
            byte[] sharedSecret  = null,
            bool error           = false,
            byte[] uniqueCallKey = null)
        {
            if (string.IsNullOrWhiteSpace(messageType))
            {
                throw new ArgumentException("Message type must not be empty.", nameof(messageType));
            }

            byte[] iv =
                sharedSecret == null
                    ? new byte[0]
                    : AesEncryption.GenerateIv();

            byte[] rawContent;

            if (keyPair != null && sharedSecret != null)
            {
                var signedMessageData =
                    new SignedMessageData()
                {
                    MessageRawData = serializedMessage,
                    Signature      =
                        RsaSignature.CreateSignature(
                            keySize: keyPair.KeySize,
                            sendersPrivateKeyBlob: keyPair.PrivateKey,
                            rawData: serializedMessage)
                };

                rawContent = serializer.Serialize(typeof(SignedMessageData), signedMessageData);
            }
            else
            {
                rawContent = serializedMessage;
            }

            byte[] messageContent =
                sharedSecret == null
                    ? rawContent
                    : AesEncryption.Encrypt(
                    dataToEncrypt: rawContent,
                    sharedSecret: sharedSecret,
                    iv: iv);

            return
                (new WireMessage()
            {
                MessageType = messageType,
                Data = messageContent,
                Iv = iv,
                Error = error,
                UniqueCallKey = uniqueCallKey
            });
        }
Esempio n. 2
0
        /// <summary>
        /// Creates a new instance of the RemotingSession class.
        /// </summary>
        /// <param name="keySize">Key size of the RSA keys for asymmetric encryption</param>
        /// <param name="clientPublicKey">Public key of this session's client</param>
        /// <param name="server">Server instance, that hosts this session</param>
        /// <param name="rawMessageTransport">Component, that does the raw message transport (send and receive)</param>
        internal RemotingSession(int keySize, byte[] clientPublicKey, IRemotingServer server,
                                 IRawMessageTransport rawMessageTransport)
        {
            _sessionId             = Guid.NewGuid();
            _lastActivityTimestamp = DateTime.Now;
            _isAuthenticated       = false;
            _keyPair  = new RsaKeyPair(keySize);
            CreatedOn = DateTime.Now;
            _remoteDelegateInvocationEventAggregator = new RemoteDelegateInvocationEventAggregator();
            _server = server ?? throw new ArgumentNullException(nameof(server));
            _delegateProxyFactory = _server.ServiceRegistry.GetService <IDelegateProxyFactory>();
            _delegateProxyCache   = new ConcurrentDictionary <Guid, IDelegateProxy>();
            _rawMessageTransport  = rawMessageTransport ?? throw new ArgumentNullException(nameof(rawMessageTransport));
            _clientPublicKeyBlob  = clientPublicKey;

            _rawMessageTransport.ReceiveMessage += OnReceiveMessage;
            _rawMessageTransport.ErrorOccured   += OnErrorOccured;

            MessageEncryption = clientPublicKey != null;

            WireMessage completeHandshakeMessage;

            if (MessageEncryption)
            {
                var encryptedSessionId =
                    RsaKeyExchange.EncryptSecret(
                        keySize: _server.SessionRepository.KeySize,
                        receiversPublicKeyBlob: clientPublicKey,
                        secretToEncrypt: _sessionId.ToByteArray(),
                        sendersPublicKeyBlob: _keyPair.PublicKey);

                var rawContent = _server.Serializer.Serialize(encryptedSessionId);

                var signedMessageData =
                    new SignedMessageData()
                {
                    MessageRawData = rawContent,
                    Signature      =
                        RsaSignature.CreateSignature(
                            keySize: keySize,
                            sendersPrivateKeyBlob: _keyPair.PrivateKey,
                            rawData: rawContent)
                };

                var rawData = _server.Serializer.Serialize(typeof(SignedMessageData), signedMessageData);

                completeHandshakeMessage =
                    new WireMessage
                {
                    MessageType = "complete_handshake",
                    Data        = rawData
                };
            }
            else
            {
                completeHandshakeMessage =
                    new WireMessage
                {
                    MessageType = "complete_handshake",
                    Data        = _sessionId.ToByteArray()
                };
            }

            _remoteDelegateInvocationEventAggregator.RemoteDelegateInvocationNeeded +=
                (delegateType, uniqueCallKey, handlerKey, arguments) =>
            {
                var sharedSecret =
                    MessageEncryption
                            ? _sessionId.ToByteArray()
                            : null;

                var remoteDelegateInvocationMessage =
                    new RemoteDelegateInvocationMessage
                {
                    UniqueCallKey     = uniqueCallKey,
                    HandlerKey        = handlerKey,
                    DelegateArguments = arguments
                };

                var remoteDelegateInvocationWebsocketMessage =
                    _server.MessageEncryptionManager
                    .CreateWireMessage(
                        serializedMessage: _server.Serializer.Serialize(remoteDelegateInvocationMessage),
                        serializer: _server.Serializer,
                        sharedSecret: sharedSecret,
                        keyPair: _keyPair,
                        messageType: "invoke");

                // Invoke remote delegate on client
                _rawMessageTransport.SendMessage(
                    _server.Serializer.Serialize(remoteDelegateInvocationWebsocketMessage));

                return(null);
            };

            _rawMessageTransport.SendMessage(_server.Serializer.Serialize(completeHandshakeMessage));
        }