internal async Task SendShortSingleMessageAsync(string messageText, UserCertificate senderUserCertificateWithPrivateKeys) { if (!DerivedDirectChannelSharedDhSecretsAE) { throw new InvalidOperationException("DerivedDirectChannelSharedDhSecretsAE = false"); } if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail(">> InviteSession.SendShortSingleMessageAsync()"); } var messageSession = new MessageSession(); var messageStart = new MessageStartPacket() { MessageId32 = (uint)_insecureRandom.Next(), DirectChannelToken32 = RemoteSessionDescription.DirectChannelToken32, MessageTimestamp64 = _localDrpPeer.Engine.Timestamp64, }; messageSession.DeriveKeys(_localDrpPeer.CryptoLibrary, SharedPingPongHmacKey, messageStart, DirectChannelSharedDhSecret); messageStart.EncryptedMessageData = messageSession.EncryptShortSingleMessage(_localDrpPeer.CryptoLibrary, messageText); // sign with HMAC messageStart.MessageHMAC = GetMessageHMAC(w => messageStart.GetSignedFieldsForMessageHMAC(w, true)); // send msgstart, wait for msgack var messageStartUdpData = messageStart.Encode(); if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("sending MSGSTART and waiting for MSGACK"); } var messageAckUdpData = await _localDrpPeer.Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("msgstart 4582", "remote user", messageStartUdpData, RemoteSessionDescription.DirectChannelEndPoint, MessageAckPacket.GetScanner(messageStart.MessageId32, this, MessageSessionStatusCode.encryptionDecryptionCompleted) // scanner also verifies HMAC ); var messageAck = MessageAckPacket.Decode(messageAckUdpData); if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("decoded MSGACK"); } // send msgpart with status=encryptionDecryptionCompleted and signature if (messageSession.Status != MessageSessionStatusCode.encryptionDecryptionCompleted) { throw new InvalidOperationException(); } var messagePart = new MessagePartPacket { MessageId32 = messageStart.MessageId32, SenderStatus = messageSession.Status, SenderSignature = UserCertificateSignature.Sign(_localDrpPeer.CryptoLibrary, w => { w.Write(MessageHMACkey); w.Write(messageSession.AesKey); w.Write(messageStart.EncryptedMessageData); w.Write(messageAck.ReceiverFinalNonce); }, senderUserCertificateWithPrivateKeys) }; messagePart.MessageHMAC = GetMessageHMAC(messagePart.GetSignedFieldsForMessageHMAC); var messagePartUdpData = messagePart.Encode(); // wait for msgack status=finalSignatureVerified if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("sending MSGPART with message data, waiting for MSGACK"); } await _localDrpPeer.Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("msgpart 3681", "remote user", messagePartUdpData, RemoteSessionDescription.DirectChannelEndPoint, MessageAckPacket.GetScanner(messageStart.MessageId32, this, MessageSessionStatusCode.finalSignatureVerified) // scanner also verifies HMAC ); }