Beispiel #1
0
        public void testSimultaneousKeyExchange()
        {
            SignalProtocolStore aliceStore          = new TestInMemorySignalProtocolStore();
            SessionBuilder      aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            SignalProtocolStore bobStore          = new TestInMemorySignalProtocolStore();
            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);
        }
Beispiel #2
0
        private KeyExchangeMessage ProcessInitiate(KeyExchangeMessage message)
        {
            uint          flags         = KeyExchangeMessage.RESPONSE_FLAG;
            SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress);

            if (message.GetVersion() >= 3 &&
                !Curve.VerifySignature(message.GetIdentityKey().GetPublicKey(),
                                       message.GetBaseKey().Serialize(),
                                       message.GetBaseKeySignature()))
            {
                throw new InvalidKeyException("Bad signature!");
            }

            SymmetricAxolotlParameters.Builder builder = SymmetricAxolotlParameters.NewBuilder();

            if (!sessionRecord.GetSessionState().HasPendingKeyExchange())
            {
                builder.SetOurIdentityKey(identityKeyStore.GetIdentityKeyPair())
                .SetOurBaseKey(Curve.GenerateKeyPair())
                .SetOurRatchetKey(Curve.GenerateKeyPair());
            }
            else
            {
                builder.SetOurIdentityKey(sessionRecord.GetSessionState().GetPendingKeyExchangeIdentityKey())
                .SetOurBaseKey(sessionRecord.GetSessionState().GetPendingKeyExchangeBaseKey())
                .SetOurRatchetKey(sessionRecord.GetSessionState().GetPendingKeyExchangeRatchetKey());
                flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG;
            }

            builder.SetTheirBaseKey(message.GetBaseKey())
            .SetTheirRatchetKey(message.GetRatchetKey())
            .SetTheirIdentityKey(message.GetIdentityKey());

            SymmetricAxolotlParameters parameters = builder.Create();

            if (!sessionRecord.IsFresh())
            {
                sessionRecord.ArchiveCurrentState();
            }

            RatchetingSession.InitializeSession(sessionRecord.GetSessionState(),
                                                Math.Min(message.GetMaxVersion(), CipherTextMessage.CURRENT_VERSION),
                                                parameters);

            sessionStore.StoreSession(remoteAddress, sessionRecord);
            identityKeyStore.SaveIdentity(remoteAddress.GetName(), message.GetIdentityKey());

            byte[] baseKeySignature = Curve.CalculateSignature(parameters.GetOurIdentityKey().GetPrivateKey(),
                                                               parameters.GetOurBaseKey().GetPublicKey().Serialize());

            return(new KeyExchangeMessage(sessionRecord.GetSessionState().GetSessionVersion(),
                                          message.GetSequence(), flags,
                                          parameters.GetOurBaseKey().GetPublicKey(),
                                          baseKeySignature, parameters.GetOurRatchetKey().GetPublicKey(),
                                          parameters.GetOurIdentityKey().GetPublicKey()));
        }
        private KeyExchangeMessage processInitiate(KeyExchangeMessage message)
        {
            uint          flags         = KeyExchangeMessage.RESPONSE_FLAG;
            SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress);

            if (!Curve.verifySignature(message.getIdentityKey().getPublicKey(),
                                       message.getBaseKey().serialize(),
                                       message.getBaseKeySignature()))
            {
                throw new InvalidKeyException("Bad signature!");
            }

            SymmetricSignalProtocolParameters.Builder builder = SymmetricSignalProtocolParameters.newBuilder();

            if (!sessionRecord.getSessionState().hasPendingKeyExchange())
            {
                builder.setOurIdentityKey(identityKeyStore.GetIdentityKeyPair())
                .setOurBaseKey(Curve.generateKeyPair())
                .setOurRatchetKey(Curve.generateKeyPair());
            }
            else
            {
                builder.setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())
                .setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())
                .setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey());
                flags |= KeyExchangeMessage.SIMULTAENOUS_INITIATE_FLAG;
            }

            builder.setTheirBaseKey(message.getBaseKey())
            .setTheirRatchetKey(message.getRatchetKey())
            .setTheirIdentityKey(message.getIdentityKey());

            SymmetricSignalProtocolParameters parameters = builder.create();

            if (!sessionRecord.isFresh())
            {
                sessionRecord.archiveCurrentState();
            }

            RatchetingSession.initializeSession(sessionRecord.getSessionState(),
                                                parameters);

            sessionStore.StoreSession(remoteAddress, sessionRecord);
            identityKeyStore.SaveIdentity(remoteAddress.getName(), message.getIdentityKey());

            byte[] baseKeySignature = Curve.calculateSignature(parameters.getOurIdentityKey().getPrivateKey(),
                                                               parameters.getOurBaseKey().getPublicKey().serialize());

            return(new KeyExchangeMessage(sessionRecord.getSessionState().getSessionVersion(),
                                          message.getSequence(), flags,
                                          parameters.getOurBaseKey().getPublicKey(),
                                          baseKeySignature, parameters.getOurRatchetKey().getPublicKey(),
                                          parameters.getOurIdentityKey().getPublicKey()));
        }
Beispiel #4
0
        private void ProcessResponse(KeyExchangeMessage message)
        {
            SessionRecord sessionRecord                  = sessionStore.LoadSession(remoteAddress);
            SessionState  sessionState                   = sessionRecord.GetSessionState();
            bool          hasPendingKeyExchange          = sessionState.HasPendingKeyExchange();
            bool          isSimultaneousInitiateResponse = message.IsResponseForSimultaneousInitiate();

            if (!hasPendingKeyExchange || sessionState.GetPendingKeyExchangeSequence() != message.GetSequence())
            {
                //Log.w(TAG, "No matching sequence for response. Is simultaneous initiate response: " + isSimultaneousInitiateResponse);
                if (!isSimultaneousInitiateResponse)
                {
                    throw new StaleKeyExchangeException();
                }
                else
                {
                    return;
                }
            }

            SymmetricAxolotlParameters.Builder parameters = SymmetricAxolotlParameters.NewBuilder();

            parameters.SetOurBaseKey(sessionRecord.GetSessionState().GetPendingKeyExchangeBaseKey())
            .SetOurRatchetKey(sessionRecord.GetSessionState().GetPendingKeyExchangeRatchetKey())
            .SetOurIdentityKey(sessionRecord.GetSessionState().GetPendingKeyExchangeIdentityKey())
            .SetTheirBaseKey(message.GetBaseKey())
            .SetTheirRatchetKey(message.GetRatchetKey())
            .SetTheirIdentityKey(message.GetIdentityKey());

            if (!sessionRecord.IsFresh())
            {
                sessionRecord.ArchiveCurrentState();
            }

            RatchetingSession.InitializeSession(sessionRecord.GetSessionState(),
                                                Math.Min(message.GetMaxVersion(), CipherTextMessage.CURRENT_VERSION),
                                                parameters.Create());

            if (sessionRecord.GetSessionState().GetSessionVersion() >= 3 &&
                !Curve.VerifySignature(message.GetIdentityKey().GetPublicKey(),
                                       message.GetBaseKey().Serialize(),
                                       message.GetBaseKeySignature()))
            {
                throw new InvalidKeyException("Base key signature doesn't match!");
            }

            sessionStore.StoreSession(remoteAddress, sessionRecord);
            identityKeyStore.SaveIdentity(remoteAddress.GetName(), message.GetIdentityKey());
        }
        private void processResponse(KeyExchangeMessage message)
        {
            SessionRecord sessionRecord                  = sessionStore.LoadSession(remoteAddress);
            SessionState  sessionState                   = sessionRecord.getSessionState();
            bool          hasPendingKeyExchange          = sessionState.hasPendingKeyExchange();
            bool          isSimultaneousInitiateResponse = message.isResponseForSimultaneousInitiate();

            if (!hasPendingKeyExchange || sessionState.getPendingKeyExchangeSequence() != message.getSequence())
            {
                Debug.WriteLine("No matching sequence for response. Is simultaneous initiate response: " + isSimultaneousInitiateResponse);
                if (!isSimultaneousInitiateResponse)
                {
                    throw new StaleKeyExchangeException();
                }
                else
                {
                    return;
                }
            }

            SymmetricSignalProtocolParameters.Builder parameters = SymmetricSignalProtocolParameters.newBuilder();

            parameters.setOurBaseKey(sessionRecord.getSessionState().getPendingKeyExchangeBaseKey())
            .setOurRatchetKey(sessionRecord.getSessionState().getPendingKeyExchangeRatchetKey())
            .setOurIdentityKey(sessionRecord.getSessionState().getPendingKeyExchangeIdentityKey())
            .setTheirBaseKey(message.getBaseKey())
            .setTheirRatchetKey(message.getRatchetKey())
            .setTheirIdentityKey(message.getIdentityKey());

            if (!sessionRecord.isFresh())
            {
                sessionRecord.archiveCurrentState();
            }

            RatchetingSession.initializeSession(sessionRecord.getSessionState(), parameters.create());

            if (!Curve.verifySignature(message.getIdentityKey().getPublicKey(),
                                       message.getBaseKey().serialize(),
                                       message.getBaseKeySignature()))
            {
                throw new InvalidKeyException("Base key signature doesn't match!");
            }

            sessionStore.StoreSession(remoteAddress, sessionRecord);
            identityKeyStore.SaveIdentity(remoteAddress.getName(), message.getIdentityKey());
        }
Beispiel #6
0
        public void testBasicKeyExchange()
        {
            SignalProtocolStore aliceStore          = new TestInMemorySignalProtocolStore();
            SessionBuilder      aliceSessionBuilder = new SessionBuilder(aliceStore, BOB_ADDRESS);

            SignalProtocolStore bobStore          = new TestInMemorySignalProtocolStore();
            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 TestInMemorySignalProtocolStore();
            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)
            {
                bobStore.SaveIdentity(ALICE_ADDRESS.getName(), aliceKeyExchangeMessage.getIdentityKey());
                bobKeyExchangeMessage = bobSessionBuilder.process(aliceKeyExchangeMessage);
            }

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

            runInteraction(aliceStore, bobStore);
        }
        /**
         * Build a new session from a {@link KeyExchangeMessage}
         * received from a remote client.
         *
         * @param message The received KeyExchangeMessage.
         * @return The KeyExchangeMessage to respond with, or null if no response is necessary.
         * @throws InvalidKeyException if the received KeyExchangeMessage is badly formatted.
         */
        public KeyExchangeMessage process(KeyExchangeMessage message)

        {
            lock (SessionCipher.SESSION_LOCK)
            {
                if (!identityKeyStore.IsTrustedIdentity(remoteAddress.getName(), message.getIdentityKey()))
                {
                    throw new UntrustedIdentityException(remoteAddress.getName(), message.getIdentityKey());
                }

                KeyExchangeMessage responseMessage = null;

                if (message.isInitiate())
                {
                    responseMessage = processInitiate(message);
                }
                else
                {
                    processResponse(message);
                }

                return(responseMessage);
            }
        }