Use RemoteConfig for UsePqRatchet.

Co-authored-by: Greyson Parrelli <greyson@signal.org>
This commit is contained in:
gram-signal
2025-06-30 11:46:36 -07:00
committed by Greyson Parrelli
parent f6b74ad2a0
commit 173983a1ab
9 changed files with 34 additions and 16 deletions

View File

@@ -6,6 +6,7 @@ import org.signal.libsignal.protocol.IdentityKey
import org.signal.libsignal.protocol.IdentityKeyPair import org.signal.libsignal.protocol.IdentityKeyPair
import org.signal.libsignal.protocol.SessionBuilder import org.signal.libsignal.protocol.SessionBuilder
import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.SignalProtocolAddress
import org.signal.libsignal.protocol.UsePqRatchet
import org.signal.libsignal.protocol.ecc.ECKeyPair import org.signal.libsignal.protocol.ecc.ECKeyPair
import org.signal.libsignal.protocol.groups.state.SenderKeyRecord import org.signal.libsignal.protocol.groups.state.SenderKeyRecord
import org.signal.libsignal.protocol.state.IdentityKeyStore import org.signal.libsignal.protocol.state.IdentityKeyStore
@@ -68,7 +69,7 @@ class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair:
if (!aciStore.containsSession(getAliceProtocolAddress())) { if (!aciStore.containsSession(getAliceProtocolAddress())) {
val sessionBuilder = SignalSessionBuilder(sessionLock, SessionBuilder(aciStore, getAliceProtocolAddress())) val sessionBuilder = SignalSessionBuilder(sessionLock, SessionBuilder(aciStore, getAliceProtocolAddress()))
sessionBuilder.process(getAlicePreKeyBundle()) sessionBuilder.process(getAlicePreKeyBundle(), UsePqRatchet.NO)
} }
return cipher.encrypt(getAliceProtocolAddress(), getAliceUnidentifiedAccess(), envelopeContent) return cipher.encrypt(getAliceProtocolAddress(), getAliceUnidentifiedAccess(), envelopeContent)
@@ -77,7 +78,7 @@ class BobClient(val serviceId: ServiceId, val e164: String, val identityKeyPair:
fun decrypt(envelope: Envelope, serverDeliveredTimestamp: Long) { fun decrypt(envelope: Envelope, serverDeliveredTimestamp: Long) {
val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, SealedSenderAccessUtil.getCertificateValidator()) val cipher = SignalServiceCipher(serviceAddress, 1, aciStore, sessionLock, SealedSenderAccessUtil.getCertificateValidator())
cipher.decrypt(envelope, serverDeliveredTimestamp) cipher.decrypt(envelope, serverDeliveredTimestamp, UsePqRatchet.NO)
} }
private fun getAliceServiceId(): ServiceId { private fun getAliceServiceId(): ServiceId {

View File

@@ -170,7 +170,8 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider {
Optional.of(new SecurityEventListener(context)), Optional.of(new SecurityEventListener(context)),
SignalExecutors.newCachedBoundedExecutor("signal-messages", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 16, 30), SignalExecutors.newCachedBoundedExecutor("signal-messages", ThreadUtil.PRIORITY_IMPORTANT_BACKGROUND_THREAD, 1, 16, 30),
ByteUnit.KILOBYTES.toBytes(256), ByteUnit.KILOBYTES.toBytes(256),
RemoteConfig::useMessageSendRestFallback); RemoteConfig::useMessageSendRestFallback,
RemoteConfig.usePqRatchet());
} }
@Override @Override

View File

@@ -142,7 +142,7 @@ object MessageDecryptor {
return try { return try {
val startTimeNanos = System.nanoTime() val startTimeNanos = System.nanoTime()
val cipherResult: SignalServiceCipherResult? = cipher.decrypt(envelope, serverDeliveredTimestamp) val cipherResult: SignalServiceCipherResult? = cipher.decrypt(envelope, serverDeliveredTimestamp, RemoteConfig.usePqRatchet)
val endTimeNanos = System.nanoTime() val endTimeNanos = System.nanoTime()
if (cipherResult == null) { if (cipherResult == null) {

View File

@@ -11,6 +11,7 @@ import org.signal.core.util.gibiBytes
import org.signal.core.util.kibiBytes import org.signal.core.util.kibiBytes
import org.signal.core.util.logging.Log import org.signal.core.util.logging.Log
import org.signal.core.util.mebiBytes import org.signal.core.util.mebiBytes
import org.signal.libsignal.protocol.UsePqRatchet
import org.thoughtcrime.securesms.BuildConfig import org.thoughtcrime.securesms.BuildConfig
import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.dependencies.AppDependencies
import org.thoughtcrime.securesms.groups.SelectionLimits import org.thoughtcrime.securesms.groups.SelectionLimits
@@ -1154,5 +1155,15 @@ object RemoteConfig {
durationUnit = DurationUnit.DAYS durationUnit = DurationUnit.DAYS
) )
/** Whether or not to use the new post-quantum ratcheting. */
@JvmStatic
@get:JvmName("usePqRatchet")
val usePqRatchet: UsePqRatchet by remoteValue(
key = "global.usePqRatchet",
hotSwappable = true
) { value ->
if (value.asBoolean(false)) UsePqRatchet.YES else UsePqRatchet.NO
}
// endregion // endregion
} }

View File

@@ -13,6 +13,7 @@ import org.signal.libsignal.protocol.InvalidRegistrationIdException;
import org.signal.libsignal.protocol.NoSessionException; import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SessionBuilder; import org.signal.libsignal.protocol.SessionBuilder;
import org.signal.libsignal.protocol.SignalProtocolAddress; import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.UsePqRatchet;
import org.signal.libsignal.protocol.groups.GroupSessionBuilder; import org.signal.libsignal.protocol.groups.GroupSessionBuilder;
import org.signal.libsignal.protocol.logging.Log; import org.signal.libsignal.protocol.logging.Log;
import org.signal.libsignal.protocol.message.DecryptionErrorMessage; import org.signal.libsignal.protocol.message.DecryptionErrorMessage;
@@ -182,6 +183,7 @@ public class SignalServiceMessageSender {
private final Scheduler scheduler; private final Scheduler scheduler;
private final long maxEnvelopeSize; private final long maxEnvelopeSize;
private final BooleanSupplier useRestFallback; private final BooleanSupplier useRestFallback;
private final UsePqRatchet usePqRatchet;
public SignalServiceMessageSender(PushServiceSocket pushServiceSocket, public SignalServiceMessageSender(PushServiceSocket pushServiceSocket,
SignalServiceDataStore store, SignalServiceDataStore store,
@@ -192,7 +194,8 @@ public class SignalServiceMessageSender {
Optional<EventListener> eventListener, Optional<EventListener> eventListener,
ExecutorService executor, ExecutorService executor,
long maxEnvelopeSize, long maxEnvelopeSize,
BooleanSupplier useRestFallback) BooleanSupplier useRestFallback,
UsePqRatchet usePqRatchet)
{ {
CredentialsProvider credentialsProvider = pushServiceSocket.getCredentialsProvider(); CredentialsProvider credentialsProvider = pushServiceSocket.getCredentialsProvider();
@@ -210,6 +213,7 @@ public class SignalServiceMessageSender {
this.scheduler = Schedulers.from(executor, false, false); this.scheduler = Schedulers.from(executor, false, false);
this.keysApi = keysApi; this.keysApi = keysApi;
this.useRestFallback = useRestFallback; this.useRestFallback = useRestFallback;
this.usePqRatchet = usePqRatchet;
} }
/** /**
@@ -2701,7 +2705,7 @@ public class SignalServiceMessageSender {
try { try {
SignalProtocolAddress preKeyAddress = new SignalProtocolAddress(recipient.getIdentifier(), preKey.getDeviceId()); SignalProtocolAddress preKeyAddress = new SignalProtocolAddress(recipient.getIdentifier(), preKey.getDeviceId());
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, preKeyAddress)); SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, preKeyAddress));
sessionBuilder.process(preKey); sessionBuilder.process(preKey, usePqRatchet);
} catch (org.signal.libsignal.protocol.UntrustedIdentityException e) { } catch (org.signal.libsignal.protocol.UntrustedIdentityException e) {
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey()); throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey());
} }
@@ -2753,7 +2757,7 @@ public class SignalServiceMessageSender {
try { try {
SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, new SignalProtocolAddress(recipient.getIdentifier(), missingDeviceId))); SignalSessionBuilder sessionBuilder = new SignalSessionBuilder(sessionLock, new SessionBuilder(aciStore, new SignalProtocolAddress(recipient.getIdentifier(), missingDeviceId)));
sessionBuilder.process(preKey); sessionBuilder.process(preKey, usePqRatchet);
} catch (org.signal.libsignal.protocol.UntrustedIdentityException e) { } catch (org.signal.libsignal.protocol.UntrustedIdentityException e) {
throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey()); throw new UntrustedIdentityException("Untrusted identity key!", recipient.getIdentifier(), preKey.getIdentityKey());
} }

View File

@@ -34,6 +34,7 @@ import org.signal.libsignal.protocol.NoSessionException;
import org.signal.libsignal.protocol.SessionCipher; import org.signal.libsignal.protocol.SessionCipher;
import org.signal.libsignal.protocol.SignalProtocolAddress; import org.signal.libsignal.protocol.SignalProtocolAddress;
import org.signal.libsignal.protocol.UntrustedIdentityException; import org.signal.libsignal.protocol.UntrustedIdentityException;
import org.signal.libsignal.protocol.UsePqRatchet;
import org.signal.libsignal.protocol.groups.GroupCipher; import org.signal.libsignal.protocol.groups.GroupCipher;
import org.signal.libsignal.protocol.logging.Log; import org.signal.libsignal.protocol.logging.Log;
import org.signal.libsignal.protocol.message.CiphertextMessage; import org.signal.libsignal.protocol.message.CiphertextMessage;
@@ -131,7 +132,7 @@ public class SignalServiceCipher {
} }
} }
public SignalServiceCipherResult decrypt(Envelope envelope, long serverDeliveredTimestamp) public SignalServiceCipherResult decrypt(Envelope envelope, long serverDeliveredTimestamp, UsePqRatchet usePqRatchet)
throws InvalidMetadataMessageException, InvalidMetadataVersionException, throws InvalidMetadataMessageException, InvalidMetadataVersionException,
ProtocolInvalidKeyIdException, ProtocolLegacyMessageException, ProtocolInvalidKeyIdException, ProtocolLegacyMessageException,
ProtocolUntrustedIdentityException, ProtocolNoSessionException, ProtocolUntrustedIdentityException, ProtocolNoSessionException,
@@ -141,7 +142,7 @@ public class SignalServiceCipher {
{ {
try { try {
if (envelope.content != null) { if (envelope.content != null) {
Plaintext plaintext = decryptInternal(envelope, serverDeliveredTimestamp); Plaintext plaintext = decryptInternal(envelope, serverDeliveredTimestamp, usePqRatchet);
Content content = Content.ADAPTER.decode(plaintext.getData()); Content content = Content.ADAPTER.decode(plaintext.getData());
return new SignalServiceCipherResult( return new SignalServiceCipherResult(
@@ -163,7 +164,7 @@ public class SignalServiceCipher {
} }
} }
private Plaintext decryptInternal(Envelope envelope, long serverDeliveredTimestamp) private Plaintext decryptInternal(Envelope envelope, long serverDeliveredTimestamp, UsePqRatchet usePqRatchet)
throws InvalidMetadataMessageException, InvalidMetadataVersionException, throws InvalidMetadataMessageException, InvalidMetadataVersionException,
ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException, ProtocolDuplicateMessageException, ProtocolUntrustedIdentityException,
ProtocolLegacyMessageException, ProtocolInvalidKeyException, ProtocolLegacyMessageException, ProtocolInvalidKeyException,
@@ -184,7 +185,7 @@ public class SignalServiceCipher {
SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.sourceServiceId, envelope.sourceDevice); SignalProtocolAddress sourceAddress = new SignalProtocolAddress(envelope.sourceServiceId, envelope.sourceDevice);
SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress)); SignalSessionCipher sessionCipher = new SignalSessionCipher(sessionLock, new SessionCipher(signalProtocolStore, sourceAddress));
paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(envelope.content.toByteArray())); paddedMessage = sessionCipher.decrypt(new PreKeySignalMessage(envelope.content.toByteArray()), usePqRatchet);
metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, envelope.serverGuid, Optional.empty(), envelope.destinationServiceId); metadata = new SignalServiceMetadata(getSourceAddress(envelope), envelope.sourceDevice, envelope.timestamp, envelope.serverTimestamp, serverDeliveredTimestamp, false, envelope.serverGuid, Optional.empty(), envelope.destinationServiceId);
signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress)); signalProtocolStore.clearSenderKeySharedWith(Collections.singleton(sourceAddress));

View File

@@ -20,9 +20,9 @@ public class SignalSessionBuilder {
this.builder = builder; this.builder = builder;
} }
public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException { public void process(PreKeyBundle preKey, UsePqRatchet usePqRatchet) throws InvalidKeyException, UntrustedIdentityException {
try (SignalSessionLock.Lock unused = lock.acquire()) { try (SignalSessionLock.Lock unused = lock.acquire()) {
builder.process(preKey, UsePqRatchet.NO); builder.process(preKey, usePqRatchet);
} }
} }
} }

View File

@@ -34,9 +34,9 @@ public class SignalSessionCipher {
} }
} }
public byte[] decrypt(PreKeySignalMessage ciphertext) throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, InvalidKeyIdException, InvalidKeyException, org.signal.libsignal.protocol.UntrustedIdentityException { public byte[] decrypt(PreKeySignalMessage ciphertext, UsePqRatchet usePqRatchet) throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, InvalidKeyIdException, InvalidKeyException, org.signal.libsignal.protocol.UntrustedIdentityException {
try (SignalSessionLock.Lock unused = lock.acquire()) { try (SignalSessionLock.Lock unused = lock.acquire()) {
return cipher.decrypt(ciphertext, UsePqRatchet.NO); return cipher.decrypt(ciphertext, usePqRatchet);
} }
} }

View File

@@ -163,7 +163,7 @@ class SignalClient {
} }
fun decryptMessage(envelope: Envelope) { fun decryptMessage(envelope: Envelope) {
cipher.decrypt(envelope, System.currentTimeMillis()) cipher.decrypt(envelope, System.currentTimeMillis(), UsePqRatchet.NO)
} }
private fun createPreKeyBundle(): PreKeyBundle { private fun createPreKeyBundle(): PreKeyBundle {