public OutgoingPushMessage encrypt(SignalProtocolAddress destination, byte[] unpaddedMessage, bool legacy, bool silent)
        {
            SessionCipher        sessionCipher    = new SessionCipher(signalProtocolStore, destination);
            PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
            CiphertextMessage    message          = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
            uint   remoteRegistrationId           = sessionCipher.getRemoteRegistrationId();
            String body = Base64.encodeBytes(message.serialize());

            uint type;

            switch (message.getType())
            {
            case CiphertextMessage.PREKEY_TYPE: type = (uint)Envelope.Types.Type.PrekeyBundle; break;    // todo check

            case CiphertextMessage.WHISPER_TYPE: type = (uint)Envelope.Types.Type.Ciphertext; break;     // todo check

            default: throw new Exception("Bad type: " + message.getType());
            }

            return(new OutgoingPushMessage(type,
                                           destination.DeviceId,
                                           remoteRegistrationId,
                                           legacy ? body : null,
                                           legacy ? null : body,
                                           silent));
        }
Ejemplo n.º 2
0
        private async Task buildSessionForDevicesAsync(Dictionary <uint, SessionCipher> sessions, IList <SignalProtocolAddress> devices)
        {
            if (devices.Count <= 0)
            {
                return;
            }
            SignalProtocolAddress device = devices[0];

            devices.RemoveAt(0);

            // Check if there exists already a session for this device:
            if (OMEMO_HELPER.OMEMO_STORE.ContainsSession(device))
            {
                // If yes, the load it:
                SessionCipher cipher = OMEMO_HELPER.loadCipher(device);
                sessions.Add(device.getDeviceId(), cipher);

                Logger.Info("[OmemoSessionBuildHelper] Session for " + device.ToString() + " loaded from cache.");
            }
            else
            {
                // Else try to build a new one by requesting the devices bundle information:
                OmemoBundleInformationResultMessage bundleMsg = await requestBundleInformationAsync(device);

                if (!(bundleMsg is null))
                {
                    SignalProtocolAddress address = OMEMO_HELPER.newSession(CHAT_JID, bundleMsg);
                    SessionCipher         cipher  = OMEMO_HELPER.loadCipher(address);
                    sessions.Add(device.getDeviceId(), cipher);

                    Logger.Info("[OmemoSessionBuildHelper] Session with " + device.ToString() + " established.");
                }
        private byte[] decrypt(SignalServiceEnvelope envelope, byte[] ciphertext)

        {
            SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSource(), (uint)envelope.getSourceDevice());
            SessionCipher         sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);

            byte[] paddedMessage;

            if (envelope.isPreKeySignalMessage())
            {
                paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
            }
            else if (envelope.isSignalMessage())
            {
                paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
            }
            else
            {
                throw new InvalidMessageException("Unknown type: " + envelope.getType() + " from " + envelope.getSource());
            }

            PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());

            return(transportDetails.getStrippedPaddingMessageBody(paddedMessage));
        }
        public OutgoingPushMessage Encrypt(SignalProtocolAddress destination, UnidentifiedAccess?unidentifiedAccess, byte[] unpaddedMessage)
        {
            if (unidentifiedAccess != null)
            {
                SealedSessionCipher  sessionCipher    = new SealedSessionCipher(signalProtocolStore, localAddress.Uuid, localAddress.GetNumber(), 1);
                PushTransportDetails transportDetails = new PushTransportDetails((uint)sessionCipher.GetSessionVersion(destination));
                byte[] ciphertext           = sessionCipher.Encrypt(destination, unidentifiedAccess.UnidentifiedCertificate, transportDetails.getPaddedMessageBody(unpaddedMessage));
                string body                 = Base64.EncodeBytes(ciphertext);
                uint   remoteRegistrationId = (uint)sessionCipher.GetRemoteRegistrationId(destination);
                return(new OutgoingPushMessage((uint)Envelope.Types.Type.UnidentifiedSender, destination.DeviceId, remoteRegistrationId, body));
            }
            else
            {
                SessionCipher        sessionCipher    = new SessionCipher(signalProtocolStore, destination);
                PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());
                CiphertextMessage    message          = sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage));
                uint   remoteRegistrationId           = sessionCipher.getRemoteRegistrationId();
                string body = Base64.EncodeBytes(message.serialize());

                var type = (message.getType()) switch
                {
                    CiphertextMessage.PREKEY_TYPE => (uint)Envelope.Types.Type.PrekeyBundle,
                    CiphertextMessage.WHISPER_TYPE => (uint)Envelope.Types.Type.Ciphertext,
                    _ => throw new Exception("Bad type: " + message.getType()),
                };
                return(new OutgoingPushMessage(type, destination.DeviceId, remoteRegistrationId, body));
            }
        }
Ejemplo n.º 5
0
        private bool onRequestBundleInformationMessage(IQMessage msg)
        {
            if (STATE != OmemoSessionBuildHelperState.REQUESTING_BUNDLE_INFORMATION)
            {
                return(true);
            }

            if (msg is OmemoBundleInformationResultMessage bundleMsg)
            {
                Logger.Info("[OmemoSessionBuildHelper] Session with " + curAddress.getName() + ':' + curAddress.getDeviceId() + " established.");
                SignalProtocolAddress address = OMEMO_HELPER.newSession(CHAT_JID, bundleMsg);
                SessionCipher         cipher  = OMEMO_HELPER.loadCipher(address);
                SESSION.DEVICE_SESSIONS.Add(curAddress.getDeviceId(), cipher);
                createSessionForNextDevice();
                return(true);
            }
            else if (msg is IQErrorMessage errMsg)
            {
                if (errMsg.ERROR_OBJ.ERROR_NAME == ErrorName.ITEM_NOT_FOUND)
                {
                    Logger.Error("[OmemoSessionBuildHelper] Failed to establish session - " + curAddress.getName() + ':' + curAddress.getDeviceId() + " doesn't support OMEMO: " + errMsg.ERROR_OBJ.ToString());
                    setState(OmemoSessionBuildHelperState.ERROR);
                    ON_SESSION_RESULT(this, new OmemoSessionBuildResult(OmemoSessionBuildError.TARGET_DOES_NOT_SUPPORT_OMEMO));
                }
                else
                {
                    Logger.Error("[OmemoSessionBuildHelper] Failed to establish session - request bundle info failed(" + curAddress.getName() + ':' + curAddress.getDeviceId() + "): " + errMsg.ERROR_OBJ.ToString());
                    setState(OmemoSessionBuildHelperState.ERROR);
                    ON_SESSION_RESULT(this, new OmemoSessionBuildResult(OmemoSessionBuildError.REQUEST_BUNDLE_INFORMATION_IQ_ERROR));
                }
                return(true);
            }
            return(false);
        }
        private byte[] decrypt(TextSecureEnvelope envelope, byte[] ciphertext)

        {
            AxolotlAddress sourceAddress = new AxolotlAddress(envelope.getSource(), envelope.getSourceDevice());
            SessionCipher  sessionCipher = new SessionCipher(axolotlStore, sourceAddress);

            byte[] paddedMessage;

            if (envelope.isPreKeyWhisperMessage())
            {
                paddedMessage = sessionCipher.decrypt(new PreKeyWhisperMessage(ciphertext));
            }
            else if (envelope.isWhisperMessage())
            {
                paddedMessage = sessionCipher.decrypt(new WhisperMessage(ciphertext));
            }
            else
            {
                throw new InvalidMessageException("Unknown type: " + envelope.getType());
            }

            PushTransportDetails transportDetails = new PushTransportDetails(sessionCipher.getSessionVersion());

            return(transportDetails.getStrippedPaddingMessageBody(paddedMessage));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// decrypt an incomming message
        /// </summary>
        /// <param name="from"></param>
        /// <param name="ciphertext"></param>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="t"></param>
        /// <param name="retry_from"></param>
        /// <param name="skip_unpad"></param>
        public object decryptMessage(string from, byte[] ciphertext, string type, string id,
                                     string t, string retry_from = null, bool skip_unpad = false)
        {
            string version = "1";

            #region pkmsg routine
            if (type == "pkmsg")
            {
                if (v2Jids.Contains(ExtractNumber(from)))
                {
                    version = "2";
                }
                try
                {
                    PreKeyWhisperMessage preKeyWhisperMessage = new PreKeyWhisperMessage(ciphertext);
                    SessionCipher        sessionCipher        = getSessionCipher(ExtractNumber(from));
                    var plaintext = sessionCipher.decrypt(preKeyWhisperMessage);
                    if (version == "2" && !skip_unpad)
                    {
                        return(unpadV2Plaintext(plaintext.ToString()));
                    }
                }
                catch (Exception e) {
                }
            }
            #endregion

            #region WhisperMessage routine
            if (type == "msg")
            {
                if (v2Jids.Contains(ExtractNumber(from)))
                {
                    version = "2";
                }
                try
                {
                    PreKeyWhisperMessage preKeyWhisperMessage = new PreKeyWhisperMessage(ciphertext);
                    SessionCipher        sessionCipher        = getSessionCipher(ExtractNumber(from));
                    var plaintext = sessionCipher.decrypt(preKeyWhisperMessage);
                    if (version == "2" && !skip_unpad)
                    {
                        return(unpadV2Plaintext(plaintext.ToString()));
                    }
                }
                catch (Exception e)
                {
                }
            }
            #endregion

            #region Group message Cipher routine
            if (type == "skmsg")
            {
                throw new NotImplementedException();
            }
            #endregion

            return(false);
        }
Ejemplo n.º 8
0
        public void testBadMessageBundle()
        {
            SignalProtocolStore aliceStore          = new TestInMemorySignalProtocolStore();
            SessionBuilder      aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            SignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            aliceSessionBuilder.process(bobPreKey);

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageOne.getType());

            byte[] goodMessage = outgoingMessageOne.serialize();
            byte[] badMessage  = new byte[goodMessage.Length];
            Array.Copy(goodMessage, 0, badMessage, 0, badMessage.Length);

            badMessage[badMessage.Length - 10] ^= 0x01;

            PreKeySignalMessage incomingMessage  = new PreKeySignalMessage(badMessage);
            SessionCipher       bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = new byte[0];

            try
            {
                plaintext = bobSessionCipher.decrypt(incomingMessage);
                throw new Exception("Decrypt should have failed!");
            }
            catch (InvalidMessageException)
            {
                // good.
            }

            Assert.IsTrue(bobStore.ContainsPreKey(31337));

            plaintext = bobSessionCipher.decrypt(new PreKeySignalMessage(goodMessage));

            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));
            Assert.IsFalse(bobStore.ContainsPreKey(31337));
        }
Ejemplo n.º 9
0
        public void testSimultaneousInitiateLostMessage()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            AxolotlStore bobStore   = new TestInMemoryAxolotlStore();

            PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
            PreKeyBundle bobPreKeyBundle   = createBobPreKeyBundle(bobStore);

            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            SessionBuilder bobSessionBuilder   = new SessionBuilder(bobStore, ALICE_ADDRESS);

            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            SessionCipher bobSessionCipher   = new SessionCipher(bobStore, ALICE_ADDRESS);

            aliceSessionBuilder.process(bobPreKeyBundle);
            bobSessionBuilder.process(alicePreKeyBundle);

            CiphertextMessage messageForBob   = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("hey there"));
            CiphertextMessage messageForAlice = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("sample message"));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, messageForBob.getType());
            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, messageForAlice.getType());

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new PreKeyWhisperMessage(messageForAlice.serialize()));
            byte[] bobPlaintext   = bobSessionCipher.decrypt(new PreKeyWhisperMessage(messageForBob.serialize()));

            Assert.AreEqual("sample message", Encoding.UTF8.GetString(alicePlaintext));
            Assert.AreEqual("hey there", Encoding.UTF8.GetString(bobPlaintext));

            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage aliceResponse = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("second message"));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, aliceResponse.getType());

            //    byte[] responsePlaintext = bobSessionCipher.decrypt(new WhisperMessage(aliceResponse.serialize()));
            //
            //    assertTrue(new String(responsePlaintext).equals("second message"));
            //    assertTrue(isSessionIdEqual(aliceStore, bobStore));
            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage finalMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("third message"));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, finalMessage.getType());

            byte[] finalPlaintext = aliceSessionCipher.decrypt(new WhisperMessage(finalMessage.serialize()));

            Assert.AreEqual("third message", Encoding.UTF8.GetString(finalPlaintext));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));
        }
        public void TestBasicSimultaneousInitiate()
        {
            ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
            ISignalProtocolStore bobStore   = new TestInMemorySignalProtocolStore();

            PreKeyBundle alicePreKeyBundle = CreateAlicePreKeyBundle(aliceStore);
            PreKeyBundle bobPreKeyBundle   = CreateBobPreKeyBundle(bobStore);

            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BobAddress);
            SessionBuilder bobSessionBuilder   = new SessionBuilder(bobStore, AliceAddress);

            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BobAddress);
            SessionCipher bobSessionCipher   = new SessionCipher(bobStore, AliceAddress);

            aliceSessionBuilder.Process(bobPreKeyBundle);
            bobSessionBuilder.Process(alicePreKeyBundle);

            CiphertextMessage messageForBob   = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("hey there"));
            CiphertextMessage messageForAlice = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("sample message"));

            Assert.AreEqual(CiphertextMessage.PrekeyType, messageForBob.GetMessageType());
            Assert.AreEqual(CiphertextMessage.PrekeyType, messageForAlice.GetMessageType());

            Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore));

            byte[] alicePlaintext = aliceSessionCipher.Decrypt(new PreKeySignalMessage(messageForAlice.Serialize()));
            byte[] bobPlaintext   = bobSessionCipher.Decrypt(new PreKeySignalMessage(messageForBob.Serialize()));

            Assert.AreEqual("sample message", Encoding.UTF8.GetString(alicePlaintext));
            Assert.AreEqual("hey there", Encoding.UTF8.GetString(bobPlaintext));

            Assert.AreEqual((uint)3, aliceStore.LoadSession(BobAddress).GetSessionState().GetSessionVersion());
            Assert.AreEqual((uint)3, bobStore.LoadSession(AliceAddress).GetSessionState().GetSessionVersion());

            Assert.IsFalse(IsSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage aliceResponse = aliceSessionCipher.Encrypt(Encoding.UTF8.GetBytes("second message"));

            Assert.AreEqual(CiphertextMessage.WhisperType, aliceResponse.GetMessageType());

            byte[] responsePlaintext = bobSessionCipher.Decrypt(new SignalMessage(aliceResponse.Serialize()));

            Assert.AreEqual("second message", Encoding.UTF8.GetString(responsePlaintext));
            Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage finalMessage = bobSessionCipher.Encrypt(Encoding.UTF8.GetBytes("third message"));

            Assert.AreEqual(CiphertextMessage.WhisperType, finalMessage.GetMessageType());

            byte[] finalPlaintext = aliceSessionCipher.Decrypt(new SignalMessage(finalMessage.Serialize()));

            Assert.AreEqual("third message", Encoding.UTF8.GetString(finalPlaintext));
            Assert.IsTrue(IsSessionIdEqual(aliceStore, bobStore));
        }
Ejemplo n.º 11
0
        public void testRepeatBundleMessageV3()
        {
            SignalProtocolStore aliceStore          = new TestInMemorySignalProtocolStore();
            SessionBuilder      aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            SignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            aliceSessionBuilder.process(bobPreKey);

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageOne.getType());
            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageTwo.getType());

            PreKeySignalMessage incomingMessage = new PreKeySignalMessage(outgoingMessageOne.serialize());

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new SignalMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            // The test

            PreKeySignalMessage incomingMessageTwo = new PreKeySignalMessage(outgoingMessageTwo.serialize());

            plaintext = bobSessionCipher.decrypt(new PreKeySignalMessage(incomingMessageTwo.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            alicePlaintext     = aliceSessionCipher.decrypt(new SignalMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));
        }
Ejemplo n.º 12
0
        public void testOptionalOneTimePreKey()
        {
            SignalProtocolStore aliceStore          = new TestInMemorySignalProtocolStore();
            SessionBuilder      aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            SignalProtocolStore bobStore = new TestInMemorySignalProtocolStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      0, null,
                                                      22, bobSignedPreKeyPair.getPublicKey(),
                                                      bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage    = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(outgoingMessage.getType(), CiphertextMessage.PREKEY_TYPE);

            PreKeySignalMessage incomingMessage = new PreKeySignalMessage(outgoingMessage.serialize());

            Assert.IsFalse(incomingMessage.getPreKeyId().HasValue);

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.IsNotNull(bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));
        }
Ejemplo n.º 13
0
        private void createSessionForNextDevice()
        {
            if ((toDoDevicesRemote == null || toDoDevicesRemote.Count <= 0) && (toDoDevicesOwn == null || toDoDevicesOwn.Count <= 0))
            {
                // All sessions created:
                if (SESSION.DEVICE_SESSIONS.Count <= 0)
                {
                    setState(OmemoSessionBuildHelperState.ERROR);
                    ON_SESSION_RESULT(this, new OmemoSessionBuildResult(OmemoSessionBuildError.TARGET_DOES_NOT_SUPPORT_OMEMO));
                }
                else
                {
                    setState(OmemoSessionBuildHelperState.ESTABLISHED);
                    ON_SESSION_RESULT(this, new OmemoSessionBuildResult(SESSION));
                }
            }
            else
            {
                if (toDoDevicesRemote == null || toDoDevicesRemote.Count <= 0)
                {
                    curAddress = new SignalProtocolAddress(BARE_ACCOUNT_JID, toDoDevicesOwn[0]);
                    toDoDevicesOwn.RemoveAt(0);
                }
                else
                {
                    curAddress = new SignalProtocolAddress(CHAT_JID, toDoDevicesRemote[0]);
                    toDoDevicesRemote.RemoveAt(0);
                }

                if (OMEMO_HELPER.containsSession(curAddress))
                {
                    SessionCipher cipher = OMEMO_HELPER.loadCipher(curAddress);
                    SESSION.DEVICE_SESSIONS.Add(curAddress.getDeviceId(), cipher);
                    createSessionForNextDevice();
                }
                else
                {
                    requestBundleInformation();
                }
            }
        }
Ejemplo n.º 14
0
        public byte[] Encrypt(SignalProtocolAddress destinationAddress, SenderCertificate senderCertificate, byte[] paddedPlaintext)
        {
            CiphertextMessage message       = new SessionCipher(SignalProtocolStore, destinationAddress).encrypt(paddedPlaintext);
            IdentityKeyPair   ourIdentity   = SignalProtocolStore.GetIdentityKeyPair();
            ECPublicKey       theirIdentity = SignalProtocolStore.GetIdentity(destinationAddress).getPublicKey();

            ECKeyPair ephemeral = Curve.generateKeyPair();

            byte[]        ephemeralSalt = ByteUtil.combine(Encoding.ASCII.GetBytes("UnidentifiedDelivery"), theirIdentity.serialize(), ephemeral.getPublicKey().serialize());
            EphemeralKeys ephemeralKeys = CalculateEphemeralKeys(theirIdentity, ephemeral.getPrivateKey(), ephemeralSalt);

            byte[] staticKeyCiphertext = Encrypt(ephemeralKeys.CipherKey, ephemeralKeys.MacKey, ourIdentity.getPublicKey().getPublicKey().serialize());

            byte[]     staticSalt = ByteUtil.combine(ephemeralKeys.ChainKey, staticKeyCiphertext);
            StaticKeys staticKeys = CalculateStaticKeys(theirIdentity, ourIdentity.getPrivateKey(), staticSalt);
            UnidentifiedSenderMessageContent content = new UnidentifiedSenderMessageContent((int)message.getType(), senderCertificate, message.serialize());

            byte[] messageBytes = Encrypt(staticKeys.CipherKey, staticKeys.MacKey, content.Serialized);

            return(new UnidentifiedSenderMessage(ephemeral.getPublicKey(), staticKeyCiphertext, messageBytes).Serialized);
        }
        public void TestMessageKeyLimits()
        {
            SessionRecord aliceSessionRecord = new SessionRecord();
            SessionRecord bobSessionRecord   = new SessionRecord();

            InitializeSessionsV3(aliceSessionRecord.GetSessionState(), bobSessionRecord.GetSessionState());

            ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
            ISignalProtocolStore bobStore   = new TestInMemorySignalProtocolStore();

            aliceStore.StoreSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord);
            bobStore.StoreSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord);

            SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1));
            SessionCipher bobCipher   = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1));

            List <CiphertextMessage> inflight = new List <CiphertextMessage>();

            for (int i = 0; i < 2010; i++)
            {
                inflight.Add(aliceCipher.Encrypt(Encoding.UTF8.GetBytes("you've never been so hungry, you've never been so cold")));
            }

            bobCipher.Decrypt(new SignalMessage(inflight[1000].Serialize()));
            bobCipher.Decrypt(new SignalMessage(inflight[inflight.Count - 1].Serialize()));

            try
            {
                bobCipher.Decrypt(new SignalMessage(inflight[0].Serialize()));
                throw new Exception("Should have failed!");
            }
            catch (DuplicateMessageException)
            {
                // good
            }
        }
Ejemplo n.º 16
0
        private void runInteraction(SignalProtocolStore aliceStore, SignalProtocolStore bobStore)
        {
            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            SessionCipher bobSessionCipher   = new SessionCipher(bobStore, ALICE_ADDRESS);

            String            originalMessage = "smert ze smert";
            CiphertextMessage aliceMessage    = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, aliceMessage.getType());

            byte[] plaintext = bobSessionCipher.decrypt(new SignalMessage(aliceMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, bobMessage.getType());

            plaintext = aliceSessionCipher.decrypt(new SignalMessage(bobMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            for (int i = 0; i < 10; i++)
            {
                String loopingMessage = ("What do we mean by saying that existence precedes essence? " +
                                         "We mean that man first of all exists, encounters himself, " +
                                         "surges up in the world--and defines himself aftward. " + i);
                CiphertextMessage aliceLoopingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(loopingMessage));

                byte[] loopingPlaintext = bobSessionCipher.decrypt(new SignalMessage(aliceLoopingMessage.serialize()));
                Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext));
            }

            for (int i = 0; i < 10; i++)
            {
                String loopingMessage = ("What do we mean by saying that existence precedes essence? " +
                                         "We mean that man first of all exists, encounters himself, " +
                                         "surges up in the world--and defines himself aftward. " + i);
                CiphertextMessage bobLoopingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(loopingMessage));

                byte[] loopingPlaintext = aliceSessionCipher.decrypt(new SignalMessage(bobLoopingMessage.serialize()));
                Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext));
            }

            HashSet <Pair <String, CiphertextMessage> > aliceOutOfOrderMessages = new HashSet <Pair <String, CiphertextMessage> >();

            for (int i = 0; i < 10; i++)
            {
                String loopingMessage = ("What do we mean by saying that existence precedes essence? " +
                                         "We mean that man first of all exists, encounters himself, " +
                                         "surges up in the world--and defines himself aftward. " + i);
                CiphertextMessage aliceLoopingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(loopingMessage));

                aliceOutOfOrderMessages.Add(new Pair <String, CiphertextMessage>(loopingMessage, aliceLoopingMessage));
            }

            for (int i = 0; i < 10; i++)
            {
                String loopingMessage = ("What do we mean by saying that existence precedes essence? " +
                                         "We mean that man first of all exists, encounters himself, " +
                                         "surges up in the world--and defines himself aftward. " + i);
                CiphertextMessage aliceLoopingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(loopingMessage));

                byte[] loopingPlaintext = bobSessionCipher.decrypt(new SignalMessage(aliceLoopingMessage.serialize()));
                Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext));
            }

            for (int i = 0; i < 10; i++)
            {
                String            loopingMessage    = ("You can only desire based on what you know: " + i);
                CiphertextMessage bobLoopingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(loopingMessage));

                byte[] loopingPlaintext = aliceSessionCipher.decrypt(new SignalMessage(bobLoopingMessage.serialize()));
                Assert.AreEqual(loopingMessage, Encoding.UTF8.GetString(loopingPlaintext));
            }

            foreach (Pair <String, CiphertextMessage> aliceOutOfOrderMessage in aliceOutOfOrderMessages)
            {
                byte[] outOfOrderPlaintext = bobSessionCipher.decrypt(new SignalMessage(aliceOutOfOrderMessage.second().serialize()));
                Assert.AreEqual(aliceOutOfOrderMessage.first(), Encoding.UTF8.GetString(outOfOrderPlaintext));
            }
        }
Ejemplo n.º 17
0
        public void testBasicPreKeyV3()
        {
            SignalProtocolStore aliceStore          = new TestInMemorySignalProtocolStore();
            SessionBuilder      aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            SignalProtocolStore bobStore            = new TestInMemorySignalProtocolStore();
            ECKeyPair           bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair           bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(),
                                                      bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage    = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessage.getType());

            PreKeySignalMessage incomingMessage = new PreKeySignalMessage(outgoingMessage.serialize());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage, new BobDecryptionCallback(bobStore, originalMessage));

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.IsNotNull(bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, bobOutgoingMessage.getType());

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new SignalMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            runInteraction(aliceStore, bobStore);

            aliceStore          = new TestInMemorySignalProtocolStore();
            aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            aliceSessionCipher  = new SessionCipher(aliceStore, BOB_ADDRESS);

            bobPreKeyPair            = Curve.generateKeyPair();
            bobSignedPreKeyPair      = Curve.generateKeyPair();
            bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(), bobSignedPreKeyPair.getPublicKey().serialize());
            bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(),
                                         1, 31338, bobPreKeyPair.getPublicKey(),
                                         23, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                         bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31338, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(23, new SignedPreKeyRecord(23, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));
            aliceSessionBuilder.process(bobPreKey);

            outgoingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            try
            {
                plaintext = bobSessionCipher.decrypt(new PreKeySignalMessage(outgoingMessage.serialize()));
                throw new Exception("shouldn't be trusted!");
            }
            catch (UntrustedIdentityException)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), new PreKeySignalMessage(outgoingMessage.serialize()).getIdentityKey());
            }

            plaintext = bobSessionCipher.decrypt(new PreKeySignalMessage(outgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                         31337, Curve.generateKeyPair().getPublicKey(),
                                         23, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                         aliceStore.GetIdentityKeyPair().getPublicKey());

            try
            {
                aliceSessionBuilder.process(bobPreKey);
                throw new Exception("shoulnd't be trusted!");
            }
            catch (UntrustedIdentityException)
            {
                // good
            }
        }
Ejemplo n.º 18
0
        public void Test_Libsignal_Enc_Dec_2()
        {
            // Generate Alices keys:
            IdentityKeyPair      aliceIdentKey     = CryptoUtils.generateOmemoIdentityKeyPair();
            IList <PreKeyRecord> alicePreKeys      = CryptoUtils.generateOmemoPreKeys();
            SignedPreKeyRecord   aliceSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(aliceIdentKey);

            // Create Alices stores:
            InMemoryIdentityKeyStore aliceIdentStore  = new InMemoryIdentityKeyStore(aliceIdentKey, ALICE_ADDRESS.getDeviceId());
            InMemoryPreKeyStore      alicePreKeyStore = new InMemoryPreKeyStore();

            foreach (PreKeyRecord key in alicePreKeys)
            {
                alicePreKeyStore.StorePreKey(key.getId(), key);
            }
            InMemorySignedPreKeyStore aliceSignedPreKeyStore = new InMemorySignedPreKeyStore();

            aliceSignedPreKeyStore.StoreSignedPreKey(aliceSignedPreKey.getId(), aliceSignedPreKey);
            InMemorySessionStore aliceSessionStore = new InMemorySessionStore();

            // Generate Bobs keys:
            IdentityKeyPair      bobIdentKey     = CryptoUtils.generateOmemoIdentityKeyPair();
            IList <PreKeyRecord> bobPreKeys      = CryptoUtils.generateOmemoPreKeys();
            SignedPreKeyRecord   bobSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(bobIdentKey);

            // Create Bobs stores:
            InMemoryIdentityKeyStore bobIdentStore  = new InMemoryIdentityKeyStore(bobIdentKey, BOB_ADDRESS.getDeviceId());
            InMemoryPreKeyStore      bobPreKeyStore = new InMemoryPreKeyStore();

            foreach (PreKeyRecord key in bobPreKeys)
            {
                bobPreKeyStore.StorePreKey(key.getId(), key);
            }
            InMemorySignedPreKeyStore bobSignedPreKeyStore = new InMemorySignedPreKeyStore();

            bobSignedPreKeyStore.StoreSignedPreKey(bobSignedPreKey.getId(), bobSignedPreKey);
            InMemorySessionStore bobSessionStore = new InMemorySessionStore();

            // Alice builds a session to Bob:
            SessionBuilder sessionBuilder = new SessionBuilder(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);
            PreKeyBundle   bobPreKey      = new PreKeyBundle(BOB_ADDRESS.getDeviceId(), BOB_ADDRESS.getDeviceId(), bobPreKeys[0].getId(), bobPreKeys[0].getKeyPair().getPublicKey(), bobSignedPreKey.getId(), bobSignedPreKey.getKeyPair().getPublicKey(), bobSignedPreKey.getSignature(), bobIdentKey.getPublicKey());

            sessionBuilder.process(bobPreKey);

            // Check if session exists:
            Assert.IsTrue(aliceSessionStore.ContainsSession(BOB_ADDRESS));
            Assert.IsTrue(aliceSessionStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);

            // Alice sends a message:
            string            aliceOrigMsg       = "$(rm -rvf .)";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);
            CiphertextMessage aliceOutMsg        = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(aliceOrigMsg));

            // Check if successfully encrypted:
            Assert.IsTrue(aliceOutMsg.getType() == CiphertextMessage.PREKEY_TYPE);

            // Bob receives the message:
            PreKeySignalMessage bobInMsg         = new PreKeySignalMessage(aliceOutMsg.serialize());
            SessionCipher       bobSessionCipher = new SessionCipher(bobSessionStore, bobPreKeyStore, bobSignedPreKeyStore, bobIdentStore, ALICE_ADDRESS);

            byte[] bobData   = bobSessionCipher.decrypt(bobInMsg);
            string bobRecMsg = Encoding.UTF8.GetString(bobData);

            // Check if successfully send:
            Assert.AreEqual(aliceOrigMsg, bobRecMsg);
            Assert.IsTrue(bobSessionStore.ContainsSession(ALICE_ADDRESS));

            //---------------------------Connection/App get restarted:---------------------------

            // Bob answers:
            string bobOrigMsg = ":(){ :|:& };:";

            // Simulate a chat break:
            bobSessionCipher = new SessionCipher(bobSessionStore, bobPreKeyStore, bobSignedPreKeyStore, bobIdentStore, ALICE_ADDRESS);
            CiphertextMessage bobOutMsg = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(bobOrigMsg));

            // Alice receives the message:
            aliceSessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);
            SignalMessage aliceInMsg = new SignalMessage(bobOutMsg.serialize());

            byte[] aliceData   = aliceSessionCipher.decrypt(aliceInMsg);
            string aliceRecMsg = Encoding.UTF8.GetString(aliceData);

            // Check if successfully send:
            Assert.AreEqual(bobOrigMsg, aliceRecMsg);
            Assert.IsTrue(bobSessionStore.ContainsSession(ALICE_ADDRESS));
        }
        private void RunInteraction(SessionRecord aliceSessionRecord, SessionRecord bobSessionRecord)
        {
            SignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
            SignalProtocolStore bobStore   = new TestInMemorySignalProtocolStore();

            aliceStore.StoreSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord);
            bobStore.StoreSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord);

            SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1));
            SessionCipher bobCipher   = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1));

            byte[]            alicePlaintext = Encoding.ASCII.GetBytes("This is a plaintext message.");
            CiphertextMessage message        = aliceCipher.encrypt(alicePlaintext);

            byte[] bobPlaintext = bobCipher.decrypt(new SignalMessage(message.serialize()));

            CollectionAssert.AreEqual(alicePlaintext, bobPlaintext);

            byte[]            bobReply = Encoding.ASCII.GetBytes("This is a message from Bob.");
            CiphertextMessage reply    = bobCipher.encrypt(bobReply);

            byte[] receivedReply = aliceCipher.decrypt(new SignalMessage(reply.serialize()));

            CollectionAssert.AreEqual(bobReply, receivedReply);

            List <CiphertextMessage> aliceCiphertextMessages = new List <CiphertextMessage>();
            List <byte[]>            alicePlaintextMessages  = new List <byte[]>();

            for (int i = 0; i < 50; i++)
            {
                alicePlaintextMessages.Add(Encoding.ASCII.GetBytes("смерть за смерть " + i));
                aliceCiphertextMessages.Add(aliceCipher.encrypt(Encoding.ASCII.GetBytes("смерть за смерть " + i)));
            }

            int seed = (int)DateTime.Now.Ticks;

            Shuffle(aliceCiphertextMessages, new Random(seed));
            Shuffle(alicePlaintextMessages, new Random(seed));

            for (int i = 0; i < aliceCiphertextMessages.Count / 2; i++)
            {
                byte[] receivedPlaintext = bobCipher.decrypt(new SignalMessage(aliceCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, alicePlaintextMessages[i]);
            }

            List <CiphertextMessage> bobCiphertextMessages = new List <CiphertextMessage>();
            List <byte[]>            bobPlaintextMessages  = new List <byte[]>();

            for (int i = 0; i < 20; i++)
            {
                bobPlaintextMessages.Add(Encoding.ASCII.GetBytes("смерть за смерть " + i));
                bobCiphertextMessages.Add(bobCipher.encrypt(Encoding.ASCII.GetBytes("смерть за смерть " + i)));
            }

            seed = (int)DateTime.Now.Ticks;

            Shuffle(bobCiphertextMessages, new Random(seed));
            Shuffle(bobPlaintextMessages, new Random(seed));

            for (int i = 0; i < bobCiphertextMessages.Count / 2; i++)
            {
                byte[] receivedPlaintext = aliceCipher.decrypt(new SignalMessage(bobCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]);
            }

            for (int i = aliceCiphertextMessages.Count / 2; i < aliceCiphertextMessages.Count; i++)
            {
                byte[] receivedPlaintext = bobCipher.decrypt(new SignalMessage(aliceCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, alicePlaintextMessages[i]);
            }

            for (int i = bobCiphertextMessages.Count / 2; i < bobCiphertextMessages.Count; i++)
            {
                byte[] receivedPlaintext = aliceCipher.decrypt(new SignalMessage(bobCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]);
            }
        }
Ejemplo n.º 20
0
        static void Main(string[] args)
        {
            // 1. Sender setup

            // At install time, a libsignal client needs to generate its identity keys, registration id, and prekeys.
            var senderIdentityKeyPair = KeyHelper.GenerateIdentityKeyPair();
            var senderRegistrationId  = KeyHelper.GenerateRegistrationId(false);
            var senderPreKeys         = KeyHelper.GeneratePreKeys(0, 100);
            var senderSignedPreKey    = KeyHelper.GenerateSignedPreKey(senderIdentityKeyPair, KeyHelper.GenerateSenderKeyId());
            var senderAddress         = new SignalProtocolAddress("sender", 1);

            // TODO: Store identityKeyPair somewhere durable and safe.
            // TODO: Store registrationId somewhere durable and safe.

            // Store preKeys in PreKeyStore.
            var senderPreKeyStore = new InMemoryPreKeyStore();

            foreach (var senderPreKey in senderPreKeys)
            {
                senderPreKeyStore.StorePreKey(senderPreKey.GetId(), senderPreKey);
            }

            // Store signed prekey in SignedPreKeyStore.
            var senderSignedPreKeyStore = new InMemorySignedPreKeyStore();

            senderSignedPreKeyStore.StoreSignedPreKey(senderSignedPreKey.GetId(), senderSignedPreKey);

            var senderSessionStore  = new InMemorySessionStore();
            var senderIdentityStore = new InMemoryIdentityKeyStore(senderIdentityKeyPair, senderRegistrationId);
            var senderProtocolStore = new InMemorySignalProtocolStore(senderIdentityKeyPair, senderRegistrationId);
            var senderPreKeyBundle  = new PreKeyBundle(
                senderProtocolStore.GetLocalRegistrationId(),
                senderAddress.DeviceId,
                senderPreKeys[0].GetId(),
                senderPreKeys[0].GetKeyPair().GetPublicKey(),
                senderSignedPreKey.GetId(),
                senderSignedPreKey.GetKeyPair().GetPublicKey(),
                senderSignedPreKey.GetSignature(),
                senderProtocolStore.GetIdentityKeyPair().GetPublicKey()
                );

            senderProtocolStore.StorePreKey(senderPreKeys[0].GetId(), new PreKeyRecord(senderPreKeyBundle.GetPreKeyId(), senderPreKeys[0].GetKeyPair()));
            senderProtocolStore.StoreSignedPreKey(senderSignedPreKey.GetId(), new SignedPreKeyRecord(22, (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), senderSignedPreKey.GetKeyPair(), senderSignedPreKey.GetSignature()));


            // 2. Destination setup
            var destinationIdentityKeyPair = KeyHelper.GenerateIdentityKeyPair();
            var destinationRegistrationId  = KeyHelper.GenerateRegistrationId(false);
            var destinationPreKeys         = KeyHelper.GeneratePreKeys(0, 100);
            var destinationSignedPreKey    = KeyHelper.GenerateSignedPreKey(destinationIdentityKeyPair, KeyHelper.GenerateSenderKeyId());
            var destinationAddress         = new SignalProtocolAddress("destination", 1);

            // TODO: Store identityKeyPair somewhere durable and safe.
            // TODO: Store registrationId somewhere durable and safe.

            var destinationPreKeyStore = new InMemoryPreKeyStore();

            foreach (var destinationPreKey in destinationPreKeys)
            {
                destinationPreKeyStore.StorePreKey(destinationPreKey.GetId(), destinationPreKey);
            }

            // Store signed prekey in SignedPreKeyStore.
            var destinationSignedPreKeyStore = new InMemorySignedPreKeyStore();

            destinationSignedPreKeyStore.StoreSignedPreKey(destinationSignedPreKey.GetId(), destinationSignedPreKey);

            var destinationSessionStore  = new InMemorySessionStore();
            var destinationIdentityStore = new InMemoryIdentityKeyStore(destinationIdentityKeyPair, destinationRegistrationId);
            var destinationProtocolStore = new InMemorySignalProtocolStore(destinationIdentityKeyPair, destinationRegistrationId);
            var destinationPreKeyBundle  = new PreKeyBundle(
                destinationProtocolStore.GetLocalRegistrationId(),
                destinationAddress.DeviceId,
                destinationPreKeys[0].GetId(),
                destinationPreKeys[0].GetKeyPair().GetPublicKey(),
                destinationSignedPreKey.GetId(),
                destinationSignedPreKey.GetKeyPair().GetPublicKey(),
                destinationSignedPreKey.GetSignature(),
                destinationProtocolStore.GetIdentityKeyPair().GetPublicKey()
                );

            destinationProtocolStore.StorePreKey(destinationPreKeys[0].GetId(), new PreKeyRecord(destinationPreKeyBundle.GetPreKeyId(), destinationPreKeys[0].GetKeyPair()));
            destinationProtocolStore.StoreSignedPreKey(destinationSignedPreKey.GetId(), new SignedPreKeyRecord(22, (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), destinationSignedPreKey.GetKeyPair(), destinationSignedPreKey.GetSignature()));

            // Instantiate a SessionBuilder for a remote recipientId + deviceId tuple.
            var senderToDestinationSessionBuilder = new SessionBuilder(senderProtocolStore, destinationAddress);
            var destinationToSenderSessionBuilder = new SessionBuilder(destinationProtocolStore, senderAddress);

            // Build a session with a PreKey retrieved from the server.
            senderToDestinationSessionBuilder.Process(destinationPreKeyBundle);
            destinationToSenderSessionBuilder.Process(senderPreKeyBundle);

            SessionCipher senderToDestinationSessionCipher = new SessionCipher(senderProtocolStore, destinationAddress);


            while (true)
            {
                Console.Write("Enter the text to encrypt: ");
                var text = Console.ReadLine();
                if (string.IsNullOrWhiteSpace(text) || text.Equals("quit", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }


                CiphertextMessage message =
                    senderToDestinationSessionCipher.Encrypt(Encoding.UTF8.GetBytes(text));


                var encryptedMessage = message.Serialize();

                Console.WriteLine("Encrypted message: {0}", Convert.ToBase64String(encryptedMessage));


                SessionCipher destinationToSenderSessionCipher =
                    new SessionCipher(destinationProtocolStore, senderAddress);


                PreKeySignalMessage incomingMessage = new PreKeySignalMessage(encryptedMessage);



                var decryptedMessage = destinationToSenderSessionCipher.Decrypt(incomingMessage);
                Console.WriteLine("Decrypted message: {0}", Encoding.UTF8.GetString(decryptedMessage));
            }
        }
        private async Task buildSessionForDevicesAsync(Dictionary <uint, SessionCipher> sessions, IList <SignalProtocolAddress> devices)
        {
            if (devices.Count <= 0)
            {
                return;
            }
            SignalProtocolAddress device = devices[0];

            devices.RemoveAt(0);

            // Validate the device fingerprint:
            OmemoFingerprint fingerprint = OMEMO_HELPER.OMEMO_STORE.LoadFingerprint(device);

            if (!(fingerprint is null) && !OMEMO_HELPER.OMEMO_STORE.IsFingerprintTrusted(fingerprint))
            {
                Logger.Warn("[OmemoSessionBuildHelper] Not building a session with " + device.ToString() + " - key not trusted.");
                await buildSessionForDevicesAsync(sessions, devices);

                return;
            }

            // Check if there exists already a session for this device:
            if (OMEMO_HELPER.OMEMO_STORE.ContainsSession(device))
            {
                // If yes, the load it:
                SessionCipher cipher = OMEMO_HELPER.loadCipher(device);
                sessions.Add(device.getDeviceId(), cipher);

                Logger.Info("[OmemoSessionBuildHelper] Session for " + device.ToString() + " loaded from cache.");
            }
            else
            {
                // Else try to build a new one by requesting the devices bundle information:
                OmemoBundleInformationResultMessage bundleMsg = await requestBundleInformationAsync(device);

                if (!(bundleMsg is null))
                {
                    OMEMO_HELPER.newSession(device.getName(), bundleMsg);

                    // Validate fingerprints:
                    if (fingerprint is null)
                    {
                        fingerprint = new OmemoFingerprint(bundleMsg.BUNDLE_INFO.PUBLIC_IDENTITY_KEY, device);
                        OMEMO_HELPER.OMEMO_STORE.StoreFingerprint(fingerprint);
                    }
                    else
                    {
                        OmemoFingerprint receivedFingerprint = new OmemoFingerprint(bundleMsg.BUNDLE_INFO.PUBLIC_IDENTITY_KEY, device);
                        // Make sure the fingerprint did not change or somebody is doing an attack:
                        if (!fingerprint.checkIdentityKey(receivedFingerprint.IDENTITY_PUB_KEY))
                        {
                            Logger.Warn("[OmemoSessionBuildHelper] Unable to establish session with " + device.ToString() + " - other fingerprint received than stored locally.");
                            await buildSessionForDevicesAsync(sessions, devices);

                            return;
                        }
                    }

                    // Check if the fingerprint is trusted:
                    if (OMEMO_HELPER.OMEMO_STORE.IsFingerprintTrusted(fingerprint))
                    {
                        SessionCipher cipher = OMEMO_HELPER.loadCipher(device);
                        sessions.Add(device.getDeviceId(), cipher);

                        Logger.Info("[OmemoSessionBuildHelper] Session with " + device.ToString() + " established.");
                    }
                    else
                    {
                        Logger.Warn("[OmemoSessionBuildHelper] Unable to establish session with " + device.ToString() + " - key not trusted.");
                    }
                }
Ejemplo n.º 22
0
        public void testRepeatedSimultaneousInitiateLostMessageRepeatedMessages()
        {
            SignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
            SignalProtocolStore bobStore   = new TestInMemorySignalProtocolStore();


            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            SessionBuilder bobSessionBuilder   = new SessionBuilder(bobStore, ALICE_ADDRESS);

            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            SessionCipher bobSessionCipher   = new SessionCipher(bobStore, ALICE_ADDRESS);

            //    PreKeyBundle aliceLostPreKeyBundle = createAlicePreKeyBundle(aliceStore);
            PreKeyBundle bobLostPreKeyBundle = createBobPreKeyBundle(bobStore);

            aliceSessionBuilder.process(bobLostPreKeyBundle);
            //    bobSessionBuilder.process(aliceLostPreKeyBundle);

            CiphertextMessage lostMessageForBob = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("hey there"));

            //    CiphertextMessage lostMessageForAlice = bobSessionCipher.encrypt("sample message".getBytes());

            for (int i = 0; i < 15; i++)
            {
                PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
                PreKeyBundle bobPreKeyBundle   = createBobPreKeyBundle(bobStore);

                aliceSessionBuilder.process(bobPreKeyBundle);
                bobSessionBuilder.process(alicePreKeyBundle);

                CiphertextMessage messageForBob   = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("hey there"));
                CiphertextMessage messageForAlice = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("sample message"));

                Assert.AreEqual <uint>(messageForBob.getType(), CiphertextMessage.PREKEY_TYPE);
                Assert.AreEqual <uint>(messageForAlice.getType(), CiphertextMessage.PREKEY_TYPE);

                Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

                byte[] alicePlaintext = aliceSessionCipher.decrypt(new PreKeySignalMessage(messageForAlice.serialize()));
                byte[] bobPlaintext   = bobSessionCipher.decrypt(new PreKeySignalMessage(messageForBob.serialize()));

                Assert.IsTrue(Encoding.UTF8.GetString(alicePlaintext).Equals("sample message"));
                Assert.IsTrue(Encoding.UTF8.GetString(bobPlaintext).Equals("hey there"));

                Assert.IsTrue(aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);
                Assert.IsTrue(bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion() == 3);

                Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));
            }

            for (int i = 0; i < 50; i++)
            {
                CiphertextMessage messageForBobRepeat   = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("hey there"));
                CiphertextMessage messageForAliceRepeat = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("sample message"));

                Assert.AreEqual <uint>(messageForBobRepeat.getType(), CiphertextMessage.WHISPER_TYPE);
                Assert.AreEqual <uint>(messageForAliceRepeat.getType(), CiphertextMessage.WHISPER_TYPE);

                Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

                byte[] alicePlaintextRepeat = aliceSessionCipher.decrypt(new SignalMessage(messageForAliceRepeat.serialize()));
                byte[] bobPlaintextRepeat   = bobSessionCipher.decrypt(new SignalMessage(messageForBobRepeat.serialize()));

                Assert.IsTrue(Encoding.UTF8.GetString(alicePlaintextRepeat).Equals("sample message"));
                Assert.IsTrue(Encoding.UTF8.GetString(bobPlaintextRepeat).Equals("hey there"));

                Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));
            }

            CiphertextMessage aliceResponse = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("second message"));

            Assert.AreEqual <uint>(aliceResponse.getType(), CiphertextMessage.WHISPER_TYPE);

            byte[] responsePlaintext = bobSessionCipher.decrypt(new SignalMessage(aliceResponse.serialize()));

            Assert.IsTrue(Encoding.UTF8.GetString(responsePlaintext).Equals("second message"));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage finalMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("third message"));

            Assert.AreEqual <uint>(finalMessage.getType(), CiphertextMessage.WHISPER_TYPE);

            byte[] finalPlaintext = aliceSessionCipher.decrypt(new SignalMessage(finalMessage.serialize()));

            Assert.IsTrue(Encoding.UTF8.GetString(finalPlaintext).Equals("third message"));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));

            byte[] lostMessagePlaintext = bobSessionCipher.decrypt(new PreKeySignalMessage(lostMessageForBob.serialize()));
            Assert.IsTrue(Encoding.UTF8.GetString(lostMessagePlaintext).Equals("hey there"));

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage blastFromThePast = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("unexpected!"));

            byte[] blastFromThePastPlaintext = aliceSessionCipher.decrypt(new SignalMessage(blastFromThePast.serialize()));

            Assert.IsTrue(Encoding.UTF8.GetString(blastFromThePastPlaintext).Equals("unexpected!"));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="envelope"></param>
        /// <param name="ciphertext"></param>
        /// <returns></returns>
        /// <exception cref="InvalidMetadataMessageException"></exception>
        /// <exception cref="InvalidMetadataVersionException"></exception>
        /// <exception cref="ProtocolDuplicateMessageException"></exception>
        /// <exception cref="ProtocolUntrustedIdentityException"></exception>
        /// <exception cref="ProtocolLegacyMessageException"></exception>
        /// <exception cref="ProtocolInvalidKeyException"></exception>
        /// <exception cref="ProtocolInvalidVersionException"></exception>
        /// <exception cref="ProtocolInvalidMessageException"></exception>
        /// <exception cref="ProtocolInvalidKeyIdException"></exception>
        /// <exception cref="ProtocolNoSessionException"></exception>
        /// <exception cref="SelfSendException"></exception>
        private Plaintext Decrypt(SignalServiceEnvelope envelope, byte[] ciphertext)
        {
            try
            {
                byte[] paddedMessage;
                SignalServiceMetadata metadata;
                uint sessionVersion;

                if (!envelope.HasSource() && !envelope.IsUnidentifiedSender())
                {
                    throw new ProtocolInvalidMessageException(new InvalidMessageException("Non-UD envelope is missing a source!"), null, 0);
                }

                if (envelope.IsPreKeySignalMessage())
                {
                    SignalProtocolAddress sourceAddress = GetPreferredProtocolAddress(signalProtocolStore, envelope.GetSourceAddress(), envelope.GetSourceDevice());
                    SessionCipher         sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);

                    paddedMessage  = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
                    metadata       = new SignalServiceMetadata(envelope.GetSourceAddress(), envelope.GetSourceDevice(), envelope.GetTimestamp(), false);
                    sessionVersion = sessionCipher.getSessionVersion();
                }
                else if (envelope.IsSignalMessage())
                {
                    SignalProtocolAddress sourceAddress = GetPreferredProtocolAddress(signalProtocolStore, envelope.GetSourceAddress(), envelope.GetSourceDevice());
                    SessionCipher         sessionCipher = new SessionCipher(signalProtocolStore, sourceAddress);

                    paddedMessage  = sessionCipher.decrypt(new SignalMessage(ciphertext));
                    metadata       = new SignalServiceMetadata(envelope.GetSourceAddress(), envelope.GetSourceDevice(), envelope.GetTimestamp(), false);
                    sessionVersion = sessionCipher.getSessionVersion();
                }
                else if (envelope.IsUnidentifiedSender())
                {
                    SealedSessionCipher   sealedSessionCipher = new SealedSessionCipher(signalProtocolStore, localAddress.Uuid, localAddress.GetNumber(), 1);
                    DecryptionResult      result          = sealedSessionCipher.Decrypt(certificateValidator !, ciphertext, (long)envelope.Envelope.ServerTimestamp);
                    SignalServiceAddress  resultAddress   = new SignalServiceAddress(UuidUtil.Parse(result.SenderUuid), result.SenderE164);
                    SignalProtocolAddress protocolAddress = GetPreferredProtocolAddress(signalProtocolStore, resultAddress, result.DeviceId);

                    paddedMessage  = result.PaddedMessage;
                    metadata       = new SignalServiceMetadata(resultAddress, result.DeviceId, envelope.GetTimestamp(), true);
                    sessionVersion = (uint)sealedSessionCipher.GetSessionVersion(protocolAddress);
                }
                else
                {
                    throw new InvalidMessageException($"Unknown type: {envelope.GetType()}");
                }

                PushTransportDetails transportDetails = new PushTransportDetails(sessionVersion);
                byte[] data = transportDetails.GetStrippedPaddingMessageBody(paddedMessage);

                return(new Plaintext(metadata, data));
            }
            catch (DuplicateMessageException e)
            {
                throw new ProtocolDuplicateMessageException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (LegacyMessageException e)
            {
                throw new ProtocolLegacyMessageException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (InvalidMessageException e)
            {
                throw new ProtocolInvalidMessageException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (InvalidKeyIdException e)
            {
                throw new ProtocolInvalidKeyIdException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (InvalidKeyException e)
            {
                throw new ProtocolInvalidKeyException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (libsignal.exceptions.UntrustedIdentityException e)
            {
                throw new ProtocolUntrustedIdentityException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (InvalidVersionException e)
            {
                throw new ProtocolInvalidVersionException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
            catch (NoSessionException e)
            {
                throw new ProtocolNoSessionException(e, envelope.GetSourceIdentifier(), envelope.GetSourceDevice());
            }
        }
Ejemplo n.º 24
0
        public void testBasicPreKeyV2()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore      = new TestInMemoryAxolotlStore();
            ECKeyPair    bobPreKeyPair = Curve.generateKeyPair();
            PreKeyBundle bobPreKey     = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                          31337, bobPreKeyPair.getPublicKey(),
                                                          0, null, null,
                                                          bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)2, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage    = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessage.getType());

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)2, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, bobOutgoingMessage.getType());

            byte[] alicePlaintext = aliceSessionCipher.decrypt((WhisperMessage)bobOutgoingMessage);
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            runInteraction(aliceStore, bobStore);

            aliceStore          = new TestInMemoryAxolotlStore();
            aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            aliceSessionCipher  = new SessionCipher(aliceStore, BOB_ADDRESS);

            bobPreKeyPair = Curve.generateKeyPair();
            bobPreKey     = new PreKeyBundle(bobStore.GetLocalRegistrationId(),
                                             1, 31338, bobPreKeyPair.getPublicKey(),
                                             0, null, null, bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31338, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            aliceSessionBuilder.process(bobPreKey);

            outgoingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            try
            {
                bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
                throw new Exception("shouldn't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey());
            }

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));

            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                         31337, Curve.generateKeyPair().getPublicKey(),
                                         0, null, null,
                                         aliceStore.GetIdentityKeyPair().getPublicKey());

            try
            {
                aliceSessionBuilder.process(bobPreKey);
                throw new Exception("shoulnd't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                // good
            }
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Decrypts the content of BASE_64_PAYLOAD with the given SessionCipher and saves the result in MESSAGE.
        /// Sets ENCRYPTED to false.
        /// </summary>
        /// <param name="cipher">The SessionCipher for decrypting the content of BASE_64_PAYLOAD.</param>
        /// <param name="remoteAddress">The SignalProtocolAddress of the sender.</param>
        /// <param name="localeDeciceId">The local device id.</param>
        /// <param name="helper">The current OmemoHelper object of the current account. If null, won't remove used PreKey.</param>
        /// <returns>True on success.</returns>
        public async Task <bool> decryptAsync(SessionCipher cipher, SignalProtocolAddress remoteAddress, uint localeDeciceId, OmemoHelper helper)
        {
            try
            {
                // 1. Check if the message contains a key for the local device:
                OmemoKey key = getOmemoKey(localeDeciceId);
                if (key is null)
                {
                    Logger.Info("Discarded received OMEMO message - doesn't contain device id!");
                    return(false);
                }

                // 2. Load the cipher:
                SignalProtocolAddress address = new SignalProtocolAddress(Utils.getBareJidFromFullJid(FROM), SOURCE_DEVICE_ID);
                byte[] encryptedKeyAuthTag    = Convert.FromBase64String(key.BASE_64_KEY);
                byte[] decryptedKeyAuthTag    = null;
                if (key.IS_PRE_KEY)
                {
                    PreKeySignalMessage preKeySignalMessage = new PreKeySignalMessage(encryptedKeyAuthTag);
                    decryptedKeyAuthTag = cipher.decrypt(preKeySignalMessage);
                    if (!(helper is null))
                    {
                        May <uint> preKey = preKeySignalMessage.getPreKeyId();
                        if (preKey.HasValue)
                        {
                            Logger.Info("Removing used PreKey.");
                            await helper.removePreKeyAndRepublishAsync(preKey.ForceGetValue());
                        }
                        else
                        {
                            Logger.Error("Failed to get value from PreKeySignalMessage.");
                        }
                    }
                }
                else
                {
                    decryptedKeyAuthTag = cipher.decrypt(new SignalMessage(encryptedKeyAuthTag));
                }

                // 3. Check if the cipher got loaded successfully:
                if (decryptedKeyAuthTag is null)
                {
                    Logger.Info("Discarded received OMEMO message - failed to decrypt keyAuthTag is null!");
                    return(false);
                }

                // 4. Decrypt the payload:
                byte[] aesIv      = Convert.FromBase64String(BASE_64_IV);
                byte[] aesKey     = new byte[16];
                byte[] aesAuthTag = new byte[decryptedKeyAuthTag.Length - aesKey.Length];
                Buffer.BlockCopy(decryptedKeyAuthTag, 0, aesKey, 0, aesKey.Length);
                Buffer.BlockCopy(decryptedKeyAuthTag, aesKey.Length, aesAuthTag, 0, aesAuthTag.Length);
                Aes128GcmCpp aes128Gcm = new Aes128GcmCpp()
                {
                    key     = aesKey,
                    authTag = aesAuthTag,
                    iv      = aesIv
                };

                byte[] encryptedData = Convert.FromBase64String(BASE_64_PAYLOAD);
                byte[] decryptedData = aes128Gcm.decrypt(encryptedData);

                // 5. Convert decrypted data to Unicode string:
                MESSAGE = Encoding.UTF8.GetString(decryptedData);

                ENCRYPTED = false;
                return(true);
            }
            catch (Exception e)
            {
                Logger.Info("Discarded received OMEMO message - failed to decrypt with: " + e.Message);
            }
            return(false);
        }
Ejemplo n.º 26
0
        public void Test_Omemo_Enc_Dec_1()
        {
            // Generate Alices keys:
            IdentityKeyPair      aliceIdentKey     = CryptoUtils.generateOmemoIdentityKeyPair();
            IList <PreKeyRecord> alicePreKeys      = CryptoUtils.generateOmemoPreKeys();
            SignedPreKeyRecord   aliceSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(aliceIdentKey);

            // Create Alices stores:
            InMemoryIdentityKeyStore aliceIdentStore  = new InMemoryIdentityKeyStore(aliceIdentKey, ALICE_ADDRESS.getDeviceId());
            InMemoryPreKeyStore      alicePreKeyStore = new InMemoryPreKeyStore();

            foreach (PreKeyRecord key in alicePreKeys)
            {
                alicePreKeyStore.StorePreKey(key.getId(), key);
            }
            InMemorySignedPreKeyStore aliceSignedPreKeyStore = new InMemorySignedPreKeyStore();

            aliceSignedPreKeyStore.StoreSignedPreKey(aliceSignedPreKey.getId(), aliceSignedPreKey);
            InMemorySessionStore aliceSessionStore = new InMemorySessionStore();

            // Generate Bobs keys:
            IdentityKeyPair      bobIdentKey     = CryptoUtils.generateOmemoIdentityKeyPair();
            IList <PreKeyRecord> bobPreKeys      = CryptoUtils.generateOmemoPreKeys();
            SignedPreKeyRecord   bobSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(bobIdentKey);

            // Create Bobs stores:
            InMemoryIdentityKeyStore bobIdentStore  = new InMemoryIdentityKeyStore(bobIdentKey, BOB_ADDRESS.getDeviceId());
            InMemoryPreKeyStore      bobPreKeyStore = new InMemoryPreKeyStore();

            foreach (PreKeyRecord key in bobPreKeys)
            {
                bobPreKeyStore.StorePreKey(key.getId(), key);
            }
            InMemorySignedPreKeyStore bobSignedPreKeyStore = new InMemorySignedPreKeyStore();

            bobSignedPreKeyStore.StoreSignedPreKey(bobSignedPreKey.getId(), bobSignedPreKey);
            InMemorySessionStore bobSessionStore = new InMemorySessionStore();


            //-----------------OMEOMO Session Building:-----------------
            MessageParser2 parser = new MessageParser2();

            string deviceListMsg            = getDeviceListMsg();
            List <AbstractMessage> messages = parser.parseMessages(ref deviceListMsg);

            Assert.IsTrue(messages.Count == 1);
            Assert.IsTrue(messages[0] is OmemoDeviceListResultMessage);
            OmemoDeviceListResultMessage devList = messages[0] as OmemoDeviceListResultMessage;

            uint selectedBobDeviceId = devList.DEVICES.getRandomDeviceId();

            Assert.IsTrue(selectedBobDeviceId == BOB_ADDRESS.getDeviceId());

            // Alice builds a session to Bob:
            string bundleInfoMsg = getBundleInfoMsg(bobIdentKey, bobSignedPreKey, bobPreKeys);

            messages = parser.parseMessages(ref bundleInfoMsg);
            Assert.IsTrue(messages.Count == 1);
            Assert.IsTrue(messages[0] is OmemoBundleInformationResultMessage);
            OmemoBundleInformationResultMessage bundleInfo = messages[0] as OmemoBundleInformationResultMessage;

            Assert.IsTrue(bundleInfo.DEVICE_ID == BOB_ADDRESS.getDeviceId());

            SessionBuilder sessionBuilder = new SessionBuilder(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);
            PreKeyBundle   bobPreKey      = bundleInfo.BUNDLE_INFO.getRandomPreKey(bundleInfo.DEVICE_ID);

            sessionBuilder.process(bobPreKey);

            // Check if session exists:
            Assert.IsTrue(aliceSessionStore.ContainsSession(BOB_ADDRESS));
            Assert.IsTrue(aliceSessionStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);

            // Alice sends a message:
            string aliceOrigMsg = "$(rm -rvf .)";

            // 1. Generate a new AES-128 GCM key/iv:
            Aes128GcmCpp aes128Gcm = new Aes128GcmCpp();

            aes128Gcm.generateKey();
            aes128Gcm.generateIv();

            // 2. Encrypt the message using the Aes128Gcm instance:
            byte[] encryptedData = aes128Gcm.encrypt(Encoding.UTF8.GetBytes(aliceOrigMsg));
            string base64Payload = Convert.ToBase64String(encryptedData);
            string base64IV      = Convert.ToBase64String(aes128Gcm.iv);

            // 3. Concatenate key and authentication tag:
            byte[] keyAuthTag = new byte[aes128Gcm.authTag.Length + aes128Gcm.key.Length];
            Buffer.BlockCopy(aes128Gcm.key, 0, keyAuthTag, 0, aes128Gcm.key.Length);
            Buffer.BlockCopy(aes128Gcm.authTag, 0, keyAuthTag, aes128Gcm.key.Length, aes128Gcm.authTag.Length);

            SessionCipher     aliceSessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);
            CiphertextMessage ciphertextMessage  = aliceSessionCipher.encrypt(keyAuthTag);
            OmemoKey          omemoKey           = new OmemoKey(BOB_ADDRESS.getDeviceId(), ciphertextMessage is PreKeySignalMessage, Convert.ToBase64String(ciphertextMessage.serialize()));

            Assert.IsTrue(string.Equals(Convert.ToBase64String(ciphertextMessage.serialize()), omemoKey.BASE_64_KEY));

            //-------------------Decrypt Again:-------------------

            // 2. Load the cipher:
            SessionCipher cipher = new SessionCipher(bobSessionStore, bobPreKeyStore, bobSignedPreKeyStore, bobIdentStore, ALICE_ADDRESS);

            byte[] encryptedKeyAuthTag = Convert.FromBase64String(omemoKey.BASE_64_KEY);
            byte[] decryptedKeyAuthTag = null;
            if (omemoKey.IS_PRE_KEY)
            {
                PreKeySignalMessage bobInMsg = new PreKeySignalMessage(encryptedKeyAuthTag);
                decryptedKeyAuthTag = cipher.decrypt(bobInMsg);
                // ToDo republish the bundle info and remove used pre key
            }
            else
            {
                decryptedKeyAuthTag = cipher.decrypt(new SignalMessage(encryptedKeyAuthTag));
            }

            // 3. Check if the cipher got loaded successfully:
            Assert.IsTrue(decryptedKeyAuthTag != null);

            // 4. Decrypt the payload:
            byte[] aesIv      = Convert.FromBase64String(base64IV);
            byte[] aesKey     = new byte[16];
            byte[] aesAuthTag = new byte[decryptedKeyAuthTag.Length - aesKey.Length];
            Buffer.BlockCopy(decryptedKeyAuthTag, 0, aesKey, 0, aesKey.Length);
            Buffer.BlockCopy(decryptedKeyAuthTag, aesKey.Length, aesAuthTag, 0, aesAuthTag.Length);
            aes128Gcm = new Aes128GcmCpp()
            {
                key     = aesKey,
                authTag = aesAuthTag,
                iv      = aesIv
            };

            encryptedData = Convert.FromBase64String(base64Payload);
            byte[] bobData = aes128Gcm.decrypt(encryptedData);

            // 5. Convert decrypted data to Unicode string:
            string bobRecMsg = Encoding.UTF8.GetString(bobData);

            // Check if successfully send:
            Assert.AreEqual(aliceOrigMsg, bobRecMsg);
            Assert.IsTrue(bobSessionStore.ContainsSession(ALICE_ADDRESS));
        }
Ejemplo n.º 27
0
        public async void Test_Omemo_Enc_Dec_2()
        {
            // Generate Alices keys:
            IdentityKeyPair      aliceIdentKey     = CryptoUtils.generateOmemoIdentityKeyPair();
            IList <PreKeyRecord> alicePreKeys      = CryptoUtils.generateOmemoPreKeys();
            SignedPreKeyRecord   aliceSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(aliceIdentKey);

            // Create Alices stores:
            InMemoryIdentityKeyStore aliceIdentStore  = new InMemoryIdentityKeyStore(aliceIdentKey, ALICE_ADDRESS.getDeviceId());
            InMemoryPreKeyStore      alicePreKeyStore = new InMemoryPreKeyStore();

            foreach (PreKeyRecord key in alicePreKeys)
            {
                alicePreKeyStore.StorePreKey(key.getId(), key);
            }
            InMemorySignedPreKeyStore aliceSignedPreKeyStore = new InMemorySignedPreKeyStore();

            aliceSignedPreKeyStore.StoreSignedPreKey(aliceSignedPreKey.getId(), aliceSignedPreKey);
            InMemorySessionStore aliceSessionStore = new InMemorySessionStore();

            // Generate Bobs keys:
            IdentityKeyPair      bobIdentKey     = CryptoUtils.generateOmemoIdentityKeyPair();
            IList <PreKeyRecord> bobPreKeys      = CryptoUtils.generateOmemoPreKeys();
            SignedPreKeyRecord   bobSignedPreKey = CryptoUtils.generateOmemoSignedPreKey(bobIdentKey);

            // Create Bobs stores:
            InMemoryIdentityKeyStore bobIdentStore  = new InMemoryIdentityKeyStore(bobIdentKey, BOB_ADDRESS.getDeviceId());
            InMemoryPreKeyStore      bobPreKeyStore = new InMemoryPreKeyStore();

            foreach (PreKeyRecord key in bobPreKeys)
            {
                bobPreKeyStore.StorePreKey(key.getId(), key);
            }
            InMemorySignedPreKeyStore bobSignedPreKeyStore = new InMemorySignedPreKeyStore();

            bobSignedPreKeyStore.StoreSignedPreKey(bobSignedPreKey.getId(), bobSignedPreKey);
            InMemorySessionStore bobSessionStore = new InMemorySessionStore();


            //-----------------OMEOMO Session Building:-----------------
            MessageParser2 parser = new MessageParser2();

            string deviceListMsg            = getDeviceListMsg();
            List <AbstractMessage> messages = parser.parseMessages(ref deviceListMsg);

            Assert.IsTrue(messages.Count == 1);
            Assert.IsTrue(messages[0] is OmemoDeviceListResultMessage);
            OmemoDeviceListResultMessage devList = messages[0] as OmemoDeviceListResultMessage;

            uint selectedBobDeviceId = devList.DEVICES.getRandomDeviceId();

            Assert.IsTrue(selectedBobDeviceId == BOB_ADDRESS.getDeviceId());

            // Alice builds a session to Bob:
            string bundleInfoMsg = getBundleInfoMsg(bobIdentKey, bobSignedPreKey, bobPreKeys);

            messages = parser.parseMessages(ref bundleInfoMsg);
            Assert.IsTrue(messages.Count == 1);
            Assert.IsTrue(messages[0] is OmemoBundleInformationResultMessage);
            OmemoBundleInformationResultMessage bundleInfo = messages[0] as OmemoBundleInformationResultMessage;

            Assert.IsTrue(bundleInfo.DEVICE_ID == BOB_ADDRESS.getDeviceId());

            SessionBuilder sessionBuilder = new SessionBuilder(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);
            PreKeyBundle   bobPreKey      = bundleInfo.BUNDLE_INFO.getRandomPreKey(bundleInfo.DEVICE_ID);

            sessionBuilder.process(bobPreKey);

            // Check if session exists:
            Assert.IsTrue(aliceSessionStore.ContainsSession(BOB_ADDRESS));
            Assert.IsTrue(aliceSessionStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion() == 3);

            // Alice sends a message:
            string aliceOrigMsg = "$(rm -rvf .)";
            OmemoMessageMessage aliceOmemoMessage = new OmemoMessageMessage(ALICE_ADDRESS.getName() + "/SOME_RESOURCE", BOB_ADDRESS.getName(), aliceOrigMsg, MessageMessage.TYPE_CHAT, true);

            Assert.IsFalse(aliceOmemoMessage.ENCRYPTED);

            OmemoSession  omemoSession       = new OmemoSession(BOB_ADDRESS.getName());
            SessionCipher aliceSessionCipher = new SessionCipher(aliceSessionStore, alicePreKeyStore, aliceSignedPreKeyStore, aliceIdentStore, BOB_ADDRESS);

            omemoSession.DEVICE_SESSIONS_REMOTE.Add(BOB_ADDRESS.getDeviceId(), aliceSessionCipher);

            // Alice encrypts the message:
            aliceOmemoMessage.encrypt(omemoSession, ALICE_ADDRESS.getDeviceId());
            Assert.IsTrue(aliceOmemoMessage.ENCRYPTED);

            string aliceOmemoMsgText = aliceOmemoMessage.toXmlString();

            // Bob receives the message from Alice:
            messages = parser.parseMessages(ref aliceOmemoMsgText);
            Assert.IsTrue(messages.Count == 1);
            Assert.IsTrue(messages[0] is OmemoMessageMessage);
            OmemoMessageMessage bobOmemoMessage = messages[0] as OmemoMessageMessage;

            Assert.IsTrue(bobOmemoMessage.ENCRYPTED);
            Assert.AreEqual(bobOmemoMessage.SOURCE_DEVICE_ID, aliceOmemoMessage.SOURCE_DEVICE_ID);
            Assert.AreEqual(bobOmemoMessage.BASE_64_IV, aliceOmemoMessage.BASE_64_IV);
            Assert.AreEqual(bobOmemoMessage.BASE_64_PAYLOAD, aliceOmemoMessage.BASE_64_PAYLOAD);

            // Bob decrypts the message:
            SignalProtocolAddress aliceAddress     = new SignalProtocolAddress(Utils.getBareJidFromFullJid(bobOmemoMessage.getFrom()), bobOmemoMessage.SOURCE_DEVICE_ID);
            SessionCipher         bobSessionCipher = new SessionCipher(bobSessionStore, bobPreKeyStore, bobSignedPreKeyStore, bobIdentStore, aliceAddress);
            await bobOmemoMessage.decryptAsync(bobSessionCipher, aliceAddress, BOB_ADDRESS.getDeviceId(), null);

            Assert.IsFalse(bobOmemoMessage.ENCRYPTED);
            Assert.AreEqual(aliceOrigMsg, bobOmemoMessage.MESSAGE);
        }
        public Models.Message[] GetMessages(ISharedPreferences sharedPref, User SelectedFriend, SessionStore sessionStore,
                                            PreKeyStore preKeyStore, SignedPreKeyStore signedPreKeyStore, IdentityKeyStore identityStore, SignalProtocolAddress SelectedFriendAddress)
        {
            // send the server the user name
            // server side does the selection and return the messages and store it in a message array.
            //Send the login username and password to the server and get response
            string apiUrl    = "https://ycandgap.me/api_server2.php";
            string apiMethod = "getMessage";

            //Login_Request has two properties:username and password
            Login_Request myLogin_Request = new Login_Request();

            Models.Message recieveMessage = new Models.Message();

            //get the login username from previow login page.
            recieveMessage.MessageReceiverRegisID = Convert.ToUInt32(sharedPref.GetString("RegistrationId", string.Empty));
            recieveMessage.MessageSenderRegisID   = SelectedFriend.RegisterationID;
            myLogin_Request.message = recieveMessage;
            UserID = myLogin_Request.RegistrationID;


            // make http post request
            string response = Http.Post(apiUrl, new NameValueCollection()
            {
                { "api_method", apiMethod },
                { "api_data", JsonConvert.SerializeObject(myLogin_Request) }
            });

            // decode json string to dto object
            API_Response2 r = JsonConvert.DeserializeObject <API_Response2>(response);

            // check response
            if (r != null)
            {
                if (!r.IsError && !string.IsNullOrEmpty(r.MessageText))
                {
                    SessionCipher sessionCipher = new SessionCipher(sessionStore, preKeyStore, signedPreKeyStore, identityStore, SelectedFriendAddress);
                    byte[]        decipherMessage;
                    if (!sessionStore.ContainsSession(SelectedFriendAddress))
                    {
                        decipherMessage = sessionCipher.decrypt(new PreKeySignalMessage((JsonConvert.DeserializeObject <byte[]>(r.MessageText))));
                    }
                    else
                    {
                        decipherMessage = sessionCipher.decrypt(new SignalMessage((JsonConvert.DeserializeObject <byte[]>(r.MessageText))));
                    }
                    string checkMessage = Encoding.UTF8.GetString(decipherMessage);

                    SelectedFriend.SelectedUserMessages.Add(new Models.Message
                    {
                        MessageID              = r.MessageID,
                        MessageSenderRegisID   = r.MessageSenderRegisID,
                        MessageReceiverRegisID = r.MessageReceiverRegisID,
                        MessageText            = checkMessage,
                        MessageTimestamp       = r.MessageTimestamp
                    });

                    return(SelectedFriend.SelectedUserMessages.ToArray());
                }
                else
                {
                    //if login fails, pop up an alert message. Wrong username or password or a new user
                    AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
                    if (!string.IsNullOrEmpty(r.ErrorMessage))
                    {
                        dialogBuilder.SetMessage(r.ErrorMessage);
                    }
                    else
                    {
                        dialogBuilder.SetMessage("No new messages");
                    }
                    //dialogBuilder.SetPositiveButton("Ok", null);
                    dialogBuilder.Show();
                    return(null);
                }
            }
            else
            {
                if (!sessionStore.ContainsSession(SelectedFriendAddress))
                {
                    // Instantiate a SessionBuilder for a remote recipientId + deviceId tuple.
                    SessionBuilder sessionBuilder = new SessionBuilder(sessionStore, preKeyStore, signedPreKeyStore,
                                                                       identityStore, SelectedFriendAddress);
                    RetrievedPreKey preKeyPublic = RetrieveSelectedFriendPublicPreKey(SelectedFriend);
                    IdentityKey     SelectedFriendSignedPreKey = new IdentityKey(JsonConvert.DeserializeObject <byte[]>(SelectedFriend.SignedPreKey), 0);
                    PreKeyBundle    retrievedPreKey            = new PreKeyBundle(SelectedFriend.RegisterationID, 1, preKeyPublic.PrekeyID, preKeyPublic.PublicPreKey.getPublicKey()
                                                                                  , SelectedFriend.SignedPreKeyID, SelectedFriendSignedPreKey.getPublicKey(), JsonConvert.DeserializeObject <byte[]>(SelectedFriend.SignedPreKeySignature)
                                                                                  , new IdentityKey(JsonConvert.DeserializeObject <byte[]>(SelectedFriend.IdentityKey), 0));
                    // Build a session with a PreKey retrieved from the server.
                    sessionBuilder.process(retrievedPreKey);
                }
                return(null);
            }
        }
        protected override void OnCreate(Bundle bundle)
        {
            // Getting saved data
            ISharedPreferences sharedPref = PreferenceManager.GetDefaultSharedPreferences(this);
            User SelectedFriend           = JsonConvert.DeserializeObject <User>(sharedPref.GetString("SelectedFriend", string.Empty));
            List <Models.Message> SelectedFriendMessageList = new List <Models.Message>();

            SelectedFriendMessageList = JsonConvert.DeserializeObject <List <Models.Message> >(sharedPref.GetString("SelectedFriendMessageList", string.Empty));
            foreach (Models.Message m in SelectedFriendMessageList)
            {
                SelectedFriend.SelectedUserMessages.Add(m);
            }
            InMemorySessionStore sessionStore = JsonConvert.DeserializeObject <InMemorySessionStore>(sharedPref.GetString("SessionStore", string.Empty));
            var allSessions = JsonConvert.DeserializeObject <List <Session> >(sharedPref.GetString("AllSessions", string.Empty));

            foreach (Session item in allSessions)
            {
                sessionStore.StoreSession(item.Name, item.DeviceID, item.array);
            }
            PreKeyStore              preKeyStore       = JsonConvert.DeserializeObject <InMemoryPreKeyStore>(sharedPref.GetString("PreKeyStore", string.Empty));
            SignedPreKeyStore        signedPreKeyStore = JsonConvert.DeserializeObject <InMemorySignedPreKeyStore>(sharedPref.GetString("SignedPreKeyStore", string.Empty));
            InMemoryIdentityKeyStore identityStore     = JsonConvert.DeserializeObject <InMemoryIdentityKeyStore>(sharedPref.GetString("IdentityStore", string.Empty));
            IdentityKeyPair          KeyPair           = new IdentityKeyPair(JsonConvert.DeserializeObject <byte[]>(sharedPref.GetString("IdentityKeyPair", string.Empty)));
            uint RegistrationID = Convert.ToUInt32(sharedPref.GetString("RegistrationId", string.Empty));

            identityStore.PutValues(KeyPair, RegistrationID);
            var allTrustedKeys = JsonConvert.DeserializeObject <List <TrustedKey> >(sharedPref.GetString("AllTrustedKeys", string.Empty));

            foreach (TrustedKey item in allTrustedKeys)
            {
                identityStore.SaveIdentity(item.Name, new IdentityKey(item.Identity, 0));
            }
            SignalProtocolAddress SelectedFriendAddress = new SignalProtocolAddress(SelectedFriend.RegisterationID.ToString(), 1);

            // Get the messages from the server
            base.OnCreate(bundle);
            TheirMessages = GetMessages(sharedPref, SelectedFriend, sessionStore, preKeyStore, signedPreKeyStore, identityStore, SelectedFriendAddress);
            // Set our view from the "ChatList" layout resource
            Title = SelectedFriend.Username;
            SetContentView(Resource.Layout.Message);
            listView = FindViewById <ListView>(Resource.Id.messageList);
            //***display FriendsListItem in ListView using Adapter
            listView.Adapter = adapter = new Adapter(this, TheirMessages, UserID);
            messageText      = FindViewById <EditText>(Resource.Id.messageText);
            sendButton       = FindViewById <Button>(Resource.Id.sendButton);

            // **implement messages sending and receiving here
            //listView.Adapter = adapter = new Adapter(this);

            sendButton.Click += (sender, e) =>
            {
                SessionCipher     sessionCipher = new SessionCipher(sessionStore, preKeyStore, signedPreKeyStore, identityStore, SelectedFriendAddress);
                CiphertextMessage cipherMessage = sessionCipher.encrypt(Encoding.UTF8.GetBytes(messageText.Text));
                SelectedFriend.SelectedUserMessages.Add(new Models.Message()
                {
                    MessageID = 1,
                    MessageReceiverRegisID = SelectedFriend.RegisterationID,
                    MessageSenderRegisID   = RegistrationID,
                    MessageText            = messageText.Text,
                    MessageTimestamp       = DateTime.Now
                });

                // Save stores in local Database
                ISharedPreferences       sharedprefs = PreferenceManager.GetDefaultSharedPreferences(this);
                ISharedPreferencesEditor editor      = sharedprefs.Edit();
                SelectedFriendMessageList.Clear();
                foreach (Models.Message m in SelectedFriend.SelectedUserMessages)
                {
                    SelectedFriendMessageList.Add(m);
                }
                editor.PutString("SelectedFriendMessageList", JsonConvert.SerializeObject(SelectedFriendMessageList));
                editor.PutString("SelectedFriend", JsonConvert.SerializeObject(SelectedFriend));
                editor.PutString("PreKeyStore", JsonConvert.SerializeObject(preKeyStore));
                editor.PutString("SignedPreKeyStore", JsonConvert.SerializeObject(signedPreKeyStore));
                List <Session> AllSessions = sessionStore.GetAllSessions();
                editor.PutString("AllSessions", JsonConvert.SerializeObject(AllSessions));
                editor.PutString("SessionStore", JsonConvert.SerializeObject(sessionStore));
                editor.PutString("IdentityStore", JsonConvert.SerializeObject(identityStore));
                List <TrustedKey> AllTrustedKeys = identityStore.GetAllTrustedKeys();
                editor.PutString("AllTrustedKeys", JsonConvert.SerializeObject(AllTrustedKeys));
                editor.Apply();

                Models.Message message = new Models.Message();
                message.MessageID = 4;
                message.MessageReceiverRegisID = SelectedFriend.RegisterationID;
                message.MessageSenderRegisID   = Convert.ToUInt32(sharedPref.GetString("RegistrationId", string.Empty));
                message.MessageText            = JsonConvert.SerializeObject(cipherMessage.serialize());
                message.MessageTimestamp       = DateTime.Now;

                //  call SendMessage() to send the
                SendMessage(message);
                //  *display the messages in user's own screen using adapter (always display in MyMessageListItem).
                adapter.NotifyDataSetInvalidated();
                listView.SetSelection(adapter.Count);
            };
        }
        private void RunInteraction(SessionRecord aliceSessionRecord, SessionRecord bobSessionRecord)
        {
            ISignalProtocolStore aliceStore = new TestInMemorySignalProtocolStore();
            ISignalProtocolStore bobStore   = new TestInMemorySignalProtocolStore();

            aliceStore.StoreSession(new SignalProtocolAddress("+14159999999", 1), aliceSessionRecord);
            bobStore.StoreSession(new SignalProtocolAddress("+14158888888", 1), bobSessionRecord);

            SessionCipher aliceCipher = new SessionCipher(aliceStore, new SignalProtocolAddress("+14159999999", 1));
            SessionCipher bobCipher   = new SessionCipher(bobStore, new SignalProtocolAddress("+14158888888", 1));

            byte[]            alicePlaintext = Encoding.UTF8.GetBytes("This is a plaintext message.");
            CiphertextMessage message        = aliceCipher.Encrypt(alicePlaintext);

            byte[] bobPlaintext = bobCipher.Decrypt(new SignalMessage(message.Serialize()));

            CollectionAssert.AreEqual(alicePlaintext, bobPlaintext);

            byte[]            bobReply = Encoding.UTF8.GetBytes("This is a message from Bob.");
            CiphertextMessage reply    = bobCipher.Encrypt(bobReply);

            byte[] receivedReply = aliceCipher.Decrypt(new SignalMessage(reply.Serialize()));

            CollectionAssert.AreEqual(bobReply, receivedReply);

            List <CiphertextMessage> aliceCiphertextMessages = new List <CiphertextMessage>();
            List <byte[]>            alicePlaintextMessages  = new List <byte[]>();

            for (int i = 0; i < 50; i++)
            {
                alicePlaintextMessages.Add(Encoding.UTF8.GetBytes("смерть за смерть " + i));
                aliceCiphertextMessages.Add(aliceCipher.Encrypt(Encoding.UTF8.GetBytes("смерть за смерть " + i)));
            }

            ulong seed = DateUtil.CurrentTimeMillis();

            HelperMethods.Shuffle(aliceCiphertextMessages, new Random((int)seed));
            HelperMethods.Shuffle(alicePlaintextMessages, new Random((int)seed));

            for (int i = 0; i < aliceCiphertextMessages.Count / 2; i++)
            {
                byte[] receivedPlaintext = bobCipher.Decrypt(new SignalMessage(aliceCiphertextMessages[i].Serialize()));
                Assert.IsTrue(ByteUtil.IsEqual(receivedPlaintext, alicePlaintextMessages[i]));
            }

            List <CiphertextMessage> bobCiphertextMessages = new List <CiphertextMessage>();
            List <byte[]>            bobPlaintextMessages  = new List <byte[]>();

            for (int i = 0; i < 20; i++)
            {
                bobPlaintextMessages.Add(Encoding.UTF8.GetBytes("смерть за смерть " + i));
                bobCiphertextMessages.Add(bobCipher.Encrypt(Encoding.UTF8.GetBytes("смерть за смерть " + i)));
            }

            seed = DateUtil.CurrentTimeMillis();

            HelperMethods.Shuffle(bobCiphertextMessages, new Random((int)seed));
            HelperMethods.Shuffle(bobPlaintextMessages, new Random((int)seed));

            for (int i = 0; i < bobCiphertextMessages.Count / 2; i++)
            {
                byte[] receivedPlaintext = aliceCipher.Decrypt(new SignalMessage(bobCiphertextMessages[i].Serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]);
            }

            for (int i = aliceCiphertextMessages.Count / 2; i < aliceCiphertextMessages.Count; i++)
            {
                byte[] receivedPlaintext = bobCipher.Decrypt(new SignalMessage(aliceCiphertextMessages[i].Serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, alicePlaintextMessages[i]);
            }

            for (int i = bobCiphertextMessages.Count / 2; i < bobCiphertextMessages.Count; i++)
            {
                byte[] receivedPlaintext = aliceCipher.Decrypt(new SignalMessage(bobCiphertextMessages[i].Serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]);
            }
        }