private static void HandleNormalTextMessage(MetaMessage metaMessage) { // TODO actually do database stuff string senderUuid = metaMessage.OtherUuid; // TODO make much better! ChatState state = GlobalKeyStore.Instance.ChatStates[senderUuid]; NormalTextMessage message = JsonConvert.DeserializeObject <NormalTextMessage>(metaMessage.Payload); MessageHeader header = new MessageHeader { DhRatchetKey = new Curve25519KeyPair(Convert.FromBase64String(message.DhKeyBase64), false, false), PreviousCount = message.PreviousCount, MessageNumber = message.MessageNumber }; byte[] associatedData = null; if (!(message.AssociatedDataBase64 is null)) { associatedData = Convert.FromBase64String(message.AssociatedDataBase64); } byte[] decryptedData = RatchetDecrypt(state, header, Convert.FromBase64String(message.EncryptedTextBase64), associatedData); string decryptedText = Encoding.UTF8.GetString(decryptedData); Device.BeginInvokeOnMainThread(async() => { await Application.Current.MainPage.DisplayAlert("Message received!", $"From: {senderUuid}\nContent: {decryptedText}", "Ok"); }); }
public static void HandleMessage(MetaMessage metaMessage) { switch (metaMessage.Type) { case MessageType.InitialMessage: HandleInitialMessage(metaMessage); break; case MessageType.NormalTextMessage: HandleNormalTextMessage(metaMessage); break; default: throw new ArgumentOutOfRangeException(); } }
private static void HandleInitialMessage(MetaMessage metaMessage) { // TODO actually do database stuff string senderUuid = metaMessage.OtherUuid; InitialMessage message = JsonConvert.DeserializeObject <InitialMessage>(metaMessage.Payload); Curve25519KeyPair otherIdentityKey = new Curve25519KeyPair(Convert.FromBase64String(message.SenderIdentityKeyBase64), false, true); Curve25519KeyPair ephemeralKey = new Curve25519KeyPair(Convert.FromBase64String(message.EphemeralKeyBase64), false, false); Curve25519KeyPair receivedSignedPreKey = new Curve25519KeyPair(Convert.FromBase64String(message.RecipientSignedPreKeyBase64), false, false); Curve25519KeyPair signedPreKeyPair = GlobalKeyStore.Instance.SignedPreKeyPairs.Find(pair => pair.XPublicKey.SequenceEqual(receivedSignedPreKey.XPublicKey)); if (signedPreKeyPair is null) { throw new Exception("Matching signed prekey pair not found"); } Curve25519KeyPair oneTimePreKeyPair; if (message.RecipientOneTimePreKeyBase64 is null) { oneTimePreKeyPair = null; } else { Curve25519KeyPair receivedOneTimePreKey = new Curve25519KeyPair(Convert.FromBase64String(message.RecipientOneTimePreKeyBase64), false, false); oneTimePreKeyPair = GlobalKeyStore.Instance.OneTimePreKeyPairs.Find(pair => pair.XPublicKey.SequenceEqual(receivedOneTimePreKey.XPublicKey)); if (oneTimePreKeyPair is null) { throw new Exception("Matching one-time prekey pair not found"); } // Remove the one-time key, never to be used again GlobalKeyStore.Instance.SignedPreKeyPairs.Remove(oneTimePreKeyPair); } byte[] secretKey = CryptoUtils.DeriveX3DhSecretReceiver(GlobalKeyStore.Instance.IdentityKeyPair, signedPreKeyPair, otherIdentityKey, ephemeralKey, oneTimePreKeyPair); GlobalKeyStore.Instance.ChatStates[senderUuid] = new ChatState { DhSendingKeyPair = signedPreKeyPair, DhReceivingKey = null, RootKey = secretKey, SendingChainKey = null, ReceivingChainKey = null, CountSent = 0, CountReceived = 0, PreviousCount = 0, MissedMessages = new Dictionary <string, (byte[], byte[])>() }; MetaMessage innerMetaMessage = new MetaMessage { OtherUuid = metaMessage.OtherUuid, Type = MessageType.NormalTextMessage, Payload = message.InnerMessagePayload, Timestamp = metaMessage.Timestamp }; NormalTextMessage innerMessage = JsonConvert.DeserializeObject <NormalTextMessage>(innerMetaMessage.Payload); string requiredAssociatedDataBase64 = Convert.ToBase64String( CryptoUtils.CalculateInitialAssociatedData(otherIdentityKey, GlobalKeyStore.Instance.IdentityKeyPair)); if (innerMessage.AssociatedDataBase64 != requiredAssociatedDataBase64) { throw new Exception($"Associated data for the initial message isn't what it should be: {innerMessage.AssociatedDataBase64} != {requiredAssociatedDataBase64}"); } HandleNormalTextMessage(innerMetaMessage); }