/**@class android.security.keystore.recovery.RecoveryController @extends java.lang.Object Backs up cryptographic keys to remote secure hardware, encrypted with the user's lock screen. <p>A system app with the {@code android.permission.RECOVER_KEYSTORE} permission may generate or import recoverable keys using this class. To generate a key, the app must call {@link #generateKey}(String) with the desired alias for the key. This returns an AndroidKeyStore reference to a 256-bit {@link javax.crypto.SecretKey}, which can be used for AES/GCM/NoPadding. In order to get the same key again at a later time, the app can call {@link #getKey}(String) with the same alias. If a key is generated in this way the key's raw material is never directly exposed to the calling app. The system app may also import key material using {@link #importKey(String, byte[])}. The app may only generate and import keys for its own {@code uid}. <p>The same system app must also register a Recovery Agent to manage syncing recoverable keys to remote secure hardware. The Recovery Agent is a service that registers itself with the controller as follows: <ul> <li>Invokes {@link #initRecoveryService(String, byte[], byte[])} <ul> <li>The first argument is the alias of the root certificate used to verify trusted hardware modules. Each trusted hardware module must have a public key signed with this root of trust. Roots of trust must be shipped with the framework. The app can list all valid roots of trust by calling {@link #getRootCertificates}(). <li>The second argument is the UTF-8 bytes of the XML listing file. It lists the X509 certificates containing the public keys of all available remote trusted hardware modules. Each of the X509 certificates can be validated against the chosen root of trust. <li>The third argument is the UTF-8 bytes of the XML signing file. The file contains a signature of the XML listing file. The signature can be validated against the chosen root of trust. </ul> <p>This will cause the controller to choose a random public key from the list. From then on the controller will attempt to sync the key chain with the trusted hardware module to whom that key belongs. <li>Invokes {@link #setServerParams(byte[])} with a byte string that identifies the device to a remote server. This server may act as the front-end to the trusted hardware modules. It is up to the Recovery Agent to decide how best to identify devices, but this could be, e.g., based on the <a href="https://developers.google.com/instance-id/">Instance ID</a> of the system app. <li>Invokes {@link #setRecoverySecretTypes(int[])} with a list of types of secret used to secure the recoverable key chain. For now only {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_LOCKSCREEN} is supported. <li>Invokes {@link #setSnapshotCreatedPendingIntent}(PendingIntent) with a {@link PendingIntent} that is to be invoked whenever a new snapshot is created. Although the controller can create snapshots without the Recovery Agent registering this intent, it is a good idea to register the intent so that the Recovery Agent is able to sync this snapshot to the trusted hardware module as soon as it is available. </ul> <p>The trusted hardware module's public key MUST be generated on secure hardware with protections equivalent to those described in the <a href="https://developer.android.com/preview/features/security/ckv-whitepaper.html">Google Cloud Key Vault Service whitepaper</a>. The trusted hardware module itself must protect the key chain from brute-forcing using the methods also described in the whitepaper: i.e., it should limit the number of allowed attempts to enter the lock screen. If the number of attempts is exceeded the key material must no longer be recoverable. <p>A recoverable key chain snapshot is considered pending if any of the following conditions are met: <ul> <li>The system app mutates the key chain. i.e., generates, imports, or removes a key. <li>The user changes their lock screen. </ul> <p>Whenever the user unlocks their device, if a snapshot is pending, the Recovery Controller generates a new snapshot. It follows these steps to do so: <ul> <li>Generates a 256-bit AES key using {@link java.security.SecureRandom}. This is the Recovery Key. <li>Wraps the key material of all keys in the recoverable key chain with the Recovery Key. <li>Encrypts the Recovery Key with both the public key of the trusted hardware module and a symmetric key derived from the user's lock screen. </ul> <p>The controller then writes this snapshot to disk, and uses the {@link PendingIntent} that was set by the Recovery Agent during initialization to inform it that a new snapshot is available. The snapshot only contains keys for that Recovery Agent's {@code uid} - i.e., keys the agent's app itself generated. If multiple Recovery Agents exist on the device, each will be notified of their new snapshots, and each snapshots' keys will be only those belonging to the same {@code uid}. <p>The Recovery Agent retrieves its most recent snapshot by calling {@link #getKeyChainSnapshot}(). It syncs the snapshot to the remote server. The snapshot contains the public key used for encryption, which the server uses to forward the encrypted recovery key to the correct trusted hardware module. The snapshot also contains the server params, which are used to identify this device to the server. <p>The client uses the server params to identify a device whose key chain it wishes to restore. This may be on a different device to the device that originally synced the key chain. The client sends the server params identifying the previous device to the server. The server returns the X509 certificate identifying the trusted hardware module in which the encrypted Recovery Key is stored. It also returns some vault parameters identifying that particular Recovery Key to the trusted hardware module. And it also returns a vault challenge, which is used as part of the vault opening protocol to ensure the recovery claim is fresh. See the whitepaper for more details. <p>The key chain is recovered via a {@link android.security.keystore.recovery.RecoverySession}. A Recovery Agent creates one by invoking {@link #createRecoverySession}(). It then invokes {@link android.security.keystore.recovery.RecoverySession#start(String, CertPath, byte[], byte[], List)} with these arguments: <ul> <li>The alias of the root of trust used to verify the trusted hardware module. <li>The X509 certificate of the trusted hardware module. <li>The vault parameters used to identify the Recovery Key to the trusted hardware module. <li>The vault challenge, as issued by the trusted hardware module. <li>A list of secrets, corresponding to the secrets used to protect the key chain. At the moment this is a single {@link android.security.keystore.recovery.KeyChainProtectionParams} containing the lock screen of the device whose key chain is to be recovered. </ul> <p>This method returns a byte array containing the Recovery Claim, which can be issued to the remote trusted hardware module. It is encrypted with the trusted hardware module's public key (which has itself been certified with the root of trust). It also contains an ephemeral symmetric key generated for this recovery session, which the remote trusted hardware module uses to encrypt its responses. This is the Session Key. <p>If the lock screen provided is correct, the remote trusted hardware module decrypts one of the layers of lock-screen encryption from the Recovery Key. It then returns this key, encrypted with the Session Key to the Recovery Agent. As the Recovery Agent does not know the Session Key, it must then invoke {@link android.security.keystore.recovery.RecoverySession#recoverKeyChainSnapshot(byte[], List)} with the encrypted Recovery Key and the list of wrapped application keys. The controller then decrypts the layer of encryption provided by the Session Key, and uses the lock screen to decrypt the final layer of encryption. It then uses the Recovery Key to decrypt all of the wrapped application keys, and imports them into its own KeyStore. The Recovery Agent's app may then access these keys by calling {@link #getKey}(String). Only this app's {@code uid} may access the keys that have been recovered. @hide */ var RecoveryController = { /**Key has been successfully synced. */ RECOVERY_STATUS_SYNCED : "0", /**Waiting for recovery agent to sync the key. */ RECOVERY_STATUS_SYNC_IN_PROGRESS : "1", /**Key cannot be synced. */ RECOVERY_STATUS_PERMANENT_FAILURE : "3", /** Failed because no snapshot is yet pending to be synced for the user. @hide */ ERROR_NO_SNAPSHOT_PENDING : "21", /** Failed due to an error internal to the recovery service. This is unexpected and indicates either a problem with the logic in the service, or a problem with a dependency of the service (such as AndroidKeyStore). @hide */ ERROR_SERVICE_INTERNAL_ERROR : "22", /** Failed because the user does not have a lock screen set. @hide */ ERROR_INSECURE_USER : "23", /** Error thrown when attempting to use a recovery session that has since been closed. @hide */ ERROR_SESSION_EXPIRED : "24", /** Failed because the format of the provided certificate is incorrect, e.g., cannot be decoded properly or misses necessary fields. <p>Note that this is different from {@link #ERROR_INVALID_CERTIFICATE}, which implies the certificate has a correct format but cannot be validated. @hide */ ERROR_BAD_CERTIFICATE_FORMAT : "25", /** Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong, the data has become corrupted, the data has been tampered with, etc. @hide */ ERROR_DECRYPTION_FAILED : "26", /** Error thrown if the format of a given key is invalid. This might be because the key has a wrong length, invalid content, etc. @hide */ ERROR_INVALID_KEY_FORMAT : "27", /** Failed because the provided certificate cannot be validated, e.g., is expired or has invalid signatures. <p>Note that this is different from {@link #ERROR_BAD_CERTIFICATE_FORMAT}, which denotes incorrect certificate formats, e.g., due to wrong encoding or structure. @hide */ ERROR_INVALID_CERTIFICATE : "28", /** Failed because the provided certificate contained serial version which is lower that the version device is already initialized with. It is not possible to downgrade serial version of the provided certificate. @hide */ ERROR_DOWNGRADE_CERTIFICATE : "29", /**Gets a new instance of the class. */ getInstance : function( ) {}, /**Checks whether the recoverable key store is currently available. <p>If it returns true, the device must currently be using a screen lock that is supported for use with the recoverable key store, i.e. AOSP PIN, pattern or password. */ isRecoverableKeyStoreEnabled : function( ) {}, /**Initializes the recovery service for the calling application. The detailed steps should be: <ol> <li>Parse {@code signatureFile} to get relevant information. <li>Validate the signer's X509 certificate, contained in {@code signatureFile}, against the root certificate pre-installed in the OS and chosen by {@code rootCertificateAlias}. <li>Verify the public-key signature, contained in {@code signatureFile}, and verify it against the entire {@code certificateFile}. <li>Parse {@code certificateFile} to get relevant information. <li>Check the serial number, contained in {@code certificateFile}, and skip the following steps if the serial number is not larger than the one previously stored. <li>Randomly choose a X509 certificate from the endpoint X509 certificates, contained in {@code certificateFile}, and validate it against the root certificate pre-installed in the OS and chosen by {@code rootCertificateAlias}. <li>Store the chosen X509 certificate and the serial in local database for later use. </ol> @param {String} rootCertificateAlias the alias of a root certificate pre-installed in the OS @param {Object {byte[]}} certificateFile the binary content of the XML file containing a list of recovery service X509 certificates, and other metadata including the serial number @param {Object {byte[]}} signatureFile the binary content of the XML file containing the public-key signature of the entire certificate file, and a signer's X509 certificate @throws CertificateException if the given certificate files cannot be parsed or validated @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ initRecoveryService : function( ) {}, /**Returns data necessary to store all recoverable keys. Key material is encrypted with user secret and recovery public key. @return {Object {android.security.keystore.recovery.KeyChainSnapshot}} Data necessary to recover keystore or {@code null} if snapshot is not available. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ getKeyChainSnapshot : function( ) {}, /**Sets a listener which notifies recovery agent that new recovery snapshot is available. {@link #getKeyChainSnapshot} can be used to get the snapshot. Note that every recovery agent can have at most one registered listener at any time. @param {Object {PendingIntent}} intent triggered when new snapshot is available. Unregisters listener if the value is {@code null}. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ setSnapshotCreatedPendingIntent : function( ) {}, /**Server parameters used to generate new recovery key blobs. This value will be included in {@code KeyChainSnapshot.getEncryptedRecoveryKeyBlob()}. The same value must be included in vaultParams {@link android.security.keystore.recovery.RecoverySession#start(CertPath, byte[], byte[], List)}. @param {Object {byte[]}} serverParams included in recovery key blob. @see #getKeyChainSnapshot @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ setServerParams : function( ) {}, /**Returns a list of aliases of keys belonging to the application. */ getAliases : function( ) {}, /**Sets the recovery status for given key. It is used to notify the keystore that the key was successfully stored on the server or that there was an error. An application can check this value using {@link #getRecoveryStatus(String, String)}. @param {String} alias The alias of the key whose status to set. @param {Number} status The status of the key. One of {@link #RECOVERY_STATUS_SYNCED}, {@link #RECOVERY_STATUS_SYNC_IN_PROGRESS} or {@link #RECOVERY_STATUS_PERMANENT_FAILURE}. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ setRecoveryStatus : function( ) {}, /**Returns the recovery status for the key with the given {@code alias}. <ul> <li>{@link #RECOVERY_STATUS_SYNCED} <li>{@link #RECOVERY_STATUS_SYNC_IN_PROGRESS} <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE} </ul> @see #setRecoveryStatus(String, int) @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ getRecoveryStatus : function( ) {}, /**Specifies a set of secret types used for end-to-end keystore encryption. Knowing all of them is necessary to recover data. @param {Object {int[]}} secretTypes {@link KeyChainProtectionParams#TYPE_LOCKSCREEN} @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ setRecoverySecretTypes : function( ) {}, /**Defines a set of secret types used for end-to-end keystore encryption. Knowing all of them is necessary to generate KeyChainSnapshot. @return {Number} list of recovery secret types @see KeyChainSnapshot @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ getRecoverySecretTypes : function( ) {}, /**Generates a recoverable key with the given {@code alias}. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. @throws LockScreenRequiredException if the user does not have a lock screen set. A lock screen is required to generate recoverable keys. @deprecated Use the method {@link #generateKey(String, byte[])} instead. */ generateKey : function( ) {}, /**Generates a recoverable key with the given {@code alias} and {@code metadata}. <p>The metadata should contain any data that needs to be cryptographically bound to the generated key, but does not need to be encrypted by the key. For example, the metadata can be a byte string describing the algorithms and non-secret parameters to be used with the key. The supplied metadata can later be obtained via {@link android.security.keystore.recovery.WrappedApplicationKey#getMetadata()}. <p>During the key recovery process, the same metadata has to be supplied via {@link android.security.keystore.recovery.WrappedApplicationKey.Builder#setMetadata(byte[])}; otherwise, the recovery process will fail due to the checking of the cryptographic binding. This can help prevent potential attacks that try to swap key materials on the backup server and trick the application to use keys with different algorithms or parameters. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. @throws LockScreenRequiredException if the user does not have a lock screen set. A lock screen is required to generate recoverable keys. */ generateKey : function( ) {}, /**Imports a 256-bit recoverable AES key with the given {@code alias} and the raw bytes {@code keyBytes}. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. @throws LockScreenRequiredException if the user does not have a lock screen set. A lock screen is required to generate recoverable keys. @deprecated Use the method {@link #importKey(String, byte[], byte[])} instead. */ importKey : function( ) {}, /**Imports a recoverable 256-bit AES key with the given {@code alias}, the raw bytes {@code keyBytes}, and the {@code metadata}. <p>The metadata should contain any data that needs to be cryptographically bound to the imported key, but does not need to be encrypted by the key. For example, the metadata can be a byte string describing the algorithms and non-secret parameters to be used with the key. The supplied metadata can later be obtained via {@link android.security.keystore.recovery.WrappedApplicationKey#getMetadata()}. <p>During the key recovery process, the same metadata has to be supplied via {@link android.security.keystore.recovery.WrappedApplicationKey.Builder#setMetadata(byte[])}; otherwise, the recovery process will fail due to the checking of the cryptographic binding. This can help prevent potential attacks that try to swap key materials on the backup server and trick the application to use keys with different algorithms or parameters. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. @throws LockScreenRequiredException if the user does not have a lock screen set. A lock screen is required to generate recoverable keys. */ importKey : function( ) {}, /**Gets a key called {@code alias} from the recoverable key store. @param {String} alias The key alias. @return {Object {java.security.Key}} The key. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. @throws UnrecoverableKeyException if key is permanently invalidated or not found. */ getKey : function( ) {}, /**Removes a key called {@code alias} from the recoverable key store. @param {String} alias The key alias. @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery service. */ removeKey : function( ) {}, /**Returns a new {@link android.security.keystore.recovery.RecoverySession}. <p>A recovery session is required to restore keys from a remote store. */ createRecoverySession : function( ) {}, /** */ getRootCertificates : function( ) {}, };