Add compile option to wipe user data upon repeated incorrect passphrases

This commit is contained in:
Oscar Mira 2023-03-16 19:03:52 +01:00
parent dbf98ebd0e
commit 8f735abe36
3 changed files with 29 additions and 2 deletions

View file

@ -181,6 +181,7 @@ android {
buildConfigField "int", "SIGNAL_CANONICAL_VERSION_CODE", "$canonicalVersionCode"
buildConfigField "String", "BACKUP_FILENAME", "\"" + BASE_APP_FILENAME.toLowerCase() + "\""
buildConfigField "boolean", "FORCE_INTERNAL_USER_FLAG", "$FORCE_INTERNAL_USER_FLAG"
buildConfigField "int", "MAX_FAILED_PASSPHRASES_FOR_WIPE", "0"
vectorDrawables.useSupportLibrary = true

View file

@ -323,13 +323,20 @@ public class PassphrasePromptActivity extends PassphraseActivity {
MasterSecret masterSecret = null;
try {
masterSecret = MasterSecretUtil.getMasterSecret(getApplicationContext(), passphrase);
} catch (InvalidPassphraseException | UnrecoverableKeyException e) {
Log.d(TAG, e);
} catch (InvalidPassphraseException e) {
MasterSecretUtil.reportFailedPassphraseAttempt(getApplicationContext());
Log.i(TAG, "Unlock attempt failed", e);
} catch (UnrecoverableKeyException e) {
Log.e(TAG, "Failed to load KeyStore HMAC key", e);
}
Arrays.fill(passphrase, (char) 0);
progressTimer.cancel();
if (masterSecret != null) {
MasterSecretUtil.reportSuccessfulPassphraseAttempt(getApplicationContext());
}
return masterSecret;
}

View file

@ -32,6 +32,7 @@ import org.signal.libsignal.protocol.ecc.Curve;
import org.signal.libsignal.protocol.ecc.ECKeyPair;
import org.signal.libsignal.protocol.ecc.ECPrivateKey;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
import org.thoughtcrime.securesms.BuildConfig;
import org.thoughtcrime.securesms.util.Base64;
import org.thoughtcrime.securesms.util.Util;
@ -235,6 +236,24 @@ public class MasterSecretUtil {
return masterSecret;
}
public static void reportFailedPassphraseAttempt(@NonNull Context context) {
long failedAttempts = retrieve(context, "passphrase_tries", 0) + 1;
long maxAttempts = BuildConfig.MAX_FAILED_PASSPHRASES_FOR_WIPE;
if (maxAttempts > 0 && maxAttempts <= failedAttempts) {
// Too many attempts. Wipe user data by overriding the KDF HMAC key.
String keyStoreAlias = retrieve(context, "keystore_alias", KEY_ALIAS_DEFAULT);
KeyStoreHelper.deleteKeyStoreEntry(keyStoreAlias);
KeyStoreHelper.createKeyStoreEntryHmac(keyStoreAlias, hasStrongBox(context));
}
getSharedPreferences(context).edit().putLong("passphrase_tries", failedAttempts).apply();
}
public static void reportSuccessfulPassphraseAttempt(@NonNull Context context) {
getSharedPreferences(context).edit().remove("passphrase_tries").apply();
}
private static byte[] retrieve(Context context, String key) {
SharedPreferences settings = getSharedPreferences(context);
String encodedValue = settings.getString(key, "");