1a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry/*
2a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * Copyright (C) 2017 The Android Open Source Project
3a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
4a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * Licensed under the Apache License, Version 2.0 (the "License");
5a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * you may not use this file except in compliance with the License.
6a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * You may obtain a copy of the License at
7a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
8a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *      http://www.apache.org/licenses/LICENSE-2.0
9a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
10a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * Unless required by applicable law or agreed to in writing, software
11a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * distributed under the License is distributed on an "AS IS" BASIS,
12a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * See the License for the specific language governing permissions and
14a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * limitations under the License.
15a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry */
16a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
17a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berrypackage com.android.server.locksettings.recoverablekeystore;
18a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
19a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport android.app.KeyguardManager;
20a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport android.content.Context;
21a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport android.security.keystore.AndroidKeyStoreSecretKey;
22a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport android.security.keystore.KeyProperties;
23a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport android.security.keystore.KeyProtection;
24a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport android.util.Log;
25a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
26a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport com.android.internal.annotations.VisibleForTesting;
276c1ee5243772d307606aff0e00d5b77455a8212bRobert Berryimport com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb;
28a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
29a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.io.IOException;
30a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.security.KeyStore;
31a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.security.KeyStoreException;
32a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.security.NoSuchAlgorithmException;
33a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.security.UnrecoverableKeyException;
34a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.security.cert.CertificateException;
35a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport java.util.Locale;
36a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
37a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport javax.crypto.KeyGenerator;
38a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport javax.crypto.SecretKey;
39a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berryimport javax.security.auth.DestroyFailedException;
40a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
41a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry/**
42a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * Manages creating and checking the validity of the platform key.
43a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
44a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * <p>The platform key is used to wrap the material of recoverable keys before persisting them to
45a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * disk. It is also used to decrypt the same keys on a screen unlock, before re-wrapping them with
46a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * a recovery key and syncing them with remote storage.
47a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
48a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * <p>Each platform key has two entries in AndroidKeyStore:
49a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
50a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * <ul>
51a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *     <li>Encrypt entry - this entry enables the root user to at any time encrypt.
52a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *     <li>Decrypt entry - this entry enables the root user to decrypt only after recent user
53a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *       authentication, i.e., within 15 seconds after a screen unlock.
54a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * </ul>
55a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
56a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * <p>Both entries are enabled only for AES/GCM/NoPadding Cipher algorithm.
57a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry *
58a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry * @hide
59a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry */
60a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berrypublic class PlatformKeyManager {
61a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final String TAG = "PlatformKeyManager";
62a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
63a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final String KEY_ALGORITHM = "AES";
64a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final int KEY_SIZE_BITS = 256;
65a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final String KEY_ALIAS_PREFIX =
66a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            "com.android.server.locksettings.recoverablekeystore/platform/";
67a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final String ENCRYPT_KEY_ALIAS_SUFFIX = "encrypt";
68a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final String DECRYPT_KEY_ALIAS_SUFFIX = "decrypt";
69a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final int USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS = 15;
70a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
71a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private final Context mContext;
72a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private final KeyStoreProxy mKeyStore;
736c1ee5243772d307606aff0e00d5b77455a8212bRobert Berry    private final RecoverableKeyStoreDb mDatabase;
74a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
75a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore";
76a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
77a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
78a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * A new instance operating on behalf of {@code userId}, storing its prefs in the location
79a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * defined by {@code context}.
80a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
81a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @param context This should be the context of the RecoverableKeyStoreLoader service.
82a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if failed to initialize AndroidKeyStore.
83a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
84a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws SecurityException if the caller does not have permission to write to /data/system.
85a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
86a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
87a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
883462c832d1acccca3cdd541dea86442eb81536abBo Zhu    public static PlatformKeyManager getInstance(Context context, RecoverableKeyStoreDb database)
893462c832d1acccca3cdd541dea86442eb81536abBo Zhu            throws KeyStoreException, NoSuchAlgorithmException {
903462c832d1acccca3cdd541dea86442eb81536abBo Zhu        return new PlatformKeyManager(
913462c832d1acccca3cdd541dea86442eb81536abBo Zhu                context.getApplicationContext(),
92a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                new KeyStoreProxyImpl(getAndLoadAndroidKeyStore()),
936c1ee5243772d307606aff0e00d5b77455a8212bRobert Berry                database);
94a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
95a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
96a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    @VisibleForTesting
97a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    PlatformKeyManager(
98a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            Context context,
99a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            KeyStoreProxy keyStore,
1006c1ee5243772d307606aff0e00d5b77455a8212bRobert Berry            RecoverableKeyStoreDb database) {
101a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        mKeyStore = keyStore;
102a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        mContext = context;
1036c1ee5243772d307606aff0e00d5b77455a8212bRobert Berry        mDatabase = database;
104a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
105a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
106a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
107a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns the current generation ID of the platform key. This increments whenever a platform
108a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * key has to be replaced. (e.g., because the user has removed and then re-added their lock
109b811553c4c6661599fa30910a49b8b54279e12beRobert Berry     * screen). Returns -1 if no key has been generated yet.
110a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
1113462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
1123462c832d1acccca3cdd541dea86442eb81536abBo Zhu     *
113a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
114a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
1153462c832d1acccca3cdd541dea86442eb81536abBo Zhu    public int getGenerationId(int userId) {
1163462c832d1acccca3cdd541dea86442eb81536abBo Zhu        return mDatabase.getPlatformKeyGenerationId(userId);
117a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
118a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
119a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
120a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns {@code true} if the platform key is available. A platform key won't be available if
121a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * the user has not set up a lock screen.
122a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
1233462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
1243462c832d1acccca3cdd541dea86442eb81536abBo Zhu     *
125a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
126a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
1273462c832d1acccca3cdd541dea86442eb81536abBo Zhu    public boolean isAvailable(int userId) {
1283462c832d1acccca3cdd541dea86442eb81536abBo Zhu        return mContext.getSystemService(KeyguardManager.class).isDeviceSecure(userId);
129a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
130a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
131a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
1326e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     * Removes the platform key from Android KeyStore.
1336e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     * It is triggered when user disables lock screen.
1346e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     *
1356e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     * @param userId The ID of the user to whose lock screen the platform key must be bound.
1366e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     * @param generationId Generation id.
1376e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     *
1386e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     * @hide
1396e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev     */
1406e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev    public void invalidatePlatformKey(int userId, int generationId) {
1416e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev        if (generationId != -1) {
1426e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev            try {
1436e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev                mKeyStore.deleteEntry(getEncryptAlias(userId, generationId));
1446e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev                mKeyStore.deleteEntry(getDecryptAlias(userId, generationId));
1456e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev            } catch (KeyStoreException e) {
1466e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev                // Ignore failed attempt to delete key.
1476e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev            }
1486e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev        }
1496e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev    }
1506e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev
1516e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev    /**
152a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Generates a new key and increments the generation ID. Should be invoked if the platform key
153a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * is corrupted and needs to be rotated.
1543f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * Updates status of old keys to {@code RecoveryController.RECOVERY_STATUS_PERMANENT_FAILURE}.
155a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
1563462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
157a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
158a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there is an error in AndroidKeyStore.
1593462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @throws InsecureUserException if the user does not have a lock screen set.
16020eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev     * @throws IOException if there was an issue with local database update.
161a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
162a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
163a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
16420eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev    @VisibleForTesting
16520eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev    void regenerate(int userId)
16620eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev            throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException, IOException {
1673462c832d1acccca3cdd541dea86442eb81536abBo Zhu        if (!isAvailable(userId)) {
1683462c832d1acccca3cdd541dea86442eb81536abBo Zhu            throw new InsecureUserException(String.format(
1693462c832d1acccca3cdd541dea86442eb81536abBo Zhu                    Locale.US, "%d does not have a lock screen set.", userId));
1703462c832d1acccca3cdd541dea86442eb81536abBo Zhu        }
1713462c832d1acccca3cdd541dea86442eb81536abBo Zhu
1723462c832d1acccca3cdd541dea86442eb81536abBo Zhu        int generationId = getGenerationId(userId);
1733462c832d1acccca3cdd541dea86442eb81536abBo Zhu        int nextId;
1743462c832d1acccca3cdd541dea86442eb81536abBo Zhu        if (generationId == -1) {
1753462c832d1acccca3cdd541dea86442eb81536abBo Zhu            nextId = 1;
1763462c832d1acccca3cdd541dea86442eb81536abBo Zhu        } else {
1776e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev            invalidatePlatformKey(userId, generationId);
1783462c832d1acccca3cdd541dea86442eb81536abBo Zhu            nextId = generationId + 1;
1793462c832d1acccca3cdd541dea86442eb81536abBo Zhu        }
1803462c832d1acccca3cdd541dea86442eb81536abBo Zhu        generateAndLoadKey(userId, nextId);
181a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
182a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
183a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
184a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns the platform key used for encryption.
1853f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * Tries to regenerate key one time if it is permanently invalid.
186a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
1873462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
188a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there was an AndroidKeyStore error.
189a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws UnrecoverableKeyException if the key could not be recovered.
190a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
1913462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @throws InsecureUserException if the user does not have a lock screen set.
19220eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev     * @throws IOException if there was an issue with local database update.
193a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
194a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
195a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
1963462c832d1acccca3cdd541dea86442eb81536abBo Zhu    public PlatformEncryptionKey getEncryptKey(int userId) throws KeyStoreException,
19720eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
1983462c832d1acccca3cdd541dea86442eb81536abBo Zhu        init(userId);
1993f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        try {
2001170a78f471400f597aa6e3b20c0626fad96338cBo Zhu            // Try to see if the decryption key is still accessible before using the encryption key.
2011170a78f471400f597aa6e3b20c0626fad96338cBo Zhu            // The auth-bound decryption will be unrecoverable if the screen lock is disabled.
2021170a78f471400f597aa6e3b20c0626fad96338cBo Zhu            getDecryptKeyInternal(userId);
2033f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            return getEncryptKeyInternal(userId);
2043f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        } catch (UnrecoverableKeyException e) {
2053f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            Log.i(TAG, String.format(Locale.US,
2063f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    "Regenerating permanently invalid Platform key for user %d.",
2073f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    userId));
2083f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            regenerate(userId);
2093f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            return getEncryptKeyInternal(userId);
2103f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        }
2113f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev    }
2123f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev
2133f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev    /**
2143f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * Returns the platform key used for encryption.
2153f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     *
2163f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @param userId The ID of the user to whose lock screen the platform key must be bound.
2173f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws KeyStoreException if there was an AndroidKeyStore error.
2183f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws UnrecoverableKeyException if the key could not be recovered.
2193f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
2203f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws InsecureUserException if the user does not have a lock screen set.
2213f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     *
2223f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @hide
2233f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     */
2243f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev    private PlatformEncryptionKey getEncryptKeyInternal(int userId) throws KeyStoreException,
2253f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
2263462c832d1acccca3cdd541dea86442eb81536abBo Zhu        int generationId = getGenerationId(userId);
2276e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev        String alias = getEncryptAlias(userId, generationId);
2281170a78f471400f597aa6e3b20c0626fad96338cBo Zhu        if (!isKeyLoaded(userId, generationId)) {
2296e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev            throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
2306e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev        }
231a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
2326e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev                alias, /*password=*/ null);
233a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        return new PlatformEncryptionKey(generationId, key);
234a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
235a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
236a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
237a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns the platform key used for decryption. Only works after a recent screen unlock.
2383f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * Tries to regenerate key one time if it is permanently invalid.
239a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
2403462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
241a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there was an AndroidKeyStore error.
242a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws UnrecoverableKeyException if the key could not be recovered.
243a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
2443462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @throws InsecureUserException if the user does not have a lock screen set.
24520eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev     * @throws IOException if there was an issue with local database update.
246a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
247a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
248a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
2493462c832d1acccca3cdd541dea86442eb81536abBo Zhu    public PlatformDecryptionKey getDecryptKey(int userId) throws KeyStoreException,
25020eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException, IOException {
2513462c832d1acccca3cdd541dea86442eb81536abBo Zhu        init(userId);
2523f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        try {
2533f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            return getDecryptKeyInternal(userId);
2543f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        } catch (UnrecoverableKeyException e) {
2553f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            Log.i(TAG, String.format(Locale.US,
2563f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    "Regenerating permanently invalid Platform key for user %d.",
2573f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    userId));
2583f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            regenerate(userId);
2593f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev            return getDecryptKeyInternal(userId);
2603f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        }
2613f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev    }
2623f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev
2633f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev    /**
2643f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * Returns the platform key used for decryption. Only works after a recent screen unlock.
2653f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     *
2663f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @param userId The ID of the user to whose lock screen the platform key must be bound.
2673f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws KeyStoreException if there was an AndroidKeyStore error.
2683f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws UnrecoverableKeyException if the key could not be recovered.
2693f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws NoSuchAlgorithmException if AES is unavailable - should never occur.
2703f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @throws InsecureUserException if the user does not have a lock screen set.
2713f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     *
2723f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     * @hide
2733f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev     */
2743f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev    private PlatformDecryptionKey getDecryptKeyInternal(int userId) throws KeyStoreException,
2753f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev           UnrecoverableKeyException, NoSuchAlgorithmException, InsecureUserException {
2763462c832d1acccca3cdd541dea86442eb81536abBo Zhu        int generationId = getGenerationId(userId);
2776e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev        String alias = getDecryptAlias(userId, generationId);
2781170a78f471400f597aa6e3b20c0626fad96338cBo Zhu        if (!isKeyLoaded(userId, generationId)) {
2796e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev            throw new UnrecoverableKeyException("KeyStore doesn't contain key " + alias);
2806e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev        }
281a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        AndroidKeyStoreSecretKey key = (AndroidKeyStoreSecretKey) mKeyStore.getKey(
2826e16724fb66e4bd14274768174379aa88c34464fDmitry Dementyev                alias, /*password=*/ null);
283a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        return new PlatformDecryptionKey(generationId, key);
284a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
285a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
286a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
287a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Initializes the class. If there is no current platform key, and the user has a lock screen
288a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * set, will create the platform key and set the generation ID.
289a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
2903462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
291a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there was an error in AndroidKeyStore.
292a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES is unavailable - should never happen.
29320eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev     * @throws IOException if there was an issue with local database update.
294a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
295a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @hide
296a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
2973462c832d1acccca3cdd541dea86442eb81536abBo Zhu    void init(int userId)
29820eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev            throws KeyStoreException, NoSuchAlgorithmException, InsecureUserException, IOException {
2993462c832d1acccca3cdd541dea86442eb81536abBo Zhu        if (!isAvailable(userId)) {
300a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            throw new InsecureUserException(String.format(
3013462c832d1acccca3cdd541dea86442eb81536abBo Zhu                    Locale.US, "%d does not have a lock screen set.", userId));
302a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        }
303a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
3043462c832d1acccca3cdd541dea86442eb81536abBo Zhu        int generationId = getGenerationId(userId);
3053462c832d1acccca3cdd541dea86442eb81536abBo Zhu        if (isKeyLoaded(userId, generationId)) {
306a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            Log.i(TAG, String.format(
307a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    Locale.US, "Platform key generation %d exists already.", generationId));
308a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            return;
309a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        }
310b811553c4c6661599fa30910a49b8b54279e12beRobert Berry        if (generationId == -1) {
3111170a78f471400f597aa6e3b20c0626fad96338cBo Zhu            Log.i(TAG, "Generating initial platform key generation ID.");
3123462c832d1acccca3cdd541dea86442eb81536abBo Zhu            generationId = 1;
313a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        } else {
314a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            Log.w(TAG, String.format(Locale.US, "Platform generation ID was %d but no "
315a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    + "entry was present in AndroidKeyStore. Generating fresh key.", generationId));
3161170a78f471400f597aa6e3b20c0626fad96338cBo Zhu            // Have to generate a fresh key, so bump the generation id
317b811553c4c6661599fa30910a49b8b54279e12beRobert Berry            generationId++;
318b811553c4c6661599fa30910a49b8b54279e12beRobert Berry        }
319b811553c4c6661599fa30910a49b8b54279e12beRobert Berry
3203462c832d1acccca3cdd541dea86442eb81536abBo Zhu        generateAndLoadKey(userId, generationId);
321a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
322a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
323a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
324a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns the alias of the encryption key with the specific {@code generationId} in the
325a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * AndroidKeyStore.
326a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
327a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * <p>These IDs look as follows:
328a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * {@code com.security.recoverablekeystore/platform/<user id>/<generation id>/encrypt}
329a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
3303462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
331a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @param generationId The generation ID.
332a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @return The alias.
333a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
3343462c832d1acccca3cdd541dea86442eb81536abBo Zhu    private String getEncryptAlias(int userId, int generationId) {
3353462c832d1acccca3cdd541dea86442eb81536abBo Zhu        return KEY_ALIAS_PREFIX + userId + "/" + generationId + "/" + ENCRYPT_KEY_ALIAS_SUFFIX;
336a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
337a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
338a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
339a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns the alias of the decryption key with the specific {@code generationId} in the
340a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * AndroidKeyStore.
341a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
342a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * <p>These IDs look as follows:
343a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * {@code com.security.recoverablekeystore/platform/<user id>/<generation id>/decrypt}
344a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
3453462c832d1acccca3cdd541dea86442eb81536abBo Zhu     * @param userId The ID of the user to whose lock screen the platform key must be bound.
346a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @param generationId The generation ID.
347a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @return The alias.
348a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
3493462c832d1acccca3cdd541dea86442eb81536abBo Zhu    private String getDecryptAlias(int userId, int generationId) {
3503462c832d1acccca3cdd541dea86442eb81536abBo Zhu        return KEY_ALIAS_PREFIX + userId + "/" + generationId + "/" + DECRYPT_KEY_ALIAS_SUFFIX;
351a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
352a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
353a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
354a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Sets the current generation ID to {@code generationId}.
35520eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev     * @throws IOException if there was an issue with local database update.
356a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
35720eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev    private void setGenerationId(int userId, int generationId) throws IOException {
35820eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev        long updatedRows = mDatabase.setPlatformKeyGenerationId(userId, generationId);
35920eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev        if (updatedRows < 0) {
36020eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev            throw new IOException("Failed to set the platform key in the local DB.");
36120eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev        }
362a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
363a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
364a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
365a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns {@code true} if a key has been loaded with the given {@code generationId} into
366a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * AndroidKeyStore.
367a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
368a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there was an error checking AndroidKeyStore.
369a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
3703462c832d1acccca3cdd541dea86442eb81536abBo Zhu    private boolean isKeyLoaded(int userId, int generationId) throws KeyStoreException {
3713462c832d1acccca3cdd541dea86442eb81536abBo Zhu        return mKeyStore.containsAlias(getEncryptAlias(userId, generationId))
3723462c832d1acccca3cdd541dea86442eb81536abBo Zhu                && mKeyStore.containsAlias(getDecryptAlias(userId, generationId));
373a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
374a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
375a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
376a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Generates a new 256-bit AES key, and loads it into AndroidKeyStore with the given
377a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * {@code generationId} determining its aliases.
378a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
379a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES is unavailable. This should never happen, as it is
380a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *     available since API version 1.
381a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there was an issue loading the keys into AndroidKeyStore.
38220eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev     * @throws IOException if there was an issue with local database update.
383a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
3843462c832d1acccca3cdd541dea86442eb81536abBo Zhu    private void generateAndLoadKey(int userId, int generationId)
38520eaaa496d04a4391314103849647b3d60384feeDmitry Dementyev            throws NoSuchAlgorithmException, KeyStoreException, IOException {
3863462c832d1acccca3cdd541dea86442eb81536abBo Zhu        String encryptAlias = getEncryptAlias(userId, generationId);
3873462c832d1acccca3cdd541dea86442eb81536abBo Zhu        String decryptAlias = getDecryptAlias(userId, generationId);
388482633fe81afed63be75fe36c4cd33b5660bd13dDmitry Dementyev        // SecretKey implementation doesn't provide reliable way to destroy the secret
389482633fe81afed63be75fe36c4cd33b5660bd13dDmitry Dementyev        // so it may live in memory for some time.
390a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        SecretKey secretKey = generateAesKey();
391a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
3921170a78f471400f597aa6e3b20c0626fad96338cBo Zhu        // Store decryption key first since it is more likely to fail.
393a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        mKeyStore.setEntry(
394a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                decryptAlias,
395a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                new KeyStore.SecretKeyEntry(secretKey),
396a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
397a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    .setUserAuthenticationRequired(true)
398a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    .setUserAuthenticationValidityDurationSeconds(
399a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                            USER_AUTHENTICATION_VALIDITY_DURATION_SECONDS)
400a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
401a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
4023462c832d1acccca3cdd541dea86442eb81536abBo Zhu                    .setBoundToSpecificSecureUserId(userId)
403a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry                    .build());
4043f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev        mKeyStore.setEntry(
4053f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                encryptAlias,
4063f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                new KeyStore.SecretKeyEntry(secretKey),
4073f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
4083f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
4093f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
4103f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev                    .build());
4113f2d1713fd8d3379f94c0c880d6242c7cbc1eea8Dmitry Dementyev
4123462c832d1acccca3cdd541dea86442eb81536abBo Zhu        setGenerationId(userId, generationId);
413a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
414a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
415a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
416a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Generates a new 256-bit AES key, in software.
417a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
418a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @return The software-generated AES key.
419a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws NoSuchAlgorithmException if AES key generation is not available. This should never
420a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *     happen, as AES has been supported since API level 1.
421a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
422a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static SecretKey generateAesKey() throws NoSuchAlgorithmException {
423a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
424a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        keyGenerator.init(KEY_SIZE_BITS);
425a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        return keyGenerator.generateKey();
426a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
427a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry
428a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    /**
429a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * Returns AndroidKeyStore-provided {@link KeyStore}, having already invoked
430a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * {@link KeyStore#load(KeyStore.LoadStoreParameter)}.
431a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     *
432a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     * @throws KeyStoreException if there was a problem getting or initializing the key store.
433a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry     */
434a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    private static KeyStore getAndLoadAndroidKeyStore() throws KeyStoreException {
435a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
436a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        try {
437a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            keyStore.load(/*param=*/ null);
438a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        } catch (CertificateException | IOException | NoSuchAlgorithmException e) {
439a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            // Should never happen.
440a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry            throw new KeyStoreException("Unable to load keystore.", e);
441a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        }
442a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry        return keyStore;
443a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry    }
444f0a4bea6b242d7673053bfd43f932e9a464ac9e0Robert Berry
445a9fae14c3345aa91721dfbb54dee8d7572a81ba8Robert Berry}
446