Beispiel #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");
            });
        }
Beispiel #2
0
        private static (byte[], MessageHeader) RatchetEncrypt(ChatState state, byte[] plainText, byte[] associatedData = null)
        {
            byte[] messageKey, derivedAssociatedData;
            (state.SendingChainKey, messageKey, derivedAssociatedData) =
                CryptoUtils.RatchetChainKey(state.SendingChainKey);

            MessageHeader header = new MessageHeader
            {
                PreviousCount = state.PreviousCount,
                MessageNumber = state.CountSent,
                DhRatchetKey  = state.DhSendingKeyPair
            };

            state.CountSent++;

            return(
                CryptoUtils.EncryptWithMessageKey(messageKey, plainText,
                                                  CombineAdAndHeader(associatedData ?? derivedAssociatedData, header)), header);
        }
Beispiel #3
0
        private static byte[] RatchetDecrypt(ChatState state, MessageHeader header, byte[] cipherText,
                                             byte[] associatedData = null)
        {
            // TODO do ratcheting with copy before it's verified to have worked

            string missedMessagesKey = Convert.ToBase64String(header.DhRatchetKey.XPublicKey) + header.MessageNumber;

            if (state.MissedMessages.TryGetValue(missedMessagesKey, out (byte[], byte[])skippedMessageTuple))
            {
                state.MissedMessages.Remove(missedMessagesKey);

                (byte[] skippedMessageKey, byte[] skippedAssociatedData) = skippedMessageTuple;
                return(CryptoUtils.DecryptWithMessageKey(skippedMessageKey, cipherText, CombineAdAndHeader(associatedData ?? skippedAssociatedData, header)));
            }

            if (state.DhReceivingKey is null || !header.DhRatchetKey.XPublicKey.SequenceEqual(state.DhReceivingKey.XPublicKey))
            {
                SkipMessageKeys(state, header.PreviousCount);

                // Ratchet the chat state
                state.PreviousCount  = state.CountSent;
                state.CountSent      = 0;
                state.CountReceived  = 0;
                state.DhReceivingKey = header.DhRatchetKey;
                (state.RootKey, state.ReceivingChainKey) = CryptoUtils.RatchetRootKey(state.RootKey,
                                                                                      state.DhSendingKeyPair.CalculateSharedSecret(state.DhReceivingKey));
                state.DhSendingKeyPair = new Curve25519KeyPair();
                (state.RootKey, state.SendingChainKey) = CryptoUtils.RatchetRootKey(state.RootKey,
                                                                                    state.DhSendingKeyPair.CalculateSharedSecret(state.DhReceivingKey));
            }

            SkipMessageKeys(state, header.MessageNumber);

            byte[] messageKey, derivedAssociatedData;
            (state.ReceivingChainKey, messageKey, derivedAssociatedData) =
                CryptoUtils.RatchetChainKey(state.ReceivingChainKey);

            state.CountReceived++;

            return(CryptoUtils.DecryptWithMessageKey(messageKey, cipherText, CombineAdAndHeader(associatedData ?? derivedAssociatedData, header)));
        }
Beispiel #4
0
        private static void SkipMessageKeys(ChatState state, uint upTo)
        {
            if (state.CountReceived + 50 < upTo)
            {
                throw new Exception("MAX_SKIP exceeded");
            }

            if (state.ReceivingChainKey is null)
            {
                return;
            }
            while (state.CountReceived < upTo)
            {
                byte[] messageKey, associatedData;
                (state.ReceivingChainKey, messageKey, associatedData) =
                    CryptoUtils.RatchetChainKey(state.ReceivingChainKey);

                string missedMessagesKey = Convert.ToBase64String(state.DhReceivingKey.XPublicKey) + state.CountReceived;
                state.MissedMessages[missedMessagesKey] = (messageKey, associatedData);

                state.CountReceived++;
            }
        }