Send/receive unencrypted messages.

This commit is contained in:
Anton Chekulaev 2020-12-09 22:12:40 +11:00
parent 3bc4338444
commit 45ff8fba36
3 changed files with 75 additions and 62 deletions

View File

@ -293,24 +293,24 @@ public class SignalServiceMessageSender {
SignalServiceDataMessage message) SignalServiceDataMessage message)
throws UntrustedIdentityException, IOException throws UntrustedIdentityException, IOException
{ {
byte[] content = createMessageContent(message, recipient); byte[] content = createMessageContent(message, recipient);
long timestamp = message.getTimestamp(); long timestamp = message.getTimestamp();
boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store); boolean useFallbackEncryption = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(message, recipient.getNumber(), store);
boolean isClosedGroup = message.group.isPresent() && message.group.get().getGroupType() == SignalServiceGroup.GroupType.SIGNAL; boolean isClosedGroup = message.group.isPresent() && message.group.get().getGroupType() == SignalServiceGroup.GroupType.SIGNAL;
SendMessageResult result = sendMessage(messageID, recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, content, false, message.getTTL(), message.getDeviceLink().isPresent(), useFallbackEncryption, isClosedGroup, false, message.hasVisibleContent()); SendMessageResult result = sendMessage(messageID, recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, content, false, message.getTTL(), message.getDeviceLink().isPresent(), useFallbackEncryption, isClosedGroup, false, message.hasVisibleContent());
// Loki - This shouldn't get invoked for note to self // // Loki - This shouldn't get invoked for note to self
boolean wouldSignalSendSyncMessage = (result.getSuccess() != null && result.getSuccess().isNeedsSync()) || unidentifiedAccess.isPresent(); // boolean wouldSignalSendSyncMessage = (result.getSuccess() != null && result.getSuccess().isNeedsSync()) || unidentifiedAccess.isPresent();
if (wouldSignalSendSyncMessage && SyncMessagesProtocol.shared.shouldSyncMessage(message)) { // if (wouldSignalSendSyncMessage && SyncMessagesProtocol.shared.shouldSyncMessage(message)) {
byte[] syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.of(recipient), timestamp, Collections.singletonList(result)); // byte[] syncMessage = createMultiDeviceSentTranscriptContent(content, Optional.of(recipient), timestamp, Collections.singletonList(result));
// Loki - Customize multi device logic // // Loki - Customize multi device logic
Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey); // Set<String> linkedDevices = MultiDeviceProtocol.shared.getAllLinkedDevices(userPublicKey);
for (String device : linkedDevices) { // for (String device : linkedDevices) {
SignalServiceAddress deviceAsAddress = new SignalServiceAddress(device); // SignalServiceAddress deviceAsAddress = new SignalServiceAddress(device);
boolean useFallbackEncryptionForSyncMessage = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(syncMessage, device, store); // boolean useFallbackEncryptionForSyncMessage = SessionManagementProtocol.shared.shouldMessageUseFallbackEncryption(syncMessage, device, store);
sendMessage(deviceAsAddress, Optional.<UnidentifiedAccess>absent(), timestamp, syncMessage, false, message.getTTL(), useFallbackEncryptionForSyncMessage, true); // sendMessage(deviceAsAddress, Optional.<UnidentifiedAccess>absent(), timestamp, syncMessage, false, message.getTTL(), useFallbackEncryptionForSyncMessage, true);
} // }
} // }
// Loki - Start a session reset if needed // Loki - Start a session reset if needed
if (message.isEndSession()) { if (message.isEndSession()) {
@ -495,36 +495,36 @@ public class SignalServiceMessageSender {
return container.setReceiptMessage(builder).build().toByteArray(); return container.setReceiptMessage(builder).build().toByteArray();
} }
private byte[] createMessageContent(SignalServiceDataMessage message, SignalServiceAddress recipient) private byte[] createMessageContent(SignalServiceDataMessage message, SignalServiceAddress recipient)
throws IOException throws IOException
{ {
Content.Builder container = Content.newBuilder(); Content.Builder container = Content.newBuilder();
if (message.getPreKeyBundle().isPresent()) { // if (message.getPreKeyBundle().isPresent()) {
PreKeyBundle preKeyBundle = message.getPreKeyBundle().get(); // PreKeyBundle preKeyBundle = message.getPreKeyBundle().get();
PreKeyBundleMessage.Builder preKeyBundleMessageBuilder = PreKeyBundleMessage.newBuilder() // PreKeyBundleMessage.Builder preKeyBundleMessageBuilder = PreKeyBundleMessage.newBuilder()
.setDeviceId(preKeyBundle.getDeviceId()) // .setDeviceId(preKeyBundle.getDeviceId())
.setIdentityKey(ByteString.copyFrom(preKeyBundle.getIdentityKey().serialize())) // .setIdentityKey(ByteString.copyFrom(preKeyBundle.getIdentityKey().serialize()))
.setPreKeyId(preKeyBundle.getPreKeyId()) // .setPreKeyId(preKeyBundle.getPreKeyId())
.setPreKey(ByteString.copyFrom(preKeyBundle.getPreKey().serialize())) // .setPreKey(ByteString.copyFrom(preKeyBundle.getPreKey().serialize()))
.setSignedKeyId(preKeyBundle.getSignedPreKeyId()) // .setSignedKeyId(preKeyBundle.getSignedPreKeyId())
.setSignedKey(ByteString.copyFrom(preKeyBundle.getSignedPreKey().serialize())) // .setSignedKey(ByteString.copyFrom(preKeyBundle.getSignedPreKey().serialize()))
.setSignature(ByteString.copyFrom(preKeyBundle.getSignedPreKeySignature())) // .setSignature(ByteString.copyFrom(preKeyBundle.getSignedPreKeySignature()))
.setIdentityKey(ByteString.copyFrom(preKeyBundle.getIdentityKey().serialize())); // .setIdentityKey(ByteString.copyFrom(preKeyBundle.getIdentityKey().serialize()));
container.setPreKeyBundleMessage(preKeyBundleMessageBuilder); // container.setPreKeyBundleMessage(preKeyBundleMessageBuilder);
} // }
if (message.getDeviceLink().isPresent()) { // if (message.getDeviceLink().isPresent()) {
DeviceLink deviceLink = message.getDeviceLink().get(); // DeviceLink deviceLink = message.getDeviceLink().get();
SignalServiceProtos.DeviceLinkMessage.Builder deviceLinkMessageBuilder = SignalServiceProtos.DeviceLinkMessage.newBuilder() // SignalServiceProtos.DeviceLinkMessage.Builder deviceLinkMessageBuilder = SignalServiceProtos.DeviceLinkMessage.newBuilder()
.setPrimaryPublicKey(deviceLink.getMasterPublicKey()) // .setPrimaryPublicKey(deviceLink.getMasterPublicKey())
.setSecondaryPublicKey(deviceLink.getSlavePublicKey()) // .setSecondaryPublicKey(deviceLink.getSlavePublicKey())
.setRequestSignature(ByteString.copyFrom(Objects.requireNonNull(deviceLink.getRequestSignature()))); // .setRequestSignature(ByteString.copyFrom(Objects.requireNonNull(deviceLink.getRequestSignature())));
if (deviceLink.getAuthorizationSignature() != null) { // if (deviceLink.getAuthorizationSignature() != null) {
deviceLinkMessageBuilder.setAuthorizationSignature(ByteString.copyFrom(deviceLink.getAuthorizationSignature())); // deviceLinkMessageBuilder.setAuthorizationSignature(ByteString.copyFrom(deviceLink.getAuthorizationSignature()));
} // }
container.setDeviceLinkMessage(deviceLinkMessageBuilder.build()); // container.setDeviceLinkMessage(deviceLinkMessageBuilder.build());
} // }
DataMessage.Builder builder = DataMessage.newBuilder(); DataMessage.Builder builder = DataMessage.newBuilder();
List<AttachmentPointer> pointers = createAttachmentPointers(message.getAttachments(), recipient); List<AttachmentPointer> pointers = createAttachmentPointers(message.getAttachments(), recipient);
@ -1365,13 +1365,17 @@ public class SignalServiceMessageSender {
if (!recipient.equals(localAddress) || unidentifiedAccess.isPresent()) { if (!recipient.equals(localAddress) || unidentifiedAccess.isPresent()) {
if (sskDatabase.isSSKBasedClosedGroup(recipient.getNumber()) && unidentifiedAccess.isPresent()) { if (sskDatabase.isSSKBasedClosedGroup(recipient.getNumber()) && unidentifiedAccess.isPresent()) {
messages.add(getSSKEncryptedMessage(recipient.getNumber(), unidentifiedAccess.get(), plaintext)); messages.add(getSSKEncryptedMessage(recipient.getNumber(), unidentifiedAccess.get(), plaintext));
} else if (useFallbackEncryption) { // } else if (useFallbackEncryption) {
messages.add(getFallbackCipherEncryptedMessage(recipient.getNumber(), plaintext, unidentifiedAccess)); // messages.add(getFallbackCipherEncryptedMessage(recipient.getNumber(), plaintext, unidentifiedAccess));
// } else {
// OutgoingPushMessage message = getEncryptedMessage(socket, recipient, unidentifiedAccess, plaintext, isClosedGroup);
// if (message != null) { // May be null in a closed group context
// messages.add(message);
// }
// }
} else { } else {
OutgoingPushMessage message = getEncryptedMessage(socket, recipient, unidentifiedAccess, plaintext, isClosedGroup); OutgoingPushMessage message = getFallbackCipherEncryptedMessage(recipient.getNumber(), plaintext, unidentifiedAccess);
if (message != null) { // May be null in a closed group context messages.add(message);
messages.add(message);
}
} }
} }
@ -1383,17 +1387,19 @@ public class SignalServiceMessageSender {
{ {
Log.d("Loki", "Using fallback cipher."); Log.d("Loki", "Using fallback cipher.");
int deviceID = SignalServiceAddress.DEFAULT_DEVICE_ID; int deviceID = SignalServiceAddress.DEFAULT_DEVICE_ID;
SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(publicKey, deviceID); // SignalProtocolAddress signalProtocolAddress = new SignalProtocolAddress(publicKey, deviceID);
byte[] userPrivateKey = store.getIdentityKeyPair().getPrivateKey().serialize(); // byte[] userPrivateKey = store.getIdentityKeyPair().getPrivateKey().serialize();
FallbackSessionCipher cipher = new FallbackSessionCipher(userPrivateKey, publicKey); // FallbackSessionCipher cipher = new FallbackSessionCipher(userPrivateKey, publicKey);
PushTransportDetails transportDetails = new PushTransportDetails(FallbackSessionCipher.getSessionVersion()); PushTransportDetails transportDetails = new PushTransportDetails(FallbackSessionCipher.getSessionVersion());
byte[] bytes = cipher.encrypt(transportDetails.getPaddedMessageBody(plaintext)); // byte[] bytes = cipher.encrypt(transportDetails.getPaddedMessageBody(plaintext));
if (bytes == null) { bytes = new byte[0]; } byte[] bytes = transportDetails.getPaddedMessageBody(plaintext);
// if (bytes == null) { bytes = new byte[0]; }
if (unidentifiedAccess.isPresent()) { if (unidentifiedAccess.isPresent()) {
SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(store, null, signalProtocolAddress); // SealedSessionCipher sealedSessionCipher = new SealedSessionCipher(store, null, signalProtocolAddress);
FallbackMessage message = new FallbackMessage(bytes); // FallbackMessage message = new FallbackMessage(bytes);
byte[] ciphertext = sealedSessionCipher.encrypt(signalProtocolAddress, unidentifiedAccess.get().getUnidentifiedCertificate(), message); // byte[] ciphertext = sealedSessionCipher.encrypt(signalProtocolAddress, unidentifiedAccess.get().getUnidentifiedCertificate(), message);
return new OutgoingPushMessage(SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER_VALUE, deviceID, 0, Base64.encodeBytes(ciphertext)); // return new OutgoingPushMessage(SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER_VALUE, deviceID, 0, Base64.encodeBytes(ciphertext));
return new OutgoingPushMessage(SignalServiceProtos.Envelope.Type.UNIDENTIFIED_SENDER_VALUE, deviceID, 0, Base64.encodeBytes(bytes));
} else { } else {
return new OutgoingPushMessage(SignalServiceProtos.Envelope.Type.FALLBACK_MESSAGE_VALUE, deviceID, 0, Base64.encodeBytes(bytes)); return new OutgoingPushMessage(SignalServiceProtos.Envelope.Type.FALLBACK_MESSAGE_VALUE, deviceID, 0, Base64.encodeBytes(bytes));
} }

View File

@ -23,7 +23,13 @@ class LokiServiceCipher(
override fun decrypt(envelope: SignalServiceEnvelope, ciphertext: ByteArray): Plaintext { override fun decrypt(envelope: SignalServiceEnvelope, ciphertext: ByteArray): Plaintext {
// return if (envelope.isFallbackMessage) decryptFallbackMessage(envelope, ciphertext) else super.decrypt(envelope, ciphertext) // return if (envelope.isFallbackMessage) decryptFallbackMessage(envelope, ciphertext) else super.decrypt(envelope, ciphertext)
return decryptFallbackMessage(envelope, ciphertext); // return decryptFallbackMessage(envelope, ciphertext);
//AC: Messages come unencrypted (for refactoring time being).
val transportDetails = PushTransportDetails(FallbackSessionCipher.sessionVersion)
val unpaddedMessageBody = transportDetails.getStrippedPaddingMessageBody(ciphertext)
val metadata = Metadata(envelope.source, envelope.sourceDevice, envelope.timestamp, false)
return Plaintext(metadata, unpaddedMessageBody)
} }
private fun decryptFallbackMessage(envelope: SignalServiceEnvelope, ciphertext: ByteArray): Plaintext { private fun decryptFallbackMessage(envelope: SignalServiceEnvelope, ciphertext: ByteArray): Plaintext {

View File

@ -30,10 +30,11 @@ public class SessionManagementProtocol(private val sessionResetImpl: SessionRese
// region Sending // region Sending
public fun shouldMessageUseFallbackEncryption(message: Any, publicKey: String, store: SignalProtocolStore): Boolean { public fun shouldMessageUseFallbackEncryption(message: Any, publicKey: String, store: SignalProtocolStore): Boolean {
if (sskDatabase.isSSKBasedClosedGroup(publicKey)) { return true } // We don't actually use fallback encryption but this indicates that we don't need a session // if (sskDatabase.isSSKBasedClosedGroup(publicKey)) { return true } // We don't actually use fallback encryption but this indicates that we don't need a session
if (message is SignalServiceDataMessage && message.preKeyBundle.isPresent) { return true; } // This covers session requests as well as end session messages // if (message is SignalServiceDataMessage && message.preKeyBundle.isPresent) { return true; } // This covers session requests as well as end session messages
val recipient = SignalProtocolAddress(publicKey, SignalServiceAddress.DEFAULT_DEVICE_ID) // val recipient = SignalProtocolAddress(publicKey, SignalServiceAddress.DEFAULT_DEVICE_ID)
return !store.containsSession(recipient) // return !store.containsSession(recipient)
return true;
} }
/** /**