summaryrefslogtreecommitdiffstats
path: root/keystore/java/android
diff options
context:
space:
mode:
Diffstat (limited to 'keystore/java/android')
-rw-r--r--keystore/java/android/security/AndroidKeyStore.java4
-rw-r--r--keystore/java/android/security/CryptoOperationException.java2
-rw-r--r--keystore/java/android/security/EcIesParameterSpec.java2
-rw-r--r--keystore/java/android/security/KeyChain.java56
-rw-r--r--keystore/java/android/security/KeyExpiredException.java2
-rw-r--r--keystore/java/android/security/KeyGeneratorSpec.java46
-rw-r--r--keystore/java/android/security/KeyNotYetValidException.java2
-rw-r--r--keystore/java/android/security/KeyPairGeneratorSpec.java86
-rw-r--r--keystore/java/android/security/KeyStore.java3
-rw-r--r--keystore/java/android/security/KeyStoreKeyGeneratorSpi.java6
-rw-r--r--keystore/java/android/security/KeyStoreKeyProperties.java13
-rw-r--r--keystore/java/android/security/KeyStoreKeySpec.java19
-rw-r--r--keystore/java/android/security/KeyStoreParameter.java81
-rw-r--r--keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java6
-rw-r--r--keystore/java/android/security/NewFingerprintEnrolledException.java39
-rw-r--r--keystore/java/android/security/UserNotAuthenticatedException.java2
16 files changed, 242 insertions, 127 deletions
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 964fb21..1c068be 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -536,6 +536,10 @@ public class AndroidKeyStore extends KeyStoreSpi {
KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
params.getUserAuthenticators()));
}
+ if (params.isInvalidatedOnNewFingerprintEnrolled()) {
+ // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+ // that.
+ }
if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
params.getUserAuthenticationValidityDurationSeconds());
diff --git a/keystore/java/android/security/CryptoOperationException.java b/keystore/java/android/security/CryptoOperationException.java
index 00c142f..1c9d005 100644
--- a/keystore/java/android/security/CryptoOperationException.java
+++ b/keystore/java/android/security/CryptoOperationException.java
@@ -25,8 +25,6 @@ package android.security;
* permitted to throw a checked exception during operation. Because crypto operations can fail
* for a variety of reasons after initialization, this base class provides type-safety for unchecked
* exceptions that may be thrown in those cases.
- *
- * @hide
*/
public class CryptoOperationException extends RuntimeException {
diff --git a/keystore/java/android/security/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java
index 3372da9..a3e5aec 100644
--- a/keystore/java/android/security/EcIesParameterSpec.java
+++ b/keystore/java/android/security/EcIesParameterSpec.java
@@ -46,8 +46,6 @@ import javax.crypto.Mac;
* MAC algorithm specified by {@link #getDemMacAlgorithm()} (e.g., {@code HmacSHA1} for standard
* DEM1).</li>
* </ul>
- *
- * @hide
*/
public class EcIesParameterSpec implements AlgorithmParameterSpec {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index dfa41e8..e9c24dd 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -127,6 +127,12 @@ public final class KeyChain {
* Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
+ public static final String EXTRA_URL = "url";
+
+ /**
+ * Extra for use with {@link #ACTION_CHOOSER}
+ * @hide Also used by KeyChainActivity implementation
+ */
public static final String EXTRA_ALIAS = "alias";
/**
@@ -224,6 +230,51 @@ public final class KeyChain {
* selected alias or null will be returned via the
* KeyChainAliasCallback callback.
*
+ * <p>The device or profile owner can intercept this before the activity
+ * is shown, to pick a specific private key alias.
+ *
+ * <p>{@code keyTypes} and {@code issuers} may be used to
+ * highlight suggested choices to the user, although to cope with
+ * sometimes erroneous values provided by servers, the user may be
+ * able to override these suggestions.
+ *
+ * <p>{@code host} and {@code port} may be used to give the user
+ * more context about the server requesting the credentials.
+ *
+ * <p>{@code alias} allows the chooser to preselect an existing
+ * alias which will still be subject to user confirmation.
+ *
+ * @param activity The {@link Activity} context to use for
+ * launching the new sub-Activity to prompt the user to select
+ * a private key; used only to call startActivity(); must not
+ * be null.
+ * @param response Callback to invoke when the request completes;
+ * must not be null
+ * @param keyTypes The acceptable types of asymmetric keys such as
+ * "RSA" or "DSA", or a null array.
+ * @param issuers The acceptable certificate issuers for the
+ * certificate matching the private key, or null.
+ * @param host The host name of the server requesting the
+ * certificate, or null if unavailable.
+ * @param port The port number of the server requesting the
+ * certificate, or -1 if unavailable.
+ * @param alias The alias to preselect if available, or null if
+ * unavailable.
+ */
+ public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response,
+ String[] keyTypes, Principal[] issuers, String host, int port, String alias) {
+ choosePrivateKeyAlias(activity, response, keyTypes, issuers, host, port, null, alias);
+ }
+
+ /**
+ * Launches an {@code Activity} for the user to select the alias
+ * for a private key and certificate pair for authentication. The
+ * selected alias or null will be returned via the
+ * KeyChainAliasCallback callback.
+ *
+ * <p>The device or profile owner can intercept this before the activity
+ * is shown, to pick a specific private key alias.</p>
+ *
* <p>{@code keyTypes} and {@code issuers} may be used to
* highlight suggested choices to the user, although to cope with
* sometimes erroneous values provided by servers, the user may be
@@ -249,12 +300,14 @@ public final class KeyChain {
* certificate, or null if unavailable.
* @param port The port number of the server requesting the
* certificate, or -1 if unavailable.
+ * @param url The full url the server is requesting the certificate
+ * for, or null if unavailable.
* @param alias The alias to preselect if available, or null if
* unavailable.
*/
public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response,
String[] keyTypes, Principal[] issuers,
- String host, int port,
+ String host, int port, String url,
String alias) {
/*
* TODO currently keyTypes, issuers are unused. They are meant
@@ -283,6 +336,7 @@ public final class KeyChain {
intent.putExtra(EXTRA_RESPONSE, new AliasResponse(response));
intent.putExtra(EXTRA_HOST, host);
intent.putExtra(EXTRA_PORT, port);
+ intent.putExtra(EXTRA_URL, url);
intent.putExtra(EXTRA_ALIAS, alias);
// the PendingIntent is used to get calling package name
intent.putExtra(EXTRA_SENDER, PendingIntent.getActivity(activity, 0, new Intent(), 0));
diff --git a/keystore/java/android/security/KeyExpiredException.java b/keystore/java/android/security/KeyExpiredException.java
index 35a5acc..a02dc33 100644
--- a/keystore/java/android/security/KeyExpiredException.java
+++ b/keystore/java/android/security/KeyExpiredException.java
@@ -19,8 +19,6 @@ package android.security;
/**
* Indicates that a cryptographic operation failed because the employed key's validity end date
* is in the past.
- *
- * @hide
*/
public class KeyExpiredException extends CryptoOperationException {
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index a22c31c..7ecc47e 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -37,15 +37,13 @@ import javax.crypto.SecretKey;
* <p>After generation, the {@code keyStoreAlias} is used with the
* {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
* interface to retrieve the {@link SecretKey}.
- *
- * @hide
*/
public class KeyGeneratorSpec implements AlgorithmParameterSpec {
private final Context mContext;
private final String mKeystoreAlias;
private final int mFlags;
- private final Integer mKeySize;
+ private final int mKeySize;
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
@@ -55,12 +53,13 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
private final boolean mRandomizedEncryptionRequired;
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
private KeyGeneratorSpec(
Context context,
String keyStoreAlias,
int flags,
- Integer keySize,
+ int keySize,
Date keyValidityStart,
Date keyValidityForOriginationEnd,
Date keyValidityForConsumptionEnd,
@@ -69,7 +68,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
String[] blockModes,
boolean randomizedEncryptionRequired,
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
if (context == null) {
throw new IllegalArgumentException("context == null");
} else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -94,6 +94,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticators = userAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
}
/**
@@ -119,9 +120,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
}
/**
- * Gets the requested key size or {@code null} if the default size should be used.
+ * Returns the requested key size or {@code -1} if default size should be used.
*/
- public Integer getKeySize() {
+ public int getKeySize() {
return mKeySize;
}
@@ -208,6 +209,17 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
}
/**
+ * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
+
+ /**
* Returns {@code true} if the key must be encrypted in the {@link java.security.KeyStore}.
*/
public boolean isEncryptionRequired() {
@@ -218,7 +230,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
private final Context mContext;
private String mKeystoreAlias;
private int mFlags;
- private Integer mKeySize;
+ private int mKeySize = -1;
private Date mKeyValidityStart;
private Date mKeyValidityForOriginationEnd;
private Date mKeyValidityForConsumptionEnd;
@@ -228,6 +240,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
private boolean mRandomizedEncryptionRequired = true;
private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private boolean mInvalidatedOnNewFingerprintEnrolled;
/**
* Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -436,6 +449,20 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
}
/**
+ * Sets whether this key must be invalidated (permanently) once a new fingerprint is
+ * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+ * protecting access to the key.
+ *
+ * <p>By default, enrolling a new fingerprint does not invalidate the key.
+ *
+ * @see #setUserAuthenticators(Set)
+ */
+ public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+ mInvalidatedOnNewFingerprintEnrolled = invalidated;
+ return this;
+ }
+
+ /**
* Builds a new instance instance of {@code KeyGeneratorSpec}.
*
* @throws IllegalArgumentException if a required field is missing or violates a constraint.
@@ -453,7 +480,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticators,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mInvalidatedOnNewFingerprintEnrolled);
}
}
}
diff --git a/keystore/java/android/security/KeyNotYetValidException.java b/keystore/java/android/security/KeyNotYetValidException.java
index f1c2cac..964cd7e 100644
--- a/keystore/java/android/security/KeyNotYetValidException.java
+++ b/keystore/java/android/security/KeyNotYetValidException.java
@@ -19,8 +19,6 @@ package android.security;
/**
* Indicates that a cryptographic operation failed because the employed key's validity start date
* is in the future.
- *
- * @hide
*/
public class KeyNotYetValidException extends CryptoOperationException {
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index fce02df..5e5cf37 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -99,6 +99,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
private final int mUserAuthenticationValidityDurationSeconds;
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
+
/**
* Parameter specification for the "{@code AndroidKeyPairGenerator}"
* instance of the {@link java.security.KeyPairGenerator} API. The
@@ -144,7 +146,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
String[] blockModes,
boolean randomizedEncryptionRequired,
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
if (context == null) {
throw new IllegalArgumentException("context == null");
} else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -194,6 +197,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticators = userAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
}
/**
@@ -203,6 +207,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
Date startDate, Date endDate, int flags) {
+
this(context,
keyStoreAlias,
keyType,
@@ -223,7 +228,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
null, // block modes
false, // randomized encryption required
0, // user authenticators
- -1 // user authentication validity duration (seconds)
+ -1, // user authentication validity duration (seconds)
+ false // invalidate on new fingerprint enrolled
);
}
@@ -317,8 +323,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* Gets the time instant before which the key pair is not yet valid.
*
* @return instant or {@code null} if not restricted.
- *
- * @hide
*/
public Date getKeyValidityStart() {
return mKeyValidityStart;
@@ -329,8 +333,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* verification.
*
* @return instant or {@code null} if not restricted.
- *
- * @hide
*/
public Date getKeyValidityForConsumptionEnd() {
return mKeyValidityForConsumptionEnd;
@@ -340,8 +342,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* Gets the time instant after which the key pair is no longer valid for encryption and signing.
*
* @return instant or {@code null} if not restricted.
- *
- * @hide
*/
public Date getKeyValidityForOriginationEnd() {
return mKeyValidityForOriginationEnd;
@@ -349,8 +349,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of purposes for which the key can be used.
- *
- * @hide
*/
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
return mPurposes;
@@ -358,8 +356,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of digest algorithms with which the key can be used.
- *
- * @hide
*/
public String[] getDigests() {
return ArrayUtils.cloneIfNotEmpty(mDigests);
@@ -367,8 +363,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
- *
- * @hide
*/
public String[] getEncryptionPaddings() {
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
@@ -376,8 +370,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of padding schemes with which the key can be used when signing/verifying.
- *
- * @hide
*/
public String[] getSignaturePaddings() {
return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
@@ -385,8 +377,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of block modes with which the key can be used.
- *
- * @hide
*/
public String[] getBlockModes() {
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
@@ -400,8 +390,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* weaknesses due to which ciphertext may leak information about plaintext. For example, if a
* given plaintext always produces the same ciphertext, an attacker may see the repeated
* ciphertexts and be able to deduce something about the plaintext.
- *
- * @hide
*/
public boolean isRandomizedEncryptionRequired() {
return mRandomizedEncryptionRequired;
@@ -415,8 +403,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* restricted.
*
* @return user authenticators or {@code 0} if the key can be used without user authentication.
- *
- * @hide
*/
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
return mUserAuthenticators;
@@ -431,14 +417,23 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
*
* @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
* is required for every use of the key.
- *
- * @hide
*/
public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
/**
+ * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
+
+ /**
* Builder class for {@link KeyPairGeneratorSpec} objects.
* <p>
* This will build a parameter spec for use with the <a href="{@docRoot}
@@ -502,6 +497,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private boolean mInvalidatedOnNewFingerprintEnrolled;
+
/**
* Creates a new instance of the {@code Builder} with the given
* {@code context}. The {@code context} passed in may be used to pop up
@@ -649,8 +646,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityStart(Date startDate) {
mKeyValidityStart = startDate;
@@ -665,8 +660,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
* @see #setKeyValidityForOriginationEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityEnd(Date endDate) {
setKeyValidityForOriginationEnd(endDate);
@@ -680,8 +673,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForConsumptionEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityForOriginationEnd(Date endDate) {
mKeyValidityForOriginationEnd = endDate;
@@ -695,8 +686,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForOriginationEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityForConsumptionEnd(Date endDate) {
mKeyValidityForConsumptionEnd = endDate;
@@ -707,8 +696,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* Sets the set of purposes for which the key can be used.
*
* <p>This must be specified for all keys. There is no default.
- *
- * @hide
*/
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
mPurposes = purposes;
@@ -720,8 +707,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* to use the key with any other digest will be rejected.
*
* <p>This must be specified for keys which are used for signing/verification.
- *
- * @hide
*/
public Builder setDigests(String... digests) {
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
@@ -734,8 +719,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* rejected.
*
* <p>This must be specified for keys which are used for encryption/decryption.
- *
- * @hide
*/
public Builder setEncryptionPaddings(String... paddings) {
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
@@ -748,8 +731,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* rejected.
*
* <p>This must be specified for RSA keys which are used for signing/verification.
- *
- * @hide
*/
public Builder setSignaturePaddings(String... paddings) {
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
@@ -761,8 +742,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* Attempts to use the key with any other block modes will be rejected.
*
* <p>This must be specified for encryption/decryption keys.
- *
- * @hide
*/
public Builder setBlockModes(String... blockModes) {
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
@@ -788,8 +767,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* <li>If you are using RSA encryption without padding, consider switching to padding
* schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
* </ul>
- *
- * @hide
*/
public Builder setRandomizedEncryptionRequired(boolean required) {
mRandomizedEncryptionRequired = required;
@@ -809,8 +786,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* without user authentication.
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
- *
- * @hide
*/
public Builder setUserAuthenticators(
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
@@ -831,8 +806,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* every use of the key.
*
* @see #setUserAuthenticators(int)
- *
- * @hide
*/
public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
mUserAuthenticationValidityDurationSeconds = seconds;
@@ -840,6 +813,20 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
}
/**
+ * Sets whether this key must be invalidated (permanently) once a new fingerprint is
+ * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+ * protecting access to the key.
+ *
+ * <p>By default, enrolling a new fingerprint does not invalidate the key.
+ *
+ * @see #setUserAuthenticators(Set)
+ */
+ public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+ mInvalidatedOnNewFingerprintEnrolled = invalidated;
+ return this;
+ }
+
+ /**
* Builds the instance of the {@code KeyPairGeneratorSpec}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -866,7 +853,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticators,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mInvalidatedOnNewFingerprintEnrolled);
}
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 84a664e..5af0527 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -552,6 +552,9 @@ public class KeyStore {
return new KeyNotYetValidException();
case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
return new UserNotAuthenticatedException();
+ // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
+ // case KeymasterDefs.KM_ERROR_TBD
+ // return new NewFingerprintEnrolledException();
default:
return new CryptoOperationException("Crypto operation failed", e);
}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index 87e7ee6..72c485a 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -133,7 +133,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
throw new IllegalStateException("Digest algorithm must be specified for HMAC key");
}
}
- int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
+ int keySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits;
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
@KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes();
int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
@@ -168,6 +168,10 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
spec.getUserAuthenticators()));
}
+ if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
+ // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+ // that.
+ }
if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
spec.getUserAuthenticationValidityDurationSeconds());
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
index 1077af4..a0faf88 100644
--- a/keystore/java/android/security/KeyStoreKeyProperties.java
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -27,8 +27,6 @@ import java.util.Collection;
/**
* Properties of {@code AndroidKeyStore} keys.
- *
- * @hide
*/
public abstract class KeyStoreKeyProperties {
private KeyStoreKeyProperties() {}
@@ -125,7 +123,7 @@ public abstract class KeyStoreKeyProperties {
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true,
- value = {UserAuthenticator.LOCK_SCREEN})
+ value = {UserAuthenticator.LOCK_SCREEN, UserAuthenticator.FINGERPRINT_READER})
public @interface UserAuthenticatorEnum {}
/**
@@ -137,6 +135,9 @@ public abstract class KeyStoreKeyProperties {
/** Lock screen. */
public static final int LOCK_SCREEN = 1 << 0;
+ /** Fingerprint reader/sensor. */
+ public static final int FINGERPRINT_READER = 1 << 1;
+
/**
* @hide
*/
@@ -144,6 +145,8 @@ public abstract class KeyStoreKeyProperties {
switch (userAuthenticator) {
case LOCK_SCREEN:
return KeymasterDefs.HW_AUTH_PASSWORD;
+ case FINGERPRINT_READER:
+ return KeymasterDefs.HW_AUTH_FINGERPRINT;
default:
throw new IllegalArgumentException(
"Unknown user authenticator: " + userAuthenticator);
@@ -157,6 +160,8 @@ public abstract class KeyStoreKeyProperties {
switch (userAuthenticator) {
case KeymasterDefs.HW_AUTH_PASSWORD:
return LOCK_SCREEN;
+ case KeymasterDefs.HW_AUTH_FINGERPRINT:
+ return FINGERPRINT_READER;
default:
throw new IllegalArgumentException(
"Unknown user authenticator: " + userAuthenticator);
@@ -202,6 +207,8 @@ public abstract class KeyStoreKeyProperties {
switch (userAuthenticator) {
case LOCK_SCREEN:
return "LOCK_SCREEN";
+ case FINGERPRINT_READER:
+ return "FINGERPRINT_READER";
default:
throw new IllegalArgumentException(
"Unknown user authenticator: " + userAuthenticator);
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index 861ed34..a89e4dd 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -22,8 +22,6 @@ import java.util.Date;
/**
* Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
* KeyStore</a>.
- *
- * @hide
*/
public class KeyStoreKeySpec implements KeySpec {
private final String mKeystoreAlias;
@@ -41,7 +39,7 @@ public class KeyStoreKeySpec implements KeySpec {
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
private final int mUserAuthenticationValidityDurationSeconds;
-
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
/**
* @hide
@@ -60,7 +58,8 @@ public class KeyStoreKeySpec implements KeySpec {
String[] blockModes,
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
@KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
mKeystoreAlias = keystoreKeyAlias;
mTeeBacked = teeBacked;
mOrigin = origin;
@@ -78,6 +77,7 @@ public class KeyStoreKeySpec implements KeySpec {
mUserAuthenticators = userAuthenticators;
mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
}
/**
@@ -200,4 +200,15 @@ public class KeyStoreKeySpec implements KeySpec {
public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
+
+ /**
+ * Returns {@code true} if this key will be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
}
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 9fce177..c24b74f 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -51,6 +51,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
private final boolean mRandomizedEncryptionRequired;
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
private final int mUserAuthenticationValidityDurationSeconds;
+ private final boolean mInvalidatedOnNewFingerprintEnrolled;
private KeyStoreParameter(int flags,
Date keyValidityStart,
@@ -63,7 +64,8 @@ public final class KeyStoreParameter implements ProtectionParameter {
String[] blockModes,
boolean randomizedEncryptionRequired,
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
- int userAuthenticationValidityDurationSeconds) {
+ int userAuthenticationValidityDurationSeconds,
+ boolean invalidatedOnNewFingerprintEnrolled) {
if ((userAuthenticationValidityDurationSeconds < 0)
&& (userAuthenticationValidityDurationSeconds != -1)) {
throw new IllegalArgumentException(
@@ -84,6 +86,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
mUserAuthenticators = userAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+ mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
}
/**
@@ -105,7 +108,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* Gets the time instant before which the key is not yet valid.
*
* @return instant or {@code null} if not restricted.
- * @hide
*/
public Date getKeyValidityStart() {
return mKeyValidityStart;
@@ -115,8 +117,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* Gets the time instant after which the key is no long valid for decryption and verification.
*
* @return instant or {@code null} if not restricted.
- *
- * @hide
*/
public Date getKeyValidityForConsumptionEnd() {
return mKeyValidityForConsumptionEnd;
@@ -126,8 +126,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* Gets the time instant after which the key is no long valid for encryption and signing.
*
* @return instant or {@code null} if not restricted.
- *
- * @hide
*/
public Date getKeyValidityForOriginationEnd() {
return mKeyValidityForOriginationEnd;
@@ -135,8 +133,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Gets the set of purposes for which the key can be used.
- *
- * @hide
*/
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
return mPurposes;
@@ -144,8 +140,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
- *
- * @hide
*/
public String[] getEncryptionPaddings() {
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
@@ -154,8 +148,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Gets the set of padding schemes with which the key can be used when signing or verifying
* signatures.
- *
- * @hide
*/
public String[] getSignaturePaddings() {
return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
@@ -167,8 +159,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* @throws IllegalStateException if this set has not been specified.
*
* @see #isDigestsSpecified()
- *
- * @hide
*/
public String[] getDigests() {
if (mDigests == null) {
@@ -182,8 +172,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* specified.
*
* @see #getDigests()
- *
- * @hide
*/
public boolean isDigestsSpecified() {
return mDigests != null;
@@ -191,8 +179,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Gets the set of block modes with which the key can be used.
- *
- * @hide
*/
public String[] getBlockModes() {
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
@@ -206,8 +192,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* weaknesses due to which ciphertext may leak information about plaintext. For example, if a
* given plaintext always produces the same ciphertext, an attacker may see the repeated
* ciphertexts and be able to deduce something about the plaintext.
- *
- * @hide
*/
public boolean isRandomizedEncryptionRequired() {
return mRandomizedEncryptionRequired;
@@ -218,8 +202,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* used iff the user has authenticated to at least one of these user authenticators.
*
* @return user authenticators or {@code 0} if the key can be used without user authentication.
- *
- * @hide
*/
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
return mUserAuthenticators;
@@ -231,14 +213,23 @@ public final class KeyStoreParameter implements ProtectionParameter {
*
* @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
* is required for every use of the key.
- *
- * @hide
*/
public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
/**
+ * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+ * enrolled. This constraint only has effect if fingerprint reader is one of the user
+ * authenticators protecting access to this key.
+ *
+ * @see #getUserAuthenticators()
+ */
+ public boolean isInvalidatedOnNewFingerprintEnrolled() {
+ return mInvalidatedOnNewFingerprintEnrolled;
+ }
+
+ /**
* Builder class for {@link KeyStoreParameter} objects.
* <p>
* This will build protection parameters for use with the
@@ -268,6 +259,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
private boolean mRandomizedEncryptionRequired = true;
private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
private int mUserAuthenticationValidityDurationSeconds = -1;
+ private boolean mInvalidatedOnNewFingerprintEnrolled;
/**
* Creates a new instance of the {@code Builder} with the given
@@ -304,8 +296,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityStart(Date startDate) {
mKeyValidityStart = startDate;
@@ -320,8 +310,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
* @see #setKeyValidityForOriginationEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityEnd(Date endDate) {
setKeyValidityForOriginationEnd(endDate);
@@ -335,8 +323,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForConsumptionEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityForOriginationEnd(Date endDate) {
mKeyValidityForOriginationEnd = endDate;
@@ -350,8 +336,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForOriginationEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityForConsumptionEnd(Date endDate) {
mKeyValidityForConsumptionEnd = endDate;
@@ -362,8 +346,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* Sets the set of purposes for which the key can be used.
*
* <p>This must be specified for all keys. There is no default.
- *
- * @hide
*/
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
mPurposes = purposes;
@@ -376,8 +358,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* rejected.
*
* <p>This must be specified for keys which are used for encryption/decryption.
- *
- * @hide
*/
public Builder setEncryptionPaddings(String... paddings) {
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
@@ -390,8 +370,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* rejected.
*
* <p>This must be specified for RSA keys which are used for signing/verification.
- *
- * @hide
*/
public Builder setSignaturePaddings(String... paddings) {
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
@@ -405,8 +383,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
*
* <p>For HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()}. For
* asymmetric signing keys this constraint must be specified.
- *
- * @hide
*/
public Builder setDigests(String... digests) {
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
@@ -418,8 +394,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* Attempts to use the key with any other block modes will be rejected.
*
* <p>This must be specified for encryption/decryption keys.
- *
- * @hide
*/
public Builder setBlockModes(String... blockModes) {
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
@@ -459,8 +433,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* <li>If you are using RSA encryption without padding, consider switching to padding
* schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
* </ul>
- *
- * @hide
*/
public Builder setRandomizedEncryptionRequired(boolean required) {
mRandomizedEncryptionRequired = required;
@@ -477,8 +449,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* without user authentication.
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
- *
- * @hide
*/
public Builder setUserAuthenticators(
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
@@ -496,8 +466,6 @@ public final class KeyStoreParameter implements ProtectionParameter {
* every use of the key.
*
* @see #setUserAuthenticators(int)
- *
- * @hide
*/
public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
mUserAuthenticationValidityDurationSeconds = seconds;
@@ -505,6 +473,20 @@ public final class KeyStoreParameter implements ProtectionParameter {
}
/**
+ * Sets whether this key must be invalidated (permanently) whenever a new fingerprint is
+ * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+ * protecting access to the key.
+ *
+ * <p>By default, enrolling a new fingerprint does not invalidate the key.
+ *
+ * @see #setUserAuthenticators(Set)
+ */
+ public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+ mInvalidatedOnNewFingerprintEnrolled = invalidated;
+ return this;
+ }
+
+ /**
* Builds the instance of the {@code KeyStoreParameter}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -522,7 +504,8 @@ public final class KeyStoreParameter implements ProtectionParameter {
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticators,
- mUserAuthenticationValidityDurationSeconds);
+ mUserAuthenticationValidityDurationSeconds,
+ mInvalidatedOnNewFingerprintEnrolled);
}
}
}
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index 33073a4..4be0638 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -160,6 +160,9 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
int userAuthenticationValidityDurationSeconds =
keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
+ // TODO: Populate the value below from key characteristics once Keymaster is ready.
+ boolean invalidatedOnNewFingerprintEnrolled = false;
+
return new KeyStoreKeySpec(entryAlias,
teeBacked,
origin,
@@ -174,7 +177,8 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
blockModes,
userAuthenticators,
teeEnforcedUserAuthenticators,
- userAuthenticationValidityDurationSeconds);
+ userAuthenticationValidityDurationSeconds,
+ invalidatedOnNewFingerprintEnrolled);
}
@Override
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
new file mode 100644
index 0000000..806b214
--- /dev/null
+++ b/keystore/java/android/security/NewFingerprintEnrolledException.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the key used by the
+ * operation is permanently invalid because a new fingerprint was enrolled.
+ */
+public class NewFingerprintEnrolledException extends CryptoOperationException {
+
+ /**
+ * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
+ */
+ public NewFingerprintEnrolledException() {
+ super("Invalid key: new fingerprint enrolled");
+ }
+
+ /**
+ * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
+ * no cause.
+ */
+ public NewFingerprintEnrolledException(String message) {
+ super(message);
+ }
+}
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
index e6342ef..f5f5f41 100644
--- a/keystore/java/android/security/UserNotAuthenticatedException.java
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -19,8 +19,6 @@ package android.security;
/**
* Indicates that a cryptographic operation could not be performed because the user has not been
* authenticated recently enough.
- *
- * @hide
*/
public class UserNotAuthenticatedException extends CryptoOperationException {