diff --git a/app/build.gradle b/app/build.gradle index b92059cce7..a94e6fb913 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -365,8 +365,7 @@ 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.3' 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 d3b974bb41..f677c8508c 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,7 +14,6 @@ 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; @@ -70,7 +69,7 @@ class ContactDiscoveryV2 { FuzzyPhoneNumberHelper.OutputResultV2 outputResult = FuzzyPhoneNumberHelper.generateOutputV2(results, inputResult); return new DirectoryResult(outputResult.getNumbers(), outputResult.getRewrites(), ignoredNumbers); - } catch (SignatureException | UnauthenticatedQuoteException | UnauthenticatedResponseException | Quote.InvalidQuoteFormatException |InvalidKeyException e) { + } catch (SignatureException | UnauthenticatedQuoteException | UnauthenticatedResponseException | Quote.InvalidQuoteFormatException 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 51dfc8c28b..89def2a3c4 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,7 +9,6 @@ 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; @@ -30,7 +29,7 @@ final class ConfirmKbsPinRepository { Log.i(TAG, "Pin set on KBS"); return PinSetResult.SUCCESS; - } catch (IOException | UnauthenticatedResponseException | InvalidKeyException e) { + } catch (IOException | UnauthenticatedResponseException 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 68be8831fd..18d29b0e5b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/RegistrationPinV2MigrationJob.java @@ -15,7 +15,6 @@ 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; @@ -61,7 +60,7 @@ public final class RegistrationPinV2MigrationJob extends BaseJob { } @Override - protected void onRun() throws IOException, UnauthenticatedResponseException, InvalidKeyException { + protected void onRun() throws IOException, UnauthenticatedResponseException { 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 d4a4559f2d..0c9cbd5201 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/pin/PinState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/pin/PinState.java @@ -22,7 +22,6 @@ 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; @@ -91,7 +90,7 @@ public final class PinState { } return kbsData; - } catch (UnauthenticatedResponseException | InvalidKeyException e) { + } catch (UnauthenticatedResponseException e) { Log.w(TAG, "Failed to restore key", e); throw new IOException(e); } catch (KeyBackupServicePinException e) { @@ -171,7 +170,7 @@ public final class PinState { */ @WorkerThread public static synchronized void onPinChangedOrCreated(@NonNull Context context, @NonNull String pin, @NonNull PinKeyboardType keyboard) - throws IOException, UnauthenticatedResponseException, InvalidKeyException + throws IOException, UnauthenticatedResponseException { Log.i(TAG, "onPinChangedOrCreated()"); @@ -273,7 +272,7 @@ public final class PinState { */ @WorkerThread public static synchronized void onMigrateToRegistrationLockV2(@NonNull Context context, @NonNull String pin) - throws IOException, UnauthenticatedResponseException, InvalidKeyException + throws IOException, UnauthenticatedResponseException { 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 5d9215f616..d6276027ab 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 @@ -14,6 +14,7 @@ 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; @@ -26,7 +27,11 @@ public final class WebRtcUtil { public static @NonNull byte[] getPublicKeyBytes(@NonNull byte[] identityKey) throws InvalidKeyException { ECPublicKey key = Curve.decodePoint(identityKey, 0); - return key.getPublicKeyBytes(); + + if (key instanceof DjbECPublicKey) { + return ((DjbECPublicKey) key).getPublicKey(); + } + throw new InvalidKeyException(); } public static @NonNull LockManager.PhoneState getInCallPhoneState(@NonNull Context context) { diff --git a/app/witness-verifications.gradle b/app/witness-verifications.gradle index ad0a27ef87..16557395af 100644 --- a/app/witness-verifications.gradle +++ b/app/witness-verifications.gradle @@ -441,6 +441,9 @@ dependencyVerification { ['org.signal:ringrtc-android:2.8.3', '1cdc73ec34b11b9eeb0a650715e1095cade226736192c091991f31367245e37a'], + ['org.signal:signal-metadata-java:0.1.2', + '6aaeb6a33bf3161a3e6ac9db7678277f7a4cf5a2c96b84342e4007ee49bab1bd'], + ['org.signal:zkgroup-android:0.7.0', '52b172565bd01526e93ebf1796b834bdc449d4fe3422c1b827e49cb8d4f13fbd'], @@ -450,11 +453,11 @@ dependencyVerification { ['org.threeten:threetenbp:1.3.6', 'f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7'], - ['org.whispersystems:signal-client-android:0.1.3', - '5d85d61da77db7960f8f8fb48efaeb543716782d73fb01c6d33741baa1ed6cb4'], + ['org.whispersystems:curve25519-java:0.5.0', + '0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d'], - ['org.whispersystems:signal-client-java:0.1.3', - '97679340b9f9a3e61c4ee3bd054abff3b8d0e8ddb95dbd917f4425849e9ff2d6'], + ['org.whispersystems:signal-protocol-java:2.8.1', + 'b19db36839ab008fdccefc7f8c005f2ea43dc7c7298a209bc424e6f9b6d5617b'], ['pl.tajchert:waitingdots:0.1.0', '2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c'], diff --git a/build.gradle b/build.gradle index 6bf79a96b0..793e41ca37 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_client_version = "0.1.0" + ext.lib_signal_metadata_version = "0.1.2" if (JavaVersion.current().isJava8Compatible()) { allprojects { diff --git a/libsignal/service/build.gradle b/libsignal/service/build.gradle index 72f36bb944..ffd3d97bcd 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.whispersystems:signal-client-java:0.1.3' + api "org.signal:signal-metadata-java:${lib_signal_metadata_version}" 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 9a432a55d4..b9aafc559e 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,6 +1,5 @@ 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; @@ -124,7 +123,7 @@ public final class KeyBackupService { @Override public KbsPinData restorePin(HashedPin hashedPin) - throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException, InvalidKeyException + throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException { int attempt = 0; SecureRandom random = new SecureRandom(); @@ -157,7 +156,7 @@ public final class KeyBackupService { } private KbsPinData restorePin(HashedPin hashedPin, TokenResponse token) - throws UnauthenticatedResponseException, IOException, TokenException, KeyBackupSystemNoDataException, InvalidKeyException + throws UnauthenticatedResponseException, IOException, TokenException, KeyBackupSystemNoDataException { try { final int remainingTries = token.getTries(); @@ -198,7 +197,7 @@ public final class KeyBackupService { } } - private RemoteAttestation getAndVerifyRemoteAttestation() throws UnauthenticatedResponseException, IOException, InvalidKeyException { + private RemoteAttestation getAndVerifyRemoteAttestation() throws UnauthenticatedResponseException, IOException { try { return RemoteAttestationUtil.getAndVerifyRemoteAttestation(pushServiceSocket, PushServiceSocket.ClientSet.KeyBackup, iasKeyStore, enclaveName, mrenclave, authorization); } catch (Quote.InvalidQuoteFormatException | UnauthenticatedQuoteException | InvalidCiphertextException | SignatureException e) { @@ -227,7 +226,7 @@ public final class KeyBackupService { KeyBackupResponse response = pushServiceSocket.putKbsData(authorization, request, remoteAttestation.getCookies(), enclaveName); KeyBackupCipher.getKeyDeleteResponseStatus(response, remoteAttestation); - } catch (InvalidCiphertextException | InvalidKeyException e) { + } catch (InvalidCiphertextException e) { throw new UnauthenticatedResponseException(e); } } @@ -262,7 +261,7 @@ public final class KeyBackupService { default: throw new AssertionError("Unknown response status " + status); } - } catch (InvalidCiphertextException | InvalidKeyException e) { + } catch (InvalidCiphertextException e) { throw new UnauthenticatedResponseException(e); } } @@ -276,7 +275,7 @@ public final class KeyBackupService { public interface RestoreSession extends HashSession { KbsPinData restorePin(HashedPin hashedPin) - throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException, InvalidKeyException; + throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException; } 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 d1c5381549..73586bd2a9 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, InvalidKeyException + throws IOException, Quote.InvalidQuoteFormatException, UnauthenticatedQuoteException, SignatureException, UnauthenticatedResponseException { 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 d21a4de2f3..a9d2a7d305 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,10 +1,8 @@ package org.whispersystems.signalservice.internal.contacts.crypto; -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.curve25519.Curve25519; +import org.whispersystems.curve25519.Curve25519KeyPair; import org.whispersystems.libsignal.kdf.HKDFv3; import org.whispersystems.libsignal.util.ByteUtil; @@ -13,12 +11,12 @@ public class RemoteAttestationKeys { private final byte[] clientKey = new byte[32]; private final byte[] serverKey = new byte[32]; - 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()); + 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()); byte[] masterSecret = ByteUtil.combine(ephemeralToEphemeral, ephemeralToStatic ); - byte[] publicKeys = ByteUtil.combine(keyPair.getPublicKey().getPublicKeyBytes(), serverPublicEphemeral, serverPublicStatic); + byte[] publicKeys = ByteUtil.combine(keyPair.getPublicKey(), 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 984ee2f01c..0e6e61624e 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.libsignal.InvalidKeyException; -import org.whispersystems.libsignal.ecc.Curve; -import org.whispersystems.libsignal.ecc.ECKeyPair; +import org.whispersystems.curve25519.Curve25519; +import org.whispersystems.curve25519.Curve25519KeyPair; +import org.whispersystems.libsignal.util.Pair; 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, InvalidKeyException + throws IOException, Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException { - ECKeyPair keyPair = buildKeyPair(); + Curve25519KeyPair 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, InvalidKeyException + throws IOException, Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException { - ECKeyPair keyPair = buildKeyPair(); + Curve25519KeyPair keyPair = buildKeyPair(); ResponsePair result = makeAttestationRequest(socket, clientSet, authorization, enclaveName, keyPair); MultiRemoteAttestationResponse response = JsonUtil.fromJson(result.body, MultiRemoteAttestationResponse.class); Map attestations = new HashMap<>(); @@ -76,18 +76,19 @@ public final class RemoteAttestationUtil { return attestations; } - private static ECKeyPair buildKeyPair() { - return Curve.generateKeyPair(); + private static Curve25519KeyPair buildKeyPair() { + Curve25519 curve = Curve25519.getInstance(Curve25519.BEST); + return curve.generateKeyPair(); } private static ResponsePair makeAttestationRequest(PushServiceSocket socket, PushServiceSocket.ClientSet clientSet, String authorization, String enclaveName, - ECKeyPair keyPair) + Curve25519KeyPair keyPair) throws IOException { - RemoteAttestationRequest attestationRequest = new RemoteAttestationRequest(keyPair.getPublicKey().getPublicKeyBytes()); + RemoteAttestationRequest attestationRequest = new RemoteAttestationRequest(keyPair.getPublicKey()); Response response = socket.makeRequest(clientSet, authorization, new LinkedList(), "/v1/attestation/" + enclaveName, "PUT", JsonUtil.toJson(attestationRequest)); ResponseBody body = response.body(); @@ -112,9 +113,9 @@ public final class RemoteAttestationUtil { private static RemoteAttestation validateAndBuildRemoteAttestation(RemoteAttestationResponse response, List cookies, KeyStore iasKeyStore, - ECKeyPair keyPair, + Curve25519KeyPair keyPair, String mrenclave) - throws Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException, InvalidKeyException + throws Quote.InvalidQuoteFormatException, InvalidCiphertextException, UnauthenticatedQuoteException, SignatureException { 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 8213de7dce..822f41295a 100644 --- a/libsignal/service/witness-verifications.gradle +++ b/libsignal/service/witness-verifications.gradle @@ -24,13 +24,19 @@ 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:signal-client-java:0.1.3', - '97679340b9f9a3e61c4ee3bd054abff3b8d0e8ddb95dbd917f4425849e9ff2d6'], + ['org.whispersystems:curve25519-java:0.5.0', + '0aadd43cf01d11e9b58f867b3c4f25c3194e8b0623d1953d32dfbfbee009e38d'], + + ['org.whispersystems:signal-protocol-java:2.8.1', + 'b19db36839ab008fdccefc7f8c005f2ea43dc7c7298a209bc424e6f9b6d5617b'], ] }