public void testSimultaneousKeyExchange()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore   bobStore          = new TestInMemoryAxolotlStore();
            SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);

            KeyExchangeMessage aliceKeyExchange = aliceSessionBuilder.process();
            KeyExchangeMessage bobKeyExchange   = bobSessionBuilder.process();

            Assert.IsNotNull(aliceKeyExchange);
            Assert.IsNotNull(bobKeyExchange);

            KeyExchangeMessage aliceResponse = aliceSessionBuilder.process(bobKeyExchange);
            KeyExchangeMessage bobResponse   = bobSessionBuilder.process(aliceKeyExchange);

            Assert.IsNotNull(aliceResponse);
            Assert.IsNotNull(bobResponse);

            KeyExchangeMessage aliceAck = aliceSessionBuilder.process(bobResponse);
            KeyExchangeMessage bobAck   = bobSessionBuilder.process(aliceResponse);

            Assert.IsNull(aliceAck);
            Assert.IsNull(bobAck);

            runInteraction(aliceStore, bobStore);
        }
        public void testBadMessageBundle()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            aliceSessionBuilder.process(bobPreKey);

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageOne.getType());

            byte[] goodMessage = outgoingMessageOne.serialize();
            byte[] badMessage  = new byte[goodMessage.Length];
            Array.Copy(goodMessage, 0, badMessage, 0, badMessage.Length);

            badMessage[badMessage.Length - 10] ^= 0x01;

            PreKeyWhisperMessage incomingMessage  = new PreKeyWhisperMessage(badMessage);
            SessionCipher        bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = new byte[0];

            try
            {
                plaintext = bobSessionCipher.decrypt(incomingMessage);
                throw new Exception("Decrypt should have failed!");
            }
            catch (InvalidMessageException e)
            {
                // good.
            }

            Assert.IsTrue(bobStore.ContainsPreKey(31337));

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(goodMessage));

            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));
            Assert.IsFalse(bobStore.ContainsPreKey(31337));
        }
Exemple #3
0
        public void testSimultaneousInitiateLostMessage()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            AxolotlStore bobStore   = new TestInMemoryAxolotlStore();

            PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
            PreKeyBundle bobPreKeyBundle   = createBobPreKeyBundle(bobStore);

            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            SessionBuilder bobSessionBuilder   = new SessionBuilder(bobStore, ALICE_ADDRESS);

            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            SessionCipher bobSessionCipher   = new SessionCipher(bobStore, ALICE_ADDRESS);

            aliceSessionBuilder.process(bobPreKeyBundle);
            bobSessionBuilder.process(alicePreKeyBundle);

            CiphertextMessage messageForBob   = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("hey there"));
            CiphertextMessage messageForAlice = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("sample message"));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, messageForBob.getType());
            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, messageForAlice.getType());

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new PreKeyWhisperMessage(messageForAlice.serialize()));
            byte[] bobPlaintext   = bobSessionCipher.decrypt(new PreKeyWhisperMessage(messageForBob.serialize()));

            Assert.AreEqual("sample message", Encoding.UTF8.GetString(alicePlaintext));
            Assert.AreEqual("hey there", Encoding.UTF8.GetString(bobPlaintext));

            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage aliceResponse = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("second message"));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, aliceResponse.getType());

            //    byte[] responsePlaintext = bobSessionCipher.decrypt(new WhisperMessage(aliceResponse.serialize()));
            //
            //    assertTrue(new String(responsePlaintext).equals("second message"));
            //    assertTrue(isSessionIdEqual(aliceStore, bobStore));
            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage finalMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("third message"));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, finalMessage.getType());

            byte[] finalPlaintext = aliceSessionCipher.decrypt(new WhisperMessage(finalMessage.serialize()));

            Assert.AreEqual("third message", Encoding.UTF8.GetString(finalPlaintext));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));
        }
        public void testBasicSimultaneousInitiate()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            PreKeyBundle alicePreKeyBundle = createAlicePreKeyBundle(aliceStore);
            PreKeyBundle bobPreKeyBundle = createBobPreKeyBundle(bobStore);

            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);

            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            aliceSessionBuilder.process(bobPreKeyBundle);
            bobSessionBuilder.process(alicePreKeyBundle);

            CiphertextMessage messageForBob = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("hey there"));
            CiphertextMessage messageForAlice = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("sample message"));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, messageForBob.getType());
            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, messageForAlice.getType());

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new PreKeyWhisperMessage(messageForAlice.serialize()));
            byte[] bobPlaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(messageForBob.serialize()));

            Assert.AreEqual("sample message", Encoding.UTF8.GetString(alicePlaintext));
            Assert.AreEqual("hey there", Encoding.UTF8.GetString(bobPlaintext));

            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());

            Assert.IsFalse(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage aliceResponse = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes("second message"));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, aliceResponse.getType());

            byte[] responsePlaintext = bobSessionCipher.decrypt(new WhisperMessage(aliceResponse.serialize()));

            Assert.AreEqual("second message", Encoding.UTF8.GetString(responsePlaintext));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));

            CiphertextMessage finalMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes("third message"));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, finalMessage.getType());

            byte[] finalPlaintext = aliceSessionCipher.decrypt(new WhisperMessage(finalMessage.serialize()));

            Assert.AreEqual("third message", Encoding.UTF8.GetString(finalPlaintext));
            Assert.IsTrue(isSessionIdEqual(aliceStore, bobStore));
        }
        public void testRepeatBundleMessageV3()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            aliceSessionBuilder.process(bobPreKey);

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageOne.getType());
            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageTwo.getType());

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize());

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new WhisperMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            // The test

            PreKeyWhisperMessage incomingMessageTwo = new PreKeyWhisperMessage(outgoingMessageTwo.serialize());

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(incomingMessageTwo.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            alicePlaintext     = aliceSessionCipher.decrypt(new WhisperMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));
        }
        public void testOptionalOneTimePreKey()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      0, null,
                                                      22, bobSignedPreKeyPair.getPublicKey(),
                                                      bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage    = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(outgoingMessage.getType(), CiphertextMessage.PREKEY_TYPE);

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize());

            Assert.IsFalse(incomingMessage.getPreKeyId().HasValue);

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.IsNotNull(bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));
        }
        public void testBasicKeyExchange()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore   bobStore          = new TestInMemoryAxolotlStore();
            SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);

            KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();

            Assert.IsNotNull(aliceKeyExchangeMessage);

            byte[]             aliceKeyExchangeMessageBytes = aliceKeyExchangeMessage.serialize();
            KeyExchangeMessage bobKeyExchangeMessage        = bobSessionBuilder.process(new KeyExchangeMessage(aliceKeyExchangeMessageBytes));

            Assert.IsNotNull(bobKeyExchangeMessage);

            byte[]             bobKeyExchangeMessageBytes = bobKeyExchangeMessage.serialize();
            KeyExchangeMessage response = aliceSessionBuilder.process(new KeyExchangeMessage(bobKeyExchangeMessageBytes));

            Assert.IsNull(response);
            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));

            runInteraction(aliceStore, bobStore);

            aliceStore              = new TestInMemoryAxolotlStore();
            aliceSessionBuilder     = new SessionBuilder(aliceStore, BOB_ADDRESS);
            aliceKeyExchangeMessage = aliceSessionBuilder.process();

            try
            {
                bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
                throw new Exception("This identity shouldn't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), aliceKeyExchangeMessage.getIdentityKey());
                bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
            }

            Assert.IsNull(aliceSessionBuilder.process(bobKeyExchangeMessage));

            runInteraction(aliceStore, bobStore);
        }
        public void testBadSignedPreKeySignature()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            IdentityKeyStore bobIdentityKeyStore = new TestInMemoryIdentityKeyStore();

            ECKeyPair bobPreKeyPair       = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();

            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobIdentityKeyStore.GetIdentityKeyPair().getPrivateKey(),
                                                                       bobSignedPreKeyPair.getPublicKey().serialize());


            for (int i = 0; i < bobSignedPreKeySignature.Length * 8; i++)
            {
                byte[] modifiedSignature = new byte[bobSignedPreKeySignature.Length];
                Array.Copy(bobSignedPreKeySignature, 0, modifiedSignature, 0, modifiedSignature.Length);

                modifiedSignature[i / 8] ^= (byte)(0x01 << (i % 8));

                PreKeyBundle bobPreKey = new PreKeyBundle(bobIdentityKeyStore.GetLocalRegistrationId(), 1,
                                                          31337, bobPreKeyPair.getPublicKey(),
                                                          22, bobSignedPreKeyPair.getPublicKey(), modifiedSignature,
                                                          bobIdentityKeyStore.GetIdentityKeyPair().getPublicKey());

                try
                {
                    aliceSessionBuilder.process(bobPreKey);
                    throw new Exception("Accepted modified device key signature!");
                }
                catch (InvalidKeyException ike)
                {
                    // good
                }
            }

            PreKeyBundle bobPreKey2 = new PreKeyBundle(bobIdentityKeyStore.GetLocalRegistrationId(), 1,
                                                       31337, bobPreKeyPair.getPublicKey(),
                                                       22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                       bobIdentityKeyStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey2);
        }
Exemple #9
0
        public void testMessageKeyLimits()
        {
            SessionRecord aliceSessionRecord = new SessionRecord();
            SessionRecord bobSessionRecord   = new SessionRecord();

            initializeSessionsV3(aliceSessionRecord.getSessionState(), bobSessionRecord.getSessionState());

            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            AxolotlStore bobStore   = new TestInMemoryAxolotlStore();

            aliceStore.StoreSession(new AxolotlAddress("+14159999999", 1), aliceSessionRecord);
            bobStore.StoreSession(new AxolotlAddress("+14158888888", 1), bobSessionRecord);

            SessionCipher aliceCipher = new SessionCipher(aliceStore, new AxolotlAddress("+14159999999", 1));
            SessionCipher bobCipher   = new SessionCipher(bobStore, new AxolotlAddress("+14158888888", 1));

            List <CiphertextMessage> inflight = new List <CiphertextMessage>();

            for (int i = 0; i < 2010; i++)
            {
                inflight.Add(aliceCipher.encrypt(Encoding.UTF8.GetBytes("you've never been so hungry, you've never been so cold")));
            }

            bobCipher.decrypt(new WhisperMessage(inflight[1000].serialize()));
            bobCipher.decrypt(new WhisperMessage(inflight[inflight.Count - 1].serialize()));

            try
            {
                bobCipher.decrypt(new WhisperMessage(inflight[0].serialize()));
                throw new Exception("Should have failed!");
            }
            catch (DuplicateMessageException dme)
            {
                // good
            }
        }
        public void testOptionalOneTimePreKey()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();
            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                          bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      0, null,
                                                      22, bobSignedPreKeyPair.getPublicKey(),
                                                      bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)3, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String originalMessage = "L'homme est condamné à être libre";
            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(outgoingMessage.getType(), CiphertextMessage.PREKEY_TYPE);

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize());
            Assert.IsFalse(incomingMessage.getPreKeyId().HasValue);

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)3, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.IsNotNull(bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getAliceBaseKey());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));
        }
Exemple #11
0
        private void runInteraction(SessionRecord aliceSessionRecord, SessionRecord bobSessionRecord)
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            AxolotlStore bobStore   = new TestInMemoryAxolotlStore();

            aliceStore.StoreSession(new AxolotlAddress("+14159999999", 1), aliceSessionRecord);
            bobStore.StoreSession(new AxolotlAddress("+14158888888", 1), bobSessionRecord);

            SessionCipher aliceCipher = new SessionCipher(aliceStore, new AxolotlAddress("+14159999999", 1));
            SessionCipher bobCipher   = new SessionCipher(bobStore, new AxolotlAddress("+14158888888", 1));

            byte[]            alicePlaintext = Encoding.UTF8.GetBytes("This is a plaintext message.");
            CiphertextMessage message        = aliceCipher.encrypt(alicePlaintext);

            byte[] bobPlaintext = bobCipher.decrypt(new WhisperMessage(message.serialize()));

            CollectionAssert.AreEqual(alicePlaintext, bobPlaintext);

            byte[]            bobReply = Encoding.UTF8.GetBytes("This is a message from Bob.");
            CiphertextMessage reply    = bobCipher.encrypt(bobReply);

            byte[] receivedReply = aliceCipher.decrypt(new WhisperMessage(reply.serialize()));

            CollectionAssert.AreEqual(bobReply, receivedReply);

            List <CiphertextMessage> aliceCiphertextMessages = new List <CiphertextMessage>();
            List <byte[]>            alicePlaintextMessages  = new List <byte[]>();

            for (int i = 0; i < 50; i++)
            {
                alicePlaintextMessages.Add(Encoding.UTF8.GetBytes("смерть за смерть " + i));
                aliceCiphertextMessages.Add(aliceCipher.encrypt(Encoding.UTF8.GetBytes("смерть за смерть " + i)));
            }

            ulong seed = DateUtil.currentTimeMillis();

            Shuffle(aliceCiphertextMessages, new Random((int)seed));
            Shuffle(alicePlaintextMessages, new Random((int)seed));

            for (int i = 0; i < aliceCiphertextMessages.Count / 2; i++)
            {
                byte[] receivedPlaintext = bobCipher.decrypt(new WhisperMessage(aliceCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, alicePlaintextMessages[i]);
            }

            List <CiphertextMessage> bobCiphertextMessages = new List <CiphertextMessage>();
            List <byte[]>            bobPlaintextMessages  = new List <byte[]>();

            for (int i = 0; i < 20; i++)
            {
                bobPlaintextMessages.Add(Encoding.UTF8.GetBytes("смерть за смерть " + i));
                bobCiphertextMessages.Add(bobCipher.encrypt(Encoding.UTF8.GetBytes("смерть за смерть " + i)));
            }

            seed = DateUtil.currentTimeMillis();

            Shuffle(bobCiphertextMessages, new Random((int)seed));
            Shuffle(bobPlaintextMessages, new Random((int)seed));

            for (int i = 0; i < bobCiphertextMessages.Count / 2; i++)
            {
                byte[] receivedPlaintext = aliceCipher.decrypt(new WhisperMessage(bobCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]);
            }

            for (int i = aliceCiphertextMessages.Count / 2; i < aliceCiphertextMessages.Count; i++)
            {
                byte[] receivedPlaintext = bobCipher.decrypt(new WhisperMessage(aliceCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, alicePlaintextMessages[i]);
            }

            for (int i = bobCiphertextMessages.Count / 2; i < bobCiphertextMessages.Count; i++)
            {
                byte[] receivedPlaintext = aliceCipher.decrypt(new WhisperMessage(bobCiphertextMessages[i].serialize()));
                CollectionAssert.AreEqual(receivedPlaintext, bobPlaintextMessages[i]);
            }
        }
        public void testBadSignedPreKeySignature()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            IdentityKeyStore bobIdentityKeyStore = new TestInMemoryIdentityKeyStore();

            ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();
            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobIdentityKeyStore.GetIdentityKeyPair().getPrivateKey(),
                                                                          bobSignedPreKeyPair.getPublicKey().serialize());


            for (int i = 0; i < bobSignedPreKeySignature.Length * 8; i++)
            {
                byte[] modifiedSignature = new byte[bobSignedPreKeySignature.Length];
                Array.Copy(bobSignedPreKeySignature, 0, modifiedSignature, 0, modifiedSignature.Length);

                modifiedSignature[i / 8] ^= (byte)(0x01 << (i % 8));

                PreKeyBundle bobPreKey = new PreKeyBundle(bobIdentityKeyStore.GetLocalRegistrationId(), 1,
                                                          31337, bobPreKeyPair.getPublicKey(),
                                                          22, bobSignedPreKeyPair.getPublicKey(), modifiedSignature,
                                                          bobIdentityKeyStore.GetIdentityKeyPair().getPublicKey());
                
                try
                {
                    aliceSessionBuilder.process(bobPreKey);
                    throw new Exception("Accepted modified device key signature!");
                }
                catch (InvalidKeyException ike)
                {
                    // good
                }
            }

            PreKeyBundle bobPreKey2 = new PreKeyBundle(bobIdentityKeyStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobIdentityKeyStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey2);
        }
        public void testBasicPreKeyV2()
        {
            AxolotlStore   aliceStore          = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore      = new TestInMemoryAxolotlStore();
            ECKeyPair    bobPreKeyPair = Curve.generateKeyPair();
            PreKeyBundle bobPreKey     = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                          31337, bobPreKeyPair.getPublicKey(),
                                                          0, null, null,
                                                          bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)2, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String            originalMessage    = "L'homme est condamné à être libre";
            SessionCipher     aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage    = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessage.getType());

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)2, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, bobOutgoingMessage.getType());

            byte[] alicePlaintext = aliceSessionCipher.decrypt((WhisperMessage)bobOutgoingMessage);
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            runInteraction(aliceStore, bobStore);

            aliceStore          = new TestInMemoryAxolotlStore();
            aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            aliceSessionCipher  = new SessionCipher(aliceStore, BOB_ADDRESS);

            bobPreKeyPair = Curve.generateKeyPair();
            bobPreKey     = new PreKeyBundle(bobStore.GetLocalRegistrationId(),
                                             1, 31338, bobPreKeyPair.getPublicKey(),
                                             0, null, null, bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31338, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            aliceSessionBuilder.process(bobPreKey);

            outgoingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            try
            {
                bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
                throw new Exception("shouldn't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey());
            }

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));

            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                         31337, Curve.generateKeyPair().getPublicKey(),
                                         0, null, null,
                                         aliceStore.GetIdentityKeyPair().getPublicKey());

            try
            {
                aliceSessionBuilder.process(bobPreKey);
                throw new Exception("shoulnd't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                // good
            }
        }
        public void testSimultaneousKeyExchange()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();
            SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);

            KeyExchangeMessage aliceKeyExchange = aliceSessionBuilder.process();
            KeyExchangeMessage bobKeyExchange = bobSessionBuilder.process();

            Assert.IsNotNull(aliceKeyExchange);
            Assert.IsNotNull(bobKeyExchange);

            KeyExchangeMessage aliceResponse = aliceSessionBuilder.process(bobKeyExchange);
            KeyExchangeMessage bobResponse = bobSessionBuilder.process(aliceKeyExchange);

            Assert.IsNotNull(aliceResponse);
            Assert.IsNotNull(bobResponse);

            KeyExchangeMessage aliceAck = aliceSessionBuilder.process(bobResponse);
            KeyExchangeMessage bobAck = bobSessionBuilder.process(aliceResponse);

            Assert.IsNull(aliceAck);
            Assert.IsNull(bobAck);

            runInteraction(aliceStore, bobStore);
        }
        public void testBasicKeyExchange()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();
            SessionBuilder bobSessionBuilder = new SessionBuilder(bobStore, ALICE_ADDRESS);

            KeyExchangeMessage aliceKeyExchangeMessage = aliceSessionBuilder.process();
            Assert.IsNotNull(aliceKeyExchangeMessage);

            byte[] aliceKeyExchangeMessageBytes = aliceKeyExchangeMessage.serialize();
            KeyExchangeMessage bobKeyExchangeMessage = bobSessionBuilder.process(new KeyExchangeMessage(aliceKeyExchangeMessageBytes));

            Assert.IsNotNull(bobKeyExchangeMessage);

            byte[] bobKeyExchangeMessageBytes = bobKeyExchangeMessage.serialize();
            KeyExchangeMessage response = aliceSessionBuilder.process(new KeyExchangeMessage(bobKeyExchangeMessageBytes));

            Assert.IsNull(response);
            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));

            runInteraction(aliceStore, bobStore);

            aliceStore = new TestInMemoryAxolotlStore();
            aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            aliceKeyExchangeMessage = aliceSessionBuilder.process();

            try
            {
                bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
                throw new Exception("This identity shouldn't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), aliceKeyExchangeMessage.getIdentityKey());
                bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
            }

            Assert.IsNull(aliceSessionBuilder.process(bobKeyExchangeMessage));

            runInteraction(aliceStore, bobStore);
        }
        public void testBasicPreKeyV2()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();
            ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                          31337, bobPreKeyPair.getPublicKey(),
                                                          0, null, null,
                                                          bobStore.GetIdentityKeyPair().getPublicKey());

            aliceSessionBuilder.process(bobPreKey);

            Assert.IsTrue(aliceStore.ContainsSession(BOB_ADDRESS));
            Assert.AreEqual((uint)2, aliceStore.LoadSession(BOB_ADDRESS).getSessionState().getSessionVersion());

            String originalMessage = "L'homme est condamné à être libre";
            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessage.getType());

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessage.serialize());
            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);
            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);

            Assert.IsTrue(bobStore.ContainsSession(ALICE_ADDRESS));
            Assert.AreEqual((uint)2, bobStore.LoadSession(ALICE_ADDRESS).getSessionState().getSessionVersion());
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            Assert.AreEqual(CiphertextMessage.WHISPER_TYPE, bobOutgoingMessage.getType());

            byte[] alicePlaintext = aliceSessionCipher.decrypt((WhisperMessage)bobOutgoingMessage);
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            runInteraction(aliceStore, bobStore);

            aliceStore = new TestInMemoryAxolotlStore();
            aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);
            aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);

            bobPreKeyPair = Curve.generateKeyPair();
            bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(),
                                         1, 31338, bobPreKeyPair.getPublicKey(),
                                         0, null, null, bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31338, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            aliceSessionBuilder.process(bobPreKey);

            outgoingMessage = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            try
            {
                bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));
                throw new Exception("shouldn't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), new PreKeyWhisperMessage(outgoingMessage.serialize()).getIdentityKey());
            }

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(outgoingMessage.serialize()));

            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                         31337, Curve.generateKeyPair().getPublicKey(),
                                         0, null, null,
                                         aliceStore.GetIdentityKeyPair().getPublicKey());

            try
            {
                aliceSessionBuilder.process(bobPreKey);
                throw new Exception("shoulnd't be trusted!");
            }
            catch (UntrustedIdentityException uie)
            {
                // good
            }
        }
        public void testBadMessageBundle()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();
            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                          bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            aliceSessionBuilder.process(bobPreKey);

            String originalMessage = "L'homme est condamné à être libre";
            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageOne.getType());

            byte[] goodMessage = outgoingMessageOne.serialize();
            byte[] badMessage = new byte[goodMessage.Length];
            Array.Copy(goodMessage, 0, badMessage, 0, badMessage.Length);

            badMessage[badMessage.Length - 10] ^= 0x01;

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(badMessage);
            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = new byte[0];

            try
            {
                plaintext = bobSessionCipher.decrypt(incomingMessage);
                throw new Exception("Decrypt should have failed!");
            }
            catch (InvalidMessageException e)
            {
                // good.
            }

            Assert.IsTrue(bobStore.ContainsPreKey(31337));

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(goodMessage));

            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));
            Assert.IsFalse(bobStore.ContainsPreKey(31337));
        }
        public void testRepeatBundleMessageV3()
        {
            AxolotlStore aliceStore = new TestInMemoryAxolotlStore();
            SessionBuilder aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            AxolotlStore bobStore = new TestInMemoryAxolotlStore();

            ECKeyPair bobPreKeyPair = Curve.generateKeyPair();
            ECKeyPair bobSignedPreKeyPair = Curve.generateKeyPair();
            byte[] bobSignedPreKeySignature = Curve.calculateSignature(bobStore.GetIdentityKeyPair().getPrivateKey(),
                                                                          bobSignedPreKeyPair.getPublicKey().serialize());

            PreKeyBundle bobPreKey = new PreKeyBundle(bobStore.GetLocalRegistrationId(), 1,
                                                      31337, bobPreKeyPair.getPublicKey(),
                                                      22, bobSignedPreKeyPair.getPublicKey(), bobSignedPreKeySignature,
                                                      bobStore.GetIdentityKeyPair().getPublicKey());

            bobStore.StorePreKey(31337, new PreKeyRecord(bobPreKey.getPreKeyId(), bobPreKeyPair));
            bobStore.StoreSignedPreKey(22, new SignedPreKeyRecord(22, DateUtil.currentTimeMillis(), bobSignedPreKeyPair, bobSignedPreKeySignature));

            aliceSessionBuilder.process(bobPreKey);

            String originalMessage = "L'homme est condamné à être libre";
            SessionCipher aliceSessionCipher = new SessionCipher(aliceStore, BOB_ADDRESS);
            CiphertextMessage outgoingMessageOne = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            CiphertextMessage outgoingMessageTwo = aliceSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageOne.getType());
            Assert.AreEqual(CiphertextMessage.PREKEY_TYPE, outgoingMessageTwo.getType());

            PreKeyWhisperMessage incomingMessage = new PreKeyWhisperMessage(outgoingMessageOne.serialize());

            SessionCipher bobSessionCipher = new SessionCipher(bobStore, ALICE_ADDRESS);

            byte[] plaintext = bobSessionCipher.decrypt(incomingMessage);
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            CiphertextMessage bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));

            byte[] alicePlaintext = aliceSessionCipher.decrypt(new WhisperMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

            // The test

            PreKeyWhisperMessage incomingMessageTwo = new PreKeyWhisperMessage(outgoingMessageTwo.serialize());

            plaintext = bobSessionCipher.decrypt(new PreKeyWhisperMessage(incomingMessageTwo.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(plaintext));

            bobOutgoingMessage = bobSessionCipher.encrypt(Encoding.UTF8.GetBytes(originalMessage));
            alicePlaintext = aliceSessionCipher.decrypt(new WhisperMessage(bobOutgoingMessage.serialize()));
            Assert.AreEqual(originalMessage, Encoding.UTF8.GetString(alicePlaintext));

        }