use of org.signal.libsignal.metadata.ProtocolInvalidKeyException in project Signal-Android by WhisperSystems.
the class SignalServiceContent method createSynchronizeMessage.
private static SignalServiceSyncMessage createSynchronizeMessage(SignalServiceMetadata metadata, SignalServiceProtos.SyncMessage content) throws ProtocolInvalidKeyException, UnsupportedDataMessageException, InvalidMessageStructureException {
if (content.hasSent()) {
Map<SignalServiceAddress, Boolean> unidentifiedStatuses = new HashMap<>();
SignalServiceProtos.SyncMessage.Sent sentContent = content.getSent();
SignalServiceDataMessage dataMessage = createSignalServiceMessage(metadata, sentContent.getMessage());
Optional<SignalServiceAddress> address = SignalServiceAddress.isValidAddress(sentContent.getDestinationUuid(), sentContent.getDestinationE164()) ? Optional.of(new SignalServiceAddress(ACI.parseOrThrow(sentContent.getDestinationUuid()), sentContent.getDestinationE164())) : Optional.<SignalServiceAddress>absent();
if (!address.isPresent() && !dataMessage.getGroupContext().isPresent()) {
throw new InvalidMessageStructureException("SyncMessage missing both destination and group ID!");
}
for (SignalServiceProtos.SyncMessage.Sent.UnidentifiedDeliveryStatus status : sentContent.getUnidentifiedStatusList()) {
if (SignalServiceAddress.isValidAddress(status.getDestinationUuid(), status.getDestinationE164())) {
SignalServiceAddress recipient = new SignalServiceAddress(ACI.parseOrThrow(status.getDestinationUuid()), status.getDestinationE164());
unidentifiedStatuses.put(recipient, status.getUnidentified());
} else {
Log.w(TAG, "Encountered an invalid UnidentifiedDeliveryStatus in a SentTranscript! Ignoring.");
}
}
return SignalServiceSyncMessage.forSentTranscript(new SentTranscriptMessage(address, sentContent.getTimestamp(), dataMessage, sentContent.getExpirationStartTimestamp(), unidentifiedStatuses, sentContent.getIsRecipientUpdate()));
}
if (content.hasRequest()) {
return SignalServiceSyncMessage.forRequest(new RequestMessage(content.getRequest()));
}
if (content.getReadList().size() > 0) {
List<ReadMessage> readMessages = new LinkedList<>();
for (SignalServiceProtos.SyncMessage.Read read : content.getReadList()) {
if (SignalServiceAddress.isValidAddress(read.getSenderUuid(), read.getSenderE164())) {
SignalServiceAddress address = new SignalServiceAddress(ACI.parseOrThrow(read.getSenderUuid()), read.getSenderE164());
readMessages.add(new ReadMessage(address, read.getTimestamp()));
} else {
Log.w(TAG, "Encountered an invalid ReadMessage! Ignoring.");
}
}
return SignalServiceSyncMessage.forRead(readMessages);
}
if (content.getViewedList().size() > 0) {
List<ViewedMessage> viewedMessages = new LinkedList<>();
for (SignalServiceProtos.SyncMessage.Viewed viewed : content.getViewedList()) {
if (SignalServiceAddress.isValidAddress(viewed.getSenderUuid(), viewed.getSenderE164())) {
SignalServiceAddress address = new SignalServiceAddress(ACI.parseOrThrow(viewed.getSenderUuid()), viewed.getSenderE164());
viewedMessages.add(new ViewedMessage(address, viewed.getTimestamp()));
} else {
Log.w(TAG, "Encountered an invalid ReadMessage! Ignoring.");
}
}
return SignalServiceSyncMessage.forViewed(viewedMessages);
}
if (content.hasViewOnceOpen()) {
if (SignalServiceAddress.isValidAddress(content.getViewOnceOpen().getSenderUuid(), content.getViewOnceOpen().getSenderE164())) {
SignalServiceAddress address = new SignalServiceAddress(ACI.parseOrThrow(content.getViewOnceOpen().getSenderUuid()), content.getViewOnceOpen().getSenderE164());
ViewOnceOpenMessage timerRead = new ViewOnceOpenMessage(address, content.getViewOnceOpen().getTimestamp());
return SignalServiceSyncMessage.forViewOnceOpen(timerRead);
} else {
throw new InvalidMessageStructureException("ViewOnceOpen message has no sender!");
}
}
if (content.hasVerified()) {
if (SignalServiceAddress.isValidAddress(content.getVerified().getDestinationUuid(), content.getVerified().getDestinationE164())) {
try {
SignalServiceProtos.Verified verified = content.getVerified();
SignalServiceAddress destination = new SignalServiceAddress(ACI.parseOrThrow(verified.getDestinationUuid()), verified.getDestinationE164());
IdentityKey identityKey = new IdentityKey(verified.getIdentityKey().toByteArray(), 0);
VerifiedMessage.VerifiedState verifiedState;
if (verified.getState() == SignalServiceProtos.Verified.State.DEFAULT) {
verifiedState = VerifiedMessage.VerifiedState.DEFAULT;
} else if (verified.getState() == SignalServiceProtos.Verified.State.VERIFIED) {
verifiedState = VerifiedMessage.VerifiedState.VERIFIED;
} else if (verified.getState() == SignalServiceProtos.Verified.State.UNVERIFIED) {
verifiedState = VerifiedMessage.VerifiedState.UNVERIFIED;
} else {
throw new InvalidMessageStructureException("Unknown state: " + verified.getState().getNumber(), metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
return SignalServiceSyncMessage.forVerified(new VerifiedMessage(destination, identityKey, verifiedState, System.currentTimeMillis()));
} catch (InvalidKeyException e) {
throw new ProtocolInvalidKeyException(e, metadata.getSender().getIdentifier(), metadata.getSenderDevice());
}
} else {
throw new InvalidMessageStructureException("Verified message has no sender!");
}
}
if (content.getStickerPackOperationList().size() > 0) {
List<StickerPackOperationMessage> operations = new LinkedList<>();
for (SignalServiceProtos.SyncMessage.StickerPackOperation operation : content.getStickerPackOperationList()) {
byte[] packId = operation.hasPackId() ? operation.getPackId().toByteArray() : null;
byte[] packKey = operation.hasPackKey() ? operation.getPackKey().toByteArray() : null;
StickerPackOperationMessage.Type type = null;
if (operation.hasType()) {
switch(operation.getType()) {
case INSTALL:
type = StickerPackOperationMessage.Type.INSTALL;
break;
case REMOVE:
type = StickerPackOperationMessage.Type.REMOVE;
break;
}
}
operations.add(new StickerPackOperationMessage(packId, packKey, type));
}
return SignalServiceSyncMessage.forStickerPackOperations(operations);
}
if (content.hasBlocked()) {
List<String> numbers = content.getBlocked().getNumbersList();
List<String> uuids = content.getBlocked().getUuidsList();
List<SignalServiceAddress> addresses = new ArrayList<>(numbers.size() + uuids.size());
List<byte[]> groupIds = new ArrayList<>(content.getBlocked().getGroupIdsList().size());
for (String uuid : uuids) {
Optional<SignalServiceAddress> address = SignalServiceAddress.fromRaw(uuid, null);
if (address.isPresent()) {
addresses.add(address.get());
}
}
for (ByteString groupId : content.getBlocked().getGroupIdsList()) {
groupIds.add(groupId.toByteArray());
}
return SignalServiceSyncMessage.forBlocked(new BlockedListMessage(addresses, groupIds));
}
if (content.hasConfiguration()) {
Boolean readReceipts = content.getConfiguration().hasReadReceipts() ? content.getConfiguration().getReadReceipts() : null;
Boolean unidentifiedDeliveryIndicators = content.getConfiguration().hasUnidentifiedDeliveryIndicators() ? content.getConfiguration().getUnidentifiedDeliveryIndicators() : null;
Boolean typingIndicators = content.getConfiguration().hasTypingIndicators() ? content.getConfiguration().getTypingIndicators() : null;
Boolean linkPreviews = content.getConfiguration().hasLinkPreviews() ? content.getConfiguration().getLinkPreviews() : null;
return SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.fromNullable(readReceipts), Optional.fromNullable(unidentifiedDeliveryIndicators), Optional.fromNullable(typingIndicators), Optional.fromNullable(linkPreviews)));
}
if (content.hasFetchLatest() && content.getFetchLatest().hasType()) {
switch(content.getFetchLatest().getType()) {
case LOCAL_PROFILE:
return SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.LOCAL_PROFILE);
case STORAGE_MANIFEST:
return SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.STORAGE_MANIFEST);
case SUBSCRIPTION_STATUS:
return SignalServiceSyncMessage.forFetchLatest(SignalServiceSyncMessage.FetchType.SUBSCRIPTION_STATUS);
}
}
if (content.hasMessageRequestResponse()) {
MessageRequestResponseMessage.Type type;
switch(content.getMessageRequestResponse().getType()) {
case ACCEPT:
type = MessageRequestResponseMessage.Type.ACCEPT;
break;
case DELETE:
type = MessageRequestResponseMessage.Type.DELETE;
break;
case BLOCK:
type = MessageRequestResponseMessage.Type.BLOCK;
break;
case BLOCK_AND_DELETE:
type = MessageRequestResponseMessage.Type.BLOCK_AND_DELETE;
break;
default:
type = MessageRequestResponseMessage.Type.UNKNOWN;
break;
}
MessageRequestResponseMessage responseMessage;
if (content.getMessageRequestResponse().hasGroupId()) {
responseMessage = MessageRequestResponseMessage.forGroup(content.getMessageRequestResponse().getGroupId().toByteArray(), type);
} else {
Optional<SignalServiceAddress> address = SignalServiceAddress.fromRaw(content.getMessageRequestResponse().getThreadUuid(), content.getMessageRequestResponse().getThreadE164());
if (address.isPresent()) {
responseMessage = MessageRequestResponseMessage.forIndividual(address.get(), type);
} else {
throw new InvalidMessageStructureException("Message request response has an invalid thread identifier!");
}
}
return SignalServiceSyncMessage.forMessageRequestResponse(responseMessage);
}
if (content.hasOutgoingPayment()) {
SignalServiceProtos.SyncMessage.OutgoingPayment outgoingPayment = content.getOutgoingPayment();
switch(outgoingPayment.getPaymentDetailCase()) {
case MOBILECOIN:
{
SignalServiceProtos.SyncMessage.OutgoingPayment.MobileCoin mobileCoin = outgoingPayment.getMobileCoin();
Money.MobileCoin amount = Money.picoMobileCoin(mobileCoin.getAmountPicoMob());
Money.MobileCoin fee = Money.picoMobileCoin(mobileCoin.getFeePicoMob());
ByteString address = mobileCoin.getRecipientAddress();
Optional<SignalServiceAddress> recipient = SignalServiceAddress.fromRaw(outgoingPayment.getRecipientUuid(), null);
return SignalServiceSyncMessage.forOutgoingPayment(new OutgoingPaymentMessage(recipient, amount, fee, mobileCoin.getReceipt(), mobileCoin.getLedgerBlockIndex(), mobileCoin.getLedgerBlockTimestamp(), address.isEmpty() ? Optional.absent() : Optional.of(address.toByteArray()), Optional.of(outgoingPayment.getNote()), mobileCoin.getOutputPublicKeysList(), mobileCoin.getSpentKeyImagesList()));
}
default:
return SignalServiceSyncMessage.empty();
}
}
if (content.hasKeys() && content.getKeys().hasStorageService()) {
byte[] storageKey = content.getKeys().getStorageService().toByteArray();
return SignalServiceSyncMessage.forKeys(new KeysMessage(Optional.of(new StorageKey(storageKey))));
}
if (content.hasContacts()) {
return SignalServiceSyncMessage.forContacts(new ContactsMessage(createAttachmentPointer(content.getContacts().getBlob()), content.getContacts().getComplete()));
}
return SignalServiceSyncMessage.empty();
}
use of org.signal.libsignal.metadata.ProtocolInvalidKeyException 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());
}
}
use of org.signal.libsignal.metadata.ProtocolInvalidKeyException in project Signal-Android by WhisperSystems.
the class MessageDecryptionUtil method decrypt.
/**
* Takes a {@link SignalServiceEnvelope} and returns a {@link DecryptionResult}, which has either
* a plaintext {@link SignalServiceContent} or information about an error that happened.
*
* Excluding the data updated in our protocol stores that results from decrypting a message, this
* method is side-effect free, preferring to return the decryption results to be handled by the
* caller.
*/
@NonNull
public static DecryptionResult decrypt(@NonNull Context context, @NonNull SignalServiceEnvelope envelope) {
SignalServiceAccountDataStore protocolStore = ApplicationDependencies.getProtocolStore().aci();
SignalServiceAddress localAddress = new SignalServiceAddress(Recipient.self().requireServiceId(), Recipient.self().requireE164());
SignalServiceCipher cipher = new SignalServiceCipher(localAddress, SignalStore.account().getDeviceId(), protocolStore, ReentrantSessionLock.INSTANCE, UnidentifiedAccessUtil.getCertificateValidator());
List<Job> jobs = new LinkedList<>();
if (envelope.isPreKeySignalMessage()) {
jobs.add(new RefreshPreKeysJob());
}
try {
try {
return DecryptionResult.forSuccess(cipher.decrypt(envelope), jobs);
} catch (ProtocolInvalidVersionException e) {
Log.w(TAG, String.valueOf(envelope.getTimestamp()), e);
return DecryptionResult.forError(MessageState.INVALID_VERSION, toExceptionMetadata(e), jobs);
} catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException | ProtocolNoSessionException | ProtocolInvalidMessageException e) {
Log.w(TAG, String.valueOf(envelope.getTimestamp()), e);
Recipient sender = Recipient.external(context, e.getSender());
if (sender.supportsMessageRetries() && Recipient.self().supportsMessageRetries() && FeatureFlags.retryReceipts()) {
jobs.add(handleRetry(context, sender, envelope, e));
postInternalErrorNotification(context);
} else {
jobs.add(new AutomaticSessionResetJob(sender.getId(), e.getSenderDevice(), envelope.getTimestamp()));
}
return DecryptionResult.forNoop(jobs);
} catch (ProtocolLegacyMessageException e) {
Log.w(TAG, "[" + envelope.getTimestamp() + "] " + envelope.getSourceIdentifier() + ":" + envelope.getSourceDevice(), e);
return DecryptionResult.forError(MessageState.LEGACY_MESSAGE, toExceptionMetadata(e), jobs);
} catch (ProtocolDuplicateMessageException e) {
Log.w(TAG, "[" + envelope.getTimestamp() + "] " + envelope.getSourceIdentifier() + ":" + envelope.getSourceDevice(), e);
return DecryptionResult.forError(MessageState.DUPLICATE_MESSAGE, toExceptionMetadata(e), jobs);
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException | InvalidMessageStructureException e) {
Log.w(TAG, "[" + envelope.getTimestamp() + "] " + envelope.getSourceIdentifier() + ":" + envelope.getSourceDevice(), e);
return DecryptionResult.forNoop(jobs);
} catch (SelfSendException e) {
Log.i(TAG, "Dropping UD message from self.");
return DecryptionResult.forNoop(jobs);
} catch (UnsupportedDataMessageException e) {
Log.w(TAG, "[" + envelope.getTimestamp() + "] " + envelope.getSourceIdentifier() + ":" + envelope.getSourceDevice(), e);
return DecryptionResult.forError(MessageState.UNSUPPORTED_DATA_MESSAGE, toExceptionMetadata(e), jobs);
}
} catch (NoSenderException e) {
Log.w(TAG, "Invalid message, but no sender info!");
return DecryptionResult.forNoop(jobs);
}
}
Aggregations