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

Commit 9ae8ef94 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Continue to decrypt other application keys if one fails to decrypt"

parents d1fac203 4857cb50
Loading
Loading
Loading
Loading
+13 −10
Original line number Original line Diff line number Diff line
@@ -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(),
@@ -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);
@@ -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);
@@ -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;
    }
    }


+42 −3
Original line number Original line Diff line number Diff line
@@ -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");
@@ -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,
@@ -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(
@@ -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");
        }
        }
    }
    }


@@ -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();