Loading services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +2 −2 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ public class KeySyncTask implements Runnable { userId, credentialType, credential, () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb, userId)); () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb)); } /** Loading Loading @@ -246,7 +246,7 @@ public class KeySyncTask implements Runnable { throws InsecureUserException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException { PlatformKeyManager platformKeyManager = mPlatformKeyManagerFactory.newInstance(); PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(); PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId); Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys( mUserId, decryptKey.getGenerationId()); return WrappedKey.unwrapKeys(decryptKey, wrappedKeys); Loading services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +68 −54 Original line number Diff line number Diff line Loading @@ -71,7 +71,6 @@ public class PlatformKeyManager { private final Context mContext; private final KeyStoreProxy mKeyStore; private final RecoverableKeyStoreDb mDatabase; private final int mUserId; private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; Loading @@ -80,34 +79,25 @@ public class PlatformKeyManager { * defined by {@code context}. * * @param context This should be the context of the RecoverableKeyStoreLoader service. * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if failed to initialize AndroidKeyStore. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * @throws InsecureUserException if the user does not have a lock screen set. * @throws SecurityException if the caller does not have permission to write to /data/system. * * @hide */ public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database, int userId) throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException { context = context.getApplicationContext(); PlatformKeyManager keyManager = new PlatformKeyManager( userId, context, public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database) throws KeyStoreException, NoSuchAlgorithmException { return new PlatformKeyManager( context.getApplicationContext(), new KeyStoreProxyImpl(getAndLoadAndroidKeyStore()), database); keyManager.init(); return keyManager; } @VisibleForTesting PlatformKeyManager( int userId, Context context, KeyStoreProxy keyStore, RecoverableKeyStoreDb database) { mUserId = userId; mKeyStore = keyStore; mContext = context; mDatabase = database; Loading @@ -118,67 +108,91 @@ public class PlatformKeyManager { * key has to be replaced. (e.g., because the user has removed and then re-added their lock * screen). Returns -1 if no key has been generated yet. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * * @hide */ public int getGenerationId() { return mDatabase.getPlatformKeyGenerationId(mUserId); public int getGenerationId(int userId) { return mDatabase.getPlatformKeyGenerationId(userId); } /** * Returns {@code true} if the platform key is available. A platform key won't be available if * the user has not set up a lock screen. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * * @hide */ public boolean isAvailable() { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(mUserId); public boolean isAvailable(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId); } /** * Generates a new key and increments the generation ID. Should be invoked if the platform key * is corrupted and needs to be rotated. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * @throws KeyStoreException if there is an error in AndroidKeyStore. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ public void regenerate() throws NoSuchAlgorithmException, KeyStoreException { int nextId = getGenerationId() + 1; generateAndLoadKey(nextId); public void regenerate(int userId) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(userId); int nextId; if (generationId == -1) { nextId = 1; } else { nextId = generationId + 1; } generateAndLoadKey(userId, nextId); } /** * Returns the platform key used for encryption. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ public PlatformEncryptionKey getEncryptKey() throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(); public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { init(userId); int generationId = getGenerationId(userId); AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( getEncryptAlias(generationId), /*password=*/ null); getEncryptAlias(userId, generationId), /*password=*/ null); return new PlatformEncryptionKey(generationId, key); } /** * Returns the platform key used for decryption. Only works after a recent screen unlock. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ public PlatformDecryptionKey getDecryptKey() throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(); public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { init(userId); int generationId = getGenerationId(userId); AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( getDecryptAlias(generationId), /*password=*/ null); getDecryptAlias(userId, generationId), /*password=*/ null); return new PlatformDecryptionKey(generationId, key); } Loading @@ -186,38 +200,36 @@ public class PlatformKeyManager { * Initializes the class. If there is no current platform key, and the user has a lock screen * set, will create the platform key and set the generation ID. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if there was an error in AndroidKeyStore. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * * @hide */ public void init() throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException { if (!isAvailable()) { void init(int userId) throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", mUserId)); Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(); if (isKeyLoaded(generationId)) { int generationId = getGenerationId(userId); if (isKeyLoaded(userId, generationId)) { Log.i(TAG, String.format( Locale.US, "Platform key generation %d exists already.", generationId)); return; } if (generationId == -1) { Log.i(TAG, "Generating initial platform ID."); generationId = 1; } else { Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no " + "entry was present in AndroidKeyStore. Generating fresh key.", generationId)); } if (generationId == -1) { generationId = 1; } else { // Had to generate a fresh key, bump the generation id generationId++; } generateAndLoadKey(generationId); generateAndLoadKey(userId, generationId); } /** Loading @@ -227,11 +239,12 @@ public class PlatformKeyManager { * <p>These IDs look as follows: * {@code com.security.recoverablekeystore/platform/<user id>/<generation id>/encrypt} * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @param generationId The generation ID. * @return The alias. */ private String getEncryptAlias(int generationId) { return KEY_ALIAS_PREFIX + mUserId + "/" + generationId + "/" + ENCRYPT_KEY_ALIAS_SUFFIX; private String getEncryptAlias(int userId, int generationId) { return KEY_ALIAS_PREFIX + userId + "/" + generationId + "/" + ENCRYPT_KEY_ALIAS_SUFFIX; } /** Loading @@ -241,18 +254,19 @@ public class PlatformKeyManager { * <p>These IDs look as follows: * {@code com.security.recoverablekeystore/platform/<user id>/<generation id>/decrypt} * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @param generationId The generation ID. * @return The alias. */ private String getDecryptAlias(int generationId) { return KEY_ALIAS_PREFIX + mUserId + "/" + generationId + "/" + DECRYPT_KEY_ALIAS_SUFFIX; private String getDecryptAlias(int userId, int generationId) { return KEY_ALIAS_PREFIX + userId + "/" + generationId + "/" + DECRYPT_KEY_ALIAS_SUFFIX; } /** * Sets the current generation ID to {@code generationId}. */ private void setGenerationId(int generationId) { mDatabase.setPlatformKeyGenerationId(mUserId, generationId); private void setGenerationId(int userId, int generationId) { mDatabase.setPlatformKeyGenerationId(userId, generationId); } /** Loading @@ -261,9 +275,9 @@ public class PlatformKeyManager { * * @throws KeyStoreException if there was an error checking AndroidKeyStore. */ private boolean isKeyLoaded(int generationId) throws KeyStoreException { return mKeyStore.containsAlias(getEncryptAlias(generationId)) && mKeyStore.containsAlias(getDecryptAlias(generationId)); private boolean isKeyLoaded(int userId, int generationId) throws KeyStoreException { return mKeyStore.containsAlias(getEncryptAlias(userId, generationId)) && mKeyStore.containsAlias(getDecryptAlias(userId, generationId)); } /** Loading @@ -274,10 +288,10 @@ public class PlatformKeyManager { * available since API version 1. * @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore. */ private void generateAndLoadKey(int generationId) private void generateAndLoadKey(int userId, int generationId) throws NoSuchAlgorithmException, KeyStoreException { String encryptAlias = getEncryptAlias(generationId); String decryptAlias = getDecryptAlias(generationId); String encryptAlias = getEncryptAlias(userId, generationId); String decryptAlias = getDecryptAlias(userId, generationId); SecretKey secretKey = generateAesKey(); mKeyStore.setEntry( Loading @@ -296,10 +310,10 @@ public class PlatformKeyManager { USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setBoundToSpecificSecureUserId(mUserId) .setBoundToSpecificSecureUserId(userId) .build()); setGenerationId(generationId); setGenerationId(userId, generationId); try { secretKey.destroy(); Loading services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +22 −9 Original line number Diff line number Diff line Loading @@ -85,22 +85,34 @@ public class RecoverableKeyStoreManager { private final RecoverySnapshotListenersStorage mListenersStorage; private final RecoverableKeyGenerator mRecoverableKeyGenerator; private final RecoverySnapshotStorage mSnapshotStorage; private final PlatformKeyManager mPlatformKeyManager; /** * Returns a new or existing instance. * * @hide */ public static synchronized RecoverableKeyStoreManager getInstance(Context mContext) { public static synchronized RecoverableKeyStoreManager getInstance(Context context) { if (mInstance == null) { RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(mContext); RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context); PlatformKeyManager platformKeyManager; try { platformKeyManager = PlatformKeyManager.getInstance(context, db); } catch (NoSuchAlgorithmException e) { // Impossible: all algorithms must be supported by AOSP throw new RuntimeException(e); } catch (KeyStoreException e) { throw new ServiceSpecificException(ERROR_KEYSTORE_INTERNAL_ERROR, e.getMessage()); } mInstance = new RecoverableKeyStoreManager( mContext.getApplicationContext(), context.getApplicationContext(), db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), new RecoverySnapshotStorage(), new RecoverySnapshotListenersStorage()); new RecoverySnapshotListenersStorage(), platformKeyManager); } return mInstance; } Loading @@ -112,13 +124,16 @@ public class RecoverableKeyStoreManager { RecoverySessionStorage recoverySessionStorage, ExecutorService executorService, RecoverySnapshotStorage snapshotStorage, RecoverySnapshotListenersStorage listenersStorage) { RecoverySnapshotListenersStorage listenersStorage, PlatformKeyManager platformKeyManager) { mContext = context; mDatabase = recoverableKeyStoreDb; mRecoverySessionStorage = recoverySessionStorage; mExecutorService = executorService; mListenersStorage = listenersStorage; mSnapshotStorage = snapshotStorage; mPlatformKeyManager = platformKeyManager; try { mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase); } catch (NoSuchAlgorithmException e) { Loading Loading @@ -380,12 +395,10 @@ public class RecoverableKeyStoreManager { int uid = Binder.getCallingUid(); int userId = UserHandle.getCallingUserId(); PlatformEncryptionKey encryptionKey; PlatformEncryptionKey encryptionKey; try { PlatformKeyManager platformKeyManager = PlatformKeyManager.getInstance( mContext, mDatabase, userId); encryptionKey = platformKeyManager.getEncryptKey(); encryptionKey = mPlatformKeyManager.getEncryptKey(userId); } catch (NoSuchAlgorithmException e) { // Impossible: all algorithms must be supported by AOSP throw new RuntimeException(e); Loading services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,7 @@ public class KeySyncTaskTest { mWrappingKey = generateAndroidKeyStoreKey(); mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey); when(mPlatformKeyManager.getDecryptKey()).thenReturn( when(mPlatformKeyManager.getDecryptKey(TEST_USER_ID)).thenReturn( new PlatformDecryptionKey(TEST_GENERATION_ID, mWrappingKey)); } Loading services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +33 −37 Original line number Diff line number Diff line Loading @@ -78,7 +78,7 @@ public class PlatformKeyManagerTest { mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME); mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context); mPlatformKeyManager = new PlatformKeyManager( USER_ID_FIXTURE, mContext, mKeyStoreProxy, mRecoverableKeyStoreDb); mContext, mKeyStoreProxy, mRecoverableKeyStoreDb); when(mContext.getSystemService(anyString())).thenReturn(mKeyguardManager); when(mContext.getSystemServiceName(any())).thenReturn("test"); Loading @@ -93,7 +93,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), Loading @@ -103,14 +103,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithCorrectPurposes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(KeyProperties.PURPOSE_ENCRYPT, getEncryptKeyProtection().getPurposes()); } @Test public void init_createsEncryptKeyWithCorrectPaddings() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.ENCRYPTION_PADDING_NONE }, Loading @@ -119,7 +119,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithCorrectBlockModes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.BLOCK_MODE_GCM }, Loading @@ -128,14 +128,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithoutAuthenticationRequired() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertFalse(getEncryptKeyProtection().isUserAuthenticationRequired()); } @Test public void init_createsDecryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), Loading @@ -145,14 +145,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyWithCorrectPurposes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(KeyProperties.PURPOSE_DECRYPT, getDecryptKeyProtection().getPurposes()); } @Test public void init_createsDecryptKeyWithCorrectPaddings() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.ENCRYPTION_PADDING_NONE }, Loading @@ -161,7 +161,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyWithCorrectBlockModes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.BLOCK_MODE_GCM }, Loading @@ -170,14 +170,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyWithAuthenticationRequired() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertTrue(getDecryptKeyProtection().isUserAuthenticationRequired()); } @Test public void init_createsDecryptKeyWithAuthenticationValidFor15Seconds() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals( USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS, Loading @@ -186,7 +186,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyBoundToTheUsersAuthentication() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals( USER_ID_FIXTURE, Loading @@ -195,7 +195,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsBothKeysWithSameMaterial() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); verify(mKeyStoreProxy, times(2)).setEntry(any(), mEntryArgumentCaptor.capture(), any()); List<KeyStore.Entry> entries = mEntryArgumentCaptor.getAllValues(); Loading @@ -206,7 +206,7 @@ public class PlatformKeyManagerTest { @Test public void init_savesGenerationIdToDatabase() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(1, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(USER_ID_FIXTURE)); Loading @@ -214,23 +214,23 @@ public class PlatformKeyManagerTest { @Test public void init_setsGenerationIdTo1() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(1, mPlatformKeyManager.getGenerationId()); assertEquals(1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void init_incrementsGenerationIdIfKeyIsUnavailable() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(2, mPlatformKeyManager.getGenerationId()); assertEquals(2, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void init_doesNotIncrementGenerationIdIfKeyAvailable() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); Loading @@ -238,21 +238,19 @@ public class PlatformKeyManagerTest { .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(1, mPlatformKeyManager.getGenerationId()); assertEquals(1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void getGenerationId_returnsMinusOneIfNotInitialized() throws Exception { assertEquals(-1, mPlatformKeyManager.getGenerationId()); assertEquals(-1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void getDecryptKey_getsDecryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.getDecryptKey(); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), Loading @@ -261,9 +259,7 @@ public class PlatformKeyManagerTest { @Test public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.getEncryptKey(); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), Loading @@ -272,18 +268,18 @@ public class PlatformKeyManagerTest { @Test public void regenerate_incrementsTheGenerationId() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.regenerate(); mPlatformKeyManager.regenerate(USER_ID_FIXTURE); assertEquals(2, mPlatformKeyManager.getGenerationId()); assertEquals(2, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void regenerate_generatesANewEncryptKeyWithTheCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.regenerate(); mPlatformKeyManager.regenerate(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), Loading @@ -293,9 +289,9 @@ public class PlatformKeyManagerTest { @Test public void regenerate_generatesANewDecryptKeyWithTheCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.regenerate(); mPlatformKeyManager.regenerate(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), Loading Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +2 −2 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ public class KeySyncTask implements Runnable { userId, credentialType, credential, () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb, userId)); () -> PlatformKeyManager.getInstance(context, recoverableKeyStoreDb)); } /** Loading Loading @@ -246,7 +246,7 @@ public class KeySyncTask implements Runnable { throws InsecureUserException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchPaddingException, BadPlatformKeyException { PlatformKeyManager platformKeyManager = mPlatformKeyManagerFactory.newInstance(); PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(); PlatformDecryptionKey decryptKey = platformKeyManager.getDecryptKey(mUserId); Map<String, WrappedKey> wrappedKeys = mRecoverableKeyStoreDb.getAllKeys( mUserId, decryptKey.getGenerationId()); return WrappedKey.unwrapKeys(decryptKey, wrappedKeys); Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/PlatformKeyManager.java +68 −54 Original line number Diff line number Diff line Loading @@ -71,7 +71,6 @@ public class PlatformKeyManager { private final Context mContext; private final KeyStoreProxy mKeyStore; private final RecoverableKeyStoreDb mDatabase; private final int mUserId; private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; Loading @@ -80,34 +79,25 @@ public class PlatformKeyManager { * defined by {@code context}. * * @param context This should be the context of the RecoverableKeyStoreLoader service. * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if failed to initialize AndroidKeyStore. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * @throws InsecureUserException if the user does not have a lock screen set. * @throws SecurityException if the caller does not have permission to write to /data/system. * * @hide */ public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database, int userId) throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException { context = context.getApplicationContext(); PlatformKeyManager keyManager = new PlatformKeyManager( userId, context, public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database) throws KeyStoreException, NoSuchAlgorithmException { return new PlatformKeyManager( context.getApplicationContext(), new KeyStoreProxyImpl(getAndLoadAndroidKeyStore()), database); keyManager.init(); return keyManager; } @VisibleForTesting PlatformKeyManager( int userId, Context context, KeyStoreProxy keyStore, RecoverableKeyStoreDb database) { mUserId = userId; mKeyStore = keyStore; mContext = context; mDatabase = database; Loading @@ -118,67 +108,91 @@ public class PlatformKeyManager { * key has to be replaced. (e.g., because the user has removed and then re-added their lock * screen). Returns -1 if no key has been generated yet. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * * @hide */ public int getGenerationId() { return mDatabase.getPlatformKeyGenerationId(mUserId); public int getGenerationId(int userId) { return mDatabase.getPlatformKeyGenerationId(userId); } /** * Returns {@code true} if the platform key is available. A platform key won't be available if * the user has not set up a lock screen. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * * @hide */ public boolean isAvailable() { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(mUserId); public boolean isAvailable(int userId) { return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId); } /** * Generates a new key and increments the generation ID. Should be invoked if the platform key * is corrupted and needs to be rotated. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * @throws KeyStoreException if there is an error in AndroidKeyStore. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ public void regenerate() throws NoSuchAlgorithmException, KeyStoreException { int nextId = getGenerationId() + 1; generateAndLoadKey(nextId); public void regenerate(int userId) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(userId); int nextId; if (generationId == -1) { nextId = 1; } else { nextId = generationId + 1; } generateAndLoadKey(userId, nextId); } /** * Returns the platform key used for encryption. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ public PlatformEncryptionKey getEncryptKey() throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(); public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { init(userId); int generationId = getGenerationId(userId); AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( getEncryptAlias(generationId), /*password=*/ null); getEncryptAlias(userId, generationId), /*password=*/ null); return new PlatformEncryptionKey(generationId, key); } /** * Returns the platform key used for decryption. Only works after a recent screen unlock. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if there was an AndroidKeyStore error. * @throws UnrecoverableKeyException if the key could not be recovered. * @throws NoSuchAlgorithmException if AES is unavailable - should never occur. * @throws InsecureUserException if the user does not have a lock screen set. * * @hide */ public PlatformDecryptionKey getDecryptKey() throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException { int generationId = getGenerationId(); public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException { init(userId); int generationId = getGenerationId(userId); AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey( getDecryptAlias(generationId), /*password=*/ null); getDecryptAlias(userId, generationId), /*password=*/ null); return new PlatformDecryptionKey(generationId, key); } Loading @@ -186,38 +200,36 @@ public class PlatformKeyManager { * Initializes the class. If there is no current platform key, and the user has a lock screen * set, will create the platform key and set the generation ID. * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @throws KeyStoreException if there was an error in AndroidKeyStore. * @throws NoSuchAlgorithmException if AES is unavailable - should never happen. * * @hide */ public void init() throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException { if (!isAvailable()) { void init(int userId) throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException { if (!isAvailable(userId)) { throw new InsecureUserException(String.format( Locale.US, "%d does not have a lock screen set.", mUserId)); Locale.US, "%d does not have a lock screen set.", userId)); } int generationId = getGenerationId(); if (isKeyLoaded(generationId)) { int generationId = getGenerationId(userId); if (isKeyLoaded(userId, generationId)) { Log.i(TAG, String.format( Locale.US, "Platform key generation %d exists already.", generationId)); return; } if (generationId == -1) { Log.i(TAG, "Generating initial platform ID."); generationId = 1; } else { Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no " + "entry was present in AndroidKeyStore. Generating fresh key.", generationId)); } if (generationId == -1) { generationId = 1; } else { // Had to generate a fresh key, bump the generation id generationId++; } generateAndLoadKey(generationId); generateAndLoadKey(userId, generationId); } /** Loading @@ -227,11 +239,12 @@ public class PlatformKeyManager { * <p>These IDs look as follows: * {@code com.security.recoverablekeystore/platform/<user id>/<generation id>/encrypt} * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @param generationId The generation ID. * @return The alias. */ private String getEncryptAlias(int generationId) { return KEY_ALIAS_PREFIX + mUserId + "/" + generationId + "/" + ENCRYPT_KEY_ALIAS_SUFFIX; private String getEncryptAlias(int userId, int generationId) { return KEY_ALIAS_PREFIX + userId + "/" + generationId + "/" + ENCRYPT_KEY_ALIAS_SUFFIX; } /** Loading @@ -241,18 +254,19 @@ public class PlatformKeyManager { * <p>These IDs look as follows: * {@code com.security.recoverablekeystore/platform/<user id>/<generation id>/decrypt} * * @param userId The ID of the user to whose lock screen the platform key must be bound. * @param generationId The generation ID. * @return The alias. */ private String getDecryptAlias(int generationId) { return KEY_ALIAS_PREFIX + mUserId + "/" + generationId + "/" + DECRYPT_KEY_ALIAS_SUFFIX; private String getDecryptAlias(int userId, int generationId) { return KEY_ALIAS_PREFIX + userId + "/" + generationId + "/" + DECRYPT_KEY_ALIAS_SUFFIX; } /** * Sets the current generation ID to {@code generationId}. */ private void setGenerationId(int generationId) { mDatabase.setPlatformKeyGenerationId(mUserId, generationId); private void setGenerationId(int userId, int generationId) { mDatabase.setPlatformKeyGenerationId(userId, generationId); } /** Loading @@ -261,9 +275,9 @@ public class PlatformKeyManager { * * @throws KeyStoreException if there was an error checking AndroidKeyStore. */ private boolean isKeyLoaded(int generationId) throws KeyStoreException { return mKeyStore.containsAlias(getEncryptAlias(generationId)) && mKeyStore.containsAlias(getDecryptAlias(generationId)); private boolean isKeyLoaded(int userId, int generationId) throws KeyStoreException { return mKeyStore.containsAlias(getEncryptAlias(userId, generationId)) && mKeyStore.containsAlias(getDecryptAlias(userId, generationId)); } /** Loading @@ -274,10 +288,10 @@ public class PlatformKeyManager { * available since API version 1. * @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore. */ private void generateAndLoadKey(int generationId) private void generateAndLoadKey(int userId, int generationId) throws NoSuchAlgorithmException, KeyStoreException { String encryptAlias = getEncryptAlias(generationId); String decryptAlias = getDecryptAlias(generationId); String encryptAlias = getEncryptAlias(userId, generationId); String decryptAlias = getDecryptAlias(userId, generationId); SecretKey secretKey = generateAesKey(); mKeyStore.setEntry( Loading @@ -296,10 +310,10 @@ public class PlatformKeyManager { USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setBoundToSpecificSecureUserId(mUserId) .setBoundToSpecificSecureUserId(userId) .build()); setGenerationId(generationId); setGenerationId(userId, generationId); try { secretKey.destroy(); Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +22 −9 Original line number Diff line number Diff line Loading @@ -85,22 +85,34 @@ public class RecoverableKeyStoreManager { private final RecoverySnapshotListenersStorage mListenersStorage; private final RecoverableKeyGenerator mRecoverableKeyGenerator; private final RecoverySnapshotStorage mSnapshotStorage; private final PlatformKeyManager mPlatformKeyManager; /** * Returns a new or existing instance. * * @hide */ public static synchronized RecoverableKeyStoreManager getInstance(Context mContext) { public static synchronized RecoverableKeyStoreManager getInstance(Context context) { if (mInstance == null) { RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(mContext); RecoverableKeyStoreDb db = RecoverableKeyStoreDb.newInstance(context); PlatformKeyManager platformKeyManager; try { platformKeyManager = PlatformKeyManager.getInstance(context, db); } catch (NoSuchAlgorithmException e) { // Impossible: all algorithms must be supported by AOSP throw new RuntimeException(e); } catch (KeyStoreException e) { throw new ServiceSpecificException(ERROR_KEYSTORE_INTERNAL_ERROR, e.getMessage()); } mInstance = new RecoverableKeyStoreManager( mContext.getApplicationContext(), context.getApplicationContext(), db, new RecoverySessionStorage(), Executors.newSingleThreadExecutor(), new RecoverySnapshotStorage(), new RecoverySnapshotListenersStorage()); new RecoverySnapshotListenersStorage(), platformKeyManager); } return mInstance; } Loading @@ -112,13 +124,16 @@ public class RecoverableKeyStoreManager { RecoverySessionStorage recoverySessionStorage, ExecutorService executorService, RecoverySnapshotStorage snapshotStorage, RecoverySnapshotListenersStorage listenersStorage) { RecoverySnapshotListenersStorage listenersStorage, PlatformKeyManager platformKeyManager) { mContext = context; mDatabase = recoverableKeyStoreDb; mRecoverySessionStorage = recoverySessionStorage; mExecutorService = executorService; mListenersStorage = listenersStorage; mSnapshotStorage = snapshotStorage; mPlatformKeyManager = platformKeyManager; try { mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mDatabase); } catch (NoSuchAlgorithmException e) { Loading Loading @@ -380,12 +395,10 @@ public class RecoverableKeyStoreManager { int uid = Binder.getCallingUid(); int userId = UserHandle.getCallingUserId(); PlatformEncryptionKey encryptionKey; PlatformEncryptionKey encryptionKey; try { PlatformKeyManager platformKeyManager = PlatformKeyManager.getInstance( mContext, mDatabase, userId); encryptionKey = platformKeyManager.getEncryptKey(); encryptionKey = mPlatformKeyManager.getEncryptKey(userId); } catch (NoSuchAlgorithmException e) { // Impossible: all algorithms must be supported by AOSP throw new RuntimeException(e); Loading
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -114,7 +114,7 @@ public class KeySyncTaskTest { mWrappingKey = generateAndroidKeyStoreKey(); mEncryptKey = new PlatformEncryptionKey(TEST_GENERATION_ID, mWrappingKey); when(mPlatformKeyManager.getDecryptKey()).thenReturn( when(mPlatformKeyManager.getDecryptKey(TEST_USER_ID)).thenReturn( new PlatformDecryptionKey(TEST_GENERATION_ID, mWrappingKey)); } Loading
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/PlatformKeyManagerTest.java +33 −37 Original line number Diff line number Diff line Loading @@ -78,7 +78,7 @@ public class PlatformKeyManagerTest { mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME); mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context); mPlatformKeyManager = new PlatformKeyManager( USER_ID_FIXTURE, mContext, mKeyStoreProxy, mRecoverableKeyStoreDb); mContext, mKeyStoreProxy, mRecoverableKeyStoreDb); when(mContext.getSystemService(anyString())).thenReturn(mKeyguardManager); when(mContext.getSystemServiceName(any())).thenReturn("test"); Loading @@ -93,7 +93,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), Loading @@ -103,14 +103,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithCorrectPurposes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(KeyProperties.PURPOSE_ENCRYPT, getEncryptKeyProtection().getPurposes()); } @Test public void init_createsEncryptKeyWithCorrectPaddings() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.ENCRYPTION_PADDING_NONE }, Loading @@ -119,7 +119,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithCorrectBlockModes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.BLOCK_MODE_GCM }, Loading @@ -128,14 +128,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsEncryptKeyWithoutAuthenticationRequired() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertFalse(getEncryptKeyProtection().isUserAuthenticationRequired()); } @Test public void init_createsDecryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), Loading @@ -145,14 +145,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyWithCorrectPurposes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(KeyProperties.PURPOSE_DECRYPT, getDecryptKeyProtection().getPurposes()); } @Test public void init_createsDecryptKeyWithCorrectPaddings() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.ENCRYPTION_PADDING_NONE }, Loading @@ -161,7 +161,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyWithCorrectBlockModes() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertArrayEquals( new String[] { KeyProperties.BLOCK_MODE_GCM }, Loading @@ -170,14 +170,14 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyWithAuthenticationRequired() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertTrue(getDecryptKeyProtection().isUserAuthenticationRequired()); } @Test public void init_createsDecryptKeyWithAuthenticationValidFor15Seconds() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals( USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS, Loading @@ -186,7 +186,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsDecryptKeyBoundToTheUsersAuthentication() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals( USER_ID_FIXTURE, Loading @@ -195,7 +195,7 @@ public class PlatformKeyManagerTest { @Test public void init_createsBothKeysWithSameMaterial() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); verify(mKeyStoreProxy, times(2)).setEntry(any(), mEntryArgumentCaptor.capture(), any()); List<KeyStore.Entry> entries = mEntryArgumentCaptor.getAllValues(); Loading @@ -206,7 +206,7 @@ public class PlatformKeyManagerTest { @Test public void init_savesGenerationIdToDatabase() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(1, mRecoverableKeyStoreDb.getPlatformKeyGenerationId(USER_ID_FIXTURE)); Loading @@ -214,23 +214,23 @@ public class PlatformKeyManagerTest { @Test public void init_setsGenerationIdTo1() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(1, mPlatformKeyManager.getGenerationId()); assertEquals(1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void init_incrementsGenerationIdIfKeyIsUnavailable() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(2, mPlatformKeyManager.getGenerationId()); assertEquals(2, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void init_doesNotIncrementGenerationIdIfKeyAvailable() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); when(mKeyStoreProxy .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/decrypt")).thenReturn(true); Loading @@ -238,21 +238,19 @@ public class PlatformKeyManagerTest { .containsAlias("com.android.server.locksettings.recoverablekeystore/" + "platform/42/1/encrypt")).thenReturn(true); mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); assertEquals(1, mPlatformKeyManager.getGenerationId()); assertEquals(1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void getGenerationId_returnsMinusOneIfNotInitialized() throws Exception { assertEquals(-1, mPlatformKeyManager.getGenerationId()); assertEquals(-1, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void getDecryptKey_getsDecryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.getDecryptKey(); mPlatformKeyManager.getDecryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/decrypt"), Loading @@ -261,9 +259,7 @@ public class PlatformKeyManagerTest { @Test public void getEncryptKey_getsDecryptKeyWithCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.getEncryptKey(); mPlatformKeyManager.getEncryptKey(USER_ID_FIXTURE); verify(mKeyStoreProxy).getKey( eq("com.android.server.locksettings.recoverablekeystore/platform/42/1/encrypt"), Loading @@ -272,18 +268,18 @@ public class PlatformKeyManagerTest { @Test public void regenerate_incrementsTheGenerationId() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.regenerate(); mPlatformKeyManager.regenerate(USER_ID_FIXTURE); assertEquals(2, mPlatformKeyManager.getGenerationId()); assertEquals(2, mPlatformKeyManager.getGenerationId(USER_ID_FIXTURE)); } @Test public void regenerate_generatesANewEncryptKeyWithTheCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.regenerate(); mPlatformKeyManager.regenerate(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/encrypt"), Loading @@ -293,9 +289,9 @@ public class PlatformKeyManagerTest { @Test public void regenerate_generatesANewDecryptKeyWithTheCorrectAlias() throws Exception { mPlatformKeyManager.init(); mPlatformKeyManager.init(USER_ID_FIXTURE); mPlatformKeyManager.regenerate(); mPlatformKeyManager.regenerate(USER_ID_FIXTURE); verify(mKeyStoreProxy).setEntry( eq("com.android.server.locksettings.recoverablekeystore/platform/42/2/decrypt"), Loading