Encrypt/decrypt device names

This commit is contained in:
AsamK 2021-05-08 19:31:09 +02:00
parent 56ac648922
commit 6cb867cbeb
6 changed files with 70 additions and 21 deletions

View file

@ -14,7 +14,7 @@ repositories {
}
dependencies {
api("com.github.turasa:signal-service-java:2.15.3_unofficial_20")
api("com.github.turasa:signal-service-java:2.15.3_unofficial_21")
implementation("com.google.protobuf:protobuf-javalite:3.10.0")
implementation("org.bouncycastle:bcprov-jdk15on:1.68")
implementation("org.slf4j:slf4j-api:1.7.30")

View file

@ -16,6 +16,7 @@
*/
package org.asamk.signal.manager;
import org.asamk.signal.manager.api.Device;
import org.asamk.signal.manager.config.ServiceConfig;
import org.asamk.signal.manager.config.ServiceEnvironment;
import org.asamk.signal.manager.config.ServiceEnvironmentConfig;
@ -108,7 +109,6 @@ import org.whispersystems.signalservice.api.messages.multidevice.DeviceContactsO
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroup;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsInputStream;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceGroupsOutputStream;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
import org.whispersystems.signalservice.api.messages.multidevice.RequestMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SentTranscriptMessage;
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
@ -119,6 +119,7 @@ import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
import org.whispersystems.signalservice.api.util.InvalidNumberException;
import org.whispersystems.signalservice.api.util.PhoneNumberFormatter;
import org.whispersystems.signalservice.api.util.SleepTimer;
@ -341,7 +342,7 @@ public class Manager implements Closeable {
}
public void updateAccountAttributes() throws IOException {
accountManager.setAccountAttributes(account.getDeviceName(),
accountManager.setAccountAttributes(account.getEncryptedDeviceName(),
null,
account.getLocalRegistrationId(),
true,
@ -422,10 +423,21 @@ public class Manager implements Closeable {
account.setRegistered(false);
}
public List<DeviceInfo> getLinkedDevices() throws IOException {
public List<Device> getLinkedDevices() throws IOException {
var devices = accountManager.getDevices();
account.setMultiDevice(devices.size() > 1);
return devices;
var identityKey = account.getIdentityKeyPair().getPrivateKey();
return devices.stream().map(d -> {
String deviceName = d.getName();
if (deviceName != null) {
try {
deviceName = DeviceNameUtil.decryptDeviceName(deviceName, identityKey);
} catch (IOException e) {
logger.debug("Failed to decrypt device name, maybe plain text?", e);
}
}
return new Device(d.getId(), deviceName, d.getCreated(), d.getLastSeen());
}).collect(Collectors.toList());
}
public void removeLinkedDevices(int deviceId) throws IOException {

View file

@ -29,6 +29,7 @@ import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.DeviceNameUtil;
import org.whispersystems.signalservice.api.util.SleepTimer;
import org.whispersystems.signalservice.api.util.UptimeSleepTimer;
import org.whispersystems.signalservice.internal.util.DynamicCredentialsProvider;
@ -47,7 +48,7 @@ public class ProvisioningManager {
private final String userAgent;
private final SignalServiceAccountManager accountManager;
private final IdentityKeyPair identityKey;
private final IdentityKeyPair tempIdentityKey;
private final int registrationId;
private final String password;
@ -56,7 +57,7 @@ public class ProvisioningManager {
this.serviceEnvironmentConfig = serviceEnvironmentConfig;
this.userAgent = userAgent;
identityKey = KeyUtils.generateIdentityKeyPair();
tempIdentityKey = KeyUtils.generateIdentityKeyPair();
registrationId = KeyHelper.generateRegistrationId(false);
password = KeyUtils.createPassword();
final SleepTimer timer = new UptimeSleepTimer();
@ -87,22 +88,26 @@ public class ProvisioningManager {
public URI getDeviceLinkUri() throws TimeoutException, IOException {
var deviceUuid = accountManager.getNewDeviceUuid();
return new DeviceLinkInfo(deviceUuid, identityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
return new DeviceLinkInfo(deviceUuid, tempIdentityKey.getPublicKey().getPublicKey()).createDeviceLinkUri();
}
public Manager finishDeviceLink(String deviceName) throws IOException, TimeoutException, UserAlreadyExists {
var ret = accountManager.getNewDeviceRegistration(identityKey);
var ret = accountManager.getNewDeviceRegistration(tempIdentityKey);
var number = ret.getNumber();
if (SignalAccount.userExists(pathConfig.getDataPath(), number)) {
throw new UserAlreadyExists(number, SignalAccount.getFileName(pathConfig.getDataPath(), number));
}
var encryptedDeviceName = deviceName == null
? null
: DeviceNameUtil.encryptDeviceName(deviceName, ret.getIdentity().getPrivateKey());
var deviceId = accountManager.finishNewDeviceRegistration(ret.getProvisioningCode(),
false,
true,
registrationId,
deviceName);
encryptedDeviceName);
// Create new account with the synced identity
var profileKey = ret.getProfileKey() == null ? KeyUtils.createProfileKey() : ret.getProfileKey();
@ -113,7 +118,7 @@ public class ProvisioningManager {
number,
ret.getUuid(),
password,
deviceName,
encryptedDeviceName,
deviceId,
ret.getIdentity(),
registrationId,

View file

@ -0,0 +1,32 @@
package org.asamk.signal.manager.api;
public class Device {
private final long id;
private final String name;
private final long created;
private final long lastSeen;
public Device(long id, String name, long created, long lastSeen) {
this.id = id;
this.name = name;
this.created = created;
this.lastSeen = lastSeen;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public long getCreated() {
return created;
}
public long getLastSeen() {
return lastSeen;
}
}

View file

@ -74,7 +74,7 @@ public class SignalAccount implements Closeable {
private String username;
private UUID uuid;
private String deviceName;
private String encryptedDeviceName;
private int deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
private boolean isMultiDevice = false;
private String password;
@ -172,7 +172,7 @@ public class SignalAccount implements Closeable {
String username,
UUID uuid,
String password,
String deviceName,
String encryptedDeviceName,
int deviceId,
IdentityKeyPair identityKey,
int registrationId,
@ -191,7 +191,7 @@ public class SignalAccount implements Closeable {
account.uuid = uuid;
account.password = password;
account.profileKey = profileKey;
account.deviceName = deviceName;
account.encryptedDeviceName = encryptedDeviceName;
account.deviceId = deviceId;
account.initStores(dataPath, identityKey, registrationId);
@ -307,7 +307,7 @@ public class SignalAccount implements Closeable {
}
}
if (rootNode.hasNonNull("deviceName")) {
deviceName = rootNode.get("deviceName").asText();
encryptedDeviceName = rootNode.get("deviceName").asText();
}
if (rootNode.hasNonNull("deviceId")) {
deviceId = rootNode.get("deviceId").asInt();
@ -579,7 +579,7 @@ public class SignalAccount implements Closeable {
rootNode.put("version", CURRENT_STORAGE_VERSION)
.put("username", username)
.put("uuid", uuid == null ? null : uuid.toString())
.put("deviceName", deviceName)
.put("deviceName", encryptedDeviceName)
.put("deviceId", deviceId)
.put("isMultiDevice", isMultiDevice)
.put("password", password)
@ -708,8 +708,8 @@ public class SignalAccount implements Closeable {
return recipientStore.resolveRecipientTrusted(getSelfAddress());
}
public String getDeviceName() {
return deviceName;
public String getEncryptedDeviceName() {
return encryptedDeviceName;
}
public int getDeviceId() {
@ -823,7 +823,7 @@ public class SignalAccount implements Closeable {
public void finishRegistration(final UUID uuid, final MasterKey masterKey, final String pin) {
this.pinMasterKey = masterKey;
this.deviceName = null;
this.encryptedDeviceName = null;
this.deviceId = SignalServiceAddress.DEFAULT_DEVICE_ID;
this.isMultiDevice = false;
this.registered = true;