Exemple #1
0
        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");
            });
        }
Exemple #2
0
        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();
            }
        }
Exemple #3
0
        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);
        }