Loading core/java/com/android/internal/widget/LockPatternUtils.java +0 −4 Original line number Diff line number Diff line Loading @@ -166,10 +166,6 @@ public class LockPatternUtils { private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents"; private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged"; public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_"; public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_"; public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_"; public static final String CURRENT_LSKF_BASED_PROTECTOR_ID_KEY = "sp-handle"; public static final String PASSWORD_HISTORY_DELIMITER = ","; Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +3 −2 Original line number Diff line number Diff line Loading @@ -35,8 +35,6 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTE import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_DECRYPT; import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; import static com.android.internal.widget.LockPatternUtils.USER_FRP; Loading Loading @@ -211,6 +209,9 @@ public class LockSettingsService extends ILockSettings.Stub { // user's credential must be presented again, e.g. via ConfirmLockPattern/ConfirmLockPassword. private static final int GK_PW_HANDLE_STORE_DURATION_MS = 10 * 60 * 1000; // 10 minutes private static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_"; private static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_"; // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. private final Object mSeparateChallengeLock = new Object(); Loading services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java +27 −22 Original line number Diff line number Diff line Loading @@ -127,18 +127,20 @@ public class SyntheticPasswordCrypto { } /** * Decrypt a legacy SP blob which did the Keystore and software encryption layers in the wrong * Decrypts a legacy SP blob which did the Keystore and software encryption layers in the wrong * order. */ public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] protectorSecret) { public static byte[] decryptBlobV1(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { try { KeyStore keyStore = getKeyStore(); SecretKey keyStoreKey = (SecretKey) keyStore.getKey(keyAlias, null); if (keyStoreKey == null) { throw new IllegalStateException("SP key is missing: " + keyAlias); SecretKey protectorKey = (SecretKey) keyStore.getKey(protectorKeyAlias, null); if (protectorKey == null) { throw new IllegalStateException("SP protector key is missing: " + protectorKeyAlias); } byte[] intermediate = decrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, blob); return decrypt(keyStoreKey, intermediate); return decrypt(protectorKey, intermediate); } catch (Exception e) { Slog.e(TAG, "Failed to decrypt V1 blob", e); throw new IllegalStateException("Failed to decrypt blob", e); Loading @@ -163,15 +165,17 @@ public class SyntheticPasswordCrypto { /** * Decrypts an SP blob that was created by {@link #createBlob}. */ public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] protectorSecret) { public static byte[] decryptBlob(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { try { final KeyStore keyStore = getKeyStore(); SecretKey keyStoreKey = (SecretKey) keyStore.getKey(keyAlias, null); if (keyStoreKey == null) { throw new IllegalStateException("SP key is missing: " + keyAlias); SecretKey protectorKey = (SecretKey) keyStore.getKey(protectorKeyAlias, null); if (protectorKey == null) { throw new IllegalStateException("SP protector key is missing: " + protectorKeyAlias); } byte[] intermediate = decrypt(keyStoreKey, blob); byte[] intermediate = decrypt(protectorKey, blob); return decrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, intermediate); } catch (CertificateException | IOException | BadPaddingException | IllegalBlockSizeException Loading @@ -185,20 +189,21 @@ public class SyntheticPasswordCrypto { /** * Creates a new SP blob by encrypting the given data. Two encryption layers are applied: an * inner layer using a hash of protectorSecret as the key, and an outer layer using a new * Keystore key with the given alias and optionally bound to a SID. * inner layer using a hash of protectorSecret as the key, and an outer layer using the * protector key, which is a Keystore key that is optionally bound to a SID. This method * creates the protector key and stores it under protectorKeyAlias. * * The reason we use a layer of software encryption, instead of using protectorSecret as the * applicationId of the Keystore key, is to work around buggy KeyMint implementations that don't * cryptographically bind the applicationId to the key. The Keystore layer has to be the outer * layer, so that LSKF verification is ratelimited by Gatekeeper when Weaver is unavailable. */ public static byte[] createBlob(String keyAlias, byte[] data, byte[] protectorSecret, public static byte[] createBlob(String protectorKeyAlias, byte[] data, byte[] protectorSecret, long sid) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); keyGenerator.init(AES_GCM_KEY_SIZE * 8, new SecureRandom()); SecretKey keyStoreKey = keyGenerator.generateKey(); SecretKey protectorKey = keyGenerator.generateKey(); final KeyStore keyStore = getKeyStore(); KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) Loading @@ -212,9 +217,9 @@ public class SyntheticPasswordCrypto { final KeyProtection protNonRollbackResistant = builder.build(); builder.setRollbackResistant(true); final KeyProtection protRollbackResistant = builder.build(); final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(keyStoreKey); final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(protectorKey); try { keyStore.setEntry(keyAlias, entry, protRollbackResistant); keyStore.setEntry(protectorKeyAlias, entry, protRollbackResistant); Slog.i(TAG, "Using rollback-resistant key"); } catch (KeyStoreException e) { if (!(e.getCause() instanceof android.security.KeyStoreException)) { Loading @@ -226,11 +231,11 @@ public class SyntheticPasswordCrypto { } Slog.w(TAG, "Rollback-resistant keys unavailable. Falling back to " + "non-rollback-resistant key"); keyStore.setEntry(keyAlias, entry, protNonRollbackResistant); keyStore.setEntry(protectorKeyAlias, entry, protNonRollbackResistant); } byte[] intermediate = encrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, data); return encrypt(keyStoreKey, intermediate); return encrypt(protectorKey, intermediate); } catch (CertificateException | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException Loading @@ -241,15 +246,15 @@ public class SyntheticPasswordCrypto { } } public static void destroyBlobKey(String keyAlias) { public static void destroyProtectorKey(String keyAlias) { KeyStore keyStore; try { keyStore = getKeyStore(); keyStore.deleteEntry(keyAlias); Slog.i(TAG, "SP key deleted: " + keyAlias); Slog.i(TAG, "Deleted SP protector key " + keyAlias); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { Slog.e(TAG, "Failed to destroy blob", e); Slog.e(TAG, "Failed to delete SP protector key " + keyAlias, e); } } Loading services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +24 −16 Original line number Diff line number Diff line Loading @@ -135,6 +135,8 @@ public class SyntheticPasswordManager { private static final byte PROTECTOR_TYPE_STRONG_TOKEN_BASED = 1; private static final byte PROTECTOR_TYPE_WEAK_TOKEN_BASED = 2; private static final String PROTECTOR_KEY_ALIAS_PREFIX = "synthetic_password_"; // The security strength of the synthetic password, in bytes private static final int SYNTHETIC_PASSWORD_SECURITY_STRENGTH = 256 / 8; Loading Loading @@ -583,7 +585,7 @@ public class SyntheticPasswordManager { for (long protectorId : mStorage.listSyntheticPasswordProtectorsForUser(SP_BLOB_NAME, userId)) { destroyWeaverSlot(protectorId, userId); destroySPBlobKey(getKeyName(protectorId)); destroyProtectorKey(getProtectorKeyAlias(protectorId)); } // Remove potential persistent state (in RPMB), to prevent them from accumulating and // causing problems. Loading Loading @@ -999,7 +1001,8 @@ public class SyntheticPasswordManager { } else { spSecret = sp.getSyntheticPassword(); } byte[] content = createSPBlob(getKeyName(protectorId), spSecret, protectorSecret, sid); byte[] content = createSpBlob(getProtectorKeyAlias(protectorId), spSecret, protectorSecret, sid); /* * We can upgrade from v1 to v2 because that's just a change in the way that * the SP is stored. However, we can't upgrade to v3 because that is a change Loading Loading @@ -1210,10 +1213,11 @@ public class SyntheticPasswordManager { } final byte[] spSecret; if (blob.mVersion == SYNTHETIC_PASSWORD_VERSION_V1) { spSecret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(protectorId), blob.mContent, protectorSecret); spSecret = SyntheticPasswordCrypto.decryptBlobV1(getProtectorKeyAlias(protectorId), blob.mContent, protectorSecret); } else { spSecret = decryptSPBlob(getKeyName(protectorId), blob.mContent, protectorSecret); spSecret = decryptSpBlob(getProtectorKeyAlias(protectorId), blob.mContent, protectorSecret); } if (spSecret == null) { Slog.e(TAG, "Fail to decrypt SP for user " + userId); Loading Loading @@ -1337,7 +1341,7 @@ public class SyntheticPasswordManager { private void destroyProtectorCommon(long protectorId, int userId) { destroyState(SP_BLOB_NAME, protectorId, userId); destroySPBlobKey(getKeyName(protectorId)); destroyProtectorKey(getProtectorKeyAlias(protectorId)); destroyState(SECDISCARDABLE_NAME, protectorId, userId); if (hasState(WEAVER_SLOT_NAME, protectorId, userId)) { destroyWeaverSlot(protectorId, userId); Loading Loading @@ -1422,17 +1426,20 @@ public class SyntheticPasswordManager { mStorage.deleteSyntheticPasswordState(userId, protectorId, stateName); } protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] protectorSecret) { return SyntheticPasswordCrypto.decryptBlob(blobKeyName, blob, protectorSecret); @VisibleForTesting protected byte[] decryptSpBlob(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { return SyntheticPasswordCrypto.decryptBlob(protectorKeyAlias, blob, protectorSecret); } protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] protectorSecret, @VisibleForTesting protected byte[] createSpBlob(String protectorKeyAlias, byte[] data, byte[] protectorSecret, long sid) { return SyntheticPasswordCrypto.createBlob(blobKeyName, data, protectorSecret, sid); return SyntheticPasswordCrypto.createBlob(protectorKeyAlias, data, protectorSecret, sid); } protected void destroySPBlobKey(String keyAlias) { SyntheticPasswordCrypto.destroyBlobKey(keyAlias); @VisibleForTesting protected void destroyProtectorKey(String keyAlias) { SyntheticPasswordCrypto.destroyProtectorKey(keyAlias); } public static long generateProtectorId() { Loading @@ -1457,8 +1464,8 @@ public class SyntheticPasswordManager { } } private String getKeyName(long protectorId) { return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, protectorId); private String getProtectorKeyAlias(long protectorId) { return String.format("%s%x", PROTECTOR_KEY_ALIAS_PREFIX, protectorId); } private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) { Loading Loading @@ -1511,7 +1518,7 @@ public class SyntheticPasswordManager { } /** * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain * Migrates all existing SP protector keys from uid 1000 app domain to LSS selinux domain. */ public boolean migrateKeyNamespace() { boolean success = true; Loading @@ -1519,7 +1526,8 @@ public class SyntheticPasswordManager { mStorage.listSyntheticPasswordProtectorsForAllUsers(SP_BLOB_NAME); for (List<Long> userProtectors : allProtectors.values()) { for (long protectorId : userProtectors) { success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(protectorId)); success &= SyntheticPasswordCrypto.migrateLockSettingsKey( getProtectorKeyAlias(protectorId)); } } return success; Loading services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java +9 −7 Original line number Diff line number Diff line Loading @@ -44,12 +44,14 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { mGateKeeper = gatekeeper; } private ArrayMap<String, byte[]> mBlobs = new ArrayMap<>(); private final ArrayMap<String, byte[]> mBlobs = new ArrayMap<>(); @Override protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] protectorSecret) { if (mBlobs.containsKey(blobKeyName) && !Arrays.equals(mBlobs.get(blobKeyName), blob)) { throw new AssertionFailedError("blobKeyName content is overwritten: " + blobKeyName); protected byte[] decryptSpBlob(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { if (mBlobs.containsKey(protectorKeyAlias) && !Arrays.equals(mBlobs.get(protectorKeyAlias), blob)) { throw new AssertionFailedError("Blob was overwritten; protectorKeyAlias=" + protectorKeyAlias); } ByteBuffer buffer = ByteBuffer.allocate(blob.length); buffer.put(blob, 0, blob.length); Loading @@ -72,7 +74,7 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { } @Override protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] protectorSecret, protected byte[] createSpBlob(String protectorKeyAlias, byte[] data, byte[] protectorSecret, long sid) { ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + data.length + Integer.BYTES + protectorSecret.length + Long.BYTES); Loading @@ -82,12 +84,12 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { buffer.put(protectorSecret); buffer.putLong(sid); byte[] result = buffer.array(); mBlobs.put(blobKeyName, result); mBlobs.put(protectorKeyAlias, result); return result; } @Override protected void destroySPBlobKey(String keyAlias) { protected void destroyProtectorKey(String keyAlias) { } @Override Loading Loading
core/java/com/android/internal/widget/LockPatternUtils.java +0 −4 Original line number Diff line number Diff line Loading @@ -166,10 +166,6 @@ public class LockPatternUtils { private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents"; private static final String IS_TRUST_USUALLY_MANAGED = "lockscreen.istrustusuallymanaged"; public static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_"; public static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_"; public static final String SYNTHETIC_PASSWORD_KEY_PREFIX = "synthetic_password_"; public static final String CURRENT_LSKF_BASED_PROTECTOR_ID_KEY = "sp-handle"; public static final String PASSWORD_HISTORY_DELIMITER = ","; Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +3 −2 Original line number Diff line number Diff line Loading @@ -35,8 +35,6 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTE import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY; import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback; import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_DECRYPT; import static com.android.internal.widget.LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE; import static com.android.internal.widget.LockPatternUtils.USER_FRP; Loading Loading @@ -211,6 +209,9 @@ public class LockSettingsService extends ILockSettings.Stub { // user's credential must be presented again, e.g. via ConfirmLockPattern/ConfirmLockPassword. private static final int GK_PW_HANDLE_STORE_DURATION_MS = 10 * 60 * 1000; // 10 minutes private static final String PROFILE_KEY_NAME_ENCRYPT = "profile_key_name_encrypt_"; private static final String PROFILE_KEY_NAME_DECRYPT = "profile_key_name_decrypt_"; // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this // Do not call into ActivityManager while holding mSpManager lock. private final Object mSeparateChallengeLock = new Object(); Loading
services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java +27 −22 Original line number Diff line number Diff line Loading @@ -127,18 +127,20 @@ public class SyntheticPasswordCrypto { } /** * Decrypt a legacy SP blob which did the Keystore and software encryption layers in the wrong * Decrypts a legacy SP blob which did the Keystore and software encryption layers in the wrong * order. */ public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] protectorSecret) { public static byte[] decryptBlobV1(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { try { KeyStore keyStore = getKeyStore(); SecretKey keyStoreKey = (SecretKey) keyStore.getKey(keyAlias, null); if (keyStoreKey == null) { throw new IllegalStateException("SP key is missing: " + keyAlias); SecretKey protectorKey = (SecretKey) keyStore.getKey(protectorKeyAlias, null); if (protectorKey == null) { throw new IllegalStateException("SP protector key is missing: " + protectorKeyAlias); } byte[] intermediate = decrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, blob); return decrypt(keyStoreKey, intermediate); return decrypt(protectorKey, intermediate); } catch (Exception e) { Slog.e(TAG, "Failed to decrypt V1 blob", e); throw new IllegalStateException("Failed to decrypt blob", e); Loading @@ -163,15 +165,17 @@ public class SyntheticPasswordCrypto { /** * Decrypts an SP blob that was created by {@link #createBlob}. */ public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] protectorSecret) { public static byte[] decryptBlob(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { try { final KeyStore keyStore = getKeyStore(); SecretKey keyStoreKey = (SecretKey) keyStore.getKey(keyAlias, null); if (keyStoreKey == null) { throw new IllegalStateException("SP key is missing: " + keyAlias); SecretKey protectorKey = (SecretKey) keyStore.getKey(protectorKeyAlias, null); if (protectorKey == null) { throw new IllegalStateException("SP protector key is missing: " + protectorKeyAlias); } byte[] intermediate = decrypt(keyStoreKey, blob); byte[] intermediate = decrypt(protectorKey, blob); return decrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, intermediate); } catch (CertificateException | IOException | BadPaddingException | IllegalBlockSizeException Loading @@ -185,20 +189,21 @@ public class SyntheticPasswordCrypto { /** * Creates a new SP blob by encrypting the given data. Two encryption layers are applied: an * inner layer using a hash of protectorSecret as the key, and an outer layer using a new * Keystore key with the given alias and optionally bound to a SID. * inner layer using a hash of protectorSecret as the key, and an outer layer using the * protector key, which is a Keystore key that is optionally bound to a SID. This method * creates the protector key and stores it under protectorKeyAlias. * * The reason we use a layer of software encryption, instead of using protectorSecret as the * applicationId of the Keystore key, is to work around buggy KeyMint implementations that don't * cryptographically bind the applicationId to the key. The Keystore layer has to be the outer * layer, so that LSKF verification is ratelimited by Gatekeeper when Weaver is unavailable. */ public static byte[] createBlob(String keyAlias, byte[] data, byte[] protectorSecret, public static byte[] createBlob(String protectorKeyAlias, byte[] data, byte[] protectorSecret, long sid) { try { KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); keyGenerator.init(AES_GCM_KEY_SIZE * 8, new SecureRandom()); SecretKey keyStoreKey = keyGenerator.generateKey(); SecretKey protectorKey = keyGenerator.generateKey(); final KeyStore keyStore = getKeyStore(); KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) Loading @@ -212,9 +217,9 @@ public class SyntheticPasswordCrypto { final KeyProtection protNonRollbackResistant = builder.build(); builder.setRollbackResistant(true); final KeyProtection protRollbackResistant = builder.build(); final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(keyStoreKey); final KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(protectorKey); try { keyStore.setEntry(keyAlias, entry, protRollbackResistant); keyStore.setEntry(protectorKeyAlias, entry, protRollbackResistant); Slog.i(TAG, "Using rollback-resistant key"); } catch (KeyStoreException e) { if (!(e.getCause() instanceof android.security.KeyStoreException)) { Loading @@ -226,11 +231,11 @@ public class SyntheticPasswordCrypto { } Slog.w(TAG, "Rollback-resistant keys unavailable. Falling back to " + "non-rollback-resistant key"); keyStore.setEntry(keyAlias, entry, protNonRollbackResistant); keyStore.setEntry(protectorKeyAlias, entry, protNonRollbackResistant); } byte[] intermediate = encrypt(protectorSecret, PROTECTOR_SECRET_PERSONALIZATION, data); return encrypt(keyStoreKey, intermediate); return encrypt(protectorKey, intermediate); } catch (CertificateException | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException Loading @@ -241,15 +246,15 @@ public class SyntheticPasswordCrypto { } } public static void destroyBlobKey(String keyAlias) { public static void destroyProtectorKey(String keyAlias) { KeyStore keyStore; try { keyStore = getKeyStore(); keyStore.deleteEntry(keyAlias); Slog.i(TAG, "SP key deleted: " + keyAlias); Slog.i(TAG, "Deleted SP protector key " + keyAlias); } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { Slog.e(TAG, "Failed to destroy blob", e); Slog.e(TAG, "Failed to delete SP protector key " + keyAlias, e); } } Loading
services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +24 −16 Original line number Diff line number Diff line Loading @@ -135,6 +135,8 @@ public class SyntheticPasswordManager { private static final byte PROTECTOR_TYPE_STRONG_TOKEN_BASED = 1; private static final byte PROTECTOR_TYPE_WEAK_TOKEN_BASED = 2; private static final String PROTECTOR_KEY_ALIAS_PREFIX = "synthetic_password_"; // The security strength of the synthetic password, in bytes private static final int SYNTHETIC_PASSWORD_SECURITY_STRENGTH = 256 / 8; Loading Loading @@ -583,7 +585,7 @@ public class SyntheticPasswordManager { for (long protectorId : mStorage.listSyntheticPasswordProtectorsForUser(SP_BLOB_NAME, userId)) { destroyWeaverSlot(protectorId, userId); destroySPBlobKey(getKeyName(protectorId)); destroyProtectorKey(getProtectorKeyAlias(protectorId)); } // Remove potential persistent state (in RPMB), to prevent them from accumulating and // causing problems. Loading Loading @@ -999,7 +1001,8 @@ public class SyntheticPasswordManager { } else { spSecret = sp.getSyntheticPassword(); } byte[] content = createSPBlob(getKeyName(protectorId), spSecret, protectorSecret, sid); byte[] content = createSpBlob(getProtectorKeyAlias(protectorId), spSecret, protectorSecret, sid); /* * We can upgrade from v1 to v2 because that's just a change in the way that * the SP is stored. However, we can't upgrade to v3 because that is a change Loading Loading @@ -1210,10 +1213,11 @@ public class SyntheticPasswordManager { } final byte[] spSecret; if (blob.mVersion == SYNTHETIC_PASSWORD_VERSION_V1) { spSecret = SyntheticPasswordCrypto.decryptBlobV1(getKeyName(protectorId), blob.mContent, protectorSecret); spSecret = SyntheticPasswordCrypto.decryptBlobV1(getProtectorKeyAlias(protectorId), blob.mContent, protectorSecret); } else { spSecret = decryptSPBlob(getKeyName(protectorId), blob.mContent, protectorSecret); spSecret = decryptSpBlob(getProtectorKeyAlias(protectorId), blob.mContent, protectorSecret); } if (spSecret == null) { Slog.e(TAG, "Fail to decrypt SP for user " + userId); Loading Loading @@ -1337,7 +1341,7 @@ public class SyntheticPasswordManager { private void destroyProtectorCommon(long protectorId, int userId) { destroyState(SP_BLOB_NAME, protectorId, userId); destroySPBlobKey(getKeyName(protectorId)); destroyProtectorKey(getProtectorKeyAlias(protectorId)); destroyState(SECDISCARDABLE_NAME, protectorId, userId); if (hasState(WEAVER_SLOT_NAME, protectorId, userId)) { destroyWeaverSlot(protectorId, userId); Loading Loading @@ -1422,17 +1426,20 @@ public class SyntheticPasswordManager { mStorage.deleteSyntheticPasswordState(userId, protectorId, stateName); } protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] protectorSecret) { return SyntheticPasswordCrypto.decryptBlob(blobKeyName, blob, protectorSecret); @VisibleForTesting protected byte[] decryptSpBlob(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { return SyntheticPasswordCrypto.decryptBlob(protectorKeyAlias, blob, protectorSecret); } protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] protectorSecret, @VisibleForTesting protected byte[] createSpBlob(String protectorKeyAlias, byte[] data, byte[] protectorSecret, long sid) { return SyntheticPasswordCrypto.createBlob(blobKeyName, data, protectorSecret, sid); return SyntheticPasswordCrypto.createBlob(protectorKeyAlias, data, protectorSecret, sid); } protected void destroySPBlobKey(String keyAlias) { SyntheticPasswordCrypto.destroyBlobKey(keyAlias); @VisibleForTesting protected void destroyProtectorKey(String keyAlias) { SyntheticPasswordCrypto.destroyProtectorKey(keyAlias); } public static long generateProtectorId() { Loading @@ -1457,8 +1464,8 @@ public class SyntheticPasswordManager { } } private String getKeyName(long protectorId) { return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, protectorId); private String getProtectorKeyAlias(long protectorId) { return String.format("%s%x", PROTECTOR_KEY_ALIAS_PREFIX, protectorId); } private byte[] computePasswordToken(LockscreenCredential credential, PasswordData data) { Loading Loading @@ -1511,7 +1518,7 @@ public class SyntheticPasswordManager { } /** * Migrate all existing SP keystore keys from uid 1000 app domain to LSS selinux domain * Migrates all existing SP protector keys from uid 1000 app domain to LSS selinux domain. */ public boolean migrateKeyNamespace() { boolean success = true; Loading @@ -1519,7 +1526,8 @@ public class SyntheticPasswordManager { mStorage.listSyntheticPasswordProtectorsForAllUsers(SP_BLOB_NAME); for (List<Long> userProtectors : allProtectors.values()) { for (long protectorId : userProtectors) { success &= SyntheticPasswordCrypto.migrateLockSettingsKey(getKeyName(protectorId)); success &= SyntheticPasswordCrypto.migrateLockSettingsKey( getProtectorKeyAlias(protectorId)); } } return success; Loading
services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java +9 −7 Original line number Diff line number Diff line Loading @@ -44,12 +44,14 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { mGateKeeper = gatekeeper; } private ArrayMap<String, byte[]> mBlobs = new ArrayMap<>(); private final ArrayMap<String, byte[]> mBlobs = new ArrayMap<>(); @Override protected byte[] decryptSPBlob(String blobKeyName, byte[] blob, byte[] protectorSecret) { if (mBlobs.containsKey(blobKeyName) && !Arrays.equals(mBlobs.get(blobKeyName), blob)) { throw new AssertionFailedError("blobKeyName content is overwritten: " + blobKeyName); protected byte[] decryptSpBlob(String protectorKeyAlias, byte[] blob, byte[] protectorSecret) { if (mBlobs.containsKey(protectorKeyAlias) && !Arrays.equals(mBlobs.get(protectorKeyAlias), blob)) { throw new AssertionFailedError("Blob was overwritten; protectorKeyAlias=" + protectorKeyAlias); } ByteBuffer buffer = ByteBuffer.allocate(blob.length); buffer.put(blob, 0, blob.length); Loading @@ -72,7 +74,7 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { } @Override protected byte[] createSPBlob(String blobKeyName, byte[] data, byte[] protectorSecret, protected byte[] createSpBlob(String protectorKeyAlias, byte[] data, byte[] protectorSecret, long sid) { ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES + data.length + Integer.BYTES + protectorSecret.length + Long.BYTES); Loading @@ -82,12 +84,12 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { buffer.put(protectorSecret); buffer.putLong(sid); byte[] result = buffer.array(); mBlobs.put(blobKeyName, result); mBlobs.put(protectorKeyAlias, result); return result; } @Override protected void destroySPBlobKey(String keyAlias) { protected void destroyProtectorKey(String keyAlias) { } @Override Loading