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