diff --git a/app/build.gradle b/app/build.gradle index 1d2c32c826..7c97e4054f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -364,7 +364,8 @@ dependencies { implementation project(':libsignal-service') implementation 'org.signal:zkgroup-android:0.7.0' - + implementation 'org.whispersystems:signal-client-android:0.1.3' + implementation 'com.google.protobuf:protobuf-javalite:3.10.0' implementation 'org.signal:argon2:13.1@aar' implementation 'org.signal:ringrtc-android:2.8.0' diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryV2.java b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryV2.java index f677c8508c..d3b974bb41 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryV2.java +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/sync/ContactDiscoveryV2.java @@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.push.IasTrustStore; import org.thoughtcrime.securesms.util.SetUtil; +import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.signalservice.api.SignalServiceAccountManager; import org.whispersystems.signalservice.api.push.TrustStore; import org.whispersystems.signalservice.internal.contacts.crypto.Quote; @@ -69,7 +70,7 @@ class ContactDiscoveryV2 { FuzzyPhoneNumberHelper.OutputResultV2 outputResult = FuzzyPhoneNumberHelper.generateOutputV2(results, inputResult); return new DirectoryResult(outputResult.getNumbers(), outputResult.getRewrites(), ignoredNumbers); - } catch (SignatureException | UnauthenticatedQuoteException | UnauthenticatedResponseException | Quote.InvalidQuoteFormatException e) { + } catch (SignatureException | UnauthenticatedQuoteException | UnauthenticatedResponseException | Quote.InvalidQuoteFormatException |InvalidKeyException e) { Log.w(TAG, "Attestation error.", e); throw new IOException(e); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java b/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java index 89def2a3c4..51dfc8c28b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/lock/v2/ConfirmKbsPinRepository.java @@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.pin.PinState; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; +import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException; import java.io.IOException; @@ -29,7 +30,7 @@ final class ConfirmKbsPinRepository { Log.i(TAG, "Pin set on KBS"); return PinSetResult.SUCCESS; - } catch (IOException | UnauthenticatedResponseException e) { + } catch (IOException | UnauthenticatedResponseException | InvalidKeyException e) { Log.w(TAG, e); PinState.onPinCreateFailure(); return PinSetResult.FAILURE; diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java index 18d29b0e5b..68be8831fd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java @@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.lock.PinHashing; import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.pin.PinState; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.signalservice.api.KeyBackupService; import org.whispersystems.signalservice.api.KeyBackupServicePinException; import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException; @@ -60,7 +61,7 @@ public final class RegistrationPinV2MigrationJob extends BaseJob { } @Override - protected void onRun() throws IOException, UnauthenticatedResponseException { + protected void onRun() throws IOException, UnauthenticatedResponseException, InvalidKeyException { if (!TextSecurePreferences.isV1RegistrationLockEnabled(context)) { Log.i(TAG, "Registration lock disabled"); return; diff --git a/app/src/main/java/org/thoughtcrime/securesms/pin/PinState.java b/app/src/main/java/org/thoughtcrime/securesms/pin/PinState.java index 0c9cbd5201..d4a4559f2d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pin/PinState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/pin/PinState.java @@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.logging.Log; import org.thoughtcrime.securesms.megaphone.Megaphones; import org.thoughtcrime.securesms.registration.service.KeyBackupSystemWrongPinException; import org.thoughtcrime.securesms.util.TextSecurePreferences; +import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.KbsPinData; import org.whispersystems.signalservice.api.KeyBackupService; @@ -90,7 +91,7 @@ public final class PinState { } return kbsData; - } catch (UnauthenticatedResponseException e) { + } catch (UnauthenticatedResponseException | InvalidKeyException e) { Log.w(TAG, "Failed to restore key", e); throw new IOException(e); } catch (KeyBackupServicePinException e) { @@ -170,7 +171,7 @@ public final class PinState { */ @WorkerThread public static synchronized void onPinChangedOrCreated(@NonNull Context context, @NonNull String pin, @NonNull PinKeyboardType keyboard) - throws IOException, UnauthenticatedResponseException + throws IOException, UnauthenticatedResponseException, InvalidKeyException { Log.i(TAG, "onPinChangedOrCreated()"); @@ -272,7 +273,7 @@ public final class PinState { */ @WorkerThread public static synchronized void onMigrateToRegistrationLockV2(@NonNull Context context, @NonNull String pin) - throws IOException, UnauthenticatedResponseException + throws IOException, UnauthenticatedResponseException, InvalidKeyException { Log.i(TAG, "onMigrateToRegistrationLockV2()"); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java index d4cf753c65..31384f3783 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcUtil.java @@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.util.ServiceUtil; import org.thoughtcrime.securesms.webrtc.locks.LockManager; import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.ecc.Curve; -import org.whispersystems.libsignal.ecc.DjbECPublicKey; import org.whispersystems.libsignal.ecc.ECPublicKey; import org.whispersystems.signalservice.api.messages.calls.OfferMessage; @@ -25,11 +24,7 @@ public final class WebRtcUtil { public static @NonNull byte[] getPublicKeyBytes(@NonNull byte[] identityKey) throws InvalidKeyException { ECPublicKey key = Curve.decodePoint(identityKey, 0); - - if (key instanceof DjbECPublicKey) { - return ((DjbECPublicKey) key).getPublicKey(); - } - throw new InvalidKeyException(); + return key.getPublicKeyBytes(); } public static @NonNull LockManager.PhoneState getInCallPhoneState(@NonNull Context context) { diff --git a/app/witness-verifications.gradle b/app/witness-verifications.gradle index e91ac2fbbf..24fe652c8d 100644 --- a/app/witness-verifications.gradle +++ b/app/witness-verifications.gradle @@ -441,9 +441,6 @@ dependencyVerification { ['org.signal:ringrtc-android:2.8.0', '49965467ed1e8634969af10f318bbaf1dd97b1d55bca05300802a5dcb6ed21a3'], - ['org.signal:signal-metadata-java:0.1.2', - '6aaeb6a33bf3161a3e6ac9db7678277f7a4cf5a2c96b84342e4007ee49bab1bd'], - ['org.signal:zkgroup-android:0.7.0', '52b172565bd01526e93ebf1796b834bdc449d4fe3422c1b827e49cb8d4f13fbd'], @@ -453,11 +450,11 @@ dependencyVerification { ['org.threeten:threetenbp:1.3.6', 'f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7'], - ['org.whispersystems:curve25519-java:0.5.0', - '0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d'], + ['org.whispersystems:signal-client-android:0.1.3', + '5d85d61da77db7960f8f8fb48efaeb543716782d73fb01c6d33741baa1ed6cb4'], - ['org.whispersystems:signal-protocol-java:2.8.1', - 'b19db36839ab008fdccefc7f8c005f2ea43dc7c7298a209bc424e6f9b6d5617b'], + ['org.whispersystems:signal-client-java:0.1.3', + '97679340b9f9a3e61c4ee3bd054abff3b8d0e8ddb95dbd917f4425849e9ff2d6'], ['pl.tajchert:waitingdots:0.1.0', '2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c'], diff --git a/build.gradle b/build.gradle index 793e41ca37..6bf79a96b0 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ wrapper { subprojects { ext.lib_signal_service_version_number = "2.15.3" ext.lib_signal_service_group_info = "org.whispersystems" - ext.lib_signal_metadata_version = "0.1.2" + ext.lib_signal_client_version = "0.1.0" if (JavaVersion.current().isJava8Compatible()) { allprojects { diff --git a/libsignal/service/build.gradle b/libsignal/service/build.gradle index ffd3d97bcd..72f36bb944 100644 --- a/libsignal/service/build.gradle +++ b/libsignal/service/build.gradle @@ -32,7 +32,7 @@ dependencies { api 'com.googlecode.libphonenumber:libphonenumber:8.12.6' api 'com.fasterxml.jackson.core:jackson-databind:2.9.9.2' - api "org.signal:signal-metadata-java:${lib_signal_metadata_version}" + api 'org.whispersystems:signal-client-java:0.1.3' api 'com.squareup.okhttp3:okhttp:3.12.10' implementation 'org.threeten:threetenbp:1.3.6' diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java index b9aafc559e..9a432a55d4 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/KeyBackupService.java @@ -1,5 +1,6 @@ package org.whispersystems.signalservice.api; +import org.whispersystems.libsignal.InvalidKeyException; import org.whispersystems.libsignal.logging.Log; import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException; import org.whispersystems.signalservice.api.kbs.HashedPin; @@ -123,7 +124,7 @@ public final class KeyBackupService { @Override public KbsPinData restorePin(HashedPin hashedPin) - throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException + throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException, InvalidKeyException { int attempt = 0; SecureRandom random = new SecureRandom(); @@ -156,7 +157,7 @@ public final class KeyBackupService { } private KbsPinData restorePin(HashedPin hashedPin, TokenResponse token) - throws UnauthenticatedResponseException, IOException, TokenException, KeyBackupSystemNoDataException + throws UnauthenticatedResponseException, IOException, TokenException, KeyBackupSystemNoDataException, InvalidKeyException { try { final int remainingTries = token.getTries(); @@ -197,7 +198,7 @@ public final class KeyBackupService { } } - private RemoteAttestation getAndVerifyRemoteAttestation() throws UnauthenticatedResponseException, IOException { + private RemoteAttestation getAndVerifyRemoteAttestation() throws UnauthenticatedResponseException, IOException, InvalidKeyException { try { return RemoteAttestationUtil.getAndVerifyRemoteAttestation(pushServiceSocket, PushServiceSocket.ClientSet.KeyBackup, iasKeyStore, enclaveName, mrenclave, authorization); } catch (Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | InvalidCiphertextException | SignatureException e) { @@ -226,7 +227,7 @@ public final class KeyBackupService { KeyBackupResponse response = pushServiceSocket.putKbsData(authorization, request, remoteAttestation.getCookies(), enclaveName); KeyBackupCipher.getKeyDeleteResponseStatus(response, remoteAttestation); - } catch (InvalidCiphertextException e) { + } catch (InvalidCiphertextException | InvalidKeyException e) { throw new UnauthenticatedResponseException(e); } } @@ -261,7 +262,7 @@ public final class KeyBackupService { default: throw new AssertionError("Unknown response status " + status); } - } catch (InvalidCiphertextException e) { + } catch (InvalidCiphertextException | InvalidKeyException e) { throw new UnauthenticatedResponseException(e); } } @@ -275,7 +276,7 @@ public final class KeyBackupService { public interface RestoreSession extends HashSession { KbsPinData restorePin(HashedPin hashedPin) - throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException; + throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException, InvalidKeyException; } public interface PinChangeSession extends HashSession { diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java index 73586bd2a9..d1c5381549 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/SignalServiceAccountManager.java @@ -366,7 +366,7 @@ public class SignalServiceAccountManager { } public Map getRegisteredUsers(KeyStore iasKeyStore, Set e164numbers, String mrenclave) - throws IOException, Quote.InvalidQuoteFormatException, UnauthenticatedQuoteException, SignatureException, UnauthenticatedResponseException + throws IOException, Quote.InvalidQuoteFormatException, UnauthenticatedQuoteException, SignatureException, UnauthenticatedResponseException, InvalidKeyException { if (e164numbers.isEmpty()) { return Collections.emptyMap(); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/contacts/crypto/RemoteAttestationKeys.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/contacts/crypto/RemoteAttestationKeys.java index a9d2a7d305..d21a4de2f3 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/contacts/crypto/RemoteAttestationKeys.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/contacts/crypto/RemoteAttestationKeys.java @@ -1,8 +1,10 @@ package org.whispersystems.signalservice.internal.contacts.crypto; -import org.whispersystems.curve25519.Curve25519; -import org.whispersystems.curve25519.Curve25519KeyPair; +import org.whispersystems.libsignal.InvalidKeyException; +import org.whispersystems.libsignal.ecc.Curve; +import org.whispersystems.libsignal.ecc.ECKeyPair; +import org.whispersystems.libsignal.ecc.ECPublicKey; import org.whispersystems.libsignal.kdf.HKDFv3; import org.whispersystems.libsignal.util.ByteUtil; @@ -11,12 +13,12 @@ public class RemoteAttestationKeys { private final byte[] clientKey = new byte[32]; private final byte[] serverKey = new byte[32]; - public RemoteAttestationKeys(Curve25519KeyPair keyPair, byte[] serverPublicEphemeral, byte[] serverPublicStatic) { - byte[] ephemeralToEphemeral = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicEphemeral, keyPair.getPrivateKey()); - byte[] ephemeralToStatic = Curve25519.getInstance(Curve25519.BEST).calculateAgreement(serverPublicStatic, keyPair.getPrivateKey()); + public RemoteAttestationKeys(ECKeyPair keyPair, byte[] serverPublicEphemeral, byte[] serverPublicStatic) throws InvalidKeyException { + byte[] ephemeralToEphemeral = Curve.calculateAgreement(ECPublicKey.fromPublicKeyBytes(serverPublicEphemeral), keyPair.getPrivateKey()); + byte[] ephemeralToStatic = Curve.calculateAgreement(ECPublicKey.fromPublicKeyBytes(serverPublicStatic), keyPair.getPrivateKey()); byte[] masterSecret = ByteUtil.combine(ephemeralToEphemeral, ephemeralToStatic ); - byte[] publicKeys = ByteUtil.combine(keyPair.getPublicKey(), serverPublicEphemeral, serverPublicStatic); + byte[] publicKeys = ByteUtil.combine(keyPair.getPublicKey().getPublicKeyBytes(), serverPublicEphemeral, serverPublicStatic); HKDFv3 generator = new HKDFv3(); byte[] keys = generator.deriveSecrets(masterSecret, publicKeys, null, clientKey.length + serverKey.length); diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteAttestationUtil.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteAttestationUtil.java index 0e6e61624e..984ee2f01c 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteAttestationUtil.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/internal/push/RemoteAttestationUtil.java @@ -1,8 +1,8 @@ package org.whispersystems.signalservice.internal.push; -import org.whispersystems.curve25519.Curve25519; -import org.whispersystems.curve25519.Curve25519KeyPair; -import org.whispersystems.libsignal.util.Pair; +import org.whispersystems.libsignal.InvalidKeyException; +import org.whispersystems.libsignal.ecc.Curve; +import org.whispersystems.libsignal.ecc.ECKeyPair; import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException; import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException; import org.whispersystems.signalservice.internal.contacts.crypto.Quote; @@ -38,9 +38,9 @@ public final class RemoteAttestationUtil { String enclaveName, String mrenclave, String authorization) - throws IOException, Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException + throws IOException, Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException, InvalidKeyException { - Curve25519KeyPair keyPair = buildKeyPair(); + ECKeyPair keyPair = buildKeyPair(); ResponsePair result = makeAttestationRequest(socket, clientSet, authorization, enclaveName, keyPair); RemoteAttestationResponse response = JsonUtil.fromJson(result.body, RemoteAttestationResponse.class); @@ -53,9 +53,9 @@ public final class RemoteAttestationUtil { String enclaveName, String mrenclave, String authorization) - throws IOException, Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException + throws IOException, Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException, InvalidKeyException { - Curve25519KeyPair keyPair = buildKeyPair(); + ECKeyPair keyPair = buildKeyPair(); ResponsePair result = makeAttestationRequest(socket, clientSet, authorization, enclaveName, keyPair); MultiRemoteAttestationResponse response = JsonUtil.fromJson(result.body, MultiRemoteAttestationResponse.class); Map attestations = new HashMap<>(); @@ -76,19 +76,18 @@ public final class RemoteAttestationUtil { return attestations; } - private static Curve25519KeyPair buildKeyPair() { - Curve25519 curve = Curve25519.getInstance(Curve25519.BEST); - return curve.generateKeyPair(); + private static ECKeyPair buildKeyPair() { + return Curve.generateKeyPair(); } private static ResponsePair makeAttestationRequest(PushServiceSocket socket, PushServiceSocket.ClientSet clientSet, String authorization, String enclaveName, - Curve25519KeyPair keyPair) + ECKeyPair keyPair) throws IOException { - RemoteAttestationRequest attestationRequest = new RemoteAttestationRequest(keyPair.getPublicKey()); + RemoteAttestationRequest attestationRequest = new RemoteAttestationRequest(keyPair.getPublicKey().getPublicKeyBytes()); Response response = socket.makeRequest(clientSet, authorization, new LinkedList(), "/v1/attestation/" + enclaveName, "PUT", JsonUtil.toJson(attestationRequest)); ResponseBody body = response.body(); @@ -113,9 +112,9 @@ public final class RemoteAttestationUtil { private static RemoteAttestation validateAndBuildRemoteAttestation(RemoteAttestationResponse response, List cookies, KeyStore iasKeyStore, - Curve25519KeyPair keyPair, + ECKeyPair keyPair, String mrenclave) - throws Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException + throws Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException, InvalidKeyException { RemoteAttestationKeys keys = new RemoteAttestationKeys(keyPair, response.getServerEphemeralPublic(), response.getServerStaticPublic()); Quote quote = new Quote(response.getQuote()); diff --git a/libsignal/service/witness-verifications.gradle b/libsignal/service/witness-verifications.gradle index 822f41295a..8213de7dce 100644 --- a/libsignal/service/witness-verifications.gradle +++ b/libsignal/service/witness-verifications.gradle @@ -24,19 +24,13 @@ dependencyVerification { ['com.squareup.okio:okio:1.15.0', '693fa319a7e8843300602b204023b7674f106ebcb577f2dd5807212b66118bd2'], - ['org.signal:signal-metadata-java:0.1.2', - '6aaeb6a33bf3161a3e6ac9db7678277f7a4cf5a2c96b84342e4007ee49bab1bd'], - ['org.signal:zkgroup-java:0.7.0', 'd0099eedd60d6f7d4df5b288175e5d585228ed8897789926bdab69bf8c05659f'], ['org.threeten:threetenbp:1.3.6', 'f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7'], - ['org.whispersystems:curve25519-java:0.5.0', - '0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d'], - - ['org.whispersystems:signal-protocol-java:2.8.1', - 'b19db36839ab008fdccefc7f8c005f2ea43dc7c7298a209bc424e6f9b6d5617b'], + ['org.whispersystems:signal-client-java:0.1.3', + '97679340b9f9a3e61c4ee3bd054abff3b8d0e8ddb95dbd917f4425849e9ff2d6'], ] }