/// <summary> /// Encrypts the message and prepares everything for sending it. /// </summary> /// <param name="sid">The device ID of the sender.</param> /// <param name="senderIdentityKey">The identity key pair of the sender.</param> /// <param name="storage">An instance of the <see cref="IOmemoStorage"/> interface.</param> /// <param name="devices">A collection of <see cref="OmemoDeviceGroup"/>s the message should be encrypted for.</param> public void encrypt(uint sid, IdentityKeyPairModel senderIdentityKey, IOmemoStorage storage, List <OmemoDeviceGroup> devices) { try { SID = sid; if (IS_PURE_KEY_EXCHANGE_MESSAGE) { // Encrypt 32 zero bytes as dummy data for devices: DoubleRachet rachet = new DoubleRachet(senderIdentityKey); keys = rachet.EncryptKeyHmacForDevices(new byte[32], devices).Select(x => new OmemoKeys(x.Item1, x.Item2.Select(x => new OmemoKey(x)).ToList())).ToList(); } else { XElement contentNode = generateEnvelope(); byte[] contentData = Encoding.UTF8.GetBytes(contentNode.ToString()); // Encrypt message: DoubleRachet rachet = new DoubleRachet(senderIdentityKey); Tuple <byte[], byte[]> encrypted = rachet.EncryptMessasge(contentData); BASE_64_PAYLOAD = Convert.ToBase64String(encrypted.Item1); // Encrypt key || HMAC for devices: keys = rachet.EncryptKeyHmacForDevices(encrypted.Item2, devices).Select(x => new OmemoKeys(x.Item1, x.Item2.Select(x => new OmemoKey(x)).ToList())).ToList(); } // Store all sessions: foreach (OmemoDeviceGroup group in devices) { foreach (KeyValuePair <uint, OmemoSessionModel> device in group.SESSIONS) { // Only store sessions in case encryption for this device was successful: if (!(keys.Where(k => string.Equals(k.BARE_JID, group.BARE_JID)).FirstOrDefault()?.KEYS.Where(k => k.DEVICE_ID == device.Key).FirstOrDefault() is null)) { storage.StoreSession(new OmemoProtocolAddress(group.BARE_JID, device.Key), device.Value); } } } ENCRYPTED = true; } catch (Exception e) { if (e is OmemoException) { throw e; } throw new OmemoException("Failed to encrypt.", e); } }
public void Test_Omemo_Send_Receive_Send() { // Generate Alices keys: IdentityKeyPairModel aliceIdentKey = KeyHelper.GenerateIdentityKeyPair(); List <PreKeyModel> alicePreKeys = KeyHelper.GeneratePreKeys(0, 1); SignedPreKeyModel aliceSignedPreKey = KeyHelper.GenerateSignedPreKey(0, aliceIdentKey.privKey); Bundle aliceBundle = new Bundle() { identityKey = aliceIdentKey.pubKey, preKeys = alicePreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList(), preKeySignature = aliceSignedPreKey.signature, signedPreKey = aliceSignedPreKey.preKey.pubKey, signedPreKeyId = aliceSignedPreKey.preKey.keyId }; InMemmoryOmemoStorage aliceStorage = new InMemmoryOmemoStorage(); DoubleRachet aliceRachet = new DoubleRachet(aliceIdentKey); // Generate Bobs keys: IdentityKeyPairModel bobIdentKey = KeyHelper.GenerateIdentityKeyPair(); List <PreKeyModel> bobPreKeys = KeyHelper.GeneratePreKeys(0, 1); SignedPreKeyModel bobSignedPreKey = KeyHelper.GenerateSignedPreKey(0, bobIdentKey.privKey); Bundle bobBundle = new Bundle() { identityKey = bobIdentKey.pubKey, preKeys = bobPreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList(), preKeySignature = bobSignedPreKey.signature, signedPreKey = bobSignedPreKey.preKey.pubKey, signedPreKeyId = bobSignedPreKey.preKey.keyId }; InMemmoryOmemoStorage bobStorage = new InMemmoryOmemoStorage(); DoubleRachet bobRachet = new DoubleRachet(bobIdentKey); //-----------------OMEOMO Session Building:----------------- MessageParser2 parser = new MessageParser2(); string deviceListMsg = GetBobsDeviceListMsg(); 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.DEVICE_ID); // Alice builds a session to Bob: string bundleInfoMsg = GetBobsBundleInfoMsg(bobBundle); 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.BUNDLE_INFO.deviceId == BOB_ADDRESS.DEVICE_ID); aliceStorage.StoreFingerprint(new OmemoFingerprint(bobBundle.identityKey, BOB_ADDRESS)); // Encrypt Message 1: string msg1 = "Hello OMEMO"; OmemoEncryptedMessage omemoEncryptedMessage = new OmemoEncryptedMessage(ALICE_ADDRESS.BARE_JID, BOB_ADDRESS.BARE_JID, msg1, MessageMessage.TYPE_CHAT, false); List <OmemoDeviceGroup> bobDevices = new List <OmemoDeviceGroup>(); OmemoDeviceGroup bobDeviceGroup = new OmemoDeviceGroup(BOB_ADDRESS.BARE_JID); bobDeviceGroup.SESSIONS[BOB_ADDRESS.DEVICE_ID] = new OmemoSessionModel(bobBundle, 0, aliceIdentKey); bobDevices.Add(bobDeviceGroup); omemoEncryptedMessage.encrypt(ALICE_ADDRESS.DEVICE_ID, aliceIdentKey, aliceStorage, bobDevices); Assert.IsTrue(omemoEncryptedMessage.ENCRYPTED); Assert.IsNotNull(aliceStorage.LoadFingerprint(BOB_ADDRESS)); Assert.IsNotNull(aliceStorage.LoadSession(BOB_ADDRESS)); // Decrypt Message 1: // Throws an exception in case something goes wrong: OmemoDecryptionContext decryptCtx1 = new OmemoDecryptionContext(BOB_ADDRESS, bobIdentKey, bobSignedPreKey, bobPreKeys, false, bobStorage); omemoEncryptedMessage.decrypt(decryptCtx1); Assert.AreEqual(msg1, omemoEncryptedMessage.MESSAGE); Assert.IsFalse(omemoEncryptedMessage.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsFalse(omemoEncryptedMessage.ENCRYPTED); Assert.IsNotNull(bobStorage.LoadFingerprint(ALICE_ADDRESS)); Assert.IsNotNull(bobStorage.LoadSession(ALICE_ADDRESS)); // Encrypt Message 2: string msg2 = "Hello OMEMO 2"; OmemoEncryptedMessage omemoEncryptedMessage2 = new OmemoEncryptedMessage(BOB_ADDRESS.BARE_JID, ALICE_ADDRESS.BARE_JID, msg2, MessageMessage.TYPE_CHAT, false); List <OmemoDeviceGroup> aliceDevices = new List <OmemoDeviceGroup>(); OmemoDeviceGroup aliceDeviceGroup = new OmemoDeviceGroup(ALICE_ADDRESS.BARE_JID); aliceDeviceGroup.SESSIONS[ALICE_ADDRESS.DEVICE_ID] = bobStorage.LoadSession(ALICE_ADDRESS); aliceDevices.Add(aliceDeviceGroup); omemoEncryptedMessage2.encrypt(BOB_ADDRESS.DEVICE_ID, bobIdentKey, bobStorage, aliceDevices); Assert.IsTrue(omemoEncryptedMessage2.ENCRYPTED); // Decrypt Message 2: // Throws an exception in case something goes wrong: OmemoDecryptionContext decryptCtx2 = new OmemoDecryptionContext(ALICE_ADDRESS, aliceIdentKey, aliceSignedPreKey, alicePreKeys, false, aliceStorage); omemoEncryptedMessage2.decrypt(decryptCtx2); Assert.AreEqual(msg2, omemoEncryptedMessage2.MESSAGE); Assert.IsFalse(omemoEncryptedMessage2.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsFalse(omemoEncryptedMessage2.ENCRYPTED); // Encrypt Message 3: string msg3 = "Hello OMEMO 3"; OmemoEncryptedMessage omemoEncryptedMessage3 = new OmemoEncryptedMessage(ALICE_ADDRESS.BARE_JID, BOB_ADDRESS.BARE_JID, msg3, MessageMessage.TYPE_CHAT, false); bobDeviceGroup.SESSIONS[BOB_ADDRESS.DEVICE_ID] = aliceStorage.LoadSession(BOB_ADDRESS); omemoEncryptedMessage3.encrypt(ALICE_ADDRESS.DEVICE_ID, aliceIdentKey, aliceStorage, bobDevices); Assert.IsFalse(omemoEncryptedMessage3.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsTrue(omemoEncryptedMessage3.ENCRYPTED); Assert.IsNotNull(aliceStorage.LoadFingerprint(BOB_ADDRESS)); Assert.IsNotNull(aliceStorage.LoadSession(BOB_ADDRESS)); // Decrypt Message 3: // Throws an exception in case something goes wrong: OmemoDecryptionContext decryptCtx3 = new OmemoDecryptionContext(BOB_ADDRESS, bobIdentKey, bobSignedPreKey, bobPreKeys, false, bobStorage); omemoEncryptedMessage3.decrypt(decryptCtx3); Assert.AreEqual(msg3, omemoEncryptedMessage3.MESSAGE); Assert.IsFalse(omemoEncryptedMessage3.IS_PURE_KEY_EXCHANGE_MESSAGE); Assert.IsFalse(omemoEncryptedMessage3.ENCRYPTED); Assert.IsNotNull(bobStorage.LoadFingerprint(ALICE_ADDRESS)); Assert.IsNotNull(bobStorage.LoadSession(ALICE_ADDRESS)); }