Search in sources :

Example 6 with NoSessionException

use of org.whispersystems.libsignal.NoSessionException in project Signal-Android by WhisperSystems.

the class SignalServiceCipher method decrypt.

private Plaintext decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolInvalidKeyException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyIdException, ProtocolNoSessionException, SelfSendException, InvalidMessageStructureException {
    try {
        byte[] paddedMessage;
        SignalServiceMetadata metadata;
        if (!envelope.hasSourceUuid() && !envelope.isUnidentifiedSender()) {
            throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!");
        }
        if (envelope.isPreKeySignalMessage()) {
            SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceUuid().get(), envelope.getSourceDevice());
            SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
            paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
            metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
            signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress));
        } else if (envelope.isSignalMessage()) {
            SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceUuid().get(), envelope.getSourceDevice());
            SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
            paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
            metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
        } else if (envelope.isPlaintextContent()) {
            paddedMessage = new PlaintextContent(ciphertext).getBody();
            metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
        } else if (envelope.isUnidentifiedSender()) {
            SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orNull(), localDeviceId));
            DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, ciphertext, envelope.getServerReceivedTimestamp());
            SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164());
            Optional<byte[]> groupId = result.getGroupId();
            boolean needsReceipt = true;
            if (envelope.hasSourceUuid()) {
                Log.w(TAG, "[" + envelope.getTimestamp() + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false");
                needsReceipt = false;
            }
            if (result.getCiphertextMessageType() == CiphertextMessage.PREKEY_TYPE) {
                signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(new SignalProtocolAddress(result.getSenderUuid(), result.getDeviceId())));
            }
            paddedMessage = result.getPaddedMessage();
            metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), needsReceipt, envelope.getServerGuid(), groupId);
        } else {
            throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
        }
        PushTransportDetails transportDetails = new PushTransportDetails();
        byte[] data = transportDetails.getStrippedPaddingMessageBody(paddedMessage);
        return new Plaintext(metadata, data);
    } catch (DuplicateMessageException e) {
        throw new ProtocolDuplicateMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (LegacyMessageException e) {
        throw new ProtocolLegacyMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidMessageException e) {
        throw new ProtocolInvalidMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidKeyIdException e) {
        throw new ProtocolInvalidKeyIdException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidKeyException e) {
        throw new ProtocolInvalidKeyException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (UntrustedIdentityException e) {
        throw new ProtocolUntrustedIdentityException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidVersionException e) {
        throw new ProtocolInvalidVersionException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (NoSessionException e) {
        throw new ProtocolNoSessionException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    }
}
Also used : SealedSessionCipher(org.signal.libsignal.metadata.SealedSessionCipher) ProtocolInvalidMessageException(org.signal.libsignal.metadata.ProtocolInvalidMessageException) InvalidMessageException(org.whispersystems.libsignal.InvalidMessageException) ProtocolInvalidMessageException(org.signal.libsignal.metadata.ProtocolInvalidMessageException) UntrustedIdentityException(org.whispersystems.libsignal.UntrustedIdentityException) ProtocolUntrustedIdentityException(org.signal.libsignal.metadata.ProtocolUntrustedIdentityException) ProtocolUntrustedIdentityException(org.signal.libsignal.metadata.ProtocolUntrustedIdentityException) ProtocolInvalidVersionException(org.signal.libsignal.metadata.ProtocolInvalidVersionException) InvalidVersionException(org.whispersystems.libsignal.InvalidVersionException) InvalidMessageStructureException(org.whispersystems.signalservice.api.InvalidMessageStructureException) ProtocolInvalidVersionException(org.signal.libsignal.metadata.ProtocolInvalidVersionException) PlaintextContent(org.whispersystems.libsignal.protocol.PlaintextContent) ProtocolInvalidKeyIdException(org.signal.libsignal.metadata.ProtocolInvalidKeyIdException) NoSessionException(org.whispersystems.libsignal.NoSessionException) ProtocolNoSessionException(org.signal.libsignal.metadata.ProtocolNoSessionException) ProtocolDuplicateMessageException(org.signal.libsignal.metadata.ProtocolDuplicateMessageException) PreKeySignalMessage(org.whispersystems.libsignal.protocol.PreKeySignalMessage) PushTransportDetails(org.whispersystems.signalservice.internal.push.PushTransportDetails) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) ProtocolLegacyMessageException(org.signal.libsignal.metadata.ProtocolLegacyMessageException) SessionCipher(org.whispersystems.libsignal.SessionCipher) SealedSessionCipher(org.signal.libsignal.metadata.SealedSessionCipher) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress) ProtocolNoSessionException(org.signal.libsignal.metadata.ProtocolNoSessionException) PreKeySignalMessage(org.whispersystems.libsignal.protocol.PreKeySignalMessage) SignalMessage(org.whispersystems.libsignal.protocol.SignalMessage) Optional(org.whispersystems.libsignal.util.guava.Optional) SignalServiceMetadata(org.whispersystems.signalservice.api.messages.SignalServiceMetadata) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) ProtocolInvalidKeyException(org.signal.libsignal.metadata.ProtocolInvalidKeyException) InvalidMetadataMessageException(org.signal.libsignal.metadata.InvalidMetadataMessageException) ProtocolInvalidKeyException(org.signal.libsignal.metadata.ProtocolInvalidKeyException) DuplicateMessageException(org.whispersystems.libsignal.DuplicateMessageException) ProtocolDuplicateMessageException(org.signal.libsignal.metadata.ProtocolDuplicateMessageException) DecryptionResult(org.signal.libsignal.metadata.SealedSessionCipher.DecryptionResult) InvalidKeyIdException(org.whispersystems.libsignal.InvalidKeyIdException) ProtocolInvalidKeyIdException(org.signal.libsignal.metadata.ProtocolInvalidKeyIdException) LegacyMessageException(org.whispersystems.libsignal.LegacyMessageException) ProtocolLegacyMessageException(org.signal.libsignal.metadata.ProtocolLegacyMessageException)

Example 7 with NoSessionException

use of org.whispersystems.libsignal.NoSessionException in project Signal-Android by signalapp.

the class SignalServiceCipher method decrypt.

private Plaintext decrypt(SignalServiceEnvelope envelope, byte[] ciphertext) throws InvalidMetadataMessageException, InvalidMetadataVersionException, ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException, ProtocolLegacyMessageException, ProtocolInvalidKeyException, ProtocolInvalidVersionException, ProtocolInvalidMessageException, ProtocolInvalidKeyIdException, ProtocolNoSessionException, SelfSendException, InvalidMessageStructureException {
    try {
        byte[] paddedMessage;
        SignalServiceMetadata metadata;
        if (!envelope.hasSourceUuid() && !envelope.isUnidentifiedSender()) {
            throw new InvalidMessageStructureException("Non-UD envelope is missing a UUID!");
        }
        if (envelope.isPreKeySignalMessage()) {
            SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceUuid().get(), envelope.getSourceDevice());
            SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
            paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(ciphertext));
            metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
            signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress));
        } else if (envelope.isSignalMessage()) {
            SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.getSourceUuid().get(), envelope.getSourceDevice());
            SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
            paddedMessage = sessionCipher.decrypt(new SignalMessage(ciphertext));
            metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
        } else if (envelope.isPlaintextContent()) {
            paddedMessage = new PlaintextContent(ciphertext).getBody();
            metadata = new SignalServiceMetadata(envelope.getSourceAddress(), envelope.getSourceDevice(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), false, envelope.getServerGuid(), Optional.absent());
        } else if (envelope.isUnidentifiedSender()) {
            SignalSealedSessionCipher sealedSessionCipher = new SignalSealedSessionCipher(sessionLock, new SealedSessionCipher(signalProtocolStore, localAddress.getServiceId().uuid(), localAddress.getNumber().orNull(), localDeviceId));
            DecryptionResult result = sealedSessionCipher.decrypt(certificateValidator, ciphertext, envelope.getServerReceivedTimestamp());
            SignalServiceAddress resultAddress = new SignalServiceAddress(ACI.parseOrThrow(result.getSenderUuid()), result.getSenderE164());
            Optional<byte[]> groupId = result.getGroupId();
            boolean needsReceipt = true;
            if (envelope.hasSourceUuid()) {
                Log.w(TAG, "[" + envelope.getTimestamp() + "] Received a UD-encrypted message sent over an identified channel. Marking as needsReceipt=false");
                needsReceipt = false;
            }
            if (result.getCiphertextMessageType() == CiphertextMessage.PREKEY_TYPE) {
                signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(new SignalProtocolAddress(result.getSenderUuid(), result.getDeviceId())));
            }
            paddedMessage = result.getPaddedMessage();
            metadata = new SignalServiceMetadata(resultAddress, result.getDeviceId(), envelope.getTimestamp(), envelope.getServerReceivedTimestamp(), envelope.getServerDeliveredTimestamp(), needsReceipt, envelope.getServerGuid(), groupId);
        } else {
            throw new InvalidMetadataMessageException("Unknown type: " + envelope.getType());
        }
        PushTransportDetails transportDetails = new PushTransportDetails();
        byte[] data = transportDetails.getStrippedPaddingMessageBody(paddedMessage);
        return new Plaintext(metadata, data);
    } catch (DuplicateMessageException e) {
        throw new ProtocolDuplicateMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (LegacyMessageException e) {
        throw new ProtocolLegacyMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidMessageException e) {
        throw new ProtocolInvalidMessageException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidKeyIdException e) {
        throw new ProtocolInvalidKeyIdException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidKeyException e) {
        throw new ProtocolInvalidKeyException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (UntrustedIdentityException e) {
        throw new ProtocolUntrustedIdentityException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (InvalidVersionException e) {
        throw new ProtocolInvalidVersionException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    } catch (NoSessionException e) {
        throw new ProtocolNoSessionException(e, envelope.getSourceIdentifier(), envelope.getSourceDevice());
    }
}
Also used : SealedSessionCipher(org.signal.libsignal.metadata.SealedSessionCipher) ProtocolInvalidMessageException(org.signal.libsignal.metadata.ProtocolInvalidMessageException) InvalidMessageException(org.whispersystems.libsignal.InvalidMessageException) ProtocolInvalidMessageException(org.signal.libsignal.metadata.ProtocolInvalidMessageException) UntrustedIdentityException(org.whispersystems.libsignal.UntrustedIdentityException) ProtocolUntrustedIdentityException(org.signal.libsignal.metadata.ProtocolUntrustedIdentityException) ProtocolUntrustedIdentityException(org.signal.libsignal.metadata.ProtocolUntrustedIdentityException) ProtocolInvalidVersionException(org.signal.libsignal.metadata.ProtocolInvalidVersionException) InvalidVersionException(org.whispersystems.libsignal.InvalidVersionException) InvalidMessageStructureException(org.whispersystems.signalservice.api.InvalidMessageStructureException) ProtocolInvalidVersionException(org.signal.libsignal.metadata.ProtocolInvalidVersionException) PlaintextContent(org.whispersystems.libsignal.protocol.PlaintextContent) ProtocolInvalidKeyIdException(org.signal.libsignal.metadata.ProtocolInvalidKeyIdException) NoSessionException(org.whispersystems.libsignal.NoSessionException) ProtocolNoSessionException(org.signal.libsignal.metadata.ProtocolNoSessionException) ProtocolDuplicateMessageException(org.signal.libsignal.metadata.ProtocolDuplicateMessageException) PreKeySignalMessage(org.whispersystems.libsignal.protocol.PreKeySignalMessage) PushTransportDetails(org.whispersystems.signalservice.internal.push.PushTransportDetails) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) ProtocolLegacyMessageException(org.signal.libsignal.metadata.ProtocolLegacyMessageException) SessionCipher(org.whispersystems.libsignal.SessionCipher) SealedSessionCipher(org.signal.libsignal.metadata.SealedSessionCipher) SignalProtocolAddress(org.whispersystems.libsignal.SignalProtocolAddress) ProtocolNoSessionException(org.signal.libsignal.metadata.ProtocolNoSessionException) PreKeySignalMessage(org.whispersystems.libsignal.protocol.PreKeySignalMessage) SignalMessage(org.whispersystems.libsignal.protocol.SignalMessage) Optional(org.whispersystems.libsignal.util.guava.Optional) SignalServiceMetadata(org.whispersystems.signalservice.api.messages.SignalServiceMetadata) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) ProtocolInvalidKeyException(org.signal.libsignal.metadata.ProtocolInvalidKeyException) InvalidMetadataMessageException(org.signal.libsignal.metadata.InvalidMetadataMessageException) ProtocolInvalidKeyException(org.signal.libsignal.metadata.ProtocolInvalidKeyException) DuplicateMessageException(org.whispersystems.libsignal.DuplicateMessageException) ProtocolDuplicateMessageException(org.signal.libsignal.metadata.ProtocolDuplicateMessageException) DecryptionResult(org.signal.libsignal.metadata.SealedSessionCipher.DecryptionResult) InvalidKeyIdException(org.whispersystems.libsignal.InvalidKeyIdException) ProtocolInvalidKeyIdException(org.signal.libsignal.metadata.ProtocolInvalidKeyIdException) LegacyMessageException(org.whispersystems.libsignal.LegacyMessageException) ProtocolLegacyMessageException(org.signal.libsignal.metadata.ProtocolLegacyMessageException)

Example 8 with NoSessionException

use of org.whispersystems.libsignal.NoSessionException in project Signal-Android by signalapp.

the class PushDecryptJob method handleMessage.

private void handleMessage(SignalServiceEnvelope envelope, Optional<Long> smsMessageId) {
    try {
        GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
        SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
        SignalServiceAddress localAddress = new SignalServiceAddress(TextSecurePreferences.getLocalNumber(context));
        SignalServiceCipher cipher = new SignalServiceCipher(localAddress, axolotlStore);
        SignalServiceContent content = cipher.decrypt(envelope);
        if (content.getDataMessage().isPresent()) {
            SignalServiceDataMessage message = content.getDataMessage().get();
            if (message.isEndSession())
                handleEndSessionMessage(envelope, message, smsMessageId);
            else if (message.isGroupUpdate())
                handleGroupMessage(envelope, message, smsMessageId);
            else if (message.isExpirationUpdate())
                handleExpirationUpdate(envelope, message, smsMessageId);
            else if (message.getAttachments().isPresent())
                handleMediaMessage(envelope, message, smsMessageId);
            else if (message.getBody().isPresent())
                handleTextMessage(envelope, message, smsMessageId);
            if (message.getGroupInfo().isPresent() && groupDatabase.isUnknownGroup(GroupUtil.getEncodedId(message.getGroupInfo().get().getGroupId(), false))) {
                handleUnknownGroupMessage(envelope, message.getGroupInfo().get());
            }
            if (message.getProfileKey().isPresent() && message.getProfileKey().get().length == 32) {
                handleProfileKey(envelope, message);
            }
        } else if (content.getSyncMessage().isPresent()) {
            SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
            if (syncMessage.getSent().isPresent())
                handleSynchronizeSentMessage(envelope, syncMessage.getSent().get());
            else if (syncMessage.getRequest().isPresent())
                handleSynchronizeRequestMessage(syncMessage.getRequest().get());
            else if (syncMessage.getRead().isPresent())
                handleSynchronizeReadMessage(syncMessage.getRead().get(), envelope.getTimestamp());
            else if (syncMessage.getVerified().isPresent())
                handleSynchronizeVerifiedMessage(syncMessage.getVerified().get());
            else
                Log.w(TAG, "Contains no known sync types...");
        } else if (content.getCallMessage().isPresent()) {
            Log.w(TAG, "Got call message...");
            SignalServiceCallMessage message = content.getCallMessage().get();
            if (message.getOfferMessage().isPresent())
                handleCallOfferMessage(envelope, message.getOfferMessage().get(), smsMessageId);
            else if (message.getAnswerMessage().isPresent())
                handleCallAnswerMessage(envelope, message.getAnswerMessage().get());
            else if (message.getIceUpdateMessages().isPresent())
                handleCallIceUpdateMessage(envelope, message.getIceUpdateMessages().get());
            else if (message.getHangupMessage().isPresent())
                handleCallHangupMessage(envelope, message.getHangupMessage().get(), smsMessageId);
            else if (message.getBusyMessage().isPresent())
                handleCallBusyMessage(envelope, message.getBusyMessage().get());
        } else if (content.getReceiptMessage().isPresent()) {
            SignalServiceReceiptMessage message = content.getReceiptMessage().get();
            if (message.isReadReceipt())
                handleReadReceipt(envelope, message);
            else if (message.isDeliveryReceipt())
                handleDeliveryReceipt(envelope, message);
        } else {
            Log.w(TAG, "Got unrecognized message...");
        }
        if (envelope.isPreKeySignalMessage()) {
            ApplicationContext.getInstance(context).getJobManager().add(new RefreshPreKeysJob(context));
        }
    } catch (InvalidVersionException e) {
        Log.w(TAG, e);
        handleInvalidVersionMessage(envelope, smsMessageId);
    } catch (InvalidMessageException | InvalidKeyIdException | InvalidKeyException | MmsException e) {
        Log.w(TAG, e);
        handleCorruptMessage(envelope, smsMessageId);
    } catch (NoSessionException e) {
        Log.w(TAG, e);
        handleNoSessionMessage(envelope, smsMessageId);
    } catch (LegacyMessageException e) {
        Log.w(TAG, e);
        handleLegacyMessage(envelope, smsMessageId);
    } catch (DuplicateMessageException e) {
        Log.w(TAG, e);
        handleDuplicateMessage(envelope, smsMessageId);
    } catch (UntrustedIdentityException e) {
        Log.w(TAG, e);
        handleUntrustedIdentityMessage(envelope, smsMessageId);
    }
}
Also used : InvalidMessageException(org.whispersystems.libsignal.InvalidMessageException) UntrustedIdentityException(org.whispersystems.libsignal.UntrustedIdentityException) SignalServiceCipher(org.whispersystems.signalservice.api.crypto.SignalServiceCipher) InvalidVersionException(org.whispersystems.libsignal.InvalidVersionException) SignalServiceReceiptMessage(org.whispersystems.signalservice.api.messages.SignalServiceReceiptMessage) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) SignalServiceSyncMessage(org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage) SignalServiceContent(org.whispersystems.signalservice.api.messages.SignalServiceContent) NoSessionException(org.whispersystems.libsignal.NoSessionException) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) SignalProtocolStore(org.whispersystems.libsignal.state.SignalProtocolStore) MmsException(org.thoughtcrime.securesms.mms.MmsException) DuplicateMessageException(org.whispersystems.libsignal.DuplicateMessageException) SignalProtocolStoreImpl(org.thoughtcrime.securesms.crypto.storage.SignalProtocolStoreImpl) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) InvalidKeyIdException(org.whispersystems.libsignal.InvalidKeyIdException) LegacyMessageException(org.whispersystems.libsignal.LegacyMessageException)

Example 9 with NoSessionException

use of org.whispersystems.libsignal.NoSessionException in project Signal-Android by WhisperSystems.

the class GroupSendUtil method sendMessage.

/**
 * Handles all of the logic of sending to a group. Will do sender key sends and legacy 1:1 sends as-needed, and give you back a list of
 * {@link SendMessageResult}s just like we're used to.
 *
 * @param groupId The groupId of the group you're sending to, or null if you're sending to a collection of recipients not joined by a group.
 * @param isRecipientUpdate True if you've already sent this message to some recipients in the past, otherwise false.
 */
@WorkerThread
private static List<SendMessageResult> sendMessage(@NonNull Context context, @Nullable GroupId.V2 groupId, @Nullable MessageId relatedMessageId, @NonNull List<Recipient> allTargets, boolean isRecipientUpdate, @NonNull SendOperation sendOperation, @Nullable CancelationSignal cancelationSignal) throws IOException, UntrustedIdentityException {
    Log.i(TAG, "Starting group send. GroupId: " + (groupId != null ? groupId.toString() : "none") + ", RelatedMessageId: " + (relatedMessageId != null ? relatedMessageId.toString() : "none") + ", Targets: " + allTargets.size() + ", RecipientUpdate: " + isRecipientUpdate + ", Operation: " + sendOperation.getClass().getSimpleName());
    Set<Recipient> unregisteredTargets = allTargets.stream().filter(Recipient::isUnregistered).collect(Collectors.toSet());
    List<Recipient> registeredTargets = allTargets.stream().filter(r -> !unregisteredTargets.contains(r)).collect(Collectors.toList());
    RecipientData recipients = new RecipientData(context, registeredTargets);
    Optional<GroupRecord> groupRecord = groupId != null ? SignalDatabase.groups().getGroup(groupId) : Optional.absent();
    List<Recipient> senderKeyTargets = new LinkedList<>();
    List<Recipient> legacyTargets = new LinkedList<>();
    for (Recipient recipient : registeredTargets) {
        Optional<UnidentifiedAccessPair> access = recipients.getAccessPair(recipient.getId());
        boolean validMembership = groupRecord.isPresent() && groupRecord.get().getMembers().contains(recipient.getId());
        if (recipient.getSenderKeyCapability() == Recipient.Capability.SUPPORTED && recipient.hasServiceId() && access.isPresent() && access.get().getTargetUnidentifiedAccess().isPresent() && validMembership) {
            senderKeyTargets.add(recipient);
        } else {
            legacyTargets.add(recipient);
        }
    }
    if (groupId == null) {
        Log.i(TAG, "Recipients not in a group. Using legacy.");
        legacyTargets.addAll(senderKeyTargets);
        senderKeyTargets.clear();
    } else if (Recipient.self().getSenderKeyCapability() != Recipient.Capability.SUPPORTED) {
        Log.i(TAG, "All of our devices do not support sender key. Using legacy.");
        legacyTargets.addAll(senderKeyTargets);
        senderKeyTargets.clear();
    } else if (SignalStore.internalValues().removeSenderKeyMinimum()) {
        Log.i(TAG, "Sender key minimum removed. Using for " + senderKeyTargets.size() + " recipients.");
    } else if (senderKeyTargets.size() < 2) {
        Log.i(TAG, "Too few sender-key-capable users (" + senderKeyTargets.size() + "). Doing all legacy sends.");
        legacyTargets.addAll(senderKeyTargets);
        senderKeyTargets.clear();
    } else {
        Log.i(TAG, "Can use sender key for " + senderKeyTargets.size() + "/" + allTargets.size() + " recipients.");
    }
    if (relatedMessageId != null) {
        SignalLocalMetrics.GroupMessageSend.onSenderKeyStarted(relatedMessageId.getId());
    }
    List<SendMessageResult> allResults = new ArrayList<>(allTargets.size());
    SignalServiceMessageSender messageSender = ApplicationDependencies.getSignalServiceMessageSender();
    if (senderKeyTargets.size() > 0 && groupId != null) {
        DistributionId distributionId = SignalDatabase.groups().getOrCreateDistributionId(groupId);
        long keyCreateTime = SenderKeyUtil.getCreateTimeForOurKey(context, distributionId);
        long keyAge = System.currentTimeMillis() - keyCreateTime;
        if (keyCreateTime != -1 && keyAge > FeatureFlags.senderKeyMaxAge()) {
            Log.w(TAG, "DistributionId " + distributionId + " was created at " + keyCreateTime + " and is " + (keyAge) + " ms old (~" + TimeUnit.MILLISECONDS.toDays(keyAge) + " days). Rotating.");
            SenderKeyUtil.rotateOurKey(context, distributionId);
        }
        try {
            List<SignalServiceAddress> targets = senderKeyTargets.stream().map(r -> recipients.getAddress(r.getId())).collect(Collectors.toList());
            List<UnidentifiedAccess> access = senderKeyTargets.stream().map(r -> recipients.requireAccess(r.getId())).collect(Collectors.toList());
            List<SendMessageResult> results = sendOperation.sendWithSenderKey(messageSender, distributionId, targets, access, isRecipientUpdate);
            allResults.addAll(results);
            int successCount = (int) results.stream().filter(SendMessageResult::isSuccess).count();
            Log.d(TAG, "Successfully sent using sender key to " + successCount + "/" + targets.size() + " sender key targets.");
            if (sendOperation.shouldIncludeInMessageLog()) {
                SignalDatabase.messageLog().insertIfPossible(sendOperation.getSentTimestamp(), senderKeyTargets, results, sendOperation.getContentHint(), sendOperation.getRelatedMessageId());
            }
            if (relatedMessageId != null) {
                SignalLocalMetrics.GroupMessageSend.onSenderKeyMslInserted(relatedMessageId.getId());
            }
        } catch (InvalidUnidentifiedAccessHeaderException e) {
            Log.w(TAG, "Someone had a bad UD header. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (NoSessionException e) {
            Log.w(TAG, "No session. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (InvalidKeyException e) {
            Log.w(TAG, "Invalid key. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (InvalidRegistrationIdException e) {
            Log.w(TAG, "Invalid registrationId. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        } catch (NotFoundException e) {
            Log.w(TAG, "Someone was unregistered. Falling back to legacy sends.", e);
            legacyTargets.addAll(senderKeyTargets);
        }
    } else if (relatedMessageId != null) {
        SignalLocalMetrics.GroupMessageSend.onSenderKeyShared(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeyEncrypted(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeyMessageSent(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeySyncSent(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onSenderKeyMslInserted(relatedMessageId.getId());
    }
    if (cancelationSignal != null && cancelationSignal.isCanceled()) {
        throw new CancelationException();
    }
    boolean onlyTargetIsSelfWithLinkedDevice = legacyTargets.isEmpty() && senderKeyTargets.isEmpty() && TextSecurePreferences.isMultiDevice(context);
    if (legacyTargets.size() > 0 || onlyTargetIsSelfWithLinkedDevice) {
        if (legacyTargets.size() > 0) {
            Log.i(TAG, "Need to do " + legacyTargets.size() + " legacy sends.");
        } else {
            Log.i(TAG, "Need to do a legacy send to send a sync message for a group of only ourselves.");
        }
        List<SignalServiceAddress> targets = legacyTargets.stream().map(r -> recipients.getAddress(r.getId())).collect(Collectors.toList());
        List<Optional<UnidentifiedAccessPair>> access = legacyTargets.stream().map(r -> recipients.getAccessPair(r.getId())).collect(Collectors.toList());
        boolean recipientUpdate = isRecipientUpdate || allResults.size() > 0;
        final MessageSendLogDatabase messageLogDatabase = SignalDatabase.messageLog();
        final AtomicLong entryId = new AtomicLong(-1);
        final boolean includeInMessageLog = sendOperation.shouldIncludeInMessageLog();
        List<SendMessageResult> results = sendOperation.sendLegacy(messageSender, targets, access, recipientUpdate, result -> {
            if (!includeInMessageLog) {
                return;
            }
            synchronized (entryId) {
                if (entryId.get() == -1) {
                    entryId.set(messageLogDatabase.insertIfPossible(recipients.requireRecipientId(result.getAddress()), sendOperation.getSentTimestamp(), result, sendOperation.getContentHint(), sendOperation.getRelatedMessageId()));
                } else {
                    messageLogDatabase.addRecipientToExistingEntryIfPossible(entryId.get(), recipients.requireRecipientId(result.getAddress()), result);
                }
            }
        }, cancelationSignal);
        allResults.addAll(results);
        int successCount = (int) results.stream().filter(SendMessageResult::isSuccess).count();
        Log.d(TAG, "Successfully sent using 1:1 to " + successCount + "/" + targets.size() + " legacy targets.");
    } else if (relatedMessageId != null) {
        SignalLocalMetrics.GroupMessageSend.onLegacyMessageSent(relatedMessageId.getId());
        SignalLocalMetrics.GroupMessageSend.onLegacySyncFinished(relatedMessageId.getId());
    }
    if (unregisteredTargets.size() > 0) {
        Log.w(TAG, "There are " + unregisteredTargets.size() + " unregistered targets. Including failure results.");
        List<SendMessageResult> unregisteredResults = unregisteredTargets.stream().filter(Recipient::hasServiceId).map(t -> SendMessageResult.unregisteredFailure(new SignalServiceAddress(t.requireServiceId(), t.getE164().orNull()))).collect(Collectors.toList());
        if (unregisteredResults.size() < unregisteredTargets.size()) {
            Log.w(TAG, "There are " + (unregisteredTargets.size() - unregisteredResults.size()) + " targets that have no UUID! Cannot report a failure for them.");
        }
        allResults.addAll(unregisteredResults);
    }
    return allResults;
}
Also used : SignalStore(org.thoughtcrime.securesms.keyvalue.SignalStore) SignalServiceDataMessage(org.whispersystems.signalservice.api.messages.SignalServiceDataMessage) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) NonNull(androidx.annotation.NonNull) RecipientUtil(org.thoughtcrime.securesms.recipients.RecipientUtil) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) NotFoundException(org.whispersystems.signalservice.api.push.exceptions.NotFoundException) SenderKeyUtil(org.thoughtcrime.securesms.crypto.SenderKeyUtil) RecipientId(org.thoughtcrime.securesms.recipients.RecipientId) Map(java.util.Map) Recipient(org.thoughtcrime.securesms.recipients.Recipient) LegacyGroupEvents(org.whispersystems.signalservice.api.SignalServiceMessageSender.LegacyGroupEvents) PartialSendCompleteListener(org.whispersystems.signalservice.internal.push.http.PartialSendCompleteListener) ApplicationDependencies(org.thoughtcrime.securesms.dependencies.ApplicationDependencies) InvalidUnidentifiedAccessHeaderException(org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException) Set(java.util.Set) UnidentifiedAccessUtil(org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil) Collectors(java.util.stream.Collectors) Objects(java.util.Objects) Log(org.signal.core.util.logging.Log) FeatureFlags(org.thoughtcrime.securesms.util.FeatureFlags) List(java.util.List) Nullable(androidx.annotation.Nullable) GroupId(org.thoughtcrime.securesms.groups.GroupId) NoSessionException(org.whispersystems.libsignal.NoSessionException) CancelationException(org.whispersystems.signalservice.api.CancelationException) Context(android.content.Context) RecipientAccessList(org.thoughtcrime.securesms.util.RecipientAccessList) SignalDatabase(org.thoughtcrime.securesms.database.SignalDatabase) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) SignalServiceTypingMessage(org.whispersystems.signalservice.api.messages.SignalServiceTypingMessage) SignalLocalMetrics(org.thoughtcrime.securesms.util.SignalLocalMetrics) WorkerThread(androidx.annotation.WorkerThread) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) SenderKeyGroupEvents(org.whispersystems.signalservice.api.SignalServiceMessageSender.SenderKeyGroupEvents) CancelationSignal(org.whispersystems.signalservice.internal.push.http.CancelationSignal) HashMap(java.util.HashMap) InvalidRegistrationIdException(org.whispersystems.libsignal.InvalidRegistrationIdException) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) UnidentifiedAccessPair(org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair) ArrayList(java.util.ArrayList) TextSecurePreferences(org.thoughtcrime.securesms.util.TextSecurePreferences) UnidentifiedAccess(org.whispersystems.signalservice.api.crypto.UnidentifiedAccess) SignalServiceCallMessage(org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage) MessageSendLogDatabase(org.thoughtcrime.securesms.database.MessageSendLogDatabase) LinkedList(java.util.LinkedList) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) MessageId(org.thoughtcrime.securesms.database.model.MessageId) Iterator(java.util.Iterator) IOException(java.io.IOException) Optional(org.whispersystems.libsignal.util.guava.Optional) TimeUnit(java.util.concurrent.TimeUnit) AtomicLong(java.util.concurrent.atomic.AtomicLong) UntrustedIdentityException(org.whispersystems.signalservice.api.crypto.UntrustedIdentityException) Collections(java.util.Collections) ArrayList(java.util.ArrayList) SignalServiceMessageSender(org.whispersystems.signalservice.api.SignalServiceMessageSender) NotFoundException(org.whispersystems.signalservice.api.push.exceptions.NotFoundException) MessageSendLogDatabase(org.thoughtcrime.securesms.database.MessageSendLogDatabase) GroupRecord(org.thoughtcrime.securesms.database.GroupDatabase.GroupRecord) NoSessionException(org.whispersystems.libsignal.NoSessionException) CancelationException(org.whispersystems.signalservice.api.CancelationException) SignalServiceAddress(org.whispersystems.signalservice.api.push.SignalServiceAddress) Optional(org.whispersystems.libsignal.util.guava.Optional) InvalidRegistrationIdException(org.whispersystems.libsignal.InvalidRegistrationIdException) Recipient(org.thoughtcrime.securesms.recipients.Recipient) UnidentifiedAccessPair(org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair) DistributionId(org.whispersystems.signalservice.api.push.DistributionId) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) LinkedList(java.util.LinkedList) SendMessageResult(org.whispersystems.signalservice.api.messages.SendMessageResult) ContentHint(org.whispersystems.signalservice.api.crypto.ContentHint) UnidentifiedAccess(org.whispersystems.signalservice.api.crypto.UnidentifiedAccess) AtomicLong(java.util.concurrent.atomic.AtomicLong) InvalidUnidentifiedAccessHeaderException(org.whispersystems.signalservice.internal.push.exceptions.InvalidUnidentifiedAccessHeaderException) WorkerThread(androidx.annotation.WorkerThread)

Example 10 with NoSessionException

use of org.whispersystems.libsignal.NoSessionException in project Conversations by siacs.

the class XmppAxolotlSession method processReceiving.

@Nullable
byte[] processReceiving(List<AxolotlKey> possibleKeys) throws CryptoFailedException {
    byte[] plaintext = null;
    FingerprintStatus status = getTrust();
    if (!status.isCompromised()) {
        Iterator<AxolotlKey> iterator = possibleKeys.iterator();
        while (iterator.hasNext()) {
            AxolotlKey encryptedKey = iterator.next();
            try {
                if (encryptedKey.prekey) {
                    PreKeySignalMessage preKeySignalMessage = new PreKeySignalMessage(encryptedKey.key);
                    Optional<Integer> optionalPreKeyId = preKeySignalMessage.getPreKeyId();
                    IdentityKey identityKey = preKeySignalMessage.getIdentityKey();
                    if (!optionalPreKeyId.isPresent()) {
                        if (iterator.hasNext()) {
                            continue;
                        }
                        throw new CryptoFailedException("PreKeyWhisperMessage did not contain a PreKeyId");
                    }
                    preKeyId = optionalPreKeyId.get();
                    if (this.identityKey != null && !this.identityKey.equals(identityKey)) {
                        if (iterator.hasNext()) {
                            continue;
                        }
                        throw new CryptoFailedException("Received PreKeyWhisperMessage but preexisting identity key changed.");
                    }
                    this.identityKey = identityKey;
                    plaintext = cipher.decrypt(preKeySignalMessage);
                } else {
                    SignalMessage signalMessage = new SignalMessage(encryptedKey.key);
                    try {
                        plaintext = cipher.decrypt(signalMessage);
                    } catch (InvalidMessageException | NoSessionException e) {
                        if (iterator.hasNext()) {
                            Log.w(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring crypto exception because possible keys left to try", e);
                            continue;
                        }
                        throw new BrokenSessionException(this.remoteAddress, e);
                    }
                    // better safe than sorry because we use that to do special after prekey handling
                    preKeyId = null;
                }
            } catch (InvalidVersionException | InvalidKeyException | LegacyMessageException | InvalidMessageException | DuplicateMessageException | InvalidKeyIdException | UntrustedIdentityException e) {
                if (iterator.hasNext()) {
                    Log.w(Config.LOGTAG, account.getJid().asBareJid() + ": ignoring crypto exception because possible keys left to try", e);
                    continue;
                }
                throw new CryptoFailedException("Error decrypting SignalMessage", e);
            }
            if (iterator.hasNext()) {
                break;
            }
        }
        if (!status.isActive()) {
            setTrust(status.toActive());
        // TODO: also (re)add to device list?
        }
    } else {
        throw new CryptoFailedException("not encrypting omemo message from fingerprint " + getFingerprint() + " because it was marked as compromised");
    }
    return plaintext;
}
Also used : InvalidMessageException(org.whispersystems.libsignal.InvalidMessageException) IdentityKey(org.whispersystems.libsignal.IdentityKey) UntrustedIdentityException(org.whispersystems.libsignal.UntrustedIdentityException) SignalMessage(org.whispersystems.libsignal.protocol.SignalMessage) PreKeySignalMessage(org.whispersystems.libsignal.protocol.PreKeySignalMessage) InvalidVersionException(org.whispersystems.libsignal.InvalidVersionException) InvalidKeyException(org.whispersystems.libsignal.InvalidKeyException) NoSessionException(org.whispersystems.libsignal.NoSessionException) PreKeySignalMessage(org.whispersystems.libsignal.protocol.PreKeySignalMessage) DuplicateMessageException(org.whispersystems.libsignal.DuplicateMessageException) InvalidKeyIdException(org.whispersystems.libsignal.InvalidKeyIdException) LegacyMessageException(org.whispersystems.libsignal.LegacyMessageException) Nullable(androidx.annotation.Nullable)

Aggregations

NoSessionException (org.whispersystems.libsignal.NoSessionException)13 InvalidKeyException (org.whispersystems.libsignal.InvalidKeyException)11 DuplicateMessageException (org.whispersystems.libsignal.DuplicateMessageException)9 InvalidMessageException (org.whispersystems.libsignal.InvalidMessageException)9 LegacyMessageException (org.whispersystems.libsignal.LegacyMessageException)9 SignalServiceAddress (org.whispersystems.signalservice.api.push.SignalServiceAddress)9 InvalidKeyIdException (org.whispersystems.libsignal.InvalidKeyIdException)7 InvalidVersionException (org.whispersystems.libsignal.InvalidVersionException)7 UntrustedIdentityException (org.whispersystems.libsignal.UntrustedIdentityException)7 IOException (java.io.IOException)6 Optional (org.whispersystems.libsignal.util.guava.Optional)6 SignalServiceDataMessage (org.whispersystems.signalservice.api.messages.SignalServiceDataMessage)6 SignalServiceCallMessage (org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage)6 Nullable (androidx.annotation.Nullable)3 ArrayList (java.util.ArrayList)3 Collections (java.util.Collections)3 HashMap (java.util.HashMap)3 Iterator (java.util.Iterator)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3