/// <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 }); }
/// <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)); }