diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt index 3b65b0e7a9..0af4d043e4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/changenumber/ChangeNumberRepository.kt @@ -7,7 +7,9 @@ import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log import org.signal.libsignal.protocol.IdentityKeyPair import org.signal.libsignal.protocol.SignalProtocolAddress +import org.signal.libsignal.protocol.state.KyberPreKeyRecord import org.signal.libsignal.protocol.state.SignalProtocolStore +import org.signal.libsignal.protocol.state.SignedPreKeyRecord import org.signal.libsignal.protocol.util.KeyHelper import org.signal.libsignal.protocol.util.Medium import org.thoughtcrime.securesms.crypto.IdentityKeyUtil @@ -38,6 +40,7 @@ import org.whispersystems.signalservice.api.push.ServiceIdType import org.whispersystems.signalservice.api.push.SignalServiceAddress import org.whispersystems.signalservice.api.push.SignedPreKeyEntity import org.whispersystems.signalservice.internal.ServiceResponse +import org.whispersystems.signalservice.internal.push.KyberPreKeyEntity import org.whispersystems.signalservice.internal.push.OutgoingPushMessage import org.whispersystems.signalservice.internal.push.RegistrationSessionMetadataResponse import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage @@ -320,6 +323,7 @@ class ChangeNumberRepository( val pniIdentity: IdentityKeyPair = if (pniUpdateMode) SignalStore.account().pniIdentityKey else IdentityKeyUtil.generateIdentityKeyPair() val deviceMessages = mutableListOf() val devicePniSignedPreKeys = mutableMapOf() + val devicePniLastResortKyberPreKeys = mutableMapOf() val pniRegistrationIds = mutableMapOf() val primaryDeviceId: Int = SignalServiceAddress.DEFAULT_DEVICE_ID @@ -329,7 +333,7 @@ class ChangeNumberRepository( .filter { it == primaryDeviceId || aciProtocolStore.containsSession(SignalProtocolAddress(selfIdentifier, it)) } .forEach { deviceId -> // Signed Prekeys - val signedPreKeyRecord = if (deviceId == primaryDeviceId) { + val signedPreKeyRecord: SignedPreKeyRecord = if (deviceId == primaryDeviceId) { if (pniUpdateMode) { ApplicationDependencies.getProtocolStore().pni().loadSignedPreKey(SignalStore.account().pniPreKeys.activeSignedPreKeyId) } else { @@ -340,6 +344,18 @@ class ChangeNumberRepository( } devicePniSignedPreKeys[deviceId] = SignedPreKeyEntity(signedPreKeyRecord.id, signedPreKeyRecord.keyPair.publicKey, signedPreKeyRecord.signature) + // Last-resort kyber prekeys + val lastResortKyberPreKeyRecord: KyberPreKeyRecord = if (deviceId == primaryDeviceId) { + if (pniUpdateMode) { + ApplicationDependencies.getProtocolStore().pni().loadKyberPreKey(SignalStore.account().pniPreKeys.lastResortKyberPreKeyId) + } else { + PreKeyUtil.generateAndStoreLastResortKyberPreKey(ApplicationDependencies.getProtocolStore().pni(), SignalStore.account().pniPreKeys, pniIdentity.privateKey) + } + } else { + PreKeyUtil.generateKyberPreKey(SecureRandom().nextInt(Medium.MAX_VALUE), pniIdentity.privateKey) + } + devicePniLastResortKyberPreKeys[deviceId] = KyberPreKeyEntity(lastResortKyberPreKeyRecord.id, lastResortKyberPreKeyRecord.keyPair.publicKey, lastResortKyberPreKeyRecord.signature) + // Registration Ids var pniRegistrationId = if (deviceId == primaryDeviceId && pniUpdateMode) { SignalStore.account().pniRegistrationId @@ -357,7 +373,9 @@ class ChangeNumberRepository( val pniChangeNumber = SyncMessage.PniChangeNumber.newBuilder() .setIdentityKeyPair(pniIdentity.serialize().toProtoByteString()) .setSignedPreKey(signedPreKeyRecord.serialize().toProtoByteString()) + .setLastResortKyberPreKey(lastResortKyberPreKeyRecord.serialize().toProtoByteString()) .setRegistrationId(pniRegistrationId) + .setNewE164(newE164) .build() deviceMessages += messageSender.getEncryptedSyncPniChangeNumberMessage(deviceId, pniChangeNumber) @@ -372,6 +390,7 @@ class ChangeNumberRepository( pniIdentity.publicKey, deviceMessages, devicePniSignedPreKeys.mapKeys { it.key.toString() }, + devicePniLastResortKyberPreKeys.mapKeys { it.key.toString() }, pniRegistrationIds.mapKeys { it.key.toString() } ) diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/account/ChangePhoneNumberRequest.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/account/ChangePhoneNumberRequest.java index 8910e177e2..15aba7abd6 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/account/ChangePhoneNumberRequest.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/account/ChangePhoneNumberRequest.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.signal.libsignal.protocol.IdentityKey; import org.whispersystems.signalservice.api.push.SignedPreKeyEntity; +import org.whispersystems.signalservice.internal.push.KyberPreKeyEntity; import org.whispersystems.signalservice.internal.push.OutgoingPushMessage; import org.whispersystems.signalservice.internal.util.JsonUtil; @@ -36,6 +37,9 @@ public final class ChangePhoneNumberRequest { @JsonProperty private Map devicePniSignedPrekeys; + @JsonProperty("devicePniPqLastResortPrekeys") + private Map devicePniLastResortKyberPrekeys; + @JsonProperty private Map pniRegistrationIds; @@ -49,16 +53,18 @@ public final class ChangePhoneNumberRequest { IdentityKey pniIdentityKey, List deviceMessages, Map devicePniSignedPrekeys, + Map devicePniLastResortKyberPrekeys, Map pniRegistrationIds) { - this.sessionId = sessionId; - this.recoveryPassword = recoveryPassword; - this.number = number; - this.registrationLock = registrationLock; - this.pniIdentityKey = pniIdentityKey; - this.deviceMessages = deviceMessages; - this.devicePniSignedPrekeys = devicePniSignedPrekeys; - this.pniRegistrationIds = pniRegistrationIds; + this.sessionId = sessionId; + this.recoveryPassword = recoveryPassword; + this.number = number; + this.registrationLock = registrationLock; + this.pniIdentityKey = pniIdentityKey; + this.deviceMessages = deviceMessages; + this.devicePniSignedPrekeys = devicePniSignedPrekeys; + this.devicePniLastResortKyberPrekeys = devicePniLastResortKyberPrekeys; + this.pniRegistrationIds = pniRegistrationIds; } public String getNumber() { diff --git a/libsignal/service/src/main/proto/SignalService.proto b/libsignal/service/src/main/proto/SignalService.proto index a0bbbadc2b..7baf8f8096 100644 --- a/libsignal/service/src/main/proto/SignalService.proto +++ b/libsignal/service/src/main/proto/SignalService.proto @@ -590,9 +590,12 @@ message SyncMessage { } message PniChangeNumber { - optional bytes identityKeyPair = 1; // Serialized libsignal-client IdentityKeyPair - optional bytes signedPreKey = 2; // Serialized libsignal-client SignedPreKeyRecord - optional uint32 registrationId = 3; + optional bytes identityKeyPair = 1; // Serialized libsignal-client IdentityKeyPair + optional bytes signedPreKey = 2; // Serialized libsignal-client SignedPreKeyRecord + optional bytes lastResortKyberPreKey = 5; // Serialized libsignal-client KyberPreKeyRecord + optional uint32 registrationId = 3; + optional string newE164 = 4; // The e164 we have changed our number to + // Next ID: 6 } message CallEvent {