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."); }
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(); }
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); }
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); }
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); }
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)); }
//--------------------------------------------------------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."); } }
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)); }
//--------------------------------------------------------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())); }
public String serialize() { return(groupId + "::" + sender.getName() + "::" + sender.getDeviceId()); }
public int CompareTo(object obj) { return(ADDRESS.getName().GetHashCode() ^ ADDRESS.getDeviceId().GetHashCode()); }