Update libsignal-service-java

This commit is contained in:
AsamK 2023-06-24 00:21:03 +02:00
parent c8e35991b9
commit e57e5b090e
8 changed files with 165 additions and 46 deletions

View file

@ -956,7 +956,7 @@
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true, "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }] "methods":[{"name":"<init>","parameterTypes":[] }, {"name":"getId","parameterTypes":[] }, {"name":"getJsonrpc","parameterTypes":[] }, {"name":"getMethod","parameterTypes":[] }, {"name":"getParams","parameterTypes":[] }]
}, },
{ {
"name":"org.asamk.signal.jsonrpc.JsonRpcResponse", "name":"org.asamk.signal.jsonrpc.JsonRpcResponse",
@ -1987,7 +1987,7 @@
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true, "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }] "methods":[{"name":"<init>","parameterTypes":[] }, {"name":"getSignature","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.api.push.SignedPreKeyEntity$ByteArrayDeserializer", "name":"org.whispersystems.signalservice.api.push.SignedPreKeyEntity$ByteArrayDeserializer",
@ -2015,7 +2015,8 @@
"name":"org.whispersystems.signalservice.internal.contacts.crypto.SignatureBodyEntity", "name":"org.whispersystems.signalservice.internal.contacts.crypto.SignatureBodyEntity",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.contacts.entities.DiscoveryRequest", "name":"org.whispersystems.signalservice.internal.contacts.entities.DiscoveryRequest",
@ -2033,13 +2034,15 @@
"name":"org.whispersystems.signalservice.internal.contacts.entities.KeyBackupRequest", "name":"org.whispersystems.signalservice.internal.contacts.entities.KeyBackupRequest",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"getData","parameterTypes":[] }, {"name":"getIv","parameterTypes":[] }, {"name":"getMac","parameterTypes":[] }, {"name":"getRequestId","parameterTypes":[] }, {"name":"getType","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.contacts.entities.KeyBackupResponse", "name":"org.whispersystems.signalservice.internal.contacts.entities.KeyBackupResponse",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.contacts.entities.MultiRemoteAttestationResponse", "name":"org.whispersystems.signalservice.internal.contacts.entities.MultiRemoteAttestationResponse",
@ -2057,19 +2060,22 @@
"name":"org.whispersystems.signalservice.internal.contacts.entities.RemoteAttestationRequest", "name":"org.whispersystems.signalservice.internal.contacts.entities.RemoteAttestationRequest",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"getClientPublic","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.contacts.entities.RemoteAttestationResponse", "name":"org.whispersystems.signalservice.internal.contacts.entities.RemoteAttestationResponse",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.contacts.entities.TokenResponse", "name":"org.whispersystems.signalservice.internal.contacts.entities.TokenResponse",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.devices.DeviceNameProtos$DeviceName", "name":"org.whispersystems.signalservice.internal.devices.DeviceNameProtos$DeviceName",
@ -2113,7 +2119,8 @@
"name":"org.whispersystems.signalservice.internal.push.AuthCredentials", "name":"org.whispersystems.signalservice.internal.push.AuthCredentials",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.push.CdsiAuthResponse", "name":"org.whispersystems.signalservice.internal.push.CdsiAuthResponse",
@ -2154,6 +2161,12 @@
"allDeclaredConstructors":true, "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }] "methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{
"name":"org.whispersystems.signalservice.internal.push.GcmRegistrationId",
"allDeclaredFields":true,
"queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true
},
{ {
"name":"org.whispersystems.signalservice.internal.push.GetAciByUsernameResponse", "name":"org.whispersystems.signalservice.internal.push.GetAciByUsernameResponse",
"allDeclaredFields":true, "allDeclaredFields":true,
@ -2231,7 +2244,7 @@
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true, "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }] "methods":[{"name":"<init>","parameterTypes":[] }, {"name":"getKeyId","parameterTypes":[] }, {"name":"getPublicKey","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.push.PreKeyEntity$ECPublicKeyDeserializer", "name":"org.whispersystems.signalservice.internal.push.PreKeyEntity$ECPublicKeyDeserializer",
@ -2317,7 +2330,7 @@
"allDeclaredFields":true, "allDeclaredFields":true,
"queryAllDeclaredMethods":true, "queryAllDeclaredMethods":true,
"queryAllDeclaredConstructors":true, "queryAllDeclaredConstructors":true,
"methods":[{"name":"getAccountAttributes","parameterTypes":[] }, {"name":"getRecoveryPassword","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getSkipDeviceTransfer","parameterTypes":[] }] "methods":[{"name":"getAccountAttributes","parameterTypes":[] }, {"name":"getAciIdentityKey","parameterTypes":[] }, {"name":"getAciPqLastResortPreKey","parameterTypes":[] }, {"name":"getAciSignedPreKey","parameterTypes":[] }, {"name":"getGcmToken","parameterTypes":[] }, {"name":"getPniIdentityKey","parameterTypes":[] }, {"name":"getPniPqLastResortPreKey","parameterTypes":[] }, {"name":"getPniSignedPreKey","parameterTypes":[] }, {"name":"getRecoveryPassword","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getSkipDeviceTransfer","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.push.ReserveUsernameRequest", "name":"org.whispersystems.signalservice.internal.push.ReserveUsernameRequest",
@ -2646,7 +2659,8 @@
"name":"org.whispersystems.signalservice.internal.push.VerifyAccountResponse", "name":"org.whispersystems.signalservice.internal.push.VerifyAccountResponse",
"allDeclaredFields":true, "allDeclaredFields":true,
"allDeclaredMethods":true, "allDeclaredMethods":true,
"allDeclaredConstructors":true "allDeclaredConstructors":true,
"methods":[{"name":"<init>","parameterTypes":[] }]
}, },
{ {
"name":"org.whispersystems.signalservice.internal.push.WhoAmIResponse", "name":"org.whispersystems.signalservice.internal.push.WhoAmIResponse",

View file

@ -113,7 +113,7 @@ public class AccountHelper {
account.setNumber(number); account.setNumber(number);
account.setAci(aci); account.setAci(aci);
account.setPni(pni); account.setPni(pni);
if (account.isPrimaryDevice() && account.getPniIdentityKeyPair() == null && account.getPni() != null) { if (account.isPrimaryDevice() && account.getPniIdentityKeyPair() == null) {
account.setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair()); account.setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair());
} }
account.getRecipientTrustedResolver().resolveSelfRecipientTrusted(account.getSelfRecipientAddress()); account.getRecipientTrustedResolver().resolveSelfRecipientTrusted(account.getSelfRecipientAddress());

View file

@ -38,18 +38,21 @@ public class PreKeyHelper {
public void refreshPreKeysIfNecessary(ServiceIdType serviceIdType) throws IOException { public void refreshPreKeysIfNecessary(ServiceIdType serviceIdType) throws IOException {
final var preKeyCounts = dependencies.getAccountManager().getPreKeyCounts(serviceIdType); final var preKeyCounts = dependencies.getAccountManager().getPreKeyCounts(serviceIdType);
if (preKeyCounts.getEcCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) { if (preKeyCounts.getEcCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) {
logger.debug("Refreshing {} ec pre keys, because only {} of {} pre keys remain",
serviceIdType,
preKeyCounts.getEcCount(),
ServiceConfig.PREKEY_MINIMUM_COUNT);
refreshPreKeys(serviceIdType); refreshPreKeys(serviceIdType);
} }
if (preKeyCounts.getKyberCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) { if (preKeyCounts.getKyberCount() < ServiceConfig.PREKEY_MINIMUM_COUNT) {
logger.debug("Refreshing {} kyber pre keys, because only {} of {} pre keys remain",
serviceIdType,
preKeyCounts.getEcCount(),
ServiceConfig.PREKEY_MINIMUM_COUNT);
refreshKyberPreKeys(serviceIdType); refreshKyberPreKeys(serviceIdType);
} }
} }
public void refreshPreKeys() throws IOException {
refreshPreKeys(ServiceIdType.ACI);
refreshPreKeys(ServiceIdType.PNI);
}
private void refreshPreKeys(ServiceIdType serviceIdType) throws IOException { private void refreshPreKeys(ServiceIdType serviceIdType) throws IOException {
final var identityKeyPair = account.getIdentityKeyPair(serviceIdType); final var identityKeyPair = account.getIdentityKeyPair(serviceIdType);
if (identityKeyPair == null) { if (identityKeyPair == null) {
@ -86,7 +89,7 @@ public class PreKeyHelper {
private List<PreKeyRecord> generatePreKeys(ServiceIdType serviceIdType) { private List<PreKeyRecord> generatePreKeys(ServiceIdType serviceIdType) {
final var offset = account.getPreKeyIdOffset(serviceIdType); final var offset = account.getPreKeyIdOffset(serviceIdType);
var records = KeyUtils.generatePreKeyRecords(offset, ServiceConfig.PREKEY_BATCH_SIZE); var records = KeyUtils.generatePreKeyRecords(offset);
account.addPreKeys(serviceIdType, records); account.addPreKeys(serviceIdType, records);
return records; return records;
@ -95,7 +98,7 @@ public class PreKeyHelper {
private SignedPreKeyRecord generateSignedPreKey(ServiceIdType serviceIdType, IdentityKeyPair identityKeyPair) { private SignedPreKeyRecord generateSignedPreKey(ServiceIdType serviceIdType, IdentityKeyPair identityKeyPair) {
final var signedPreKeyId = account.getNextSignedPreKeyId(serviceIdType); final var signedPreKeyId = account.getNextSignedPreKeyId(serviceIdType);
var record = KeyUtils.generateSignedPreKeyRecord(identityKeyPair, signedPreKeyId); var record = KeyUtils.generateSignedPreKeyRecord(signedPreKeyId, identityKeyPair);
account.addSignedPreKey(serviceIdType, record); account.addSignedPreKey(serviceIdType, record);
return record; return record;
@ -139,9 +142,7 @@ public class PreKeyHelper {
) { ) {
final var offset = account.getKyberPreKeyIdOffset(serviceIdType); final var offset = account.getKyberPreKeyIdOffset(serviceIdType);
var records = KeyUtils.generateKyberPreKeyRecords(offset, var records = KeyUtils.generateKyberPreKeyRecords(offset, identityKeyPair.getPrivateKey());
ServiceConfig.PREKEY_BATCH_SIZE,
identityKeyPair.getPrivateKey());
account.addKyberPreKeys(serviceIdType, records); account.addKyberPreKeys(serviceIdType, records);
return records; return records;

View file

@ -378,7 +378,7 @@ public class ManagerImpl implements Manager {
} }
void refreshPreKeys() throws IOException { void refreshPreKeys() throws IOException {
context.getPreKeyHelper().refreshPreKeys(); context.getPreKeyHelper().refreshPreKeysIfNecessary();
} }
@Override @Override

View file

@ -29,16 +29,19 @@ import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
import org.asamk.signal.manager.helper.AccountFileUpdater; import org.asamk.signal.manager.helper.AccountFileUpdater;
import org.asamk.signal.manager.helper.PinHelper; import org.asamk.signal.manager.helper.PinHelper;
import org.asamk.signal.manager.storage.SignalAccount; import org.asamk.signal.manager.storage.SignalAccount;
import org.asamk.signal.manager.util.KeyUtils;
import org.asamk.signal.manager.util.NumberVerificationUtils; import org.asamk.signal.manager.util.NumberVerificationUtils;
import org.asamk.signal.manager.util.Utils; import org.asamk.signal.manager.util.Utils;
import org.signal.libsignal.usernames.BaseUsernameException; import org.signal.libsignal.usernames.BaseUsernameException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations; import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations; import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI; import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.ServiceIdType;
import org.whispersystems.signalservice.api.push.SignalServiceAddress; import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException; import org.whispersystems.signalservice.api.push.exceptions.AlreadyVerifiedException;
import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException; import org.whispersystems.signalservice.api.push.exceptions.DeprecatedVersionException;
@ -48,6 +51,8 @@ import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider
import java.io.IOException; import java.io.IOException;
import java.util.function.Consumer; import java.util.function.Consumer;
import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_MAXIMUM_ID;
public class RegistrationManagerImpl implements RegistrationManager { public class RegistrationManagerImpl implements RegistrationManager {
private final static Logger logger = LoggerFactory.getLogger(RegistrationManagerImpl.class); private final static Logger logger = LoggerFactory.getLogger(RegistrationManagerImpl.class);
@ -138,12 +143,21 @@ public class RegistrationManagerImpl implements RegistrationManager {
public void verifyAccount( public void verifyAccount(
String verificationCode, String pin String verificationCode, String pin
) throws IOException, PinLockedException, IncorrectPinException { ) throws IOException, PinLockedException, IncorrectPinException {
var sessionId = account.getSessionId(account.getNumber()); if (account.getPniIdentityKeyPair() == null) {
final var result = NumberVerificationUtils.verifyNumber(sessionId, account.setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair());
}
final var aciPreKeys = generatePreKeysForType(ServiceIdType.ACI);
final var pniPreKeys = generatePreKeysForType(ServiceIdType.PNI);
final var result = NumberVerificationUtils.verifyNumber(account.getSessionId(account.getNumber()),
verificationCode, verificationCode,
pin, pin,
pinHelper, pinHelper,
this::verifyAccountWithCode); (sessionId1, verificationCode1, registrationLock) -> verifyAccountWithCode(sessionId1,
verificationCode1,
registrationLock,
aciPreKeys,
pniPreKeys));
final var response = result.first(); final var response = result.first();
final var masterKey = result.second(); final var masterKey = result.second();
if (masterKey == null) { if (masterKey == null) {
@ -153,7 +167,7 @@ public class RegistrationManagerImpl implements RegistrationManager {
//accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID))); //accountManager.setGcmId(Optional.of(GoogleCloudMessaging.getInstance(this).register(REGISTRATION_ID)));
final var aci = ACI.parseOrNull(response.getUuid()); final var aci = ACI.parseOrNull(response.getUuid());
final var pni = PNI.parseOrNull(response.getPni()); final var pni = PNI.parseOrNull(response.getPni());
account.finishRegistration(aci, pni, masterKey, pin); account.finishRegistration(aci, pni, masterKey, pin, aciPreKeys, pniPreKeys);
accountFileUpdater.updateAccountIdentifiers(account.getNumber(), aci); accountFileUpdater.updateAccountIdentifiers(account.getNumber(), aci);
ManagerImpl m = null; ManagerImpl m = null;
@ -228,7 +242,11 @@ public class RegistrationManagerImpl implements RegistrationManager {
} }
private VerifyAccountResponse verifyAccountWithCode( private VerifyAccountResponse verifyAccountWithCode(
final String sessionId, final String verificationCode, final String registrationLock final String sessionId,
final String verificationCode,
final String registrationLock,
final PreKeyCollection aciPreKeys,
final PreKeyCollection pniPreKeys
) throws IOException { ) throws IOException {
try { try {
Utils.handleResponseException(accountManager.verifyAccount(verificationCode, sessionId)); Utils.handleResponseException(accountManager.verifyAccount(verificationCode, sessionId));
@ -238,9 +256,41 @@ public class RegistrationManagerImpl implements RegistrationManager {
return Utils.handleResponseException(accountManager.registerAccount(sessionId, return Utils.handleResponseException(accountManager.registerAccount(sessionId,
null, null,
account.getAccountAttributes(registrationLock), account.getAccountAttributes(registrationLock),
aciPreKeys,
pniPreKeys,
null,
true)); true));
} }
private PreKeyCollection generatePreKeysForType(ServiceIdType serviceIdType) {
final var accountData = account.getAccountData(serviceIdType);
final var keyPair = accountData.getIdentityKeyPair();
final var preKeyMetadata = accountData.getPreKeyMetadata();
final var preKeyIdOffset = preKeyMetadata.getPreKeyIdOffset();
final var oneTimeEcPreKeys = KeyUtils.generatePreKeyRecords(preKeyIdOffset);
final var nextSignedPreKeyId = preKeyMetadata.getNextSignedPreKeyId();
final var signedPreKey = KeyUtils.generateSignedPreKeyRecord(nextSignedPreKeyId, keyPair);
final var privateKey = keyPair.getPrivateKey();
final var kyberPreKeyIdOffset = preKeyMetadata.getKyberPreKeyIdOffset();
final var oneTimeKyberPreKeys = KeyUtils.generateKyberPreKeyRecords(kyberPreKeyIdOffset, privateKey);
final var lastResortKyberPreKeyId = (kyberPreKeyIdOffset + oneTimeKyberPreKeys.size()) % PREKEY_MAXIMUM_ID;
final var lastResortKyberPreKey = KeyUtils.generateKyberPreKeyRecord(lastResortKyberPreKeyId, privateKey);
return new PreKeyCollection(keyPair,
nextSignedPreKeyId,
preKeyIdOffset,
lastResortKyberPreKeyId,
kyberPreKeyIdOffset,
serviceIdType,
keyPair.getPublicKey(),
signedPreKey,
oneTimeEcPreKeys,
lastResortKyberPreKey,
oneTimeKyberPreKeys);
}
@Override @Override
public void close() { public void close() {
if (account != null) { if (account != null) {

View file

@ -64,6 +64,7 @@ import org.slf4j.LoggerFactory;
import org.whispersystems.signalservice.api.SignalServiceAccountDataStore; import org.whispersystems.signalservice.api.SignalServiceAccountDataStore;
import org.whispersystems.signalservice.api.SignalServiceDataStore; import org.whispersystems.signalservice.api.SignalServiceDataStore;
import org.whispersystems.signalservice.api.account.AccountAttributes; import org.whispersystems.signalservice.api.account.AccountAttributes;
import org.whispersystems.signalservice.api.account.PreKeyCollection;
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess; import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
import org.whispersystems.signalservice.api.kbs.MasterKey; import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.push.ACI; import org.whispersystems.signalservice.api.push.ACI;
@ -299,6 +300,26 @@ public class SignalAccount implements Closeable {
save(); save();
} }
private void setPreKeys(ServiceIdType serviceIdType, PreKeyCollection preKeyCollection) {
final var accountData = getAccountData(serviceIdType);
final var preKeyMetadata = accountData.getPreKeyMetadata();
preKeyMetadata.nextSignedPreKeyId = preKeyCollection.getNextSignedPreKeyId();
preKeyMetadata.preKeyIdOffset = preKeyCollection.getEcOneTimePreKeyIdOffset();
preKeyMetadata.kyberPreKeyIdOffset = preKeyCollection.getOneTimeKyberPreKeyIdOffset();
preKeyMetadata.activeLastResortKyberPreKeyId = preKeyCollection.getLastResortKyberPreKeyId();
accountData.getPreKeyStore().removeAllPreKeys();
accountData.getSignedPreKeyStore().removeAllSignedPreKeys();
accountData.getKyberPreKeyStore().removeAllKyberPreKeys();
addPreKeys(serviceIdType, preKeyCollection.getOneTimeEcPreKeys());
addSignedPreKey(serviceIdType, preKeyCollection.getSignedPreKey());
addKyberPreKeys(serviceIdType, preKeyCollection.getOneTimeKyberPreKeys());
addLastResortKyberPreKey(serviceIdType, preKeyCollection.getLastResortKyberPreKey());
save();
}
private static SignalAccount createLinkedAccount( private static SignalAccount createLinkedAccount(
File dataPath, File dataPath,
String accountPath, String accountPath,
@ -394,7 +415,7 @@ public class SignalAccount implements Closeable {
setProfileKey(KeyUtils.createProfileKey()); setProfileKey(KeyUtils.createProfileKey());
} }
getProfileStore().storeProfileKey(getSelfRecipientId(), getProfileKey()); getProfileStore().storeProfileKey(getSelfRecipientId(), getProfileKey());
if (isPrimaryDevice() && getPniIdentityKeyPair() == null && getPni() != null) { if (isPrimaryDevice() && getPniIdentityKeyPair() == null) {
setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair()); setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair());
} }
} }
@ -1053,6 +1074,10 @@ public class SignalAccount implements Closeable {
public void addPreKeys(ServiceIdType serviceIdType, List<PreKeyRecord> records) { public void addPreKeys(ServiceIdType serviceIdType, List<PreKeyRecord> records) {
final var accountData = getAccountData(serviceIdType); final var accountData = getAccountData(serviceIdType);
final var preKeyMetadata = accountData.getPreKeyMetadata(); final var preKeyMetadata = accountData.getPreKeyMetadata();
logger.debug("Adding {} {} pre keys with offset {}",
records.size(),
serviceIdType,
preKeyMetadata.preKeyIdOffset);
for (var record : records) { for (var record : records) {
if (preKeyMetadata.preKeyIdOffset != record.getId()) { if (preKeyMetadata.preKeyIdOffset != record.getId()) {
logger.error("Invalid pre key id {}, expected {}", record.getId(), preKeyMetadata.preKeyIdOffset); logger.error("Invalid pre key id {}, expected {}", record.getId(), preKeyMetadata.preKeyIdOffset);
@ -1067,6 +1092,7 @@ public class SignalAccount implements Closeable {
public void addSignedPreKey(ServiceIdType serviceIdType, SignedPreKeyRecord record) { public void addSignedPreKey(ServiceIdType serviceIdType, SignedPreKeyRecord record) {
final var accountData = getAccountData(serviceIdType); final var accountData = getAccountData(serviceIdType);
final var preKeyMetadata = accountData.getPreKeyMetadata(); final var preKeyMetadata = accountData.getPreKeyMetadata();
logger.debug("Adding {} signed pre key with offset {}", serviceIdType, preKeyMetadata.nextSignedPreKeyId);
if (preKeyMetadata.nextSignedPreKeyId != record.getId()) { if (preKeyMetadata.nextSignedPreKeyId != record.getId()) {
logger.error("Invalid signed pre key id {}, expected {}", logger.error("Invalid signed pre key id {}, expected {}",
record.getId(), record.getId(),
@ -1088,6 +1114,10 @@ public class SignalAccount implements Closeable {
public void addKyberPreKeys(ServiceIdType serviceIdType, List<KyberPreKeyRecord> records) { public void addKyberPreKeys(ServiceIdType serviceIdType, List<KyberPreKeyRecord> records) {
final var accountData = getAccountData(serviceIdType); final var accountData = getAccountData(serviceIdType);
final var preKeyMetadata = accountData.getPreKeyMetadata(); final var preKeyMetadata = accountData.getPreKeyMetadata();
logger.debug("Adding {} {} kyber pre keys with offset {}",
records.size(),
serviceIdType,
preKeyMetadata.kyberPreKeyIdOffset);
for (var record : records) { for (var record : records) {
if (preKeyMetadata.kyberPreKeyIdOffset != record.getId()) { if (preKeyMetadata.kyberPreKeyIdOffset != record.getId()) {
logger.error("Invalid kyber pre key id {}, expected {}", logger.error("Invalid kyber pre key id {}, expected {}",
@ -1104,6 +1134,9 @@ public class SignalAccount implements Closeable {
public void addLastResortKyberPreKey(ServiceIdType serviceIdType, KyberPreKeyRecord record) { public void addLastResortKyberPreKey(ServiceIdType serviceIdType, KyberPreKeyRecord record) {
final var accountData = getAccountData(serviceIdType); final var accountData = getAccountData(serviceIdType);
final var preKeyMetadata = accountData.getPreKeyMetadata(); final var preKeyMetadata = accountData.getPreKeyMetadata();
logger.debug("Adding {} last resort kyber pre key with offset {}",
serviceIdType,
preKeyMetadata.kyberPreKeyIdOffset);
if (preKeyMetadata.kyberPreKeyIdOffset != record.getId()) { if (preKeyMetadata.kyberPreKeyIdOffset != record.getId()) {
logger.error("Invalid last resort kyber pre key id {}, expected {}", logger.error("Invalid last resort kyber pre key id {}, expected {}",
record.getId(), record.getId(),
@ -1606,7 +1639,14 @@ public class SignalAccount implements Closeable {
return phoneNumberUnlisted == null || !phoneNumberUnlisted; return phoneNumberUnlisted == null || !phoneNumberUnlisted;
} }
public void finishRegistration(final ACI aci, final PNI pni, final MasterKey masterKey, final String pin) { public void finishRegistration(
final ACI aci,
final PNI pni,
final MasterKey masterKey,
final String pin,
final PreKeyCollection aciPreKeys,
final PreKeyCollection pniPreKeys
) {
this.pinMasterKey = masterKey; this.pinMasterKey = masterKey;
this.storageManifestVersion = -1; this.storageManifestVersion = -1;
this.setStorageManifest(null); this.setStorageManifest(null);
@ -1621,17 +1661,14 @@ public class SignalAccount implements Closeable {
this.lastReceiveTimestamp = 0; this.lastReceiveTimestamp = 0;
save(); save();
clearAllPreKeys(); setPreKeys(ServiceIdType.ACI, aciPreKeys);
setPreKeys(ServiceIdType.PNI, pniPreKeys);
aciAccountData.getSessionStore().archiveAllSessions(); aciAccountData.getSessionStore().archiveAllSessions();
pniAccountData.getSessionStore().archiveAllSessions(); pniAccountData.getSessionStore().archiveAllSessions();
getSenderKeyStore().deleteAll(); getSenderKeyStore().deleteAll();
getRecipientTrustedResolver().resolveSelfRecipientTrusted(getSelfRecipientAddress()); getRecipientTrustedResolver().resolveSelfRecipientTrusted(getSelfRecipientAddress());
trustSelfIdentity(ServiceIdType.ACI); trustSelfIdentity(ServiceIdType.ACI);
if (getPniIdentityKeyPair() == null) { trustSelfIdentity(ServiceIdType.PNI);
setPniIdentityKeyPair(KeyUtils.generateIdentityKeyPair());
} else {
trustSelfIdentity(ServiceIdType.PNI);
}
} }
private void trustSelfIdentity(ServiceIdType serviceIdType) { private void trustSelfIdentity(ServiceIdType serviceIdType) {
@ -1699,12 +1736,28 @@ public class SignalAccount implements Closeable {
void call(); void call();
} }
private static class PreKeyMetadata { public static class PreKeyMetadata {
private int preKeyIdOffset = 1; private int preKeyIdOffset = 1;
private int nextSignedPreKeyId = 1; private int nextSignedPreKeyId = 1;
private int kyberPreKeyIdOffset = 1; private int kyberPreKeyIdOffset = 1;
private int activeLastResortKyberPreKeyId = -1; private int activeLastResortKyberPreKeyId = -1;
public int getPreKeyIdOffset() {
return preKeyIdOffset;
}
public int getNextSignedPreKeyId() {
return nextSignedPreKeyId;
}
public int getKyberPreKeyIdOffset() {
return kyberPreKeyIdOffset;
}
public int getActiveLastResortKyberPreKeyId() {
return activeLastResortKyberPreKeyId;
}
} }
public class AccountData { public class AccountData {

View file

@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Base64; import java.util.Base64;
import java.util.List; import java.util.List;
import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_BATCH_SIZE;
import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_MAXIMUM_ID; import static org.asamk.signal.manager.config.ServiceConfig.PREKEY_MAXIMUM_ID;
public class KeyUtils { public class KeyUtils {
@ -47,9 +48,9 @@ public class KeyUtils {
return new IdentityKeyPair(djbIdentityKey, djbPrivateKey); return new IdentityKeyPair(djbIdentityKey, djbPrivateKey);
} }
public static List<PreKeyRecord> generatePreKeyRecords(final int offset, final int batchSize) { public static List<PreKeyRecord> generatePreKeyRecords(final int offset) {
var records = new ArrayList<PreKeyRecord>(batchSize); var records = new ArrayList<PreKeyRecord>(PREKEY_BATCH_SIZE);
for (var i = 0; i < batchSize; i++) { for (var i = 0; i < PREKEY_BATCH_SIZE; i++) {
var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID; var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID;
var keyPair = Curve.generateKeyPair(); var keyPair = Curve.generateKeyPair();
var record = new PreKeyRecord(preKeyId, keyPair); var record = new PreKeyRecord(preKeyId, keyPair);
@ -60,7 +61,7 @@ public class KeyUtils {
} }
public static SignedPreKeyRecord generateSignedPreKeyRecord( public static SignedPreKeyRecord generateSignedPreKeyRecord(
final IdentityKeyPair identityKeyPair, final int signedPreKeyId final int signedPreKeyId, final IdentityKeyPair identityKeyPair
) { ) {
var keyPair = Curve.generateKeyPair(); var keyPair = Curve.generateKeyPair();
byte[] signature; byte[] signature;
@ -73,10 +74,10 @@ public class KeyUtils {
} }
public static List<KyberPreKeyRecord> generateKyberPreKeyRecords( public static List<KyberPreKeyRecord> generateKyberPreKeyRecords(
final int offset, final int batchSize, final ECPrivateKey privateKey final int offset, final ECPrivateKey privateKey
) { ) {
var records = new ArrayList<KyberPreKeyRecord>(batchSize); var records = new ArrayList<KyberPreKeyRecord>(PREKEY_BATCH_SIZE);
for (var i = 0; i < batchSize; i++) { for (var i = 0; i < PREKEY_BATCH_SIZE; i++) {
var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID; var preKeyId = (offset + i) % PREKEY_MAXIMUM_ID;
records.add(generateKyberPreKeyRecord(preKeyId, privateKey)); records.add(generateKyberPreKeyRecord(preKeyId, privateKey));
} }

View file

@ -16,7 +16,7 @@ dependencyResolutionManagement {
library("logback", "ch.qos.logback", "logback-classic").version("1.4.8") library("logback", "ch.qos.logback", "logback-classic").version("1.4.8")
library("signalservice", "com.github.turasa", "signal-service-java").version("2.15.3_unofficial_73") library("signalservice", "com.github.turasa", "signal-service-java").version("2.15.3_unofficial_74")
library("protobuf", "com.google.protobuf", "protobuf-javalite").version("3.23.0") library("protobuf", "com.google.protobuf", "protobuf-javalite").version("3.23.0")
library("sqlite", "org.xerial", "sqlite-jdbc").version("3.42.0.0") library("sqlite", "org.xerial", "sqlite-jdbc").version("3.42.0.0")
library("hikari", "com.zaxxer", "HikariCP").version("5.0.1") library("hikari", "com.zaxxer", "HikariCP").version("5.0.1")