From: AsamK Date: Sat, 8 May 2021 17:31:09 +0000 (+0200) Subject: Encrypt/decrypt device names X-Git-Tag: v0.8.2~13 X-Git-Url: https://git.nmode.ca/signal-cli/commitdiff_plain/6cb867cbebec69a7652fec0b9e6cb2860e99bcbf?ds=inline Encrypt/decrypt device names --- diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts index 327d1538..a9b5a95f 100644 --- a/lib/build.gradle.kts +++ b/lib/build.gradle.kts @@ -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") diff --git a/lib/src/main/java/org/asamk/signal/manager/Manager.java b/lib/src/main/java/org/asamk/signal/manager/Manager.java index a1a4b278..acd48c34 100644 --- a/lib/src/main/java/org/asamk/signal/manager/Manager.java +++ b/lib/src/main/java/org/asamk/signal/manager/Manager.java @@ -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 getLinkedDevices() throws IOException { + public List 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 { diff --git a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java index d27d911e..e813340e 100644 --- a/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java +++ b/lib/src/main/java/org/asamk/signal/manager/ProvisioningManager.java @@ -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, diff --git a/lib/src/main/java/org/asamk/signal/manager/api/Device.java b/lib/src/main/java/org/asamk/signal/manager/api/Device.java new file mode 100644 index 00000000..76074cbf --- /dev/null +++ b/lib/src/main/java/org/asamk/signal/manager/api/Device.java @@ -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; + } +} diff --git a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java index f12361a1..93178a91 100644 --- a/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java +++ b/lib/src/main/java/org/asamk/signal/manager/storage/SignalAccount.java @@ -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; diff --git a/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java b/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java index 7165d07c..d6c59498 100644 --- a/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java +++ b/src/main/java/org/asamk/signal/commands/ListDevicesCommand.java @@ -7,10 +7,10 @@ import org.asamk.signal.PlainTextWriterImpl; import org.asamk.signal.commands.exceptions.CommandException; import org.asamk.signal.commands.exceptions.IOErrorException; import org.asamk.signal.manager.Manager; +import org.asamk.signal.manager.api.Device; import org.asamk.signal.util.DateUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo; import java.io.IOException; import java.util.List; @@ -27,7 +27,7 @@ public class ListDevicesCommand implements LocalCommand { public void handleCommand(final Namespace ns, final Manager m) throws CommandException { final var writer = new PlainTextWriterImpl(System.out); - List devices; + List devices; try { devices = m.getLinkedDevices(); } catch (IOException e) {