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));
        }
示例#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.");
                }
示例#3
0
        public OmemoFingerprint toOmemoFingerprint()
        {
            SignalProtocolAddress address = new SignalProtocolAddress(bareJid, deviceId);
            ECPublicKey           pubKey  = Curve.decodePoint(identityPubKey, 0);

            return(new OmemoFingerprint(pubKey, address, lastSeen, trusted));
        }
        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));
        }
示例#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);
        }
示例#6
0
        public bool IsTrustedIdentity(SignalProtocolAddress address, IdentityKey identityKey, Direction direction)
        {
            IdentityKey trusted;

            trustedKeys.TryGetValue(address, out trusted); // get(name)
            return(trusted == null || trusted.Equals(identityKey));
        }
示例#7
0
        public static SessionRecord LoadSession(SignalProtocolAddress address)
        {
            string        index = GetSessionCacheIndex(address.Name, address.DeviceId);
            SessionRecord record;

            lock (DBLock)
            {
                if (SessionsCache.TryGetValue(index, out record))
                {
                    return(record);
                }
                using (var ctx = new LibsignalDBContext())
                {
                    var session = ctx.Sessions
                                  .Where(s => s.Username == address.Name && s.DeviceId == address.DeviceId)
                                  .AsNoTracking()
                                  .SingleOrDefault();
                    if (session != null)
                    {
                        record = new SessionRecord(Base64.decode(session.Session));
                    }
                    else
                    {
                        record = new SessionRecord();
                    }
                    SessionsCache[index] = record;
                    return(record);
                }
            }
        }
示例#8
0
 public static void SaveIdentityLocked(SignalProtocolAddress address, string identity)
 {
     lock (DBLock)
     {
         using (var ctx = new LibsignalDBContext())
         {
             var old = ctx.Identities
                       .Where(i => i.Username == address.Name)
                       .FirstOrDefault(); //could contain stale data
             if (old == null)
             {
                 ctx.Identities.Add(new SignalIdentity()
                 {
                     IdentityKey    = identity,
                     Username       = address.Name,
                     VerifiedStatus = VerifiedStatus.Default
                 });
             }
             else if (old.IdentityKey != identity)
             {
                 if (old.VerifiedStatus == VerifiedStatus.Verified)
                 {
                     old.VerifiedStatus = VerifiedStatus.Unverified;
                 }
                 old.IdentityKey = identity;
                 var childSessions = ctx.Sessions
                                     .Where(s => s.Username == address.Name && s.DeviceId != address.DeviceId);
                 ctx.Sessions.RemoveRange(childSessions);
                 var messages = InsertIdentityChangedMessages(address.Name);
                 SignalLibHandle.Instance.DispatchHandleIdentityKeyChange(messages);
             }
             ctx.SaveChanges();
         }
     }
 }
示例#9
0
 //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
 #region --Constructors--
 public OmemoFingerprint(ECPublicKey identityPubKey, SignalProtocolAddress address, DateTime lastSeen, bool trusted)
 {
     IDENTITY_PUB_KEY = identityPubKey;
     ADDRESS          = address;
     this.lastSeen    = lastSeen;
     this.trusted     = trusted;
 }
示例#10
0
        public static void StoreSession(SignalProtocolAddress address, SessionRecord record)
        {
            string index = GetSessionCacheIndex(address.Name, address.DeviceId);

            lock (DBLock)
            {
                using (var ctx = new LibsignalDBContext())
                {
                    var session = ctx.Sessions
                                  .Where(s => s.DeviceId == address.DeviceId && s.Username == address.Name)
                                  .SingleOrDefault();
                    if (session != null)
                    {
                        session.Session = Base64.encodeBytes(record.serialize());
                    }
                    else
                    {
                        ctx.Sessions.Add(new SignalSession()
                        {
                            DeviceId = address.DeviceId,
                            Session  = Base64.encodeBytes(record.serialize()),
                            Username = address.Name
                        });
                    }
                    SessionsCache[index] = record;
                    ctx.SaveChanges();
                }
            }
        }
示例#11
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();
 }
        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));
            }
        }
示例#13
0
        public OmemoFingerprint getFingerprint(SignalProtocolAddress address, string accountId)
        {
            string chatId = ChatTable.generateId(address.getName(), accountId);
            string id     = OmemoFingerprintTable.generateId(chatId, address);
            List <OmemoFingerprintTable> list = dB.Query <OmemoFingerprintTable>(true, "SELECT * FROM " + DBTableConsts.OMEMO_FINGERPRINT_TABLE + " WHERE id = ?;", id);

            return(list.Count <= 0 ? null : list[0].toOmemoFingerprint());
        }
        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);
        }
示例#15
0
        public SignalProtocolAddress newSession(string chatJid, uint recipientDeviceId, PreKeyBundle recipientPreKey)
        {
            SignalProtocolAddress address = new SignalProtocolAddress(chatJid, recipientDeviceId);
            SessionBuilder        builder = new SessionBuilder(OMEMO_STORE, address);

            builder.process(recipientPreKey);
            return(address);
        }
 //--------------------------------------------------------Misc Methods:---------------------------------------------------------------\\
 #region --Misc Methods (Public)--
 public SessionRecord LoadSession(SignalProtocolAddress address)
 {
     if (ContainsSession(address))
     {
         return(SESSIONS[address]);
     }
     return(new SessionRecord());
 }
示例#17
0
        public SignalProtocolAddress newSession(string chatJid, uint recipientDeviceId, PreKeyBundle recipientPreKey)
        {
            SignalProtocolAddress address = new SignalProtocolAddress(chatJid, recipientDeviceId);
            SessionBuilder        builder = new SessionBuilder(SESSION_STORE, PRE_KEY_STORE, SIGNED_PRE_KEY_STORE, IDENTITY_STORE, address);

            builder.process(recipientPreKey);
            return(address);
        }
示例#18
0
        public SessionRecord getSession(SignalProtocolAddress address, string accountId)
        {
            List <SessionStoreTable> list = dB.Query <SessionStoreTable>(true, "SELECT * FROM " + DBTableConsts.SESSION_STORE_TABLE + " WHERE id = ?;", SessionStoreTable.generateId(address, accountId));

            if (list.Count <= 0)
            {
                return(null);
            }
            return(new SessionRecord(list[0].session));
        }
        private async Task <OutgoingPushMessage> GetEncryptedMessage(CancellationToken token,
                                                                     PushServiceSocket socket,
                                                                     SignalServiceAddress recipient,
                                                                     UnidentifiedAccess?unidentifiedAccess,
                                                                     uint deviceId,
                                                                     byte[] plaintext)
        {
            SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(recipient.E164number, deviceId);
            SignalServiceCipher   cipher = new SignalServiceCipher(LocalAddress, Store, null);

            if (!Store.ContainsSession(signalProtocolAddress))
            {
                try
                {
                    List <PreKeyBundle> preKeys = await socket.GetPreKeys(token, recipient, unidentifiedAccess, deviceId);

                    foreach (PreKeyBundle preKey in preKeys)
                    {
                        if (CredentialsProvider.User.Equals(recipient.E164number) && CredentialsProvider.DeviceId == preKey.getDeviceId())
                        {
                            continue;
                        }
                        try
                        {
                            SignalProtocolAddress preKeyAddress  = new SignalProtocolAddress(recipient.E164number, preKey.getDeviceId());
                            SessionBuilder        sessionBuilder = new SessionBuilder(Store, preKeyAddress);
                            sessionBuilder.process(preKey);
                        }
                        catch (libsignal.exceptions.UntrustedIdentityException)
                        {
                            throw new UntrustedIdentityException("Untrusted identity key!", recipient.E164number, preKey.getIdentityKey());
                        }
                    }

                    if (EventListener != null)
                    {
                        EventListener.OnSecurityEvent(recipient);
                    }
                }
                catch (InvalidKeyException e)
                {
                    throw new Exception(e.Message);
                }
            }

            try
            {
                return(cipher.Encrypt(signalProtocolAddress, unidentifiedAccess, plaintext));
            }
            catch (libsignal.exceptions.UntrustedIdentityException e)
            {
                throw new UntrustedIdentityException("Untrusted on send", e.getName(), e.getUntrustedIdentity());
            }
        }
示例#20
0
        public SessionRecord LoadSession(SignalProtocolAddress address)
        {
            SessionRecord session = OmemoSignalKeyDBManager.INSTANCE.getSession(address, ACCOUNT.getBareJid());

            if (session is null)
            {
                Logger.Warn("No existing libsignal session found for: " + address.ToString());
                session = new SessionRecord();
            }
            return(session);
        }
示例#21
0
        public SessionRecord LoadSession(SignalProtocolAddress address)
        {
            SessionRecord session = SignalKeyDBManager.INSTANCE.getSession(address, ACCOUNT.getIdAndDomain());

            if (session == null)
            {
                Logger.Warn("No existing session information found.");
                session = new SessionRecord();
            }
            return(session);
        }
示例#22
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()
     });
 }
 internal static IdentityKey GetIdentityKey(SignalProtocolAddress address)
 {
     lock (DBLock)
     {
         using (var ctx = new LibsignalDBContext())
         {
             return(new IdentityKey(Base64.Decode(ctx.Identities
                                                  .Where(identity => identity.Username == address.Name)
                                                  .Single().IdentityKey), 0));
         }
     }
 }
        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;
        }
示例#25
0
 public static bool ContainsSession(SignalProtocolAddress address)
 {
     lock (DBLock)
     {
         using (var ctx = new LibsignalDBContext())
         {
             var session = ctx.Sessions
                           .Where(s => s.Username == address.Name && s.DeviceId == address.DeviceId)
                           .SingleOrDefault();
             return(session != null);
         }
     }
 }
示例#26
0
        private byte[] Decrypt(UnidentifiedSenderMessageContent message)
        {
            SignalProtocolAddress sender = new SignalProtocolAddress(message.SenderCertificate.Sender, (uint)message.SenderCertificate.SenderDeviceId);

            switch ((uint)message.Type)
            {
            case CiphertextMessage.WHISPER_TYPE: return(new SessionCipher(SignalProtocolStore, sender).decrypt(new SignalMessage(message.Content)));

            case CiphertextMessage.PREKEY_TYPE: return(new SessionCipher(SignalProtocolStore, sender).decrypt(new PreKeySignalMessage(message.Content)));

            default: throw new InvalidMessageException("Unknown type: " + message.Type);
            }
        }
示例#27
0
 //--------------------------------------------------------Constructor:----------------------------------------------------------------\\
 #region --Constructors--
 /// <summary>
 /// Basic Constructor
 /// </summary>
 /// <history>
 /// 10/08/2018 Created [Fabian Sauter]
 /// </history>
 internal OmemoSessionBuildHelper(string chatJid, string bareAccountJid, string fullAccountJid, Action <OmemoSessionBuildHelper, OmemoSessionBuildResult> onSessionResult, XMPPConnection2 connection, OmemoHelper omemoHelper)
 {
     this.CONNECTION              = connection;
     this.ON_SESSION_RESULT       = onSessionResult;
     this.CHAT_JID                = chatJid;
     this.BARE_ACCOUNT_JID        = bareAccountJid;
     this.FULL_ACCOUNT_JID        = fullAccountJid;
     this.OMEMO_HELPER            = omemoHelper;
     this.STATE                   = OmemoSessionBuildHelperState.NOT_STARTED;
     this.requestDeviceListHelper = null;
     this.requestBundleInfoHelper = null;
     this.SESSION                 = new OmemoSession(chatJid);
     this.curAddress              = null;
 }
示例#28
0
 /// <summary>
 /// Validates if the given identity public key should be trusted.
 /// </summary>
 /// <param name="address">The signal protocol address corresponding to the given public identity key.</param>
 /// <param name="publicKey">The public identity key we want to validate.</param>
 /// <param name="omemoStore">The OMEMO store that keeps all OMEMO related keys.</param>
 /// <returns>True if we trust else false.</returns>
 private Task <bool> isFingerprintTrustedAsync(SignalProtocolAddress address, ECPublicKey publicKey, IOmemoStore omemoStore)
 {
     return(Task.Run(() =>
     {
         OmemoFingerprint fingerprint = omemoStore.LoadFingerprint(address);
         if (!(fingerprint is null))
         {
             if (!fingerprint.checkIdentityKey(publicKey))
             {
                 Logger.Warn("Received not OMEMO encrypted message with a not matching public identity key from: " + address.ToString());
                 return false;
             }
             fingerprint.lastSeen = DateTime.Now;
         }
 public static void DeleteSession(SignalProtocolAddress address)
 {
     lock (DBLock)
     {
         string index = GetSessionCacheIndex(address.Name, address.DeviceId);
         SessionsCache.Remove(index);
         using (var ctx = new LibsignalDBContext())
         {
             var sessions = ctx.Sessions
                            .Where(s => s.Username == address.Name && s.DeviceId == address.DeviceId);
             ctx.Sessions.RemoveRange(sessions);
             ctx.SaveChanges();
         }
     }
 }
        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());
            }
        }