diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/UnidentifiedAccessUtil.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/UnidentifiedAccessUtil.java index ad545f3c94..59e5d75731 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/UnidentifiedAccessUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/UnidentifiedAccessUtil.java @@ -7,90 +7,57 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import org.session.libsignal.metadata.SignalProtos; -import org.session.libsignal.metadata.certificate.CertificateValidator; -import org.session.libsignal.metadata.certificate.InvalidCertificateException; import org.session.libsignal.utilities.logging.Log; import org.session.libsession.messaging.threads.recipients.Recipient; import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.Util; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.crypto.UnidentifiedAccess; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; import org.session.libsignal.service.api.push.SignalServiceAddress; public class UnidentifiedAccessUtil { private static final String TAG = UnidentifiedAccessUtil.class.getSimpleName(); - public static CertificateValidator getCertificateValidator() { - return new CertificateValidator(); - } - @WorkerThread - public static Optional getAccessFor(@NonNull Context context, + public static Optional getAccessFor(@NonNull Context context, @NonNull Recipient recipient) { - if (!TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) { - Log.i(TAG, "Unidentified delivery is disabled. [other]"); - return Optional.absent(); + byte[] theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient); + byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context); + byte[] ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate(context); + + if (TextSecurePreferences.isUniversalUnidentifiedAccess(context)) { + ourUnidentifiedAccessKey = Util.getSecretBytes(16); } - try { - byte[] theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient); - byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context); - byte[] ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate(context); - - if (TextSecurePreferences.isUniversalUnidentifiedAccess(context)) { - ourUnidentifiedAccessKey = Util.getSecretBytes(16); - } - - Log.i(TAG, "Their access key present? " + (theirUnidentifiedAccessKey != null) + - " | Our access key present? " + (ourUnidentifiedAccessKey != null) + - " | Our certificate present? " + (ourUnidentifiedAccessCertificate != null)); - - if (theirUnidentifiedAccessKey != null && - ourUnidentifiedAccessKey != null && - ourUnidentifiedAccessCertificate != null) - { - return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(theirUnidentifiedAccessKey, - ourUnidentifiedAccessCertificate), - new UnidentifiedAccess(ourUnidentifiedAccessKey, - ourUnidentifiedAccessCertificate))); - } - - return Optional.absent(); - } catch (InvalidCertificateException e) { - Log.w(TAG, e); - return Optional.absent(); + Log.i(TAG, "Their access key present? " + (theirUnidentifiedAccessKey != null) + + " | Our access key present? " + (ourUnidentifiedAccessKey != null) + + " | Our certificate present? " + (ourUnidentifiedAccessCertificate != null)); + + if (theirUnidentifiedAccessKey != null && + ourUnidentifiedAccessKey != null && + ourUnidentifiedAccessCertificate != null) + { + return Optional.of(new UnidentifiedAccess(theirUnidentifiedAccessKey)); } + + return Optional.absent(); } - public static Optional getAccessForSync(@NonNull Context context) { - if (!TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) { - Log.i(TAG, "Unidentified delivery is disabled. [self]"); - return Optional.absent(); + public static Optional getAccessForSync(@NonNull Context context) { + byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context); + byte[] ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate(context); + + if (TextSecurePreferences.isUniversalUnidentifiedAccess(context)) { + ourUnidentifiedAccessKey = Util.getSecretBytes(16); } - try { - byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context); - byte[] ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate(context); - - if (TextSecurePreferences.isUniversalUnidentifiedAccess(context)) { - ourUnidentifiedAccessKey = Util.getSecretBytes(16); - } - - if (ourUnidentifiedAccessKey != null && ourUnidentifiedAccessCertificate != null) { - return Optional.of(new UnidentifiedAccessPair(new UnidentifiedAccess(ourUnidentifiedAccessKey, - ourUnidentifiedAccessCertificate), - new UnidentifiedAccess(ourUnidentifiedAccessKey, - ourUnidentifiedAccessCertificate))); - } - - return Optional.absent(); - } catch (InvalidCertificateException e) { - Log.w(TAG, e); - return Optional.absent(); + if (ourUnidentifiedAccessKey != null && ourUnidentifiedAccessCertificate != null) { + return Optional.of(new UnidentifiedAccess(ourUnidentifiedAccessKey)); } + + return Optional.absent(); } public static @NonNull byte[] getSelfUnidentifiedAccessKey(@NonNull Context context) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java index 0db956eb7a..5e7b0194d8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushGroupSendJob.java @@ -16,6 +16,7 @@ import org.session.libsession.messaging.threads.Address; import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.TextSecurePreferences; +import org.session.libsignal.service.api.crypto.UnidentifiedAccess; import org.session.libsignal.service.internal.push.SignalServiceProtos; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; @@ -37,7 +38,6 @@ import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.SignalServiceMessageSender; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; import org.session.libsignal.service.api.crypto.UntrustedIdentityException; import org.session.libsignal.service.api.messages.SendMessageResult; import org.session.libsignal.service.api.messages.SignalServiceAttachment; @@ -236,7 +236,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType { Address address = message.getRecipient().getAddress(); List addresses = Stream.of(destinations).map(this::getPushAddress).toList(); - List> unidentifiedAccess = Stream.of(addresses) + List> unidentifiedAccess = Stream.of(addresses) .map(a -> Address.fromSerialized(a.getNumber())) .map(a -> Recipient.from(context, a, false)) .map(recipient -> UnidentifiedAccessUtil.getAccessFor(context, recipient)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java index 998b4a21e4..f4473c1144 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushMediaSendJob.java @@ -13,6 +13,7 @@ import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAt import org.session.libsession.messaging.threads.recipients.Recipient.UnidentifiedAccessMode; import org.session.libsession.utilities.TextSecurePreferences; +import org.session.libsignal.service.api.crypto.UnidentifiedAccess; import org.thoughtcrime.securesms.ApplicationContext; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.database.DatabaseFactory; @@ -33,7 +34,6 @@ import org.thoughtcrime.securesms.transport.RetryLaterException; import org.thoughtcrime.securesms.transport.UndeliverableMessageException; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.SignalServiceMessageSender; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; import org.session.libsignal.service.api.crypto.UntrustedIdentityException; import org.session.libsignal.service.api.messages.SendMessageResult; import org.session.libsignal.service.api.messages.SignalServiceAttachment; @@ -181,17 +181,15 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis()); } - if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) { - if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { - log(TAG, "Marking recipient as UD-unrestricted following a UD send."); - DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED); - } else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) { - log(TAG, "Marking recipient as UD-enabled following a UD send."); - DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED); - } else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) { - log(TAG, "Marking recipient as UD-disabled following a non-UD send."); - DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED); - } + if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { + log(TAG, "Marking recipient as UD-unrestricted following a UD send."); + DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED); + } else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) { + log(TAG, "Marking recipient as UD-enabled following a UD send."); + DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED); + } else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) { + log(TAG, "Marking recipient as UD-disabled following a non-UD send."); + DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED); } if (messageId > 0 && message.getExpiresIn() > 0 && !message.isExpirationUpdate()) { @@ -207,12 +205,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { database.markAsPendingInsecureSmsFallback(messageId); notifyMediaMessageDeliveryFailed(context, messageId); } - } catch (UntrustedIdentityException uie) { - warn(TAG, "Failure", uie); - if (messageId >= 0) { - database.addMismatchedIdentity(messageId, Address.fromSerialized(uie.getE164Number()), uie.getIdentityKey()); - database.markAsSentFailed(messageId); - } } catch (SnodeAPI.Error e) { Log.d("Loki", "Couldn't send message due to error: " + e.getDescription()); if (messageId >= 0) { @@ -238,8 +230,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { } private boolean deliver(OutgoingMediaMessage message) - throws RetryLaterException, InsecureFallbackApprovalException, UntrustedIdentityException, - UndeliverableMessageException, SnodeAPI.Error + throws RetryLaterException, InsecureFallbackApprovalException, UndeliverableMessageException, SnodeAPI.Error { try { Recipient recipient = Recipient.from(context, destination, false); @@ -250,11 +241,10 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { List serviceAttachments = getAttachmentPointersFor(attachments); Optional profileKey = getProfileKey(message.getRecipient()); Optional quote = getQuoteFor(message); - Optional sticker = getStickerFor(message); List sharedContacts = getSharedContactsFor(message); List previews = getPreviewsFor(message); - Optional unidentifiedAccessPair = UnidentifiedAccessUtil.getAccessFor(context, recipient); + Optional unidentifiedAccessPair = UnidentifiedAccessUtil.getAccessFor(context, recipient); SignalServiceDataMessage mediaMessage = SignalServiceDataMessage.newBuilder() .withBody(message.getBody()) @@ -298,7 +288,7 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType { try { // send to ourselves to sync multi-device - Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); + Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); SendMessageResult selfSendResult = messageSender.sendMessage(messageId, localAddress, syncAccess, mediaSelfSendMessage); if (selfSendResult.getLokiAPIError() != null) { throw selfSendResult.getLokiAPIError(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java index c74fd15aa8..87549bd602 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/PushTextSendJob.java @@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException; import org.thoughtcrime.securesms.transport.RetryLaterException; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.SignalServiceMessageSender; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; import org.session.libsignal.service.api.crypto.UntrustedIdentityException; import org.session.libsignal.service.api.messages.SendMessageResult; import org.session.libsignal.service.api.messages.SignalServiceDataMessage; @@ -124,17 +123,15 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { DatabaseFactory.getMmsSmsDatabase(context).incrementReadReceiptCount(id, System.currentTimeMillis()); } - if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) { - if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { - log(TAG, "Marking recipient as UD-unrestricted following a UD send."); - DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED); - } else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) { - log(TAG, "Marking recipient as UD-enabled following a UD send."); - DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED); - } else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) { - log(TAG, "Marking recipient as UD-disabled following a non-UD send."); - DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED); - } + if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN && profileKey == null) { + log(TAG, "Marking recipient as UD-unrestricted following a UD send."); + DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED); + } else if (unidentified && accessMode == UnidentifiedAccessMode.UNKNOWN) { + log(TAG, "Marking recipient as UD-enabled following a UD send."); + DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED); + } else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) { + log(TAG, "Marking recipient as UD-disabled following a non-UD send."); + DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED); } if (record.getExpiresIn() > 0 && messageId >= 0) { @@ -196,15 +193,10 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { SignalServiceAddress address = getPushAddress(recipient.getAddress()); SignalServiceAddress localAddress = new SignalServiceAddress(userPublicKey); Optional profileKey = getProfileKey(recipient); - Optional unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient); + Optional unidentifiedAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient); log(TAG, "Have access key to use: " + unidentifiedAccess.isPresent()); -// PreKeyBundle preKeyBundle = null; -// if (message.isEndSession()) { -// preKeyBundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(destination.serialize()); -// } - SignalServiceDataMessage textSecureMessage = SignalServiceDataMessage.newBuilder() .withTimestamp(message.getDateSent()) .withBody(message.getBody()) @@ -237,7 +229,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType { try { // send to ourselves to sync multi-device - Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); + Optional syncAccess = UnidentifiedAccessUtil.getAccessForSync(context); SendMessageResult selfSendResult = messageSender.sendMessage(messageId, localAddress, syncAccess, textSecureSelfSendMessage); if (selfSendResult.getLokiAPIError() != null) { throw selfSendResult.getLokiAPIError(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java index a3ce38a374..ad0325045b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/TypingSendJob.java @@ -5,20 +5,19 @@ import androidx.annotation.NonNull; import com.annimon.stream.Stream; import org.session.libsession.messaging.jobs.Data; +import org.session.libsignal.libsignal.util.guava.Optional; +import org.session.libsignal.service.api.crypto.UnidentifiedAccess; import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.dependencies.InjectableType; import org.thoughtcrime.securesms.jobmanager.Job; import org.session.libsignal.utilities.logging.Log; -import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.SignalServiceMessageSender; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; import org.session.libsignal.service.api.messages.SignalServiceTypingMessage; import org.session.libsignal.service.api.messages.SignalServiceTypingMessage.Action; import org.session.libsignal.service.api.push.SignalServiceAddress; import org.session.libsession.messaging.threads.recipients.Recipient; -import org.session.libsession.utilities.GroupUtil; import org.session.libsession.utilities.TextSecurePreferences; import java.util.Collections; @@ -93,7 +92,7 @@ public class TypingSendJob extends BaseJob implements InjectableType { } List addresses = Stream.of(recipients).map(r -> new SignalServiceAddress(r.getAddress().serialize())).toList(); - List> unidentifiedAccess = Stream.of(recipients).map(r -> UnidentifiedAccessUtil.getAccessFor(context, r)).toList(); + List> unidentifiedAccess = Stream.of(recipients).map(r -> UnidentifiedAccessUtil.getAccessFor(context, r)).toList(); SignalServiceTypingMessage typingMessage = new SignalServiceTypingMessage(typing ? Action.STARTED : Action.STOPPED, System.currentTimeMillis()); messageSender.sendTyping(addresses, unidentifiedAccess, typingMessage); diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt index 4b4673936d..009fb08b48 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/ClosedGroupUpdateMessageSendJobV2.kt @@ -223,7 +223,7 @@ class ClosedGroupUpdateMessageSendJobV2 private constructor(parameters: Paramete } try { // isClosedGroup can always be false as it's only used in the context of legacy closed groups - messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess, + messageSender.sendMessage(0, address, udAccess, sentTime, serializedContentMessage, false, ttl, true, false, false, Optional.absent()) } catch (e: Exception) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt index b5e1f31e2c..e921f08062 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/loki/protocol/MultiDeviceProtocol.kt @@ -34,7 +34,7 @@ object MultiDeviceProtocol { val recipient = recipient(context, userPublicKey) val udAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient) try { - messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess, + messageSender.sendMessage(0, address, udAccess, Date().time, serializedMessage, false, configurationMessage.ttl.toInt(), true, false, true, Optional.absent()) TextSecurePreferences.setLastConfigurationSyncTime(context, now) @@ -53,7 +53,7 @@ object MultiDeviceProtocol { val recipient = recipient(context, userPublicKey) val udAccess = UnidentifiedAccessUtil.getAccessFor(context, recipient) try { - messageSender.sendMessage(0, address, udAccess.get().targetUnidentifiedAccess, + messageSender.sendMessage(0, address, udAccess, Date().time, serializedMessage, false, configurationMessage.ttl.toInt(), true, false, true, Optional.absent()) } catch (e: Exception) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UnidentifiedAccessUtil.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UnidentifiedAccessUtil.kt index 56427bfb62..31a9a0bc01 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UnidentifiedAccessUtil.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UnidentifiedAccessUtil.kt @@ -1,39 +1,42 @@ package org.session.libsession.messaging.utilities +import android.content.Context import com.goterl.lazycode.lazysodium.LazySodiumAndroid import com.goterl.lazycode.lazysodium.SodiumAndroid - import org.session.libsession.messaging.MessagingConfiguration - -import org.session.libsignal.utilities.logging.Log +import org.session.libsession.utilities.TextSecurePreferences.isUniversalUnidentifiedAccess +import org.session.libsession.utilities.Util.getSecretBytes import org.session.libsignal.metadata.SignalProtos -import org.session.libsignal.metadata.certificate.InvalidCertificateException import org.session.libsignal.service.api.crypto.UnidentifiedAccess -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair +import org.session.libsignal.utilities.logging.Log object UnidentifiedAccessUtil { private val TAG = UnidentifiedAccessUtil::class.simpleName private val sodium by lazy { LazySodiumAndroid(SodiumAndroid()) } - fun getAccessFor(recipientPublicKey: String): UnidentifiedAccessPair? { - try { - val theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipientPublicKey) - val ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey() - val ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate() - - Log.i(TAG, "Their access key present? " + (theirUnidentifiedAccessKey != null) + - " | Our access key present? " + (ourUnidentifiedAccessKey != null) + - " | Our certificate present? " + (ourUnidentifiedAccessCertificate != null)) - - if (theirUnidentifiedAccessKey != null && ourUnidentifiedAccessKey != null && ourUnidentifiedAccessCertificate != null) { - return UnidentifiedAccessPair(UnidentifiedAccess(theirUnidentifiedAccessKey, ourUnidentifiedAccessCertificate), - UnidentifiedAccess(ourUnidentifiedAccessKey, ourUnidentifiedAccessCertificate)) - } - return null - } catch (e: InvalidCertificateException) { - Log.w(TAG, e) - return null + fun getAccessFor(recipientPublicKey: String): UnidentifiedAccess? { + val theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipientPublicKey) + val ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey() + val ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate() + + Log.i(TAG, "Their access key present? " + (theirUnidentifiedAccessKey != null) + + " | Our access key present? " + (ourUnidentifiedAccessKey != null) + + " | Our certificate present? " + (ourUnidentifiedAccessCertificate != null)) + + return if (theirUnidentifiedAccessKey != null && ourUnidentifiedAccessKey != null && ourUnidentifiedAccessCertificate != null) { + UnidentifiedAccess(theirUnidentifiedAccessKey) + } else null + } + + fun getAccessForSync(context: Context): UnidentifiedAccess? { + var ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey() + val ourUnidentifiedAccessCertificate = getUnidentifiedAccessCertificate() + if (isUniversalUnidentifiedAccess(context)) { + ourUnidentifiedAccessKey = getSecretBytes(16) } + return if (ourUnidentifiedAccessKey != null && ourUnidentifiedAccessCertificate != null) { + UnidentifiedAccess(ourUnidentifiedAccessKey) + } else null } private fun getTargetUnidentifiedAccessKey(recipientPublicKey: String): ByteArray? { diff --git a/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt b/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt index fa18dd4d7e..1b5f817864 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/TextSecurePreferences.kt @@ -448,13 +448,6 @@ object TextSecurePreferences { return getBooleanPreference(context, UNIVERSAL_UNIDENTIFIED_ACCESS, false) } - @JvmStatic - fun isUnidentifiedDeliveryEnabled(context: Context): Boolean { - // Loki - Always enable unidentified sender - return true - // return getBooleanPreference(context, UNIDENTIFIED_DELIVERY_ENABLED, true); - } - @JvmStatic fun getUpdateApkRefreshTime(context: Context): Long { return getLongPreference(context, UPDATE_APK_REFRESH_TIME_PREF, 0L) diff --git a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/DerivedMessageSecrets.java b/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/DerivedMessageSecrets.java deleted file mode 100644 index ef1c28cda8..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/DerivedMessageSecrets.java +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (C) 2014-2016 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. - */ - -package org.session.libsignal.libsignal.kdf; - -import org.session.libsignal.libsignal.util.ByteUtil; - -import java.text.ParseException; - -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -public class DerivedMessageSecrets { - - public static final int SIZE = 80; - private static final int CIPHER_KEY_LENGTH = 32; - private static final int MAC_KEY_LENGTH = 32; - private static final int IV_LENGTH = 16; - - private final SecretKeySpec cipherKey; - private final SecretKeySpec macKey; - private final IvParameterSpec iv; - - public DerivedMessageSecrets(byte[] okm) { - try { - byte[][] keys = ByteUtil.split(okm, CIPHER_KEY_LENGTH, MAC_KEY_LENGTH, IV_LENGTH); - - this.cipherKey = new SecretKeySpec(keys[0], "AES"); - this.macKey = new SecretKeySpec(keys[1], "HmacSHA256"); - this.iv = new IvParameterSpec(keys[2]); - } catch (ParseException e) { - throw new AssertionError(e); - } - } - - public SecretKeySpec getCipherKey() { - return cipherKey; - } - - public SecretKeySpec getMacKey() { - return macKey; - } - - public IvParameterSpec getIv() { - return iv; - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/DerivedRootSecrets.java b/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/DerivedRootSecrets.java deleted file mode 100644 index e43bcccddd..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/DerivedRootSecrets.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (C) 2014-2016 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. - */ -package org.session.libsignal.libsignal.kdf; - -import org.session.libsignal.libsignal.util.ByteUtil; - -public class DerivedRootSecrets { - - public static final int SIZE = 64; - - private final byte[] rootKey; - private final byte[] chainKey; - - public DerivedRootSecrets(byte[] okm) { - byte[][] keys = ByteUtil.split(okm, 32, 32); - this.rootKey = keys[0]; - this.chainKey = keys[1]; - } - - public byte[] getRootKey() { - return rootKey; - } - - public byte[] getChainKey() { - return chainKey; - } - -} diff --git a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDF.java b/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDF.java index 546529b2d5..c0b65b38af 100644 --- a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDF.java +++ b/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDF.java @@ -6,9 +6,6 @@ package org.session.libsignal.libsignal.kdf; -import org.session.libsignal.libsignal.kdf.HKDFv2; -import org.session.libsignal.libsignal.kdf.HKDFv3; - import java.io.ByteArrayOutputStream; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -22,7 +19,6 @@ public abstract class HKDF { public static HKDF createFor(int messageVersion) { switch (messageVersion) { - case 2: return new HKDFv2(); case 3: return new HKDFv3(); default: throw new AssertionError("Unknown version: " + messageVersion); } diff --git a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDFv2.java b/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDFv2.java deleted file mode 100644 index 501bc9b1a8..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/libsignal/kdf/HKDFv2.java +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (C) 2014-2016 Open Whisper Systems - * - * Licensed according to the LICENSE file in this repository. - */ -package org.session.libsignal.libsignal.kdf; - -public class HKDFv2 extends HKDF { - @Override - protected int getIterationStartOffset() { - return 0; - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/CertificateValidator.java b/libsignal/src/main/java/org/session/libsignal/metadata/certificate/CertificateValidator.java deleted file mode 100644 index 3671cf3865..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/CertificateValidator.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.session.libsignal.metadata.certificate; - - -import java.util.HashSet; -import java.util.Set; - -public class CertificateValidator { - - @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - private static final Set REVOKED = new HashSet() {{ - - }}; - - public void validate(SenderCertificate certificate, long validationTime) throws InvalidCertificateException { - if (certificate.getSender() == null || certificate.getSenderDeviceId() <= 0) { - throw new InvalidCertificateException("Sender or sender device id is invalid"); - } - } - - // VisibleForTesting - void validate(ServerCertificate certificate) throws InvalidCertificateException { - } -} - diff --git a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/InvalidCertificateException.java b/libsignal/src/main/java/org/session/libsignal/metadata/certificate/InvalidCertificateException.java deleted file mode 100644 index 989ce597c8..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/InvalidCertificateException.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.session.libsignal.metadata.certificate; - - -public class InvalidCertificateException extends Exception { - public InvalidCertificateException(String s) { - super(s); - } - - public InvalidCertificateException(Exception e) { - super(e); - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/SenderCertificate.java b/libsignal/src/main/java/org/session/libsignal/metadata/certificate/SenderCertificate.java deleted file mode 100644 index 586b0659ee..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/SenderCertificate.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.session.libsignal.metadata.certificate; - - -import com.google.protobuf.InvalidProtocolBufferException; - -import org.session.libsignal.metadata.SignalProtos; - - -public class SenderCertificate { - - private final int senderDeviceId; - private final String sender; - - private final byte[] serialized; - private final byte[] certificate; - - public SenderCertificate(byte[] serialized) throws InvalidCertificateException { - try { - SignalProtos.SenderCertificate certificate = SignalProtos.SenderCertificate.parseFrom(serialized); - - if (!certificate.hasSenderDevice() || !certificate.hasSender()) { - throw new InvalidCertificateException("Missing fields"); - } - - this.sender = certificate.getSender(); - this.senderDeviceId = certificate.getSenderDevice(); - - this.serialized = serialized; - this.certificate = certificate.toByteArray(); - } catch (InvalidProtocolBufferException e) { - throw new InvalidCertificateException(e); - } - } - - - public int getSenderDeviceId() { - return senderDeviceId; - } - - public String getSender() { - return sender; - } - - public byte[] getSerialized() { - return serialized; - } - - public byte[] getCertificate() { - return certificate; - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/ServerCertificate.java b/libsignal/src/main/java/org/session/libsignal/metadata/certificate/ServerCertificate.java deleted file mode 100644 index 7b794e6eb1..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/metadata/certificate/ServerCertificate.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.session.libsignal.metadata.certificate; - - -import com.google.protobuf.InvalidProtocolBufferException; - -import org.session.libsignal.metadata.SignalProtos; -import org.session.libsignal.libsignal.InvalidKeyException; -import org.session.libsignal.libsignal.ecc.Curve; -import org.session.libsignal.libsignal.ecc.ECPublicKey; - -public class ServerCertificate { - - private final int keyId; - private final ECPublicKey key; - - private final byte[] serialized; - private final byte[] certificate; - private final byte[] signature; - - public ServerCertificate(byte[] serialized) throws InvalidCertificateException { - try { - SignalProtos.ServerCertificate wrapper = SignalProtos.ServerCertificate.parseFrom(serialized); - - if (!wrapper.hasCertificate() || !wrapper.hasSignature()) { - throw new InvalidCertificateException("Missing fields"); - } - - SignalProtos.ServerCertificate.Certificate certificate = SignalProtos.ServerCertificate.Certificate.parseFrom(wrapper.getCertificate()); - - if (!certificate.hasId() || !certificate.hasKey()) { - throw new InvalidCertificateException("Missing fields"); - } - - this.keyId = certificate.getId(); - this.key = Curve.decodePoint(certificate.getKey().toByteArray(), 0); - this.serialized = serialized; - this.certificate = wrapper.getCertificate().toByteArray(); - this.signature = wrapper.getSignature().toByteArray(); - - } catch (InvalidProtocolBufferException e) { - throw new InvalidCertificateException(e); - } catch (InvalidKeyException e) { - throw new InvalidCertificateException(e); - } - } - - public int getKeyId() { - return keyId; - } - - public ECPublicKey getKey() { - return key; - } - - public byte[] getSerialized() { - return serialized; - } - - public byte[] getCertificate() { - return certificate; - } - - public byte[] getSignature() { - return signature; - } -} diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java b/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java index e3ba867dac..6190023c97 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java +++ b/libsignal/src/main/java/org/session/libsignal/service/api/SignalServiceMessageSender.java @@ -14,7 +14,6 @@ import org.session.libsignal.utilities.logging.Log; import org.session.libsignal.libsignal.util.guava.Optional; import org.session.libsignal.service.api.crypto.AttachmentCipherOutputStream; import org.session.libsignal.service.api.crypto.UnidentifiedAccess; -import org.session.libsignal.service.api.crypto.UnidentifiedAccessPair; import org.session.libsignal.service.api.crypto.UntrustedIdentityException; import org.session.libsignal.service.api.messages.SendMessageResult; import org.session.libsignal.service.api.messages.SignalServiceAttachment; @@ -165,21 +164,21 @@ public class SignalServiceMessageSender { * @throws IOException */ public void sendReceipt(SignalServiceAddress recipient, - Optional unidentifiedAccess, + Optional unidentifiedAccess, SignalServiceReceiptMessage message) throws IOException { byte[] content = createReceiptContent(message); boolean useFallbackEncryption = true; - sendMessage(recipient, getTargetUnidentifiedAccess(unidentifiedAccess), message.getWhen(), content, false, message.getTTL(), useFallbackEncryption); + sendMessage(recipient, unidentifiedAccess, message.getWhen(), content, false, message.getTTL(), useFallbackEncryption); } public void sendTyping(List recipients, - List> unidentifiedAccess, + List> unidentifiedAccess, SignalServiceTypingMessage message) throws IOException { byte[] content = createTypingContent(message); - sendMessage(0, recipients, getTargetUnidentifiedAccess(unidentifiedAccess), message.getTimestamp(), content, true, message.getTTL(), false, false); + sendMessage(0, recipients, unidentifiedAccess, message.getTimestamp(), content, true, message.getTTL(), false, false); } /** @@ -191,14 +190,14 @@ public class SignalServiceMessageSender { */ public SendMessageResult sendMessage(long messageID, SignalServiceAddress recipient, - Optional unidentifiedAccess, + Optional unidentifiedAccess, SignalServiceDataMessage message) throws IOException { byte[] content = createMessageContent(message, recipient); long timestamp = message.getTimestamp(); boolean isClosedGroup = message.group.isPresent() && message.group.get().getGroupType() == SignalServiceGroup.GroupType.SIGNAL; - SendMessageResult result = sendMessage(messageID, recipient, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, content, false, message.getTTL(), true, isClosedGroup, message.hasVisibleContent(), message.getSyncTarget()); + SendMessageResult result = sendMessage(messageID, recipient, unidentifiedAccess, timestamp, content, false, message.getTTL(), true, isClosedGroup, message.hasVisibleContent(), message.getSyncTarget()); return result; } @@ -212,7 +211,7 @@ public class SignalServiceMessageSender { */ public List sendMessage(long messageID, List recipients, - List> unidentifiedAccess, + List> unidentifiedAccess, SignalServiceDataMessage message) throws IOException { // Loki - We only need the first recipient in the line below. This is because the recipient is only used to determine @@ -221,7 +220,7 @@ public class SignalServiceMessageSender { long timestamp = message.getTimestamp(); boolean isClosedGroup = message.group.isPresent() && message.group.get().getGroupType() == SignalServiceGroup.GroupType.SIGNAL; - return sendMessage(messageID, recipients, getTargetUnidentifiedAccess(unidentifiedAccess), timestamp, content, false, message.getTTL(), isClosedGroup, message.hasVisibleContent()); + return sendMessage(messageID, recipients, unidentifiedAccess, timestamp, content, false, message.getTTL(), isClosedGroup, message.hasVisibleContent()); } public void setMessagePipe(SignalServiceMessagePipe pipe, SignalServiceMessagePipe unidentifiedPipe) { @@ -885,25 +884,6 @@ public class SignalServiceMessageSender { return new OutgoingPushMessageList(publicKey, timestamp, messages, false); } - private Optional getTargetUnidentifiedAccess(Optional unidentifiedAccess) { - if (unidentifiedAccess.isPresent()) { - return unidentifiedAccess.get().getTargetUnidentifiedAccess(); - } - - return Optional.absent(); - } - - private List> getTargetUnidentifiedAccess(List> unidentifiedAccess) { - List> results = new LinkedList<>(); - - for (Optional item : unidentifiedAccess) { - if (item.isPresent()) results.add(item.get().getTargetUnidentifiedAccess()); - else results.add(Optional.absent()); - } - - return results; - } - public static interface EventListener { public void onSecurityEvent(SignalServiceAddress address); diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccess.java b/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccess.java index 518896ce00..176621f657 100644 --- a/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccess.java +++ b/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccess.java @@ -1,8 +1,6 @@ package org.session.libsignal.service.api.crypto; -import org.session.libsignal.metadata.certificate.InvalidCertificateException; -import org.session.libsignal.metadata.certificate.SenderCertificate; import org.session.libsignal.libsignal.util.ByteUtil; import java.security.InvalidAlgorithmParameterException; @@ -19,23 +17,16 @@ import javax.crypto.spec.SecretKeySpec; public class UnidentifiedAccess { private final byte[] unidentifiedAccessKey; - private final SenderCertificate unidentifiedCertificate; - public UnidentifiedAccess(byte[] unidentifiedAccessKey, byte[] unidentifiedCertificate) - throws InvalidCertificateException + public UnidentifiedAccess(byte[] unidentifiedAccessKey) { this.unidentifiedAccessKey = unidentifiedAccessKey; - this.unidentifiedCertificate = new SenderCertificate(unidentifiedCertificate); } public byte[] getUnidentifiedAccessKey() { return unidentifiedAccessKey; } - public SenderCertificate getUnidentifiedCertificate() { - return unidentifiedCertificate; - } - public static byte[] deriveAccessKeyFrom(byte[] profileKey) { try { byte[] nonce = new byte[12]; @@ -47,17 +38,7 @@ public class UnidentifiedAccess { byte[] ciphertext = cipher.doFinal(input); return ByteUtil.trim(ciphertext, 16); - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { - throw new AssertionError(e); - } catch (NoSuchPaddingException e) { - throw new AssertionError(e); - } catch (InvalidAlgorithmParameterException e) { - throw new AssertionError(e); - } catch (BadPaddingException e) { - throw new AssertionError(e); - } catch (IllegalBlockSizeException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException | InvalidAlgorithmParameterException | BadPaddingException | IllegalBlockSizeException e) { throw new AssertionError(e); } } diff --git a/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccessPair.java b/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccessPair.java deleted file mode 100644 index 4fb6e8629a..0000000000 --- a/libsignal/src/main/java/org/session/libsignal/service/api/crypto/UnidentifiedAccessPair.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.session.libsignal.service.api.crypto; - - -import org.session.libsignal.libsignal.util.guava.Optional; - -public class UnidentifiedAccessPair { - - private final Optional targetUnidentifiedAccess; - private final Optional selfUnidentifiedAccess; - - public UnidentifiedAccessPair(UnidentifiedAccess targetUnidentifiedAccess, UnidentifiedAccess selfUnidentifiedAccess) { - this.targetUnidentifiedAccess = Optional.of(targetUnidentifiedAccess); - this.selfUnidentifiedAccess = Optional.of(selfUnidentifiedAccess); - } - - public Optional getTargetUnidentifiedAccess() { - return targetUnidentifiedAccess; - } - - public Optional getSelfUnidentifiedAccess() { - return selfUnidentifiedAccess; - } -}