Beispiel #1
0
        public void Test_OmemoKeyExchangeMessage()
        {
            Random rand = new Random();

            byte[] hmac = new byte[16];
            rand.NextBytes(hmac);
            byte[] sessionKey = new byte[32];
            rand.NextBytes(sessionKey);

            IdentityKeyPairModel identityKey     = KeyHelper.GenerateIdentityKeyPair();
            SignedPreKeyModel    signedPreKey    = KeyHelper.GenerateSignedPreKey(0, identityKey.privKey);
            OmemoSessionModel    refOmemoSession = new OmemoSessionModel(new Bundle()
            {
                identityKey     = identityKey.pubKey,
                preKeys         = KeyHelper.GeneratePreKeys(0, 10),
                preKeySignature = signedPreKey.signature,
                signedPreKey    = signedPreKey.preKey.pubKey,
                signedPreKeyId  = signedPreKey.preKey.keyId
            }, 0, KeyHelper.GenerateIdentityKeyPair())
            {
                ek = KeyHelper.GenerateKeyPair().pubKey
            };
            OmemoMessage refOmemoMessage = new OmemoMessage(refOmemoSession);
            OmemoAuthenticatedMessage refOmemoAuthenticatedMessage = new OmemoAuthenticatedMessage(new byte[16], refOmemoMessage.ToByteArray());
            OmemoKeyExchangeMessage   refOmemoKeyExchangeMessage   = new OmemoKeyExchangeMessage((uint)rand.Next(), (uint)rand.Next(), KeyHelper.GenerateKeyPair().pubKey, KeyHelper.GenerateKeyPair().pubKey, refOmemoAuthenticatedMessage);

            byte[] data = refOmemoKeyExchangeMessage.ToByteArray();
            Assert.IsTrue(data.Length > 0);

            OmemoKeyExchangeMessage omemoKeyExchangeMessage = new OmemoKeyExchangeMessage(data);

            Assert.IsTrue(omemoKeyExchangeMessage.Equals(refOmemoKeyExchangeMessage));
        }
Beispiel #2
0
        public void Test_OmemoBundleInformation()
        {
            IdentityKeyPairModel bobIdentKey     = KeyHelper.GenerateIdentityKeyPair();
            List <PreKeyModel>   bobPreKeys      = KeyHelper.GeneratePreKeys(0, 100);
            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
            };
            string bundleInfo = GetBobsBundleInfoMsg(bobBundle);

            MessageParser2         parser   = new MessageParser2();
            List <AbstractMessage> messages = parser.parseMessages(ref bundleInfo);

            // Check if message parsed successfully:
            Assert.IsTrue(messages.Count == 1);
            Assert.IsInstanceOfType(messages[0], typeof(OmemoBundleInformationResultMessage));

            OmemoBundleInformationResultMessage bundleInfoMsg = messages[0] as OmemoBundleInformationResultMessage;

            // Check if keys match:
            Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.identityKey.Equals(bobIdentKey.pubKey));
            Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.preKeys.SequenceEqual(bobPreKeys.Select(key => new PreKeyModel(null, key.pubKey, key.keyId)).ToList()));
            Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.preKeySignature.SequenceEqual(bobSignedPreKey.signature));
            Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.signedPreKey.Equals(bobSignedPreKey.preKey.pubKey));
            Assert.IsTrue(bundleInfoMsg.BUNDLE_INFO.bundle.signedPreKeyId == bobSignedPreKey.preKey.keyId);
        }
Beispiel #3
0
        public void Test_PreKeyGeneration()
        {
            for (uint count = 0; count < 250; count++)
            {
                List <PreKeyModel> keys = KeyHelper.GeneratePreKeys(1, count);
                Assert.AreEqual(keys.Count, (int)count);
            }

            // Rollover:
            for (uint count = 0; count < 10; count++)
            {
                List <PreKeyModel> keys = KeyHelper.GeneratePreKeys(0x7FFFFFFF, count);
                Assert.AreEqual(keys.Count, (int)count);
            }

            for (uint count = 0; count < 10; count++)
            {
                List <PreKeyModel> keys = KeyHelper.GeneratePreKeys(0x7FFFFFFF - count, 100);
                Assert.AreEqual(keys.Count, 100);
            }

            // Key IDs are unique:
            List <uint>        ids   = new List <uint>();
            List <PreKeyModel> keys2 = KeyHelper.GeneratePreKeys(0x7FFFFFFF - 100, 1000);

            for (int i = 0; i < keys2.Count; i++)
            {
                Assert.IsFalse(ids.Contains(keys2[i].keyId));
                ids.Add(keys2[i].keyId);
            }
        }
Beispiel #4
0
        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));
        }
        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));
            }
        }