Esempio n. 1
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.");
                }
Esempio n. 2
0
 public OmemoDeviceTable(SignalProtocolAddress device, string accountId)
 {
     this.id        = generateId(accountId, device.getName(), device.getDeviceId());
     this.accountId = accountId;
     this.name      = device.getName();
     this.deviceId  = device.getDeviceId();
 }
Esempio n. 3
0
        private void requestBundleInformation()
        {
            setState(OmemoSessionBuildHelperState.REQUESTING_BUNDLE_INFORMATION);
            if (requestBundleInfoHelper != null)
            {
                requestBundleInfoHelper?.Dispose();
                requestBundleInfoHelper = null;
            }

            requestBundleInfoHelper = new MessageResponseHelper <IQMessage>(CONNECTION, onRequestBundleInformationMessage, onTimeout);
            OmemoRequestBundleInformationMessage msg = new OmemoRequestBundleInformationMessage(FULL_ACCOUNT_JID, curAddress.getName(), curAddress.getDeviceId());

            requestBundleInfoHelper.start(msg);
        }
Esempio n. 4
0
        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.PREKEY_BUNDLE; 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.getDeviceId(),
                                           remoteRegistrationId,
                                           legacy ? body : null,
                                           legacy ? null : body,
                                           silent));
        }
        public bool ContainsSession(SignalProtocolAddress address)
        {
            var name     = address.getName();
            var deviceId = address.getDeviceId();
            var query    = conn.Table <Session>().Where(v => v.Name == name && v.DeviceId == deviceId);

            return(query.Count() != 0);
        }
Esempio n. 6
0
 public void setSession(SignalProtocolAddress address, SessionRecord record, string accountId)
 {
     dB.InsertOrReplace(new SessionStoreTable()
     {
         id        = SessionStoreTable.generateId(address, accountId),
         accountId = accountId,
         deviceId  = address.getDeviceId(),
         name      = address.getName(),
         session   = record.serialize()
     });
 }
        public void StoreSession(SignalProtocolAddress address, SessionRecord record)
        {
            DeleteSession(address); // TODO: sqlite-net combined private keys for insertOrReplace

            var session = new Session()
            {
                DeviceId = address.getDeviceId(), Name = address.getName(), Record = record.serialize()
            };

            conn.InsertOrReplace(session);
            return;
        }
        public SessionRecord LoadSession(SignalProtocolAddress address)
        {
            var name     = address.getName();
            var deviceId = address.getDeviceId();
            var query    = conn.Table <Session>().Where(t => t.Name == name && t.DeviceId == deviceId);

            if (query != null && query.Any())
            {
                return(new SessionRecord(query.First().Record));
            }
            else
            {
                return(new SessionRecord());
            }
        }
 public void DeleteSession(SignalProtocolAddress address)
 {
     var name     = address.getName();
     var deviceId = address.getDeviceId();
     var query    = conn.Table <Session>().Delete(t => t.Name == name && t.DeviceId == deviceId);
 }
Esempio n. 10
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));
        }
Esempio n. 11
0
        //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
        #region --Set-, Get- Methods--


        #endregion
        //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
        #region --Misc Methods (Public)--
        public static string generateId(SignalProtocolAddress address, string accountId)
        {
            return(address.getName() + "_" + address.getDeviceId() + "_" + accountId);
        }
        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.");
                    }
                }
Esempio n. 13
0
        public void Test_Libsignal_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();

            // 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));
        }
Esempio n. 14
0
        //--------------------------------------------------------Set-, Get- Methods:---------------------------------------------------------\\
        #region --Set-, Get- Methods--


        #endregion
        //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
        #region --Misc Methods (Public)--
        public static string generateId(string chatId, SignalProtocolAddress address)
        {
            return(generateId(chatId, address.getName(), address.getDeviceId()));
        }
Esempio n. 15
0
 public String serialize()
 {
     return(groupId + "::" + sender.getName() + "::" + sender.getDeviceId());
 }
Esempio n. 16
0
 public int CompareTo(object obj)
 {
     return(ADDRESS.getName().GetHashCode() ^ ADDRESS.getDeviceId().GetHashCode());
 }