Loading services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +13 −10 Original line number Original line Diff line number Diff line Loading @@ -519,11 +519,11 @@ public class RecoverableKeyStoreManager { byte[] locallyEncryptedKey; byte[] locallyEncryptedKey; try { try { // TODO: Remove the extraneous logging here // TODO: Remove the extraneous logging here Log.e(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()", Log.d(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()", sessionEntry.getKeyClaimant())); sessionEntry.getKeyClaimant())); Log.e(TAG, constructLoggingMessage("sessionEntry.getVaultParams()", Log.d(TAG, constructLoggingMessage("sessionEntry.getVaultParams()", sessionEntry.getVaultParams())); sessionEntry.getVaultParams())); Log.e(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse)); Log.d(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse)); locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse( locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse( sessionEntry.getKeyClaimant(), sessionEntry.getKeyClaimant(), sessionEntry.getVaultParams(), sessionEntry.getVaultParams(), Loading @@ -543,9 +543,9 @@ public class RecoverableKeyStoreManager { try { try { // TODO: Remove the extraneous logging here // TODO: Remove the extraneous logging here Log.e(TAG, constructLoggingMessage("sessionEntry.getLskfHash()", Log.d(TAG, constructLoggingMessage("sessionEntry.getLskfHash()", sessionEntry.getLskfHash())); sessionEntry.getLskfHash())); Log.e(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey)); Log.d(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey)); return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey); return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey); } catch (InvalidKeyException e) { } catch (InvalidKeyException e) { Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e); Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e); Loading Loading @@ -585,8 +585,8 @@ public class RecoverableKeyStoreManager { try { try { // TODO: Remove the extraneous logging here // TODO: Remove the extraneous logging here Log.e(TAG, constructLoggingMessage("recoveryKey", recoveryKey)); Log.d(TAG, constructLoggingMessage("recoveryKey", recoveryKey)); Log.e(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial)); Log.d(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial)); byte[] keyMaterial = byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial); KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial); keyMaterialByAlias.put(alias, keyMaterial); keyMaterialByAlias.put(alias, keyMaterial); Loading @@ -600,13 +600,16 @@ public class RecoverableKeyStoreManager { throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, "Failed to recover key with alias '" + alias + "': " + e.getMessage()); "Failed to recover key with alias '" + alias + "': " + e.getMessage()); } catch (AEADBadTagException e) { } catch (AEADBadTagException e) { // TODO: Remove the extraneous logging here Log.e(TAG, "Got AEADBadTagException during decrypting application key with alias: " Log.e(TAG, "Got AEADBadTagException during decrypting application key with alias: " + alias, e); + alias, e); throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, // Ignore the exception to continue to recover the other application keys. "Failed to recover key with alias '" + alias + "': " + e.getMessage()); } } } } if (keyMaterialByAlias.isEmpty()) { Log.e(TAG, "Failed to recover any of the application keys."); throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, "Failed to recover any of the application keys."); } return keyMaterialByAlias; return keyMaterialByAlias; } } Loading services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +42 −3 Original line number Original line Diff line number Diff line Loading @@ -125,6 +125,7 @@ public class RecoverableKeyStoreManagerTest { private static final byte[] RECOVERY_RESPONSE_HEADER = private static final byte[] RECOVERY_RESPONSE_HEADER = "V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8); "V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8); private static final String TEST_ALIAS = "nick"; private static final String TEST_ALIAS = "nick"; private static final String TEST_ALIAS2 = "bob"; private static final int RECOVERABLE_KEY_SIZE_BYTES = 32; private static final int RECOVERABLE_KEY_SIZE_BYTES = 32; private static final int GENERATION_ID = 1; private static final int GENERATION_ID = 1; private static final byte[] NONCE = getUtf8Bytes("nonce"); private static final byte[] NONCE = getUtf8Bytes("nonce"); Loading Loading @@ -424,7 +425,7 @@ public class RecoverableKeyStoreManagerTest { } } @Test @Test public void recoverKeys_throwsIfFailedToDecryptAnApplicationKey() throws Exception { public void recoverKeys_throwsIfFailedToDecryptAllApplicationKeys() throws Exception { mRecoverableKeyStoreManager.startRecoverySession( mRecoverableKeyStoreManager.startRecoverySession( TEST_SESSION_ID, TEST_SESSION_ID, TEST_PUBLIC_KEY, TEST_PUBLIC_KEY, Loading @@ -442,7 +443,7 @@ public class RecoverableKeyStoreManagerTest { keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey); keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey); WrappedApplicationKey badApplicationKey = new WrappedApplicationKey( WrappedApplicationKey badApplicationKey = new WrappedApplicationKey( TEST_ALIAS, TEST_ALIAS, randomBytes(32)); encryptedApplicationKey(randomRecoveryKey(), randomBytes(32))); try { try { mRecoverableKeyStoreManager.recoverKeys( mRecoverableKeyStoreManager.recoverKeys( Loading @@ -451,7 +452,7 @@ public class RecoverableKeyStoreManagerTest { /*applicationKeys=*/ ImmutableList.of(badApplicationKey)); /*applicationKeys=*/ ImmutableList.of(badApplicationKey)); fail("should have thrown"); fail("should have thrown"); } catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) { assertThat(e.getMessage()).startsWith("Failed to recover key with alias 'nick'"); assertThat(e.getMessage()).startsWith("Failed to recover any of the application keys"); } } } } Loading Loading @@ -486,6 +487,44 @@ public class RecoverableKeyStoreManagerTest { assertThat(recoveredKeys.get(TEST_ALIAS)).isEqualTo(applicationKeyBytes); assertThat(recoveredKeys.get(TEST_ALIAS)).isEqualTo(applicationKeyBytes); } } @Test public void recoverKeys_worksOnOtherApplicationKeysIfOneDecryptionFails() throws Exception { mRecoverableKeyStoreManager.startRecoverySession( TEST_SESSION_ID, TEST_PUBLIC_KEY, TEST_VAULT_PARAMS, TEST_VAULT_CHALLENGE, ImmutableList.of(new KeyChainProtectionParams( TYPE_LOCKSCREEN, UI_FORMAT_PASSWORD, KeyDerivationParams.createSha256Params(TEST_SALT), TEST_SECRET))); byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID) .getKeyClaimant(); SecretKey recoveryKey = randomRecoveryKey(); byte[] encryptedClaimResponse = encryptClaimResponse( keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey); byte[] applicationKeyBytes1 = randomBytes(32); byte[] applicationKeyBytes2 = randomBytes(32); WrappedApplicationKey applicationKey1 = new WrappedApplicationKey( TEST_ALIAS, // Use a different recovery key here, so the decryption will fail encryptedApplicationKey(randomRecoveryKey(), applicationKeyBytes1)); WrappedApplicationKey applicationKey2 = new WrappedApplicationKey( TEST_ALIAS2, encryptedApplicationKey(recoveryKey, applicationKeyBytes2)); Map<String, byte[]> recoveredKeys = mRecoverableKeyStoreManager.recoverKeys( TEST_SESSION_ID, encryptedClaimResponse, ImmutableList.of(applicationKey1, applicationKey2)); assertThat(recoveredKeys).hasSize(1); assertThat(recoveredKeys.get(TEST_ALIAS2)).isEqualTo(applicationKeyBytes2); } @Test @Test public void setSnapshotCreatedPendingIntent() throws Exception { public void setSnapshotCreatedPendingIntent() throws Exception { int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid(); Loading Loading
services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +13 −10 Original line number Original line Diff line number Diff line Loading @@ -519,11 +519,11 @@ public class RecoverableKeyStoreManager { byte[] locallyEncryptedKey; byte[] locallyEncryptedKey; try { try { // TODO: Remove the extraneous logging here // TODO: Remove the extraneous logging here Log.e(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()", Log.d(TAG, constructLoggingMessage("sessionEntry.getKeyClaimant()", sessionEntry.getKeyClaimant())); sessionEntry.getKeyClaimant())); Log.e(TAG, constructLoggingMessage("sessionEntry.getVaultParams()", Log.d(TAG, constructLoggingMessage("sessionEntry.getVaultParams()", sessionEntry.getVaultParams())); sessionEntry.getVaultParams())); Log.e(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse)); Log.d(TAG, constructLoggingMessage("encryptedClaimResponse", encryptedClaimResponse)); locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse( locallyEncryptedKey = KeySyncUtils.decryptRecoveryClaimResponse( sessionEntry.getKeyClaimant(), sessionEntry.getKeyClaimant(), sessionEntry.getVaultParams(), sessionEntry.getVaultParams(), Loading @@ -543,9 +543,9 @@ public class RecoverableKeyStoreManager { try { try { // TODO: Remove the extraneous logging here // TODO: Remove the extraneous logging here Log.e(TAG, constructLoggingMessage("sessionEntry.getLskfHash()", Log.d(TAG, constructLoggingMessage("sessionEntry.getLskfHash()", sessionEntry.getLskfHash())); sessionEntry.getLskfHash())); Log.e(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey)); Log.d(TAG, constructLoggingMessage("locallyEncryptedKey", locallyEncryptedKey)); return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey); return KeySyncUtils.decryptRecoveryKey(sessionEntry.getLskfHash(), locallyEncryptedKey); } catch (InvalidKeyException e) { } catch (InvalidKeyException e) { Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e); Log.e(TAG, "Got InvalidKeyException during decrypting recovery key", e); Loading Loading @@ -585,8 +585,8 @@ public class RecoverableKeyStoreManager { try { try { // TODO: Remove the extraneous logging here // TODO: Remove the extraneous logging here Log.e(TAG, constructLoggingMessage("recoveryKey", recoveryKey)); Log.d(TAG, constructLoggingMessage("recoveryKey", recoveryKey)); Log.e(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial)); Log.d(TAG, constructLoggingMessage("encryptedKeyMaterial", encryptedKeyMaterial)); byte[] keyMaterial = byte[] keyMaterial = KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial); KeySyncUtils.decryptApplicationKey(recoveryKey, encryptedKeyMaterial); keyMaterialByAlias.put(alias, keyMaterial); keyMaterialByAlias.put(alias, keyMaterial); Loading @@ -600,13 +600,16 @@ public class RecoverableKeyStoreManager { throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, "Failed to recover key with alias '" + alias + "': " + e.getMessage()); "Failed to recover key with alias '" + alias + "': " + e.getMessage()); } catch (AEADBadTagException e) { } catch (AEADBadTagException e) { // TODO: Remove the extraneous logging here Log.e(TAG, "Got AEADBadTagException during decrypting application key with alias: " Log.e(TAG, "Got AEADBadTagException during decrypting application key with alias: " + alias, e); + alias, e); throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, // Ignore the exception to continue to recover the other application keys. "Failed to recover key with alias '" + alias + "': " + e.getMessage()); } } } } if (keyMaterialByAlias.isEmpty()) { Log.e(TAG, "Failed to recover any of the application keys."); throw new ServiceSpecificException(ERROR_DECRYPTION_FAILED, "Failed to recover any of the application keys."); } return keyMaterialByAlias; return keyMaterialByAlias; } } Loading
services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +42 −3 Original line number Original line Diff line number Diff line Loading @@ -125,6 +125,7 @@ public class RecoverableKeyStoreManagerTest { private static final byte[] RECOVERY_RESPONSE_HEADER = private static final byte[] RECOVERY_RESPONSE_HEADER = "V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8); "V1 reencrypted_recovery_key".getBytes(StandardCharsets.UTF_8); private static final String TEST_ALIAS = "nick"; private static final String TEST_ALIAS = "nick"; private static final String TEST_ALIAS2 = "bob"; private static final int RECOVERABLE_KEY_SIZE_BYTES = 32; private static final int RECOVERABLE_KEY_SIZE_BYTES = 32; private static final int GENERATION_ID = 1; private static final int GENERATION_ID = 1; private static final byte[] NONCE = getUtf8Bytes("nonce"); private static final byte[] NONCE = getUtf8Bytes("nonce"); Loading Loading @@ -424,7 +425,7 @@ public class RecoverableKeyStoreManagerTest { } } @Test @Test public void recoverKeys_throwsIfFailedToDecryptAnApplicationKey() throws Exception { public void recoverKeys_throwsIfFailedToDecryptAllApplicationKeys() throws Exception { mRecoverableKeyStoreManager.startRecoverySession( mRecoverableKeyStoreManager.startRecoverySession( TEST_SESSION_ID, TEST_SESSION_ID, TEST_PUBLIC_KEY, TEST_PUBLIC_KEY, Loading @@ -442,7 +443,7 @@ public class RecoverableKeyStoreManagerTest { keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey); keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey); WrappedApplicationKey badApplicationKey = new WrappedApplicationKey( WrappedApplicationKey badApplicationKey = new WrappedApplicationKey( TEST_ALIAS, TEST_ALIAS, randomBytes(32)); encryptedApplicationKey(randomRecoveryKey(), randomBytes(32))); try { try { mRecoverableKeyStoreManager.recoverKeys( mRecoverableKeyStoreManager.recoverKeys( Loading @@ -451,7 +452,7 @@ public class RecoverableKeyStoreManagerTest { /*applicationKeys=*/ ImmutableList.of(badApplicationKey)); /*applicationKeys=*/ ImmutableList.of(badApplicationKey)); fail("should have thrown"); fail("should have thrown"); } catch (ServiceSpecificException e) { } catch (ServiceSpecificException e) { assertThat(e.getMessage()).startsWith("Failed to recover key with alias 'nick'"); assertThat(e.getMessage()).startsWith("Failed to recover any of the application keys"); } } } } Loading Loading @@ -486,6 +487,44 @@ public class RecoverableKeyStoreManagerTest { assertThat(recoveredKeys.get(TEST_ALIAS)).isEqualTo(applicationKeyBytes); assertThat(recoveredKeys.get(TEST_ALIAS)).isEqualTo(applicationKeyBytes); } } @Test public void recoverKeys_worksOnOtherApplicationKeysIfOneDecryptionFails() throws Exception { mRecoverableKeyStoreManager.startRecoverySession( TEST_SESSION_ID, TEST_PUBLIC_KEY, TEST_VAULT_PARAMS, TEST_VAULT_CHALLENGE, ImmutableList.of(new KeyChainProtectionParams( TYPE_LOCKSCREEN, UI_FORMAT_PASSWORD, KeyDerivationParams.createSha256Params(TEST_SALT), TEST_SECRET))); byte[] keyClaimant = mRecoverySessionStorage.get(Binder.getCallingUid(), TEST_SESSION_ID) .getKeyClaimant(); SecretKey recoveryKey = randomRecoveryKey(); byte[] encryptedClaimResponse = encryptClaimResponse( keyClaimant, TEST_SECRET, TEST_VAULT_PARAMS, recoveryKey); byte[] applicationKeyBytes1 = randomBytes(32); byte[] applicationKeyBytes2 = randomBytes(32); WrappedApplicationKey applicationKey1 = new WrappedApplicationKey( TEST_ALIAS, // Use a different recovery key here, so the decryption will fail encryptedApplicationKey(randomRecoveryKey(), applicationKeyBytes1)); WrappedApplicationKey applicationKey2 = new WrappedApplicationKey( TEST_ALIAS2, encryptedApplicationKey(recoveryKey, applicationKeyBytes2)); Map<String, byte[]> recoveredKeys = mRecoverableKeyStoreManager.recoverKeys( TEST_SESSION_ID, encryptedClaimResponse, ImmutableList.of(applicationKey1, applicationKey2)); assertThat(recoveredKeys).hasSize(1); assertThat(recoveredKeys.get(TEST_ALIAS2)).isEqualTo(applicationKeyBytes2); } @Test @Test public void setSnapshotCreatedPendingIntent() throws Exception { public void setSnapshotCreatedPendingIntent() throws Exception { int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid(); Loading