Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 48aedd8a authored by Eric Biggers's avatar Eric Biggers
Browse files

Fix excessive scrypt time on lightweight devices

The LSKF stretching is not supposed to be user-noticeable.  But
sometimes it actually is, especially on watch form factor devices.

We *could* just remove the LSKF stretching entirely, as it's not where
the real security comes from in the vast majority of cases.  However, by
instead tuning it to be 4x faster, we get 75% of the time back (i.e.
most of it) while still leaving the brute-forcing much slower than not
having scrypt at all.  So, let's do that for now.

This change applies to new LSKFs only.  Existing LSKFs are unaffected
and continue to use the old scrypt parameters that are stored on-disk.

Bug: 416772194
Flag: android.security.scrypt_parameter_change
Test: atest FrameworksServicesTests:com.android.server.locksettings
Test: Added logging before and after stretchLskf, and verified that this
      change made stretchLskf about 4x faster for new LSKFs.
Test: Verified that device with LSKF already set can still be unlocked
      after taking this change.
Change-Id: I0c14edfafa5bce0d67b5705e0576cb11c653f9d7
parent 12b00cbf
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -49,6 +49,16 @@ flag {
    bug: "325129836"
}

flag {
    name: "scrypt_parameter_change"
    namespace: "security"
    description: "Use n=9 instead of n=11 for scrypt for lock screen knowledge factors"
    bug: "416772194"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "software_ratelimiter"
    namespace: "security"
+21 −2
Original line number Diff line number Diff line
@@ -174,9 +174,24 @@ class SyntheticPasswordManager {
    // The security strength of the synthetic password, in bytes
    private static final int SYNTHETIC_PASSWORD_SECURITY_STRENGTH = 256 / 8;

    private static final int PASSWORD_SCRYPT_LOG_N = 11;
    /*
     * These scrypt parameters are chosen to keep the scrypt time below 50ms or so, even in the
     * worst case (e.g., a watch form-factor device with the scrypt code running on an
     * energy-efficient CPU at a reduced frequency).
     *
     * The purpose of the scrypt step is just to slow down brute-force attacks on high-entropy
     * LSKFs. In practice, LSKFs are usually low-entropy, e.g. 4 or 6-digit PINs. With that little
     * entropy, the scrypt step provides no meaningful security benefit anyway, and the real
     * security comes from the "hardware" rate-limiting done by Gatekeeper or Weaver.
     *
     * Thus, while scrypt is still done to provide some value for rare high-entropy LSKFs, it's
     * tuned to always be quick enough so that users barely feel the cost.
     */
    private static final int PASSWORD_SCRYPT_LOG_N = 9;
    private static final int PASSWORD_SCRYPT_LOG_N__OLD = 11;
    private static final int PASSWORD_SCRYPT_LOG_R = 3;
    private static final int PASSWORD_SCRYPT_LOG_P = 1;

    private static final int PASSWORD_SALT_LENGTH = 16;
    private static final int STRETCHED_LSKF_LENGTH = 32;
    private static final String TAG = "SyntheticPasswordManager";
@@ -385,7 +400,11 @@ class SyntheticPasswordManager {

        public static PasswordData create(int credentialType, int pinLength) {
            PasswordData result = new PasswordData();
            if (android.security.Flags.scryptParameterChange()) {
                result.scryptLogN = PASSWORD_SCRYPT_LOG_N;
            } else {
                result.scryptLogN = PASSWORD_SCRYPT_LOG_N__OLD;
            }
            result.scryptLogR = PASSWORD_SCRYPT_LOG_R;
            result.scryptLogP = PASSWORD_SCRYPT_LOG_P;
            result.credentialType = credentialType;