Switch to libsignal for PIN hashing.

This commit is contained in:
Greyson Parrelli
2023-05-10 15:53:31 -04:00
parent 13248506c5
commit acb6510312
21 changed files with 148 additions and 195 deletions

View File

@@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.lock.PinHashing
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity
import org.thoughtcrime.securesms.lock.v2.KbsConstants
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
@@ -39,6 +38,7 @@ import org.thoughtcrime.securesms.util.ServiceUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.whispersystems.signalservice.api.kbs.PinHashUtil
class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFragment__account) {
@@ -247,7 +247,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
pinEditText.typeface = Typeface.DEFAULT
turnOffButton.setOnClickListener {
val pin = pinEditText.text.toString()
val correct = PinHashing.verifyLocalPinHash(SignalStore.kbsValues().localPinHash!!, pin)
val correct = PinHashUtil.verifyLocalPinHash(SignalStore.kbsValues().localPinHash!!, pin)
if (correct) {
SignalStore.pinValues().setPinRemindersEnabled(false)
viewModel.refreshState()

View File

@@ -8,12 +8,12 @@ import androidx.navigation.fragment.findNavController
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.app.changenumber.ChangeNumberUtil.changeNumberSuccess
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.lock.PinHashing
import org.thoughtcrime.securesms.registration.fragments.BaseRegistrationLockFragment
import org.thoughtcrime.securesms.registration.viewmodel.BaseRegistrationViewModel
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.SupportEmailUtil
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.whispersystems.signalservice.api.kbs.PinHashUtil
class ChangeNumberRegistrationLockFragment : BaseRegistrationLockFragment(R.layout.fragment_change_number_registration_lock) {
@@ -42,7 +42,7 @@ class ChangeNumberRegistrationLockFragment : BaseRegistrationLockFragment(R.layo
}
override fun handleSuccessfulPinEntry(pin: String) {
val pinsDiffer: Boolean = SignalStore.kbsValues().localPinHash?.let { !PinHashing.verifyLocalPinHash(it, pin) } ?: false
val pinsDiffer: Boolean = SignalStore.kbsValues().localPinHash?.let { !PinHashUtil.verifyLocalPinHash(it, pin) } ?: false
pinButton.cancelSpinning()

View File

@@ -4,10 +4,10 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.core.util.StringStringSerializer;
import org.thoughtcrime.securesms.lock.PinHashing;
import org.thoughtcrime.securesms.util.JsonUtils;
import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
import java.io.IOException;
@@ -75,7 +75,7 @@ public final class KbsValues extends SignalStoreValues {
getStore().beginWrite()
.putString(TOKEN_RESPONSE, tokenResponse)
.putBlob(MASTER_KEY, masterKey.serialize())
.putString(LOCK_LOCAL_PIN_HASH, PinHashing.localPinHash(pin))
.putString(LOCK_LOCAL_PIN_HASH, PinHashUtil.localPinHash(pin))
.putString(PIN, pin)
.putLong(LAST_CREATE_FAILED_TIMESTAMP, -1)
.putBoolean(OPTED_OUT, false)

View File

@@ -1,64 +0,0 @@
package org.thoughtcrime.securesms.lock;
import androidx.annotation.NonNull;
import org.signal.argon2.Argon2;
import org.signal.argon2.Argon2Exception;
import org.signal.argon2.MemoryCost;
import org.signal.argon2.Type;
import org.signal.argon2.UnknownTypeException;
import org.signal.argon2.Version;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.internal.registrationpin.PinHasher;
public final class PinHashing {
private PinHashing() {
}
public static HashedPin hashPin(@NonNull String pin, @NonNull KeyBackupService.HashSession hashSession) {
return PinHasher.hashPin(PinHasher.normalize(pin), password -> {
try {
return new Argon2.Builder(Version.V13)
.type(Type.Argon2id)
.memoryCost(MemoryCost.MiB(16))
.parallelism(1)
.iterations(32)
.hashLength(64)
.build()
.hash(password, hashSession.hashSalt())
.getHash();
} catch (Argon2Exception e) {
throw new AssertionError(e);
}
});
}
public static String localPinHash(@NonNull String pin) {
byte[] normalized = PinHasher.normalize(pin);
try {
return new Argon2.Builder(Version.V13)
.type(Type.Argon2i)
.memoryCost(MemoryCost.KiB(256))
.parallelism(1)
.iterations(50)
.hashLength(32)
.build()
.hash(normalized, Util.getSecretBytes(16))
.getEncoded();
} catch (Argon2Exception e) {
throw new AssertionError(e);
}
}
public static boolean verifyLocalPinHash(@NonNull String localPinHash, @NonNull String pin) {
byte[] normalized = PinHasher.normalize(pin);
try {
return Argon2.verify(localPinHash, normalized);
} catch (UnknownTypeException e) {
throw new AssertionError(e);
}
}
}

View File

@@ -35,6 +35,7 @@ import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
import org.thoughtcrime.securesms.lock.v2.KbsConstants;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
import java.util.Objects;
@@ -121,7 +122,7 @@ public final class SignalPinReminderDialog {
if (text.length() >= KbsConstants.MINIMUM_PIN_LENGTH) {
submit.setEnabled(true);
if (PinHashing.verifyLocalPinHash(localHash, text)) {
if (PinHashUtil.verifyLocalPinHash(localHash, text)) {
dialog.dismiss();
mainCallback.onReminderCompleted(text, callback.hadWrongGuess());
}
@@ -180,7 +181,7 @@ public final class SignalPinReminderDialog {
if (pin.length() < KbsConstants.MINIMUM_PIN_LENGTH) return;
if (PinHashing.verifyLocalPinHash(localPinHash, pin)) {
if (PinHashUtil.verifyLocalPinHash(localPinHash, pin)) {
callback.onPinCorrect(pin);
} else {
callback.onPinWrong();

View File

@@ -8,7 +8,7 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import org.whispersystems.signalservice.internal.registrationpin.PinValidityChecker;
import org.whispersystems.signalservice.api.kbs.PinValidityChecker;
public final class CreateKbsPinViewModel extends ViewModel implements BaseKbsPinViewModel {

View File

@@ -8,15 +8,15 @@ import androidx.annotation.Nullable;
import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.svr2.PinHash;
import org.thoughtcrime.securesms.KbsEnclave;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.PinHashing;
import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.KeyBackupServicePinException;
import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.internal.ServiceResponse;
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
@@ -162,7 +162,7 @@ public class KbsRepository {
try {
Log.i(TAG, "Restoring pin from KBS");
HashedPin hashedPin = PinHashing.hashPin(pin, session);
PinHash hashedPin = PinHashUtil.hashPin(pin, session.hashSalt());
KbsPinData kbsData = session.restorePin(hashedPin);
if (kbsData != null) {

View File

@@ -8,6 +8,7 @@ import androidx.annotation.WorkerThread;
import org.signal.core.util.logging.Log;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.svr2.PinHash;
import org.thoughtcrime.securesms.KbsEnclave;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobmanager.JobTracker;
@@ -16,15 +17,14 @@ import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
import org.thoughtcrime.securesms.jobs.StorageForcePushJob;
import org.thoughtcrime.securesms.keyvalue.KbsValues;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.PinHashing;
import org.thoughtcrime.securesms.lock.RegistrationLockReminders;
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType;
import org.thoughtcrime.securesms.megaphone.Megaphones;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.KeyBackupService;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
import org.whispersystems.signalservice.internal.contacts.crypto.UnauthenticatedResponseException;
import java.io.IOException;
@@ -119,8 +119,8 @@ public final class PinState {
MasterKey masterKey = kbsValues.getOrCreateMasterKey();
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService(kbsEnclave);
KeyBackupService.PinChangeSession pinChangeSession = keyBackupService.newPinChangeSession();
HashedPin hashedPin = PinHashing.hashPin(pin, pinChangeSession);
KbsPinData kbsData = pinChangeSession.setPin(hashedPin, masterKey);
PinHash pinHash = PinHashUtil.hashPin(pin, pinChangeSession.hashSalt());
KbsPinData kbsData = pinChangeSession.setPin(pinHash, masterKey);
kbsValues.setKbsMasterKey(kbsData, pin);
kbsValues.setPinForgottenOrSkipped(false);
@@ -221,8 +221,8 @@ public final class PinState {
MasterKey masterKey = kbsValues.getOrCreateMasterKey();
KeyBackupService keyBackupService = ApplicationDependencies.getKeyBackupService(kbsEnclave);
KeyBackupService.PinChangeSession pinChangeSession = keyBackupService.newPinChangeSession();
HashedPin hashedPin = PinHashing.hashPin(pin, pinChangeSession);
KbsPinData kbsData = pinChangeSession.setPin(hashedPin, masterKey);
PinHash pinHash = PinHashUtil.hashPin(pin, pinChangeSession.hashSalt());
KbsPinData kbsData = pinChangeSession.setPin(pinHash, masterKey);
pinChangeSession.enableRegistrationLock(masterKey);
@@ -299,8 +299,8 @@ public final class PinState {
KeyBackupService kbs = ApplicationDependencies.getKeyBackupService(enclave);
KeyBackupService.PinChangeSession pinChangeSession = kbs.newPinChangeSession();
HashedPin hashedPin = PinHashing.hashPin(pin, pinChangeSession);
KbsPinData newData = pinChangeSession.setPin(hashedPin, masterKey);
PinHash pinHash = PinHashUtil.hashPin(pin, pinChangeSession.hashSalt());
KbsPinData newData = pinChangeSession.setPin(pinHash, masterKey);
SignalStore.kbsValues().setKbsMasterKey(newData, pin);

View File

@@ -16,7 +16,6 @@ import org.thoughtcrime.securesms.jobs.NewRegistrationUsernameSyncJob;
import org.thoughtcrime.securesms.jobs.StorageAccountRestoreJob;
import org.thoughtcrime.securesms.jobs.StorageSyncJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.lock.PinHashing;
import org.thoughtcrime.securesms.pin.KbsRepository;
import org.thoughtcrime.securesms.pin.KeyBackupSystemWrongPinException;
import org.thoughtcrime.securesms.pin.TokenData;
@@ -32,6 +31,7 @@ import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.signalservice.api.KbsPinData;
import org.whispersystems.signalservice.api.KeyBackupSystemNoDataException;
import org.whispersystems.signalservice.api.kbs.PinHashUtil;
import org.whispersystems.signalservice.api.push.exceptions.IncorrectCodeException;
import org.whispersystems.signalservice.internal.ServiceResponse;
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
@@ -281,7 +281,7 @@ public final class RegistrationViewModel extends BaseRegistrationViewModel {
String localPinHash = SignalStore.kbsValues().getLocalPinHash();
if (hasRecoveryPassword() && localPinHash != null) {
if (PinHashing.verifyLocalPinHash(localPinHash, pin)) {
if (PinHashUtil.verifyLocalPinHash(localPinHash, pin)) {
Log.i(TAG, "Local pin matches input, attempting registration");
return ReRegistrationData.canProceed(new KbsPinData(SignalStore.kbsValues().getOrCreateMasterKey(), SignalStore.kbsValues().getRegistrationLockTokenResponse()));
} else {