public async Task <string> CreateConnectionAsync(string counterPartyVaspId)
        {
            var counterPartyVaspCode = counterPartyVaspId.Substring(4, 8);
            var vaspTransportKey     = await _vaspCodesService.GetTransportKeyAsync(counterPartyVaspCode);

            if (vaspTransportKey == null)
            {
                throw new InvalidOperationException($"Couldn't get TransportKey for vasp code {counterPartyVaspCode}");
            }

            var sessionKey   = ECDH_Key.GenerateKey();
            var topic        = TopicGenerator.GenerateConnectionTopic();
            var privateKeyId = await _whisperRpc.RegisterKeyPairAsync(sessionKey.PrivateKey);

            var filter = await _whisperRpc.CreateMessageFilterAsync(topic, privateKeyId);

            _activeTopics.Add(topic);

            var connection = new Connection
            {
                Id                 = Guid.NewGuid().ToString("N"),
                Filter             = filter,
                InboundTopic       = topic,
                Status             = ConnectionStatus.Active,
                CounterPartyVaspId = counterPartyVaspId,
                PrivateKey         = sessionKey.PrivateKey,
            };

            _connections[connection.Id] = connection;

            return(connection.Id);
        }
Esempio n. 2
0
        private async Task HandleSessionRequestAsync(
            string connectionId,
            string sessionId,
            string senderVaspId,
            string ecdhPkA)
        {
            var key = ECDH_Key.GenerateKey();

            var session = new Session
            {
                Id    = sessionId,
                Type  = SessionType.Beneficiary,
                State = SessionState.Invited,
                CounterPartyVaspId = senderVaspId,
                ConnectionId       = connectionId,
                CreationDateTime   = DateTime.UtcNow,
                EcdhPrivateKey     = key.PrivateKey,
                TempAesMessageKey  = ECDH_Key.ImportKey(_privateMessageKey)
                                     .GenerateSharedSecretHex(await _vaspCodesService.GetMessageKeyAsync(senderVaspId.Substring(4)))
            };

            if (!string.IsNullOrWhiteSpace(ecdhPkA))
            {
                session.EstablishedAesMessageKey = key.GenerateSharedSecretHex(ecdhPkA);
            }

            _sessions[sessionId] = session;

            await TriggerAsyncEvent(BeneficiarySessionCreated, new BeneficiarySessionCreatedEvent
            {
                SessionId          = sessionId,
                CounterPartyVaspId = session.CounterPartyVaspId
            });
        }
        public static VaspClient Create(
            VaspInformation vaspInfo,
            VaspContractInfo vaspContractInfo,
            string handshakePrivateKeyHex,
            string signaturePrivateKeyHex,
            IEthereumRpc nodeClientEthereumRpc,
            IWhisperRpc nodeClientWhisperRpc,
            IEnsProvider ensProvider,
            ISignService signService,
            ITransportClient transportClient)
        {
            var handshakeKey = ECDH_Key.ImportKey(handshakePrivateKeyHex);

            var vaspClient = new VaspClient(
                handshakeKey,
                signaturePrivateKeyHex,
                vaspContractInfo,
                vaspInfo,
                nodeClientEthereumRpc,
                nodeClientWhisperRpc,
                ensProvider,
                transportClient,
                signService);

            return(vaspClient);
        }
Esempio n. 4
0
        public async Task <string> CreateSessionAndSendSessionRequestAsync(string counterPartyVaspId)
        {
            var session = new Session
            {
                Id    = Guid.NewGuid().ToString("N"),
                Type  = SessionType.Originator,
                State = SessionState.Created,
                CounterPartyVaspId = counterPartyVaspId,
                CreationDateTime   = DateTime.UtcNow,
                EcdhPrivateKey     = ECDH_Key.GenerateKey().PrivateKey,
            };

            _sessions[session.Id] = session;

            var whisperConnection = await _transportService.CreateConnectionAsync(session.CounterPartyVaspId);

            session.ConnectionId = whisperConnection;

            var messageKey = await _vaspCodesService.GetMessageKeyAsync(session.CounterPartyVaspId.Substring(4));

            session.TempAesMessageKey = ECDH_Key.ImportKey(_privateMessageKey).GenerateSharedSecretHex(messageKey);

            await SendMessageAsync(
                session,
                MessageType.SessionRequest,
                Instruction.Invite,
                ECDH_Key.ImportKey(session.EcdhPrivateKey).PublicKey,
                new SessionRequest());

            return(session.Id);
        }
        private async Task HandleAcceptMessageAsync(OpenVaspPayload payload)
        {
            var connection = _connections[payload.ConnectionId];

            if (connection == null)
            {
                throw new ArgumentException($"Connection with id '{payload.ConnectionId}' was not found");
            }

            var sharedSecret = ECDH_Key.ImportKey(connection.PrivateKey).GenerateSharedSecretHex(payload.EcdhPk);

            (connection.Filter, connection.SymKeyId) = await RegisterConnectionAsync(connection.InboundTopic, sharedSecret);

            connection.SharedPrivateEncryptionKey = sharedSecret;
            connection.OutboundTopic = payload.ReturnTopic;

            await AcknowledgeMessageAsync(
                payload,
                connection.SymKeyId,
                null);

            var senderVaspCode = payload.SenderVaspId.Substring(4, 8);
            var signingKey     = await _vaspCodesService.GetSigningKeyAsync(senderVaspCode);

            await TriggerAsyncEvent(TransportMessageReceived,
                                    new TransportMessageEvent
            {
                ConnectionId = payload.ConnectionId,
                SenderVaspId = payload.SenderVaspId,
                Instruction  = payload.Instruction,
                Payload      = payload.OvMessage,
                Timestamp    = DateTime.UtcNow,
                SigningKey   = signingKey
            });
        }
Esempio n. 6
0
        public void ValidateEcdhKeysSharedKeyGenerationForPrivateKeyTest(string aliceKeyStr, string bobKeyStr, string expectedSharedStr)
        {
            BigInteger aliceKey       = new BigInteger(aliceKeyStr.Replace("L", ""));
            BigInteger bobKey         = new BigInteger(bobKeyStr.Replace("L", ""));
            var        aliceConverted = aliceKey.ToByteArray().ToHex(true);
            var        bobConverted   = bobKey.ToByteArray().ToHex(true);

            ECDH_Key alice = ECDH_Key.ImportKey(aliceConverted);
            ECDH_Key bob   = ECDH_Key.ImportKey(bobConverted);

            var shared1 = alice.GenerateSharedSecretHex(bob.PublicKey);
            var shared2 = bob.GenerateSharedSecretHex(alice.PublicKey);

            var res = new BigInteger(shared1.HexToByteArray()).ToString();

            Assert.Equal(shared1, shared2);
            Assert.Equal(expectedSharedStr.Replace("L", ""), res);

            testOutputHelper.WriteLine(shared1);
            testOutputHelper.WriteLine(shared2);
            testOutputHelper.WriteLine(res);

            EthECKey aliceKeyEth = new EthECKey(aliceConverted);
            EthECKey bobKeyEth   = new EthECKey(bob.PublicKey.HexToByteArray(), false);

            var shared3 = aliceKeyEth.CalculateCommonSecret(bobKeyEth).ToHex(true);

            testOutputHelper.WriteLine(shared3);

            Assert.Equal(shared1, shared3);
        }
Esempio n. 7
0
        public void ValidateEcdhKeysSharedKeyGenerationForPubKeyTest(string privateKeySecp256k1, string publicKeySecp256k1, string sharedKey)
        {
            ECDH_Key alice = ECDH_Key.ImportKey(privateKeySecp256k1);

            var shared1 = alice.GenerateSharedSecretHex(publicKeySecp256k1);

            Assert.Equal(sharedKey, shared1);
        }
Esempio n. 8
0
        public void GenerateHandshakeKeyForVaspSmartContractTest()
        {
            ECDH_Key alice       = ECDH_Key.GenerateKey();
            ECDH_Key importValid = ECDH_Key.ImportKey(alice.PrivateKey);

            Assert.Equal(alice.PrivateKey, importValid.PrivateKey);
            Assert.Equal(alice.PublicKey, importValid.PublicKey);
        }
        private async Task StartAsync()
        {
            var transportKey = ECDH_Key.ImportKey(_privateTransportKey);
            var privateKeyId = await _whisperRpc.RegisterKeyPairAsync(transportKey.PrivateKey);

            var filter = await _whisperRpc.CreateMessageFilterAsync(_vaspId.Substring(4), privateKeyId);

            _filter = filter;
            _timer.Start();
        }
Esempio n. 10
0
        public void SharedSecretECDHGenerationTest()
        {
            ECDH_Key alice = ECDH_Key.GenerateKey();
            ECDH_Key bob   = ECDH_Key.GenerateKey();

            var shared1 = alice.GenerateSharedSecretHex(bob.PublicKey);
            var shared2 = bob.GenerateSharedSecretHex(alice.PublicKey);

            Assert.Equal(shared1, shared2);
        }
Esempio n. 11
0
        public void GenerateHandshakeKeyForVaspSmartContractTest()
        {
            ECDH_Key alice       = ECDH_Key.GenerateKey();
            ECDH_Key importValid = ECDH_Key.ImportKey(alice.PrivateKey);

            Assert.Equal(alice.PrivateKey, importValid.PrivateKey);
            Assert.Equal(alice.PublicKey, importValid.PublicKey);

            testOutputHelper.WriteLine(alice.PrivateKey.HexToByteArray().Length.ToString());

            testOutputHelper.WriteLine(alice.PrivateKey);
            testOutputHelper.WriteLine(alice.PublicKey);
        }
Esempio n. 12
0
        public void SharedSecretECDHImportTest()
        {
            EthECKey ecKey1 = EthECKey.GenerateKey();
            EthECKey ecKey2 = EthECKey.GenerateKey();

            ECDH_Key alice = ECDH_Key.ImportKey(ecKey1.GetPrivateKey());
            ECDH_Key bob   = ECDH_Key.ImportKey(ecKey2.GetPrivateKey());

            var ecPubKey1 = ecKey1.GetPubKey().ToHex(true);
            var ecPubKey2 = ecKey2.GetPubKey().ToHex(true);

            var shared1 = alice.GenerateSharedSecretHex(bob.PublicKey);
            var shared2 = bob.GenerateSharedSecretHex(alice.PublicKey);

            Assert.Equal(shared1, shared2);
        }
Esempio n. 13
0
        public async Task SessionReplyAsync(
            string sessionId,
            SessionReplyMessageCode code)
        {
            var session = _sessions[sessionId];

            await SendMessageAsync(
                session,
                MessageType.SessionReply,
                code == SessionReplyMessageCode.SessionAccepted?Instruction.Accept : Instruction.Deny,
                ECDH_Key.ImportKey(session.EcdhPrivateKey).PublicKey,
                new SessionReply
            {
                Code = ((int)code).ToString()
            });
        }
Esempio n. 14
0
        public void ValidateEcdhKeysSharedKeyGenerationForPrivateKeyTest(string aliceKeyStr, string bobKeyStr, string expectedSharedStr)
        {
            BigInteger aliceKey       = new BigInteger(aliceKeyStr.Replace("L", ""));
            BigInteger bobKey         = new BigInteger(bobKeyStr.Replace("L", ""));
            var        aliceConverted = aliceKey.ToByteArray().ToHex(true);
            var        bobConverted   = bobKey.ToByteArray().ToHex(true);

            ECDH_Key alice = ECDH_Key.ImportKey(aliceConverted);
            ECDH_Key bob   = ECDH_Key.ImportKey(bobConverted);

            var shared1 = alice.GenerateSharedSecretHex(bob.PublicKey);
            var shared2 = bob.GenerateSharedSecretHex(alice.PublicKey);

            var res = new BigInteger(shared1.HexToByteArray()).ToString();

            Assert.Equal(shared1, shared2);
            Assert.Equal(expectedSharedStr.Replace("L", ""), res);
        }
        /// <summary>
        /// Create a session and send a request session message to beneficiary Vasp.
        /// </summary>
        /// <param name="originator">Information about a client who sends a transfer</param>
        /// <param name="beneficiaryVaan">Information about a receiver of the transfer</param>
        /// <returns>OriginatorSession through which transfer request and transfer dispatch should be requested.</returns>
        public async Task <OriginatorSession> CreateSessionAsync(
            Originator originator,
            VirtualAssetsAccountNumber beneficiaryVaan,
            IOriginatorVaspCallbacks _originatorVaspCallbacks)
        {
            string counterPartyVaspContractAddress = await _ensProvider.GetContractAddressByVaspCodeAsync(beneficiaryVaan.VaspCode);

            var contractInfo = await _ethereumRpc.GetVaspContractInfoAync(counterPartyVaspContractAddress);

            var sessionKey = ECDH_Key.GenerateKey();
            var sharedKey  = sessionKey.GenerateSharedSecretHex(contractInfo.HandshakeKey);

            var session = new OriginatorSession(
                originator,
                this._vaspContractInfo,
                this.VaspInfo,
                beneficiaryVaan,
                contractInfo.SigningKey,
                contractInfo.HandshakeKey,
                sharedKey,
                sessionKey.PublicKey,
                this._signatureKey,
                _whisperRpc,
                _transportClient,
                _signService,
                _originatorVaspCallbacks);

            if (_originatorSessionsDict.TryAdd(session.SessionId, session))
            {
                this.NotifySessionCreated(session);
                session.OnSessionTermination += this.ProcessSessionTermination;
                await session.StartAsync();

                return(session);
            }

            await session.TerminateAsync(TerminationMessage.TerminationMessageCode
                                         .SessionClosedTransferCancelledByOriginator);

            //TODO: process it as exception or retry
            return(null);
        }
Esempio n. 16
0
 //TODO: Get rid of Whisper completely
 private VaspClient(
     ECDH_Key handshakeKey,
     string signatureHexKey,
     VaspContractInfo vaspContractInfo,
     VaspInformation vaspInfo,
     IEthereumRpc nodeClientEthereumRpc,
     IWhisperRpc nodeClientWhisperRpc,
     IEnsProvider ensProvider,
     ITransportClient transportClient,
     ISignService signService)
 {
     this._handshakeKey            = handshakeKey;
     this._signatureKey            = signatureHexKey;
     this._vaspContractInfo        = vaspContractInfo;
     this.VaspInfo                 = vaspInfo;
     this._ethereumRpc             = nodeClientEthereumRpc;
     this._whisperRpc              = nodeClientWhisperRpc;
     this._cancellationTokenSource = new CancellationTokenSource();
     this._ensProvider             = ensProvider;
     this._transportClient         = transportClient;
     this._signService             = signService;
 }
Esempio n. 17
0
        public async Task HandleSessionReplyAsync(string sessionId, string messageCode, string ecdhPkB)
        {
            var session = _sessions[sessionId];

            if (session.State != SessionState.Initiated)
            {
                _logger?.LogWarning(
                    $"Can't process reply for session {sessionId} that is in {session.State} state. Skipping.");
                return;
            }

            var sessionReplyCode = (SessionReplyMessageCode)Enum.Parse(typeof(SessionReplyMessageCode), messageCode);

            session.State = sessionReplyCode == SessionReplyMessageCode.SessionAccepted
                ? SessionState.Open
                : SessionState.Declined;

            if (!string.IsNullOrWhiteSpace(ecdhPkB))
            {
                session.EstablishedAesMessageKey =
                    ECDH_Key.ImportKey(session.EcdhPrivateKey).GenerateSharedSecretHex(ecdhPkB);
            }

            if (session.State == SessionState.Open)
            {
                await TriggerAsyncEvent(OriginatorSessionApproved, new OriginatorSessionApprovedEvent
                {
                    SessionId = sessionId
                });
            }
            else
            {
                await TriggerAsyncEvent(OriginatorSessionDeclined, new OriginatorSessionDeclinedEvent
                {
                    SessionId = sessionId
                });
            }
        }
        public async Task CreateVaspForBank()
        {
            var signature = new EthECKey(Settings.PersonSignaturePrivateKeyHex);
            var handshake = ECDH_Key.ImportKey(Settings.PersonHandshakePrivateKeyHex);

            var signPub      = signature.GetPubKey().ToHex(prefix: true);
            var handshakePub = handshake.PublicKey;

            (VaspInformation vaspInfo, VaspContractInfo vaspContractInfo) = await VaspInformationBuilder.CreateForBankAsync(
                NodeClient.EthereumRpc,
                Settings.VaspSmartContractAddressBank,
                Settings.Bic);

            VaspClient vasp = VaspClient.Create(
                vaspInfo,
                vaspContractInfo,
                Settings.BankHandshakePrivateKeyHex,
                Settings.BankSignaturePrivateKeyHex,
                NodeClient.EthereumRpc,
                NodeClient.WhisperRpc,
                _fakeEnsProvider,
                _signService,
                NodeClient.TransportClient);

            // VASP paramaters must be derived from smart contract
            Assert.NotNull(vasp.VaspInfo.Name);
            Assert.NotNull(vasp.VaspInfo.VaspIdentity);
            Assert.NotNull(vasp.VaspInfo.PostalAddress);

            // VASP natural person parameters should be same what we pass in constructor
            Assert.Equal(vasp.VaspInfo.BIC, Settings.Bic);

            Assert.Null(vasp.VaspInfo.NaturalPersonIds);
            Assert.Null(vasp.VaspInfo.PlaceOfBirth);
            Assert.Null(vasp.VaspInfo.JuridicalPersonIds);
        }
Esempio n. 19
0
        private async Task TransportClientOnTransportMessageReceived(TransportMessageEvent evt)
        {
            MessageContent messageContent;
            string         messagePlaintext;
            string         sig;

            var session = _sessions.Values.SingleOrDefault(x => x.ConnectionId == evt.ConnectionId);

            if (session == null)
            {
                var messageKey = await _vaspCodesService.GetMessageKeyAsync(evt.SenderVaspId.Substring(4));

                var aesMessageKey = ECDH_Key.ImportKey(_privateMessageKey).GenerateSharedSecretHex(messageKey);
                (messageContent, messagePlaintext, sig) =
                    _messageFormatterService.Deserialize(evt.Payload, aesMessageKey, evt.SigningKey);
            }
            else if (string.IsNullOrWhiteSpace(session.EstablishedAesMessageKey))
            {
                (messageContent, messagePlaintext, sig) =
                    _messageFormatterService.Deserialize(evt.Payload, session.TempAesMessageKey, evt.SigningKey);
            }
            else
            {
                try
                {
                    (messageContent, messagePlaintext, sig) =
                        _messageFormatterService.Deserialize(evt.Payload, session.EstablishedAesMessageKey,
                                                             evt.SigningKey);
                }
                catch (InvalidCipherTextException)
                {
                    (messageContent, messagePlaintext, sig) =
                        _messageFormatterService.Deserialize(evt.Payload, session.TempAesMessageKey,
                                                             evt.SigningKey);
                }
            }

            switch (evt.Instruction)
            {
            case Instruction.Invite:
                await HandleSessionRequestAsync(
                    evt.ConnectionId,
                    messageContent.Header.SessionId,
                    evt.SenderVaspId,
                    messageContent.Header.EcdhPk);

                break;

            case Instruction.Accept:
            case Instruction.Deny:
                var messageCode = messageContent.RawBody.ToObject <SessionReply>().Code;
                await HandleSessionReplyAsync(
                    messageContent.Header.SessionId,
                    messageCode,
                    messageContent.Header.EcdhPk);

                break;

            case Instruction.Close:
                switch (messageContent.Header.MessageType)
                {
                case MessageType.Abort:
                    await HandleSessionAbortAsync(
                        messageContent.Header.SessionId,
                        messageContent.RawBody.ToObject <SessionAbort>().Code);

                    break;

                case MessageType.Termination:
                    await HandleTerminationAsync(messageContent.Header.SessionId);

                    break;
                }

                break;

            case Instruction.Update:
                await TriggerAsyncEvent(ApplicationMessageReceived, new ApplicationMessageReceivedEvent
                {
                    Type      = messageContent.Header.MessageType,
                    SessionId = session.Id,
                    Payload   = messageContent.RawBody
                });

                break;

            default:
                throw new NotSupportedException(
                          $"Instruction type {Enum.GetName(typeof(Instruction), evt.Instruction)} is not supported");
            }
        }
        public async Task SendAsync(string connectionId, string message, Instruction instruction, string receiverVaspId)
        {
            var connection = _connections[connectionId];

            var receiverVaspCode = (receiverVaspId ?? connection.CounterPartyVaspId).Substring(4, 8);

            var envelopeId = Guid.NewGuid().ToString("N");

            var payload = new OpenVaspPayload(
                instruction,
                _vaspId,
                connection.Id,
                envelopeId)
            {
                ReturnTopic = connection.InboundTopic,
                OvMessage   = message
            };

            if (instruction == Instruction.Invite || instruction == Instruction.Accept || instruction == Instruction.Deny)
            {
                payload.EcdhPk = ECDH_Key.ImportKey(connection.PrivateKey).PublicKey;
            }

            var topic = connection.OutboundTopic ?? receiverVaspCode;

            if (string.IsNullOrWhiteSpace(topic))
            {
                throw new InvalidOperationException($"Topic is empty for connection {connection.Id}");
            }

            var envelope = new MessageEnvelope
            {
                Topic = topic,
            };

            if (instruction == Instruction.Invite || instruction == Instruction.Close && string.IsNullOrWhiteSpace(connection.SymKeyId))
            {
                envelope.EncryptionType = EncryptionType.Asymmetric;

                var vaspTransportKey = await _vaspCodesService.GetTransportKeyAsync(receiverVaspCode);

                if (vaspTransportKey == null)
                {
                    throw new InvalidOperationException($"Transport key for vasp code {receiverVaspCode} cannot be found during message sending");
                }

                envelope.EncryptionKey = vaspTransportKey.DecompressPublicKey().ToHex(true);
            }
            else if (instruction == Instruction.Accept || instruction == Instruction.Deny ||
                     instruction == Instruction.Close && connection.Status == ConnectionStatus.PartiallyActive)
            {
                envelope.EncryptionType = EncryptionType.Asymmetric;
                envelope.EncryptionKey  = connection.CounterPartyPublicKey.DecompressPublicKey().ToHex(true);
            }
            else
            {
                envelope.EncryptionType = EncryptionType.Symmetric;
                envelope.EncryptionKey  = connection.SymKeyId;
            }

            var outboundEnvelope = new OutboundEnvelope
            {
                Id           = envelopeId,
                ConnectionId = connectionId,
                Envelope     = envelope,
                TotalResents = 0,
                Payload      = payload.ToString()
            };

            _openVaspPayloads[payload.EnvelopeId] = payload;

            await _outboundEnvelopeService.SendEnvelopeAsync(outboundEnvelope, instruction != Instruction.Deny);

            if (instruction == Instruction.Deny)
            {
                await DeactivateAsync(connectionId);
            }
        }
        private async Task HandleInviteMessageAsync(OpenVaspPayload payload)
        {
            var senderVaspCode   = payload.SenderVaspId.Substring(4, 8);
            var vaspTransportKey = await _vaspCodesService.GetTransportKeyAsync(senderVaspCode);

            if (vaspTransportKey == null)
            {
                _logger?.LogError($"Transport key for vasp code {senderVaspCode} cannot be found during invitation processing");
                return;
            }

            _connections.TryGetValue(payload.ConnectionId, out var connection);
            if (connection != null)
            {
                bool isSameData = connection.CounterPartyVaspId == payload.SenderVaspId &&
                                  connection.OutboundTopic == payload.ReturnTopic;
                if (isSameData)
                {
                    _logger?.LogWarning(
                        $"Received invite for already existing connectionId {payload.ConnectionId} with the same data. Skipping.");

                    await AcknowledgeMessageAsync(
                        payload,
                        null,
                        payload.EcdhPk.DecompressPublicKey().ToHex(true));
                }
                else
                {
                    _logger?.LogWarning(
                        $"Received invite for already existing connectionId {payload.ConnectionId} with the different data:{Environment.NewLine}"
                        + $"SenderVaspId: {connection.CounterPartyVaspId} - {payload.SenderVaspId},{Environment.NewLine}"
                        + $"Topic: {connection.OutboundTopic} - {payload.ReturnTopic},{Environment.NewLine}");
                }
                return;
            }

            var topic        = TopicGenerator.GenerateConnectionTopic();
            var sessionKey   = ECDH_Key.GenerateKey();
            var sharedSecret = sessionKey.GenerateSharedSecretHex(payload.EcdhPk);

            var(filter, symKeyId) = await RegisterConnectionAsync(topic, sharedSecret);

            var newConnection = new Connection
            {
                Id                         = payload.ConnectionId,
                Filter                     = filter,
                InboundTopic               = topic,
                OutboundTopic              = payload.ReturnTopic,
                Status                     = ConnectionStatus.PartiallyActive,
                CounterPartyVaspId         = payload.SenderVaspId,
                SymKeyId                   = symKeyId,
                SharedPrivateEncryptionKey = sharedSecret,
                PrivateKey                 = sessionKey.PrivateKey,
                CounterPartyPublicKey      = payload.EcdhPk,
            };

            _connections[newConnection.Id] = newConnection;

            await AcknowledgeMessageAsync(
                payload,
                null,
                payload.EcdhPk.DecompressPublicKey().ToHex(true));

            var signingKey = await _vaspCodesService.GetSigningKeyAsync(senderVaspCode);

            await TriggerAsyncEvent(TransportMessageReceived,
                                    new TransportMessageEvent
            {
                ConnectionId = payload.ConnectionId,
                SenderVaspId = payload.SenderVaspId,
                Instruction  = payload.Instruction,
                Payload      = payload.OvMessage,
                Timestamp    = DateTime.UtcNow,
                SigningKey   = signingKey
            });
        }