/** * Build a new session from a {@link org.whispersystems.libaxolotl.state.PreKeyBundle} retrieved from * a server. * * @param preKey A PreKey for the destination recipient, retrieved from a server. * @throws InvalidKeyException when the {@link org.whispersystems.libaxolotl.state.PreKeyBundle} is * badly formatted. * @throws org.whispersystems.libaxolotl.UntrustedIdentityException when the sender's * {@link IdentityKey} is not * trusted. */ public void Process(PreKeyBundle preKey) { lock (SessionCipher.SESSION_LOCK) { if (!identityKeyStore.IsTrustedIdentity(remoteAddress.GetName(), preKey.GetIdentityKey())) { throw new UntrustedIdentityException(remoteAddress.GetName(), preKey.GetIdentityKey()); } if (preKey.GetSignedPreKey() != null && !Curve.VerifySignature(preKey.GetIdentityKey().GetPublicKey(), preKey.GetSignedPreKey().Serialize(), preKey.GetSignedPreKeySignature())) { throw new InvalidKeyException("Invalid Signature on Device Key!"); } if (preKey.GetSignedPreKey() == null && preKey.GetPreKey() == null) { throw new InvalidKeyException("Both Signed and Unsigned Prekeys are Absent!"); } bool supportsV3 = preKey.GetSignedPreKey() != null; SessionRecord sessionRecord = sessionStore.LoadSession(remoteAddress); ECKeyPair ourBaseKey = Curve.GenerateKeyPair(); ECPublicKey theirSignedPreKey = supportsV3 ? preKey.GetSignedPreKey() : preKey.GetPreKey(); ECPublicKey test = preKey.GetPreKey(); // TODO: Cleanup May <ECPublicKey> theirOneTimePreKey = (test == null) ? May <ECPublicKey> .NoValue : new May <ECPublicKey>(test); May <uint> theirOneTimePreKeyId = theirOneTimePreKey.HasValue ? new May <uint>(preKey.GetPreKeyId()) : May <uint> .NoValue; AliceAxolotlParameters.Builder parameters = AliceAxolotlParameters.NewBuilder(); parameters.SetOurBaseKey(ourBaseKey) .SetOurIdentityKey(identityKeyStore.GetIdentityKeyPair()) .SetTheirIdentityKey(preKey.GetIdentityKey()) .SetTheirSignedPreKey(theirSignedPreKey) .SetTheirRatchetKey(theirSignedPreKey) .SetTheirOneTimePreKey(supportsV3 ? theirOneTimePreKey : May <ECPublicKey> .NoValue); if (!sessionRecord.IsFresh()) { sessionRecord.ArchiveCurrentState(); } RatchetingSession.InitializeSession(sessionRecord.GetSessionState(), supportsV3 ? (uint)3 : 2, parameters.Create()); sessionRecord.GetSessionState().SetUnacknowledgedPreKeyMessage(theirOneTimePreKeyId, preKey.GetSignedPreKeyId(), ourBaseKey.GetPublicKey()); sessionRecord.GetSessionState().SetLocalRegistrationId(identityKeyStore.GetLocalRegistrationId()); sessionRecord.GetSessionState().SetRemoteRegistrationId(preKey.GetRegistrationId()); sessionRecord.GetSessionState().SetAliceBaseKey(ourBaseKey.GetPublicKey().Serialize()); sessionStore.StoreSession(remoteAddress, sessionRecord); identityKeyStore.SaveIdentity(remoteAddress.GetName(), preKey.GetIdentityKey()); } }
/// <summary> /// Build a new session from a {@link org.whispersystems.libsignal.state.PreKeyBundle} retrieved from /// a server. /// </summary> /// @param preKey A PreKey for the destination recipient, retrieved from a server. /// @throws InvalidKeyException when the {@link org.whispersystems.libsignal.state.PreKeyBundle} is /// badly formatted. /// @throws org.whispersystems.libsignal.UntrustedIdentityException when the sender's /// {@link IdentityKey} is not /// trusted. /// public void Process(PreKeyBundle preKey) { lock (SessionCipher.SessionLock) { if (!_identityKeyStore.IsTrustedIdentity(_remoteAddress, preKey.GetIdentityKey(), Direction.Sending)) { throw new UntrustedIdentityException(_remoteAddress.Name, preKey.GetIdentityKey()); } if (preKey.GetSignedPreKey() != null && !Curve.VerifySignature(preKey.GetIdentityKey().GetPublicKey(), preKey.GetSignedPreKey().Serialize(), preKey.GetSignedPreKeySignature())) { throw new InvalidKeyException("Invalid signature on device key!"); } if (preKey.GetSignedPreKey() == null) { throw new InvalidKeyException("No signed prekey!"); } SessionRecord sessionRecord = _sessionStore.LoadSession(_remoteAddress); EcKeyPair ourBaseKey = Curve.GenerateKeyPair(); IEcPublicKey theirSignedPreKey = preKey.GetSignedPreKey(); IEcPublicKey test = preKey.GetPreKey(); May <IEcPublicKey> theirOneTimePreKey = (test == null) ? May <IEcPublicKey> .NoValue : new May <IEcPublicKey>(test); May <uint> theirOneTimePreKeyId = theirOneTimePreKey.HasValue ? new May <uint>(preKey.GetPreKeyId()) : May <uint> .NoValue; AliceSignalProtocolParameters.Builder parameters = AliceSignalProtocolParameters.NewBuilder(); parameters.SetOurBaseKey(ourBaseKey) .SetOurIdentityKey(_identityKeyStore.GetIdentityKeyPair()) .SetTheirIdentityKey(preKey.GetIdentityKey()) .SetTheirSignedPreKey(theirSignedPreKey) .SetTheirRatchetKey(theirSignedPreKey) .SetTheirOneTimePreKey(theirOneTimePreKey); if (!sessionRecord.IsFresh()) { sessionRecord.ArchiveCurrentState(); } RatchetingSession.InitializeSession(sessionRecord.GetSessionState(), parameters.Create()); sessionRecord.GetSessionState().SetUnacknowledgedPreKeyMessage(theirOneTimePreKeyId, preKey.GetSignedPreKeyId(), ourBaseKey.GetPublicKey()); sessionRecord.GetSessionState().SetLocalRegistrationId(_identityKeyStore.GetLocalRegistrationId()); sessionRecord.GetSessionState().SetRemoteRegistrationId(preKey.GetRegistrationId()); sessionRecord.GetSessionState().SetAliceBaseKey(ourBaseKey.GetPublicKey().Serialize()); _identityKeyStore.SaveIdentity(_remoteAddress, preKey.GetIdentityKey()); _sessionStore.StoreSession(_remoteAddress, sessionRecord); } }
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 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 May <uint> ProcessV3(SessionRecord sessionRecord, PreKeySignalMessage message) { if (sessionRecord.HasSessionState(message.GetMessageVersion(), message.GetBaseKey().Serialize())) { Debug.WriteLine("We've already setup a session for this V3 message, letting bundled message fall through..."); return(May <uint> .NoValue); } EcKeyPair ourSignedPreKey = _signedPreKeyStore.LoadSignedPreKey(message.GetSignedPreKeyId()).GetKeyPair(); BobSignalProtocolParameters.Builder parameters = BobSignalProtocolParameters.NewBuilder(); parameters.SetTheirBaseKey(message.GetBaseKey()) .SetTheirIdentityKey(message.GetIdentityKey()) .SetOurIdentityKey(_identityKeyStore.GetIdentityKeyPair()) .SetOurSignedPreKey(ourSignedPreKey) .SetOurRatchetKey(ourSignedPreKey); if (message.GetPreKeyId().HasValue) { parameters.SetOurOneTimePreKey(new May <EcKeyPair>(_preKeyStore.LoadPreKey(message.GetPreKeyId().ForceGetValue()).GetKeyPair())); } else { parameters.SetOurOneTimePreKey(May <EcKeyPair> .NoValue); } if (!sessionRecord.IsFresh()) { sessionRecord.ArchiveCurrentState(); } RatchetingSession.InitializeSession(sessionRecord.GetSessionState(), parameters.Create()); sessionRecord.GetSessionState().SetLocalRegistrationId(_identityKeyStore.GetLocalRegistrationId()); sessionRecord.GetSessionState().SetRemoteRegistrationId(message.GetRegistrationId()); sessionRecord.GetSessionState().SetAliceBaseKey(message.GetBaseKey().Serialize()); if (message.GetPreKeyId().HasValue) { return(message.GetPreKeyId()); } else { return(May <uint> .NoValue); } }
private May <uint> ProcessV3(SessionRecord sessionRecord, PreKeyWhisperMessage message) { if (sessionRecord.HasSessionState(message.GetMessageVersion(), message.GetBaseKey().Serialize())) { return(May <uint> .NoValue); } SignedPreKeyRecord signedPreKeyRecord = signedPreKeyStore.LoadSignedPreKey(message.GetSignedPreKeyId()); ECKeyPair ourSignedPreKey = signedPreKeyRecord.GetKeyPair(); BobAxolotlParameters.Builder parameters = BobAxolotlParameters.NewBuilder(); parameters.SetTheirBaseKey(message.GetBaseKey()) .SetTheirIdentityKey(message.GetIdentityKey()) .SetOurIdentityKey(identityKeyStore.GetIdentityKeyPair()) .SetOurSignedPreKey(ourSignedPreKey) .SetOurRatchetKey(ourSignedPreKey); if (message.GetPreKeyId().HasValue) { parameters.SetOurOneTimePreKey(new May <ECKeyPair>(preKeyStore.LoadPreKey(message.GetPreKeyId().ForceGetValue()).GetKeyPair())); } else { parameters.SetOurOneTimePreKey(May <ECKeyPair> .NoValue); } if (!sessionRecord.IsFresh()) { sessionRecord.ArchiveCurrentState(); } RatchetingSession.InitializeSession(sessionRecord.GetSessionState(), message.GetMessageVersion(), parameters.Create()); sessionRecord.GetSessionState().SetLocalRegistrationId(identityKeyStore.GetLocalRegistrationId()); sessionRecord.GetSessionState().SetRemoteRegistrationId(message.GetRegistrationId()); sessionRecord.GetSessionState().SetAliceBaseKey(message.GetBaseKey().Serialize()); if (message.GetPreKeyId().HasValue&& message.GetPreKeyId().ForceGetValue() != Medium.MAX_VALUE) { return(message.GetPreKeyId()); } else { return(May <uint> .NoValue); } }
private May <uint> ProcessV2(SessionRecord sessionRecord, PreKeyWhisperMessage message) { if (!message.GetPreKeyId().HasValue) { throw new InvalidKeyIdException("V2 message requires one time prekey id!"); } if (!preKeyStore.ContainsPreKey(message.GetPreKeyId().ForceGetValue()) && sessionStore.ContainsSession(remoteAddress)) { return(May <uint> .NoValue); } ECKeyPair ourPreKey = preKeyStore.LoadPreKey(message.GetPreKeyId().ForceGetValue()).GetKeyPair(); BobAxolotlParameters.Builder parameters = BobAxolotlParameters.NewBuilder(); parameters.SetOurIdentityKey(identityKeyStore.GetIdentityKeyPair()) .SetOurSignedPreKey(ourPreKey) .SetOurRatchetKey(ourPreKey) .SetOurOneTimePreKey(May <ECKeyPair> .NoValue) //absent .SetTheirIdentityKey(message.GetIdentityKey()) .SetTheirBaseKey(message.GetBaseKey()); if (!sessionRecord.IsFresh()) { sessionRecord.ArchiveCurrentState(); } RatchetingSession.InitializeSession(sessionRecord.GetSessionState(), message.GetMessageVersion(), parameters.Create()); sessionRecord.GetSessionState().SetLocalRegistrationId(identityKeyStore.GetLocalRegistrationId()); sessionRecord.GetSessionState().SetRemoteRegistrationId(message.GetRegistrationId()); sessionRecord.GetSessionState().SetAliceBaseKey(message.GetBaseKey().Serialize()); if (message.GetPreKeyId().ForceGetValue() != Medium.MAX_VALUE) { return(message.GetPreKeyId()); } else { return(May <uint> .NoValue); // May.absent(); } }