internal async Task <string> ReceiveShortSingleMessageAsync(UserCertificate senderUserCertificate) { if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail(">>InviteSession.ReceiveShortSingleMessageAsync()"); } if (!DerivedDirectChannelSharedDhSecretsAE) { throw new InvalidOperationException("DerivedDirectChannelSharedDhSecretsAE = false"); } var messageSession = new MessageSession(); // wait for msgstart if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("waiting for MSGSTART"); } var messageStartUdpData = await _localDrpPeer.Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("msgstart 480", "remote user", null, RemoteSessionDescription.DirectChannelEndPoint, MessageStartPacket.GetScanner(LocalDirectChannelToken32, this) // scanner verifies MessageHMAC ); var messageStart = MessageStartPacket.Decode(messageStartUdpData); if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("decoded MSGSTART"); } messageSession.DeriveKeys(_localDrpPeer.CryptoLibrary, SharedPingPongHmacKey, messageStart, DirectChannelSharedDhSecret); // decrypt var receivedMessage = messageSession.DecryptShortSingleMessage(_localDrpPeer.CryptoLibrary, messageStart.EncryptedMessageData); // respond with msgack + ReceiverFinalNonce if (messageSession.Status != MessageSessionStatusCode.encryptionDecryptionCompleted) { throw new InvalidOperationException(); } var messageAck = new MessageAckPacket { MessageId32 = messageStart.MessageId32, ReceiverStatus = messageSession.Status, ReceiverFinalNonce = _localDrpPeer.CryptoLibrary.GetRandomBytes(MessageAckPacket.ReceiverFinalNonceSize), }; messageAck.MessageHMAC = GetMessageHMAC(messageAck.GetSignedFieldsForMessageHMAC); var messageAckUdpData = messageAck.Encode(); if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("responding with MSGACK to MSGSTART"); } _localDrpPeer.Engine.RespondToRequestAndRetransmissions(messageStart.DecodedUdpData, messageAckUdpData, RemoteSessionDescription.DirectChannelEndPoint); // wait for msgpart with status=encryptionDecryptionCompleted if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("waiting for with MSGPART"); } var messagePartUdpData = await _localDrpPeer.Engine.OptionallySendUdpRequestAsync_Retransmit_WaitForResponse("msgpart 42486", "remote user", null, RemoteSessionDescription.DirectChannelEndPoint, MessagePartPacket.GetScanner(messageStart.MessageId32, this, MessageSessionStatusCode.encryptionDecryptionCompleted) // scanner verifies MessageHMAC ); var messagePart = MessagePartPacket.Decode(messagePartUdpData); // verify signature of sender user if (!messagePart.SenderSignature.Verify(_localDrpPeer.CryptoLibrary, w => { w.Write(MessageHMACkey); w.Write(messageSession.AesKey); w.Write(messageStart.EncryptedMessageData); w.Write(messageAck.ReceiverFinalNonce); }, senderUserCertificate)) { throw new BadSignatureException("bad MSGPART sender signature 3408"); } if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("verified sender signature"); } // send msgack status=finalSignatureVerified messageSession.Status = MessageSessionStatusCode.finalSignatureVerified; var messageAck_finalSignatureVerified = new MessageAckPacket { MessageId32 = messageStart.MessageId32, ReceiverStatus = messageSession.Status, }; messageAck_finalSignatureVerified.MessageHMAC = GetMessageHMAC(messageAck_finalSignatureVerified.GetSignedFieldsForMessageHMAC); var messageAck_finalSignatureVerified_UdpData = messageAck_finalSignatureVerified.Encode(); if (Logger.WriteToLog_detail_enabled) { Logger.WriteToLog_detail("sending MSGACK response to MSGPART"); } _localDrpPeer.Engine.RespondToRequestAndRetransmissions(messagePart.DecodedUdpData, messageAck_finalSignatureVerified_UdpData, RemoteSessionDescription.DirectChannelEndPoint); return(receivedMessage); }