Merge "New AndroidKeyStore API in android.security.keystore." into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index 948b68a..fac703e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28353,15 +28353,67 @@
     ctor public KeyChainException(java.lang.Throwable);
   }
 
+  public final deprecated class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method public android.content.Context getContext();
+    method public java.util.Date getEndDate();
+    method public int getKeySize();
+    method public java.lang.String getKeyType();
+    method public java.lang.String getKeystoreAlias();
+    method public java.math.BigInteger getSerialNumber();
+    method public java.util.Date getStartDate();
+    method public javax.security.auth.x500.X500Principal getSubjectDN();
+    method public boolean isEncryptionRequired();
+  }
+
+  public static final deprecated class KeyPairGeneratorSpec.Builder {
+    ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
+    method public android.security.KeyPairGeneratorSpec build();
+    method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+    method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
+    method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
+    method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
+    method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+  }
+
+  public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
+    method public android.content.Context getContext();
+    method public boolean isEncryptionRequired();
+  }
+
+  public static final deprecated class KeyStoreParameter.Builder {
+    ctor public KeyStoreParameter.Builder(android.content.Context);
+    method public android.security.KeyStoreParameter build();
+    method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
+  }
+
+  public class NetworkSecurityPolicy {
+    method public static android.security.NetworkSecurityPolicy getInstance();
+    method public boolean isCleartextTrafficPermitted();
+  }
+
+}
+
+package android.security.keystore {
+
   public class KeyExpiredException extends java.security.InvalidKeyException {
     ctor public KeyExpiredException();
     ctor public KeyExpiredException(java.lang.String);
     ctor public KeyExpiredException(java.lang.String, java.lang.Throwable);
   }
 
-  public class KeyGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+  public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
     method public java.lang.String[] getBlockModes();
-    method public android.content.Context getContext();
+    method public java.util.Date getCertificateNotAfter();
+    method public java.util.Date getCertificateNotBefore();
+    method public java.math.BigInteger getCertificateSerialNumber();
+    method public javax.security.auth.x500.X500Principal getCertificateSubject();
+    method public java.lang.String[] getDigests();
     method public java.lang.String[] getEncryptionPaddings();
     method public int getKeySize();
     method public java.util.Date getKeyValidityForConsumptionEnd();
@@ -28369,28 +28421,53 @@
     method public java.util.Date getKeyValidityStart();
     method public java.lang.String getKeystoreAlias();
     method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isEncryptionRequired();
+    method public boolean isDigestsSpecified();
+    method public boolean isEncryptionAtRestRequired();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
   }
 
-  public static class KeyGeneratorSpec.Builder {
-    ctor public KeyGeneratorSpec.Builder(android.content.Context);
-    method public android.security.KeyGeneratorSpec build();
-    method public android.security.KeyGeneratorSpec.Builder setAlias(java.lang.String);
-    method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...);
-    method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired();
-    method public android.security.KeyGeneratorSpec.Builder setKeySize(int);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setPurposes(int);
-    method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+  public static final class KeyGenParameterSpec.Builder {
+    ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
+    method public android.security.keystore.KeyGenParameterSpec build();
+    method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(java.math.BigInteger);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionAtRestRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+  }
+
+  public class KeyInfo implements java.security.spec.KeySpec {
+    method public java.lang.String[] getBlockModes();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public int getKeySize();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public java.lang.String getKeystoreAlias();
+    method public int getOrigin();
+    method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public boolean isInsideSecureHardware();
+    method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -28399,63 +28476,13 @@
     ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable);
   }
 
-  public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
-    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
-    method public java.lang.String[] getBlockModes();
-    method public android.content.Context getContext();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
-    method public java.util.Date getEndDate();
-    method public int getKeySize();
-    method public java.lang.String getKeyType();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
-    method public java.lang.String getKeystoreAlias();
-    method public int getPurposes();
-    method public java.math.BigInteger getSerialNumber();
-    method public java.lang.String[] getSignaturePaddings();
-    method public java.util.Date getStartDate();
-    method public javax.security.auth.x500.X500Principal getSubjectDN();
-    method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isEncryptionRequired();
-    method public boolean isRandomizedEncryptionRequired();
-    method public boolean isUserAuthenticationRequired();
-  }
-
-  public static final class KeyPairGeneratorSpec.Builder {
-    ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
-    method public android.security.KeyPairGeneratorSpec build();
-    method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
-    method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
-    method public android.security.KeyPairGeneratorSpec.Builder setBlockModes(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setDigests(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
-    method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setPurposes(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
-    method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
-    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-  }
-
   public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
     ctor public KeyPermanentlyInvalidatedException();
     ctor public KeyPermanentlyInvalidatedException(java.lang.String);
     ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
   }
 
-  public abstract class KeyStoreKeyProperties {
+  public abstract class KeyProperties {
     field public static final java.lang.String BLOCK_MODE_CBC = "CBC";
     field public static final java.lang.String BLOCK_MODE_CTR = "CTR";
     field public static final java.lang.String BLOCK_MODE_ECB = "ECB";
@@ -28490,29 +28517,10 @@
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
   }
 
-  public class KeyStoreKeySpec implements java.security.spec.KeySpec {
+  public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
     method public java.lang.String[] getBlockModes();
     method public java.lang.String[] getDigests();
     method public java.lang.String[] getEncryptionPaddings();
-    method public int getKeySize();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
-    method public java.lang.String getKeystoreAlias();
-    method public int getOrigin();
-    method public int getPurposes();
-    method public java.lang.String[] getSignaturePaddings();
-    method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isInsideSecureHardware();
-    method public boolean isUserAuthenticationRequired();
-    method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
-  }
-
-  public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
-    method public java.lang.String[] getBlockModes();
-    method public android.content.Context getContext();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
     method public java.util.Date getKeyValidityForConsumptionEnd();
     method public java.util.Date getKeyValidityForOriginationEnd();
     method public java.util.Date getKeyValidityStart();
@@ -28520,32 +28528,26 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
-    method public boolean isEncryptionRequired();
+    method public boolean isEncryptionAtRestRequired();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
   }
 
-  public static final class KeyStoreParameter.Builder {
-    ctor public KeyStoreParameter.Builder(android.content.Context);
-    method public android.security.KeyStoreParameter build();
-    method public android.security.KeyStoreParameter.Builder setBlockModes(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setPurposes(int);
-    method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int);
-  }
-
-  public class NetworkSecurityPolicy {
-    method public static android.security.NetworkSecurityPolicy getInstance();
-    method public boolean isCleartextTrafficPermitted();
+  public static final class KeyProtection.Builder {
+    ctor public KeyProtection.Builder(int);
+    method public android.security.keystore.KeyProtection build();
+    method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setEncryptionAtRestRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9ce9d2a..2318704 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30378,15 +30378,67 @@
     ctor public KeyChainException(java.lang.Throwable);
   }
 
+  public final deprecated class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
+    method public android.content.Context getContext();
+    method public java.util.Date getEndDate();
+    method public int getKeySize();
+    method public java.lang.String getKeyType();
+    method public java.lang.String getKeystoreAlias();
+    method public java.math.BigInteger getSerialNumber();
+    method public java.util.Date getStartDate();
+    method public javax.security.auth.x500.X500Principal getSubjectDN();
+    method public boolean isEncryptionRequired();
+  }
+
+  public static final deprecated class KeyPairGeneratorSpec.Builder {
+    ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
+    method public android.security.KeyPairGeneratorSpec build();
+    method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+    method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
+    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
+    method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
+    method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
+    method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
+    method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
+    method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
+  }
+
+  public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
+    method public android.content.Context getContext();
+    method public boolean isEncryptionRequired();
+  }
+
+  public static final deprecated class KeyStoreParameter.Builder {
+    ctor public KeyStoreParameter.Builder(android.content.Context);
+    method public android.security.KeyStoreParameter build();
+    method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
+  }
+
+  public class NetworkSecurityPolicy {
+    method public static android.security.NetworkSecurityPolicy getInstance();
+    method public boolean isCleartextTrafficPermitted();
+  }
+
+}
+
+package android.security.keystore {
+
   public class KeyExpiredException extends java.security.InvalidKeyException {
     ctor public KeyExpiredException();
     ctor public KeyExpiredException(java.lang.String);
     ctor public KeyExpiredException(java.lang.String, java.lang.Throwable);
   }
 
-  public class KeyGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+  public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
     method public java.lang.String[] getBlockModes();
-    method public android.content.Context getContext();
+    method public java.util.Date getCertificateNotAfter();
+    method public java.util.Date getCertificateNotBefore();
+    method public java.math.BigInteger getCertificateSerialNumber();
+    method public javax.security.auth.x500.X500Principal getCertificateSubject();
+    method public java.lang.String[] getDigests();
     method public java.lang.String[] getEncryptionPaddings();
     method public int getKeySize();
     method public java.util.Date getKeyValidityForConsumptionEnd();
@@ -30394,28 +30446,53 @@
     method public java.util.Date getKeyValidityStart();
     method public java.lang.String getKeystoreAlias();
     method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isEncryptionRequired();
+    method public boolean isDigestsSpecified();
+    method public boolean isEncryptionAtRestRequired();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
   }
 
-  public static class KeyGeneratorSpec.Builder {
-    ctor public KeyGeneratorSpec.Builder(android.content.Context);
-    method public android.security.KeyGeneratorSpec build();
-    method public android.security.KeyGeneratorSpec.Builder setAlias(java.lang.String);
-    method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...);
-    method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired();
-    method public android.security.KeyGeneratorSpec.Builder setKeySize(int);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.KeyGeneratorSpec.Builder setPurposes(int);
-    method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+  public static final class KeyGenParameterSpec.Builder {
+    ctor public KeyGenParameterSpec.Builder(java.lang.String, int);
+    method public android.security.keystore.KeyGenParameterSpec build();
+    method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(java.math.BigInteger);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionAtRestRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
+  }
+
+  public class KeyInfo implements java.security.spec.KeySpec {
+    method public java.lang.String[] getBlockModes();
+    method public java.lang.String[] getDigests();
+    method public java.lang.String[] getEncryptionPaddings();
+    method public int getKeySize();
+    method public java.util.Date getKeyValidityForConsumptionEnd();
+    method public java.util.Date getKeyValidityForOriginationEnd();
+    method public java.util.Date getKeyValidityStart();
+    method public java.lang.String getKeystoreAlias();
+    method public int getOrigin();
+    method public int getPurposes();
+    method public java.lang.String[] getSignaturePaddings();
+    method public int getUserAuthenticationValidityDurationSeconds();
+    method public boolean isInsideSecureHardware();
+    method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -30424,63 +30501,13 @@
     ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable);
   }
 
-  public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
-    method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec();
-    method public java.lang.String[] getBlockModes();
-    method public android.content.Context getContext();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
-    method public java.util.Date getEndDate();
-    method public int getKeySize();
-    method public java.lang.String getKeyType();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
-    method public java.lang.String getKeystoreAlias();
-    method public int getPurposes();
-    method public java.math.BigInteger getSerialNumber();
-    method public java.lang.String[] getSignaturePaddings();
-    method public java.util.Date getStartDate();
-    method public javax.security.auth.x500.X500Principal getSubjectDN();
-    method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isEncryptionRequired();
-    method public boolean isRandomizedEncryptionRequired();
-    method public boolean isUserAuthenticationRequired();
-  }
-
-  public static final class KeyPairGeneratorSpec.Builder {
-    ctor public KeyPairGeneratorSpec.Builder(android.content.Context);
-    method public android.security.KeyPairGeneratorSpec build();
-    method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec);
-    method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String);
-    method public android.security.KeyPairGeneratorSpec.Builder setBlockModes(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setDigests(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired();
-    method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException;
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setPurposes(int);
-    method public android.security.KeyPairGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger);
-    method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date);
-    method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal);
-    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
-  }
-
   public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
     ctor public KeyPermanentlyInvalidatedException();
     ctor public KeyPermanentlyInvalidatedException(java.lang.String);
     ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
   }
 
-  public abstract class KeyStoreKeyProperties {
+  public abstract class KeyProperties {
     field public static final java.lang.String BLOCK_MODE_CBC = "CBC";
     field public static final java.lang.String BLOCK_MODE_CTR = "CTR";
     field public static final java.lang.String BLOCK_MODE_ECB = "ECB";
@@ -30515,29 +30542,10 @@
     field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS";
   }
 
-  public class KeyStoreKeySpec implements java.security.spec.KeySpec {
+  public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
     method public java.lang.String[] getBlockModes();
     method public java.lang.String[] getDigests();
     method public java.lang.String[] getEncryptionPaddings();
-    method public int getKeySize();
-    method public java.util.Date getKeyValidityForConsumptionEnd();
-    method public java.util.Date getKeyValidityForOriginationEnd();
-    method public java.util.Date getKeyValidityStart();
-    method public java.lang.String getKeystoreAlias();
-    method public int getOrigin();
-    method public int getPurposes();
-    method public java.lang.String[] getSignaturePaddings();
-    method public int getUserAuthenticationValidityDurationSeconds();
-    method public boolean isInsideSecureHardware();
-    method public boolean isUserAuthenticationRequired();
-    method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
-  }
-
-  public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter {
-    method public java.lang.String[] getBlockModes();
-    method public android.content.Context getContext();
-    method public java.lang.String[] getDigests();
-    method public java.lang.String[] getEncryptionPaddings();
     method public java.util.Date getKeyValidityForConsumptionEnd();
     method public java.util.Date getKeyValidityForOriginationEnd();
     method public java.util.Date getKeyValidityStart();
@@ -30545,32 +30553,26 @@
     method public java.lang.String[] getSignaturePaddings();
     method public int getUserAuthenticationValidityDurationSeconds();
     method public boolean isDigestsSpecified();
-    method public boolean isEncryptionRequired();
+    method public boolean isEncryptionAtRestRequired();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
   }
 
-  public static final class KeyStoreParameter.Builder {
-    ctor public KeyStoreParameter.Builder(android.content.Context);
-    method public android.security.KeyStoreParameter build();
-    method public android.security.KeyStoreParameter.Builder setBlockModes(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setKeyValidityStart(java.util.Date);
-    method public android.security.KeyStoreParameter.Builder setPurposes(int);
-    method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...);
-    method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean);
-    method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int);
-  }
-
-  public class NetworkSecurityPolicy {
-    method public static android.security.NetworkSecurityPolicy getInstance();
-    method public boolean isCleartextTrafficPermitted();
+  public static final class KeyProtection.Builder {
+    ctor public KeyProtection.Builder(int);
+    method public android.security.keystore.KeyProtection build();
+    method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setEncryptionAtRestRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
+    method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index fea3b2c..4005a05 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -88,7 +88,7 @@
 <h3 id="GeneratingANewSecretKey">Generating a New Secret Key</h3>
 
 <p>To generate the key, use a {@link javax.crypto.KeyGenerator} with
-  {@link android.security.KeyGeneratorSpec}.
+  {@link android.security.keystore.KeyGenParameterSpec}.
 
 <h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3>
 
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
index ea90ca3..e9f8320 100644
--- a/keystore/java/android/security/AndroidKeyPairGenerator.java
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -16,6 +16,10 @@
 
 package android.security;
 
+import android.annotation.NonNull;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
 import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
 import com.android.org.conscrypt.NativeConstants;
 import com.android.org.conscrypt.OpenSSLEngine;
@@ -36,6 +40,7 @@
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.RSAKeyGenParameterSpec;
 import java.security.spec.X509EncodedKeySpec;
+import java.util.Locale;
 
 /**
  * Provides a way to create instances of a KeyPair which will be placed in the
@@ -54,13 +59,13 @@
 
     public static class RSA extends AndroidKeyPairGenerator {
         public RSA() {
-            super(KeyStoreKeyProperties.KEY_ALGORITHM_RSA);
+            super(KeyProperties.KEY_ALGORITHM_RSA);
         }
     }
 
     public static class EC extends AndroidKeyPairGenerator {
         public EC() {
-            super(KeyStoreKeyProperties.KEY_ALGORITHM_EC);
+            super(KeyProperties.KEY_ALGORITHM_EC);
         }
     }
 
@@ -80,18 +85,18 @@
 
     private final String mAlgorithm;
 
-    private android.security.KeyStore mKeyStore;
+    private KeyStore mKeyStore;
 
-    private KeyPairGeneratorSpec mSpec;
-    private @KeyStoreKeyProperties.KeyAlgorithmEnum String mKeyAlgorithm;
+    private KeyGenParameterSpec mSpec;
+    private @KeyProperties.KeyAlgorithmEnum String mKeyAlgorithm;
     private int mKeyType;
     private int mKeySize;
 
-    protected AndroidKeyPairGenerator(@KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) {
+    protected AndroidKeyPairGenerator(@KeyProperties.KeyAlgorithmEnum String algorithm) {
         mAlgorithm = algorithm;
     }
 
-    @KeyStoreKeyProperties.KeyAlgorithmEnum String getAlgorithm() {
+    @KeyProperties.KeyAlgorithmEnum String getAlgorithm() {
         return mAlgorithm;
     }
 
@@ -113,15 +118,16 @@
     @Override
     public KeyPair generateKeyPair() {
         if (mKeyStore == null || mSpec == null) {
-            throw new IllegalStateException(
-                    "Must call initialize with an android.security.KeyPairGeneratorSpec first");
+            throw new IllegalStateException("Not initialized");
+
         }
 
-        if (((mSpec.getFlags() & KeyStore.FLAG_ENCRYPTED) != 0)
+        final int flags = mSpec.getFlags();
+        if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
                 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
             throw new IllegalStateException(
-                    "Android keystore must be in initialized and unlocked state "
-                            + "if encryption is required");
+                    "Encryption at rest using secure lock screen credential requested for key pair"
+                    + ", but the user has not yet entered the credential");
         }
 
         final String alias = mSpec.getKeystoreAlias();
@@ -131,8 +137,9 @@
         byte[][] args = getArgsForKeyType(mKeyType, mSpec.getAlgorithmParameterSpec());
 
         final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+
         if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mKeyType, mKeySize,
-                mSpec.getFlags(), args)) {
+                flags, args)) {
             throw new IllegalStateException("could not generate key in keystore");
         }
 
@@ -175,7 +182,7 @@
         }
 
         if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes, KeyStore.UID_SELF,
-                mSpec.getFlags())) {
+                flags)) {
             Credentials.deleteAllTypesForAlias(mKeyStore, alias);
             throw new IllegalStateException("Can't store certificate in AndroidKeyStore");
         }
@@ -188,17 +195,17 @@
             throws Exception {
         final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
         certGen.setPublicKey(publicKey);
-        certGen.setSerialNumber(mSpec.getSerialNumber());
-        certGen.setSubjectDN(mSpec.getSubjectDN());
-        certGen.setIssuerDN(mSpec.getSubjectDN());
-        certGen.setNotBefore(mSpec.getStartDate());
-        certGen.setNotAfter(mSpec.getEndDate());
+        certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
+        certGen.setSubjectDN(mSpec.getCertificateSubject());
+        certGen.setIssuerDN(mSpec.getCertificateSubject());
+        certGen.setNotBefore(mSpec.getCertificateNotBefore());
+        certGen.setNotAfter(mSpec.getCertificateNotAfter());
         certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyAlgorithm(mKeyAlgorithm));
         return certGen.generate(privateKey);
     }
 
-    private @KeyStoreKeyProperties.KeyAlgorithmEnum String getKeyAlgorithm(
-            KeyPairGeneratorSpec spec) {
+    @NonNull
+    private @KeyProperties.KeyAlgorithmEnum String getKeyAlgorithm(KeyPairGeneratorSpec spec) {
         String result = spec.getKeyType();
         if (result != null) {
             return result;
@@ -250,10 +257,10 @@
     }
 
     private static String getDefaultSignatureAlgorithmForKeyAlgorithm(
-            @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) {
-        if (KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
+            @KeyProperties.KeyAlgorithmEnum String algorithm) {
+        if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
             return "sha256WithRSA";
-        } else if (KeyStoreKeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
+        } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
             return "sha256WithECDSA";
         } else {
             throw new IllegalArgumentException("Unsupported key type " + algorithm);
@@ -282,14 +289,86 @@
             throws InvalidAlgorithmParameterException {
         if (params == null) {
             throw new InvalidAlgorithmParameterException(
-                    "must supply params of type android.security.KeyPairGeneratorSpec");
-        } else if (!(params instanceof KeyPairGeneratorSpec)) {
-            throw new InvalidAlgorithmParameterException(
-                    "params must be of type android.security.KeyPairGeneratorSpec");
+                    "Must supply params of type " + KeyGenParameterSpec.class.getName()
+                    + " or " + KeyPairGeneratorSpec.class.getName());
         }
 
-        KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params;
-        @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithm = getKeyAlgorithm(spec);
+        String keyAlgorithm;
+        KeyGenParameterSpec spec;
+        if (params instanceof KeyPairGeneratorSpec) {
+            KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
+            try {
+                KeyGenParameterSpec.Builder specBuilder;
+                keyAlgorithm = getKeyAlgorithm(legacySpec).toUpperCase(Locale.US);
+                if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+                    specBuilder = new KeyGenParameterSpec.Builder(
+                            legacySpec.getKeystoreAlias(),
+                            KeyProperties.PURPOSE_SIGN
+                            | KeyProperties.PURPOSE_VERIFY);
+                    specBuilder.setDigests(
+                            KeyProperties.DIGEST_NONE,
+                            KeyProperties.DIGEST_MD5,
+                            KeyProperties.DIGEST_SHA1,
+                            KeyProperties.DIGEST_SHA224,
+                            KeyProperties.DIGEST_SHA256,
+                            KeyProperties.DIGEST_SHA384,
+                            KeyProperties.DIGEST_SHA512);
+                } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+                    specBuilder = new KeyGenParameterSpec.Builder(
+                            legacySpec.getKeystoreAlias(),
+                            KeyProperties.PURPOSE_ENCRYPT
+                            | KeyProperties.PURPOSE_DECRYPT
+                            | KeyProperties.PURPOSE_SIGN
+                            | KeyProperties.PURPOSE_VERIFY);
+                    specBuilder.setDigests(
+                            KeyProperties.DIGEST_NONE,
+                            KeyProperties.DIGEST_MD5,
+                            KeyProperties.DIGEST_SHA1,
+                            KeyProperties.DIGEST_SHA224,
+                            KeyProperties.DIGEST_SHA256,
+                            KeyProperties.DIGEST_SHA384,
+                            KeyProperties.DIGEST_SHA512);
+                    specBuilder.setSignaturePaddings(
+                            KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+                    specBuilder.setBlockModes(KeyProperties.BLOCK_MODE_ECB);
+                    specBuilder.setEncryptionPaddings(
+                            KeyProperties.ENCRYPTION_PADDING_NONE,
+                            KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+                    // Disable randomized encryption requirement to support encryption padding NONE
+                    // above.
+                    specBuilder.setRandomizedEncryptionRequired(false);
+                } else {
+                    throw new InvalidAlgorithmParameterException(
+                            "Unsupported key algorithm: " + keyAlgorithm);
+                }
+
+                if (legacySpec.getKeySize() != -1) {
+                    specBuilder.setKeySize(legacySpec.getKeySize());
+                }
+                if (legacySpec.getAlgorithmParameterSpec() != null) {
+                    specBuilder.setAlgorithmParameterSpec(legacySpec.getAlgorithmParameterSpec());
+                }
+                specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
+                specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
+                specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
+                specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
+                specBuilder.setEncryptionAtRestRequired(legacySpec.isEncryptionRequired());
+                specBuilder.setUserAuthenticationRequired(false);
+
+                spec = specBuilder.build();
+            } catch (NullPointerException | IllegalArgumentException e) {
+                throw new InvalidAlgorithmParameterException(e);
+            }
+        } else if (params instanceof KeyGenParameterSpec) {
+            spec = (KeyGenParameterSpec) params;
+            keyAlgorithm = getAlgorithm();
+        } else {
+            throw new InvalidAlgorithmParameterException(
+                    "Unsupported params class: " + params.getClass().getName()
+                    + ". Supported: " + KeyGenParameterSpec.class.getName()
+                    + ", " + KeyPairGeneratorSpec.class);
+        }
+
         int keyType = KeyStore.getKeyTypeForAlgorithm(keyAlgorithm);
         if (keyType == -1) {
             throw new InvalidAlgorithmParameterException(
@@ -300,7 +379,7 @@
             keySize = getDefaultKeySize(keyType);
             if (keySize == -1) {
                 throw new InvalidAlgorithmParameterException(
-                    "Unsupported key algorithm: " + keyAlgorithm);
+                        "Unsupported key algorithm: " + keyAlgorithm);
             }
         }
         checkCorrectParametersSpec(keyType, keySize, spec.getAlgorithmParameterSpec());
@@ -310,6 +389,6 @@
         mKeyType = keyType;
         mKeySize = keySize;
         mSpec = spec;
-        mKeyStore = android.security.KeyStore.getInstance();
+        mKeyStore = KeyStore.getInstance();
     }
 }
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index b834641..69bf877 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -24,6 +24,8 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
 import android.util.Log;
 
 import java.io.ByteArrayInputStream;
@@ -129,11 +131,10 @@
                 keymasterDigest = keymasterDigests.get(0);
             }
 
-            @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
+            @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
             try {
-                keyAlgorithmString =
-                        KeyStoreKeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
-                                keymasterAlgorithm, keymasterDigest);
+                keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
+                        keymasterAlgorithm, keymasterDigest);
             } catch (IllegalArgumentException e) {
                 throw (UnrecoverableKeyException)
                         new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
@@ -270,7 +271,70 @@
     }
 
     private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain,
-            KeyStoreParameter params) throws KeyStoreException {
+            java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
+        KeyProtection spec;
+        if (param instanceof KeyStoreParameter) {
+            KeyStoreParameter legacySpec = (KeyStoreParameter) param;
+            try {
+                String keyAlgorithm = key.getAlgorithm();
+                KeyProtection.Builder specBuilder;
+                if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+                    specBuilder =
+                            new KeyProtection.Builder(
+                                    KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
+                    specBuilder.setDigests(
+                            KeyProperties.DIGEST_NONE,
+                            KeyProperties.DIGEST_MD5,
+                            KeyProperties.DIGEST_SHA1,
+                            KeyProperties.DIGEST_SHA224,
+                            KeyProperties.DIGEST_SHA256,
+                            KeyProperties.DIGEST_SHA384,
+                            KeyProperties.DIGEST_SHA512);
+                } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+                    specBuilder =
+                            new KeyProtection.Builder(
+                                    KeyProperties.PURPOSE_ENCRYPT
+                                    | KeyProperties.PURPOSE_DECRYPT
+                                    | KeyProperties.PURPOSE_SIGN
+                                    | KeyProperties.PURPOSE_VERIFY);
+                    specBuilder.setDigests(
+                            KeyProperties.DIGEST_NONE,
+                            KeyProperties.DIGEST_MD5,
+                            KeyProperties.DIGEST_SHA1,
+                            KeyProperties.DIGEST_SHA224,
+                            KeyProperties.DIGEST_SHA256,
+                            KeyProperties.DIGEST_SHA384,
+                            KeyProperties.DIGEST_SHA512);
+                    specBuilder.setSignaturePaddings(
+                            KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+                    specBuilder.setBlockModes(KeyProperties.BLOCK_MODE_ECB);
+                    specBuilder.setEncryptionPaddings(
+                            KeyProperties.ENCRYPTION_PADDING_NONE,
+                            KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+                    // Disable randomized encryption requirement to support encryption padding NONE
+                    // above.
+                    specBuilder.setRandomizedEncryptionRequired(false);
+                } else {
+                    throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm);
+                }
+                specBuilder.setEncryptionAtRestRequired(legacySpec.isEncryptionRequired());
+                specBuilder.setUserAuthenticationRequired(false);
+
+                spec = specBuilder.build();
+            } catch (NullPointerException | IllegalArgumentException e) {
+                throw new KeyStoreException("Unsupported protection parameter", e);
+            }
+        } else if (param instanceof KeyProtection) {
+            spec = (KeyProtection) param;
+        } else if (param != null) {
+            throw new KeyStoreException(
+                    "Unsupported protection parameter class:" + param.getClass().getName()
+                    + ". Supported: " + KeyStoreParameter.class.getName() + ", "
+                    + KeyProtection.class.getName());
+        } else {
+            spec = null;
+        }
+
         byte[] keyBytes = null;
 
         final String pkeyAlias;
@@ -383,7 +447,7 @@
             Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias);
         }
 
-        final int flags = (params == null) ? 0 : params.getFlags();
+        final int flags = (spec == null) ? 0 : spec.getFlags();
 
         if (shouldReplacePrivateKey
                 && !mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes,
@@ -402,8 +466,16 @@
         }
     }
 
-    private void setSecretKeyEntry(String entryAlias, SecretKey key, KeyStoreParameter params)
+    private void setSecretKeyEntry(String entryAlias, SecretKey key,
+            java.security.KeyStore.ProtectionParameter param)
             throws KeyStoreException {
+        if ((param != null) && (!(param instanceof KeyProtection))) {
+            throw new KeyStoreException(
+                    "Unsupported protection parameter class: " + param.getClass().getName()
+                    + ". Supported: " + KeyProtection.class.getName());
+        }
+        KeyProtection params = (KeyProtection) param;
+
         if (key instanceof KeyStoreSecretKey) {
             // KeyStore-backed secret key. It cannot be duplicated into another entry and cannot
             // overwrite its own entry.
@@ -453,10 +525,9 @@
         int keymasterAlgorithm;
         int keymasterDigest;
         try {
-            keymasterAlgorithm = KeyStoreKeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(
-                    keyAlgorithmString);
-            keymasterDigest =
-                    KeyStoreKeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString);
+            keymasterAlgorithm =
+                    KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(keyAlgorithmString);
+            keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString);
         } catch (IllegalArgumentException e) {
             throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
         }
@@ -467,7 +538,7 @@
         int[] keymasterDigests;
         if (params.isDigestsSpecified()) {
             // Digest(s) specified in parameters
-            keymasterDigests = KeyStoreKeyProperties.Digest.allToKeymaster(params.getDigests());
+            keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
             if (keymasterDigest != -1) {
                 // Digest also specified in the JCA key algorithm name.
                 if (!com.android.internal.util.ArrayUtils.contains(
@@ -509,33 +580,32 @@
             }
         }
 
-        @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes();
+        @KeyProperties.PurposeEnum int purposes = params.getPurposes();
         int[] keymasterBlockModes =
-                KeyStoreKeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
-        if (((purposes & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0)
+                KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
+        if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
                 && (params.isRandomizedEncryptionRequired())) {
             for (int keymasterBlockMode : keymasterBlockModes) {
                 if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
                     throw new KeyStoreException(
                             "Randomized encryption (IND-CPA) required but may be violated by block"
                             + " mode: "
-                            + KeyStoreKeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
-                            + ". See KeyStoreParameter documentation.");
+                            + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
+                            + ". See KeyProtection documentation.");
                 }
             }
         }
-        for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
+        for (int keymasterPurpose : KeyProperties.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
         args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
         if (params.getSignaturePaddings().length > 0) {
             throw new KeyStoreException("Signature paddings not supported for symmetric keys");
         }
-        int[] keymasterPaddings = KeyStoreKeyProperties.EncryptionPadding.allToKeymaster(
+        int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
                 params.getEncryptionPaddings());
         args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
         KeymasterUtils.addUserAuthArgs(args,
-                params.getContext(),
                 params.isUserAuthenticationRequired(),
                 params.getUserAuthenticationValidityDurationSeconds());
         args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
@@ -551,7 +621,7 @@
         // TODO: Remove this once keymaster does not require us to specify the size of imported key.
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
 
-        if (((purposes & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0)
+        if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
                 && (!params.isRandomizedEncryptionRequired())) {
             // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
@@ -789,19 +859,12 @@
             return;
         }
 
-        if (param != null && !(param instanceof KeyStoreParameter)) {
-            throw new KeyStoreException(
-                    "protParam should be android.security.KeyStoreParameter; was: "
-                    + param.getClass().getName());
-        }
-
         if (entry instanceof PrivateKeyEntry) {
             PrivateKeyEntry prE = (PrivateKeyEntry) entry;
-            setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(),
-                    (KeyStoreParameter) param);
+            setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), param);
         } else if (entry instanceof SecretKeyEntry) {
             SecretKeyEntry secE = (SecretKeyEntry) entry;
-            setSecretKeyEntry(alias, secE.getSecretKey(), (KeyStoreParameter) param);
+            setSecretKeyEntry(alias, secE.getSecretKey(), param);
         } else {
             throw new KeyStoreException(
                     "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
diff --git a/keystore/java/android/security/ArrayUtils.java b/keystore/java/android/security/ArrayUtils.java
index 2047d3f..71b99d0 100644
--- a/keystore/java/android/security/ArrayUtils.java
+++ b/keystore/java/android/security/ArrayUtils.java
@@ -5,7 +5,7 @@
 /**
  * @hide
  */
-abstract class ArrayUtils {
+public abstract class ArrayUtils {
     private ArrayUtils() {}
 
     public static String[] nullToEmpty(String[] array) {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 3853eca..19b62a6 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -28,6 +28,8 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.security.keystore.KeyProperties;
+
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.security.InvalidKeyException;
@@ -266,7 +268,7 @@
      */
     public static void choosePrivateKeyAlias(@NonNull Activity activity,
             @NonNull KeyChainAliasCallback response,
-            @KeyStoreKeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers,
+            @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers,
             @Nullable String host, int port, @Nullable String alias) {
         choosePrivateKeyAlias(activity, response, keyTypes, issuers, host, port, null, alias);
     }
@@ -312,7 +314,7 @@
      */
     public static void choosePrivateKeyAlias(@NonNull Activity activity,
             @NonNull KeyChainAliasCallback response,
-            @KeyStoreKeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers,
+            @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers,
             @Nullable String host, int port, @Nullable String url, @Nullable String alias) {
         /*
          * TODO currently keyTypes, issuers are unused. They are meant
@@ -439,10 +441,10 @@
      * "RSA").
      */
     public static boolean isKeyAlgorithmSupported(
-            @NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) {
+            @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) {
         final String algUpper = algorithm.toUpperCase(Locale.US);
-        return KeyStoreKeyProperties.KEY_ALGORITHM_EC.equals(algUpper)
-                || KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equals(algUpper);
+        return KeyProperties.KEY_ALGORITHM_EC.equals(algUpper)
+                || KeyProperties.KEY_ALGORITHM_RSA.equals(algUpper);
     }
 
     /**
@@ -453,7 +455,7 @@
      * that makes it non-exportable.
      */
     public static boolean isBoundKeyAlgorithm(
-            @NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) {
+            @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) {
         if (!isKeyAlgorithmSupported(algorithm)) {
             return false;
         }
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
deleted file mode 100644
index e63566b..0000000
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * 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;
-
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.KeyguardManager;
-import android.content.Context;
-import android.text.TextUtils;
-
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Date;
-
-import javax.crypto.Cipher;
-import javax.crypto.KeyGenerator;
-
-/**
- * {@link AlgorithmParameterSpec} for initializing a {@link KeyGenerator} of the
- * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class
- * specifies whether user authentication is required for using the key, what uses the key is
- * authorized for (e.g., only in {@code CBC} mode), whether the key should be encrypted at rest, the
- * key's and validity start and end dates.
- *
- * <p>To generate a key, create an instance of this class using the {@link Builder}, initialize a
- * {@code KeyGenerator} of the desired key type (e.g., {@code AES} or {@code HmacSHA256}) from the
- * {@code AndroidKeyStore} provider with the {@code KeyGeneratorSpec} instance, and then generate a
- * key using {@link KeyGenerator#generateKey()}.
- *
- * <p>The generated key will be returned by the {@code KeyGenerator} and also stored in the Android
- * KeyStore under the alias specified in this {@code KeyGeneratorSpec}. To obtain the key from the
- * Android KeyStore use
- * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or
- * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}.
- *
- * <p>NOTE: The key material of the keys generating using the {@code KeyGeneratorSpec} is not
- * accessible.
- *
- * <p><h3>Example</h3>
- * The following example illustrates how to generate an HMAC key in the Android KeyStore under alias
- * {@code key1} authorized to be used only for HMAC with SHA-256 digest and only if the user has
- * been authenticated within the last five minutes.
- * <pre> {@code
- * KeyGenerator keyGenerator = KeyGenerator.getInstance(
- *         KeyStoreKeyProperties.KEY_ALGORITHM_HMAC_SHA256,
- *         "AndroidKeyStore");
- * keyGenerator.initialize(
- *         new KeyGeneratorSpec.Builder(context)
- *                 .setAlias("key1")
- *                 .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN
- *                         | KeyStoreKeyProperties.PURPOSE_VERIFY)
- *                 // Only permit this key to be used if the user authenticated
- *                 // within the last five minutes.
- *                 .setUserAuthenticationRequired(true)
- *                 .setUserAuthenticationValidityDurationSeconds(5 * 60)
- *                 .build());
- * SecretKey key = keyGenerator.generateKey();
- *
- * // The key can also be obtained from the Android KeyStore any time as follows:
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * SecretKey key = (SecretKey) keyStore.getKey("key1", null);
- * }</pre>
- */
-public class KeyGeneratorSpec implements AlgorithmParameterSpec {
-
-    private final Context mContext;
-    private final String mKeystoreAlias;
-    private final int mFlags;
-    private final int mKeySize;
-    private final Date mKeyValidityStart;
-    private final Date mKeyValidityForOriginationEnd;
-    private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-    private final @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
-    private final boolean mRandomizedEncryptionRequired;
-    private final boolean mUserAuthenticationRequired;
-    private final int mUserAuthenticationValidityDurationSeconds;
-
-    private KeyGeneratorSpec(
-            Context context,
-            String keyStoreAlias,
-            int flags,
-            int keySize,
-            Date keyValidityStart,
-            Date keyValidityForOriginationEnd,
-            Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyProperties.PurposeEnum int purposes,
-            @KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
-            @KeyStoreKeyProperties.BlockModeEnum String[] blockModes,
-            boolean randomizedEncryptionRequired,
-            boolean userAuthenticationRequired,
-            int userAuthenticationValidityDurationSeconds) {
-        if (context == null) {
-            throw new IllegalArgumentException("context == null");
-        } else if (TextUtils.isEmpty(keyStoreAlias)) {
-            throw new IllegalArgumentException("keyStoreAlias must not be empty");
-        } else if ((userAuthenticationValidityDurationSeconds < 0)
-                && (userAuthenticationValidityDurationSeconds != -1)) {
-            throw new IllegalArgumentException(
-                    "userAuthenticationValidityDurationSeconds must not be negative");
-        }
-
-        mContext = context;
-        mKeystoreAlias = keyStoreAlias;
-        mFlags = flags;
-        mKeySize = keySize;
-        mKeyValidityStart = keyValidityStart;
-        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
-        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
-        mPurposes = purposes;
-        mEncryptionPaddings =
-                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
-        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
-        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
-        mUserAuthenticationRequired = userAuthenticationRequired;
-        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-    }
-
-    /**
-     * Gets the Android context used for operations with this instance.
-     */
-    public Context getContext() {
-        return mContext;
-    }
-
-    /**
-     * Returns the alias that will be used in the {@code java.security.KeyStore} in conjunction with
-     * the {@code AndroidKeyStore}.
-     */
-    public String getKeystoreAlias() {
-        return mKeystoreAlias;
-    }
-
-    /**
-     * @hide
-     */
-    public int getFlags() {
-        return mFlags;
-    }
-
-    /**
-     * Returns the requested key size or {@code -1} if default size should be used.
-     */
-    public int getKeySize() {
-        return mKeySize;
-    }
-
-    /**
-     * Gets the time instant before which the key is not yet valid.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityStart() {
-        return mKeyValidityStart;
-    }
-
-    /**
-     * Gets the time instant after which the key is no longer valid for decryption and verification.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityForConsumptionEnd() {
-        return mKeyValidityForConsumptionEnd;
-    }
-
-    /**
-     * Gets the time instant after which the key is no longer valid for encryption and signing.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityForOriginationEnd() {
-        return mKeyValidityForOriginationEnd;
-    }
-
-    /**
-     * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
-     * Attempts to use the key for any other purpose will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
-     */
-    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
-        return mPurposes;
-    }
-
-    /**
-     * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code NoPadding}) with
-     * which the key can be used when encrypting/decrypting. Attempts to use the key with any
-     * other padding scheme will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
-        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
-    }
-
-    /**
-     * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used
-     * when encrypting/decrypting. Attempts to use the key with any other block modes will be
-     * rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() {
-        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
-    }
-
-    /**
-     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
-     * different ciphertexts for the same plaintext every time. The formal cryptographic property
-     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
-     * IND-CPA})</em>. This property is important because it mitigates several classes of
-     * 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.
-     */
-    public boolean isRandomizedEncryptionRequired() {
-        return mRandomizedEncryptionRequired;
-    }
-
-    /**
-     * Returns {@code true} if user authentication is required for this key to be used.
-     *
-     * @see #getUserAuthenticationValidityDurationSeconds()
-     */
-    public boolean isUserAuthenticationRequired() {
-        return mUserAuthenticationRequired;
-    }
-
-    /**
-     * Gets the duration of time (seconds) for which this key can be used after the user is
-     * successfully authenticated. This has effect only if user authentication is required.
-     *
-     * @return duration in seconds or {@code -1} if authentication is required for every use of the
-     *         key.
-     *
-     * @see #isUserAuthenticationRequired()
-     */
-    public int getUserAuthenticationValidityDurationSeconds() {
-        return mUserAuthenticationValidityDurationSeconds;
-    }
-
-    /**
-     * Returns {@code true} if the key must be encrypted at rest. This will protect the key with the
-     * secure lock screen credential (e.g., password, PIN, or pattern).
-     */
-    public boolean isEncryptionRequired() {
-        return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
-    }
-
-    public static class Builder {
-        private final Context mContext;
-        private String mKeystoreAlias;
-        private int mFlags;
-        private int mKeySize = -1;
-        private Date mKeyValidityStart;
-        private Date mKeyValidityForOriginationEnd;
-        private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-        private @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-        private @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
-        private boolean mRandomizedEncryptionRequired = true;
-        private boolean mUserAuthenticationRequired;
-        private int mUserAuthenticationValidityDurationSeconds = -1;
-
-        /**
-         * Creates a new instance of the {@code Builder} with the given {@code context}. The
-         * {@code context} passed in may be used to pop up some UI to ask the user to unlock or
-         * initialize the Android KeyStore facility.
-         */
-        public Builder(@NonNull Context context) {
-            if (context == null) {
-                throw new NullPointerException("context == null");
-            }
-            mContext = context;
-        }
-
-        /**
-         * Sets the alias to be used to retrieve the key later from a {@link java.security.KeyStore}
-         * instance using the {@code AndroidKeyStore} provider.
-         *
-         * <p>The alias must be provided. There is no default.
-         */
-        @NonNull
-        public Builder setAlias(@NonNull String alias) {
-            if (alias == null) {
-                throw new NullPointerException("alias == null");
-            }
-            mKeystoreAlias = alias;
-            return this;
-        }
-
-        /**
-         * Sets the size (in bits) of the key to be generated.
-         *
-         * <p>By default, the key size will be determines based on the key algorithm. For example,
-         * for {@code HmacSHA256}, the key size will default to {@code 256}.
-         */
-        @NonNull
-        public Builder setKeySize(int keySize) {
-            mKeySize = keySize;
-            return this;
-        }
-
-        /**
-         * Indicates that this key must be encrypted at rest. This will protect the key with the
-         * secure lock screen credential (e.g., password, PIN, or pattern).
-         *
-         * <p>Note that this feature requires that the secure lock screen (e.g., password, PIN,
-         * pattern) is set up, otherwise key generation will fail. Moreover, this key will be
-         * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device
-         * Administrator). Finally, this key cannot be used until the user unlocks the secure lock
-         * screen after boot.
-         *
-         * @see KeyguardManager#isDeviceSecure()
-         */
-        @NonNull
-        public Builder setEncryptionRequired() {
-            mFlags |= KeyStore.FLAG_ENCRYPTED;
-            return this;
-        }
-
-        /**
-         * Sets the time instant before which the key is not yet valid.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * @see #setKeyValidityEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityStart(Date startDate) {
-            mKeyValidityStart = startDate;
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * @see #setKeyValidityStart(Date)
-         * @see #setKeyValidityForConsumptionEnd(Date)
-         * @see #setKeyValidityForOriginationEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityEnd(Date endDate) {
-            setKeyValidityForOriginationEnd(endDate);
-            setKeyValidityForConsumptionEnd(endDate);
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid for encryption and signing.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * @see #setKeyValidityForConsumptionEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityForOriginationEnd(Date endDate) {
-            mKeyValidityForOriginationEnd = endDate;
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid for decryption and
-         * verification.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * @see #setKeyValidityForOriginationEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
-            mKeyValidityForConsumptionEnd = endDate;
-            return this;
-        }
-
-        /**
-         * Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
-         * Attempts to use the key for any other purpose will be rejected.
-         *
-         * <p>This must be specified for all keys. There is no default.
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
-         */
-        @NonNull
-        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
-            mPurposes = purposes;
-            return this;
-        }
-
-        /**
-         * Sets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code NoPadding}) with
-         * which the key can be used when encrypting/decrypting. Attempts to use the key with any
-         * other padding scheme will be rejected.
-         *
-         * <p>This must be specified for keys which are used for encryption/decryption.
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
-         */
-        @NonNull
-        public Builder setEncryptionPaddings(
-                @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) {
-            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
-            return this;
-        }
-
-        /**
-         * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be
-         * used when encrypting/decrypting. Attempts to use the key with any other block modes will
-         * be rejected.
-         *
-         * <p>This must be specified for encryption/decryption keys.
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
-         */
-        @NonNull
-        public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) {
-            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
-            return this;
-        }
-
-        /**
-         * Sets whether encryption using this key must be sufficiently randomized to produce
-         * different ciphertexts for the same plaintext every time. The formal cryptographic
-         * property being required is <em>indistinguishability under chosen-plaintext attack
-         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
-         * of 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.
-         *
-         * <p>By default, {@code IND-CPA} is required.
-         *
-         * <p>When {@code IND-CPA} is required:
-         * <ul>
-         * <li>block modes which do not offer {@code IND-CPA}, such as {@code ECB}, are prohibited;
-         * </li>
-         * <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM},
-         * caller-provided IVs are rejected when encrypting, to ensure that only random IVs are
-         * used.</li>
-         *
-         * <p>Before disabling this requirement, consider the following approaches instead:
-         * <ul>
-         * <li>If you are generating a random IV for encryption and then initializing a {@code}
-         * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
-         * instead. This will occur if the {@code Cipher} is initialized for encryption without an
-         * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
-         * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
-         * random, such as the name of the file being encrypted, or transaction ID, or password,
-         * or a device identifier), consider changing your design to use a random IV which will then
-         * be provided in addition to the ciphertext to the entities which need to decrypt the
-         * ciphertext.</li>
-         * </ul>
-         */
-        @NonNull
-        public Builder setRandomizedEncryptionRequired(boolean required) {
-            mRandomizedEncryptionRequired = required;
-            return this;
-        }
-
-        /**
-         * Sets whether user authentication is required to use this key.
-         *
-         * <p>By default, the key can be used without user authentication.
-         *
-         * <p>When user authentication is required, the user authorizes the use of the key by
-         * authenticating to this Android device using a subset of their secure lock screen
-         * credentials. Different authentication methods are used depending on whether the every
-         * use of the key must be authenticated (as specified by
-         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
-         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
-         * information</a>.
-         *
-         * @see #setUserAuthenticationValidityDurationSeconds(int)
-         */
-        @NonNull
-        public Builder setUserAuthenticationRequired(boolean required) {
-            mUserAuthenticationRequired = required;
-            return this;
-        }
-
-        /**
-         * Sets the duration of time (seconds) for which this key can be used after the user is
-         * successfully authenticated. This has effect only if user authentication is required.
-         *
-         * <p>By default, the user needs to authenticate for every use of the key.
-         *
-         * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
-         *        every use of the key.
-         *
-         * @see #setUserAuthenticationRequired(boolean)
-         */
-        @NonNull
-        public Builder setUserAuthenticationValidityDurationSeconds(
-                @IntRange(from = -1) int seconds) {
-            mUserAuthenticationValidityDurationSeconds = seconds;
-            return this;
-        }
-
-        /**
-         * Builds a new instance instance of {@code KeyGeneratorSpec}.
-         *
-         * @throws IllegalArgumentException if a required field is missing or violates a constraint.
-         */
-        @NonNull
-        public KeyGeneratorSpec build() {
-            return new KeyGeneratorSpec(mContext,
-                    mKeystoreAlias,
-                    mFlags,
-                    mKeySize,
-                    mKeyValidityStart,
-                    mKeyValidityForOriginationEnd,
-                    mKeyValidityForConsumptionEnd,
-                    mPurposes,
-                    mEncryptionPaddings,
-                    mBlockModes,
-                    mRandomizedEncryptionRequired,
-                    mUserAuthenticationRequired,
-                    mUserAuthenticationValidityDurationSeconds);
-        }
-    }
-}
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index b07c052..efbce41 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -17,14 +17,14 @@
 package android.security;
 
 import android.app.KeyguardManager;
-import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
 import android.text.TextUtils;
 
 import java.math.BigInteger;
-import java.security.KeyPairGenerator;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.cert.Certificate;
@@ -34,72 +34,32 @@
 import javax.security.auth.x500.X500Principal;
 
 /**
- * {@link AlgorithmParameterSpec} for initializing a {@link KeyPairGenerator} of the
- * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class
- * specifies whether user authentication is required for using the private key, what uses the
- * private key is authorized for (e.g., only for signing -- decryption not permitted), whether the
- * private key should be encrypted at rest, the private key's and validity start and end dates.
+ * This provides the required parameters needed for initializing the
+ * {@code KeyPairGenerator} that works with
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
+ * facility</a>. The Android KeyStore facility is accessed through a
+ * {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore}
+ * provider. The {@code context} passed in may be used to pop up some UI to ask
+ * the user to unlock or initialize the Android KeyStore facility.
+ * <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 PrivateKey} and its associated
+ * {@link Certificate} chain.
+ * <p>
+ * The KeyPair generator will create a self-signed certificate with the subject
+ * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer
+ * Distinguished Name along with the other parameters specified with the
+ * {@link Builder}.
+ * <p>
+ * The self-signed X.509 certificate may be replaced at a later time by a
+ * certificate signed by a real Certificate Authority.
  *
- * <p>To generate a key pair, create an instance of this class using the {@link Builder}, initialize
- * a {@code KeyPairGenerator} of the desired key type (e.g., {@code EC} or {@code RSA}) from the
- * {@code AndroidKeyStore} provider with the {@code KeyPairGeneratorSpec} instance, and then
- * generate a key pair using {@link KeyPairGenerator#generateKeyPair()}.
- *
- * <p>The generated key pair will be returned by the {@code KeyPairGenerator} and also stored in the
- * Android KeyStore under the alias specified in this {@code KeyPairGeneratorSpec}. To obtain the
- * private key from the Android KeyStore use
- * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or
- * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}.
- * To obtain the public key from the Android KeyStore use
- * {@link java.security.KeyStore#getCertificate(String)} and then
- * {@link Certificate#getPublicKey()}.
- *
- * <p>A self-signed X.509 certificate will be also generated and stored in the Android KeyStore.
- * This is because the {@link java.security.KeyStore} abstraction does not support storing key pairs
- * without a certificate. The subject, serial number, and validity dates of the certificate can be
- * specified in this {@code KeyPairGeneratorSpec}. The self-signed certificate may be replaced at a
- * later time by a certificate signed by a Certificate Authority (CA).
- *
- * <p>NOTE: The key material of the private keys generating using the {@code KeyPairGeneratorSpec}
- * is not accessible. The key material of the public keys is accessible.
- *
- * <p><h3>Example</h3>
- * The following example illustrates how to generate an EC key pair in the Android KeyStore under
- * alias {@code key2} authorized to be used only for signing using SHA-256, SHA-384, or SHA-512
- * digest and only if the user has been authenticated within the last five minutes.
- * <pre> {@code
- * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
- *         KeyStoreKeyProperties.KEY_ALGORITHM_EC,
- *         "AndroidKeyStore");
- * keyPairGenerator.initialize(
- *         new KeyGeneratorSpec.Builder(context)
- *                 .setAlias("key2")
- *                 .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN
- *                         | KeyStoreKeyProperties.PURPOSE_VERIFY)
- *                 .setDigests(KeyStoreKeyProperties.DIGEST_SHA256
- *                         | KeyStoreKeyProperties.DIGEST_SHA384
- *                         | KeyStoreKeyProperties.DIGEST_SHA512)
- *                 // Only permit this key to be used if the user authenticated
- *                 // within the last five minutes.
- *                 .setUserAuthenticationRequired(true)
- *                 .setUserAuthenticationValidityDurationSeconds(5 * 60)
- *                 .build());
- * KeyPair keyPair = keyPairGenerator.generateKey();
- *
- * // The key pair can also be obtained from the Android KeyStore any time as follows:
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * PrivateKey privateKey = (PrivateKey) keyStore.getKey("key2", null);
- * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey();
- * }</pre>
+ * @deprecated Use {@link KeyGenParameterSpec} instead.
  */
+@Deprecated
 public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
 
-    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
-    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
-    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
-    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
-
     private final Context mContext;
 
     private final String mKeystoreAlias;
@@ -120,28 +80,6 @@
 
     private final int mFlags;
 
-    private final Date mKeyValidityStart;
-
-    private final Date mKeyValidityForOriginationEnd;
-
-    private final Date mKeyValidityForConsumptionEnd;
-
-    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-
-    private final @KeyStoreKeyProperties.DigestEnum String[] mDigests;
-
-    private final @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-
-    private final @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
-
-    private final @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
-
-    private final boolean mRandomizedEncryptionRequired;
-
-    private final boolean mUserAuthenticationRequired;
-
-    private final int mUserAuthenticationValidityDurationSeconds;
-
     /**
      * Parameter specification for the "{@code AndroidKeyPairGenerator}"
      * instance of the {@link java.security.KeyPairGenerator} API. The
@@ -162,7 +100,7 @@
      * @param context Android context for the activity
      * @param keyStoreAlias name to use for the generated key in the Android
      *            keystore
-     * @param keyType key algorithm to use (EC, RSA)
+     * @param keyType key algorithm to use (RSA, DSA, EC)
      * @param keySize size of key to generate
      * @param spec the underlying key type parameters
      * @param subjectDN X.509 v3 Subject Distinguished Name
@@ -176,39 +114,21 @@
      */
     public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
             AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
-            Date startDate, Date endDate, int flags,
-            Date keyValidityStart,
-            Date keyValidityForOriginationEnd,
-            Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyProperties.PurposeEnum int purposes,
-            @KeyStoreKeyProperties.DigestEnum String[] digests,
-            @KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
-            @KeyStoreKeyProperties.SignaturePaddingEnum String[] signaturePaddings,
-            @KeyStoreKeyProperties.BlockModeEnum String[] blockModes,
-            boolean randomizedEncryptionRequired,
-            boolean userAuthenticationRequired,
-            int userAuthenticationValidityDurationSeconds) {
+            Date startDate, Date endDate, int flags) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
-        } else if ((userAuthenticationValidityDurationSeconds < 0)
-                && (userAuthenticationValidityDurationSeconds != -1)) {
-            throw new IllegalArgumentException(
-                    "userAuthenticationValidityDurationSeconds must not be negative");
-        }
-
-        if (subjectDN == null) {
-            subjectDN = DEFAULT_CERT_SUBJECT;
-        }
-        if (startDate == null) {
-            startDate = DEFAULT_CERT_NOT_BEFORE;
-        }
-        if (endDate == null) {
-            endDate = DEFAULT_CERT_NOT_AFTER;
-        }
-        if (serialNumber == null) {
-            serialNumber = DEFAULT_CERT_SERIAL_NUMBER;
+        } else if (subjectDN == null) {
+            throw new IllegalArgumentException("subjectDN == null");
+        } else if (serialNumber == null) {
+            throw new IllegalArgumentException("serialNumber == null");
+        } else if (startDate == null) {
+            throw new IllegalArgumentException("startDate == null");
+        } else if (endDate == null) {
+            throw new IllegalArgumentException("endDate == null");
+        } else if (endDate.before(startDate)) {
+            throw new IllegalArgumentException("endDate < startDate");
         }
 
         if (endDate.before(startDate)) {
@@ -225,50 +145,6 @@
         mStartDate = startDate;
         mEndDate = endDate;
         mFlags = flags;
-        mKeyValidityStart = keyValidityStart;
-        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
-        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
-        mPurposes = purposes;
-        mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
-        mEncryptionPaddings =
-                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
-        mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
-        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
-        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
-        mUserAuthenticationRequired = userAuthenticationRequired;
-        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
-    }
-
-    /**
-     * TODO: Remove this constructor once tests are switched over to the new one above.
-     * @hide
-     */
-    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,
-                keySize,
-                spec,
-                subjectDN,
-                serialNumber,
-                startDate,
-                endDate,
-                flags,
-                startDate,
-                endDate,
-                endDate,
-                0, // purposes
-                null, // digests
-                null, // encryption paddings
-                null, // signature paddings
-                null, // block modes
-                false, // randomized encryption required
-                false, // user authentication required
-                -1 // user authentication validity duration (seconds)
-                );
     }
 
     /**
@@ -288,10 +164,10 @@
 
     /**
      * Returns the type of key pair (e.g., {@code EC}, {@code RSA}) to be generated. See
-     * {@link KeyStoreKeyProperties}.{@code KEY_ALGORITHM} constants.
+     * {@link KeyProperties}.{@code KEY_ALGORITHM} constants.
      */
     @Nullable
-    public @KeyStoreKeyProperties.KeyAlgorithmEnum String getKeyType() {
+    public @KeyProperties.KeyAlgorithmEnum String getKeyType() {
         return mKeyType;
     }
 
@@ -352,148 +228,27 @@
     /**
      * @hide
      */
-    int getFlags() {
+    public int getFlags() {
         return mFlags;
     }
 
     /**
      * Returns {@code true} if the key must be encrypted at rest. This will protect the key pair
      * with the secure lock screen credential (e.g., password, PIN, or pattern).
+     *
+     * <p>Note that encrypting the key at rest requires that the secure lock screen (e.g., password,
+     * PIN, pattern) is set up, otherwise key generation will fail. Moreover, this key will be
+     * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device
+     * Administrator). Finally, this key cannot be used until the user unlocks the secure lock
+     * screen after boot.
+     *
+     * @see KeyguardManager#isDeviceSecure()
      */
     public boolean isEncryptionRequired() {
         return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
     }
 
     /**
-     * Gets the time instant before which the key pair is not yet valid.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityStart() {
-        return mKeyValidityStart;
-    }
-
-    /**
-     * Gets the time instant after which the key pair is no longer valid for decryption and
-     * verification.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityForConsumptionEnd() {
-        return mKeyValidityForConsumptionEnd;
-    }
-
-    /**
-     * 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.
-     */
-    @Nullable
-    public Date getKeyValidityForOriginationEnd() {
-        return mKeyValidityForOriginationEnd;
-    }
-
-    /**
-     * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
-     * Attempts to use the key for any other purpose will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
-     */
-    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
-        return mPurposes;
-    }
-
-    /**
-     * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384} with which the key
-     * can be used.
-     *
-     * @see KeyStoreKeyProperties.Digest
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.DigestEnum String[] getDigests() {
-        return ArrayUtils.cloneIfNotEmpty(mDigests);
-    }
-
-    /**
-     * Gets the set of padding schemes (e.g., {@code OEAPPadding}, {@code PKCS1Padding},
-     * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
-     * the key with any other padding scheme will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
-        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
-    }
-
-    /**
-     * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
-     * can be used when signing/verifying. Attempts to use the key with any other padding scheme
-     * will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
-        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
-    }
-
-    /**
-     * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used
-     * when encrypting/decrypting. Attempts to use the key with any other block modes will be
-     * rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() {
-        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
-    }
-
-    /**
-     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
-     * different ciphertexts for the same plaintext every time. The formal cryptographic property
-     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
-     * IND-CPA})</em>. This property is important because it mitigates several classes of
-     * 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.
-     */
-    public boolean isRandomizedEncryptionRequired() {
-        return mRandomizedEncryptionRequired;
-    }
-
-    /**
-     * Returns {@code true} if user authentication is required for this key to be used.
-     *
-     * <p>This restriction applies only to private key operations. Public key operations are not
-     * restricted.
-     *
-     * @see #getUserAuthenticationValidityDurationSeconds()
-     */
-    public boolean isUserAuthenticationRequired() {
-        return mUserAuthenticationRequired;
-    }
-
-    /**
-     * Gets the duration of time (seconds) for which this key can be used after the user is
-     * successfully authenticated. This has effect only if user authentication is required.
-     *
-     * <p>This restriction applies only to private key operations. Public key operations are not
-     * restricted.
-     *
-     * @return duration in seconds or {@code -1} if authentication is required for every use of the
-     *         key.
-     *
-     * @see #isUserAuthenticationRequired()
-     */
-    public int getUserAuthenticationValidityDurationSeconds() {
-        return mUserAuthenticationValidityDurationSeconds;
-    }
-
-    /**
      * Builder class for {@link KeyPairGeneratorSpec} objects.
      * <p>
      * This will build a parameter spec for use with the <a href="{@docRoot}
@@ -513,7 +268,10 @@
      *                 .setSubject(new X500Principal(&quot;CN=myKey&quot;)).setSerial(BigInteger.valueOf(1337))
      *                 .setStartDate(start.getTime()).setEndDate(end.getTime()).build();
      * </pre>
+     *
+     *  @deprecated Use {@link KeyGenParameterSpec.Builder} instead.
      */
+    @Deprecated
     public final static class Builder {
         private final Context mContext;
 
@@ -535,28 +293,6 @@
 
         private int mFlags;
 
-        private Date mKeyValidityStart;
-
-        private Date mKeyValidityForOriginationEnd;
-
-        private Date mKeyValidityForConsumptionEnd;
-
-        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-
-        private @KeyStoreKeyProperties.DigestEnum String[] mDigests;
-
-        private @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-
-        private @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
-
-        private @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
-
-        private boolean mRandomizedEncryptionRequired = true;
-
-        private boolean mUserAuthenticationRequired;
-
-        private int mUserAuthenticationValidityDurationSeconds = -1;
-
         /**
          * Creates a new instance of the {@code Builder} with the given
          * {@code context}. The {@code context} passed in may be used to pop up
@@ -586,11 +322,11 @@
 
         /**
          * Sets the type of key pair (e.g., {@code EC}, {@code RSA}) of the key pair to be
-         * generated. See {@link KeyStoreKeyProperties}.{@code KEY_ALGORITHM} constants.
+         * generated. See {@link KeyProperties}.{@code KEY_ALGORITHM} constants.
          *
          */
         @NonNull
-        public Builder setKeyType(@NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String keyType)
+        public Builder setKeyType(@NonNull @KeyProperties.KeyAlgorithmEnum String keyType)
                 throws NoSuchAlgorithmException {
             if (keyType == null) {
                 throw new NullPointerException("keyType == null");
@@ -632,10 +368,6 @@
         /**
          * Sets the subject used for the self-signed certificate of the
          * generated key pair.
-         *
-         * <p>The subject must be specified on API Level
-         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
-         * newer platforms the subject defaults to {@code CN=fake} if not specified.
          */
         @NonNull
         public Builder setSubject(@NonNull X500Principal subject) {
@@ -649,10 +381,6 @@
         /**
          * Sets the serial number used for the self-signed certificate of the
          * generated key pair.
-         *
-         * <p>The serial number must be specified on API Level
-         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
-         * newer platforms the serial number defaults to {@code 1} if not specified.
          */
         @NonNull
         public Builder setSerialNumber(@NonNull BigInteger serialNumber) {
@@ -666,10 +394,6 @@
         /**
          * Sets the start of the validity period for the self-signed certificate
          * of the generated key pair.
-         *
-         * <p>The date must be specified on API Level
-         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
-         * newer platforms the date defaults to {@code Jan 1 1970} if not specified.
          */
         @NonNull
         public Builder setStartDate(@NonNull Date startDate) {
@@ -683,10 +407,6 @@
         /**
          * Sets the end of the validity period for the self-signed certificate
          * of the generated key pair.
-         *
-         * <p>The date must be specified on API Level
-         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
-         * newer platforms the date defaults to {@code Jan 1 2048} if not specified.
          */
         @NonNull
         public Builder setEndDate(@NonNull Date endDate) {
@@ -716,239 +436,6 @@
         }
 
         /**
-         * Sets the time instant before which the key is not yet valid.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @see #setKeyValidityEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityStart(Date startDate) {
-            mKeyValidityStart = startDate;
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @see #setKeyValidityStart(Date)
-         * @see #setKeyValidityForConsumptionEnd(Date)
-         * @see #setKeyValidityForOriginationEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityEnd(Date endDate) {
-            setKeyValidityForOriginationEnd(endDate);
-            setKeyValidityForConsumptionEnd(endDate);
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid for encryption and signing.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @see #setKeyValidityForConsumptionEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityForOriginationEnd(Date endDate) {
-            mKeyValidityForOriginationEnd = endDate;
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid for decryption and
-         * verification.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @see #setKeyValidityForOriginationEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
-            mKeyValidityForConsumptionEnd = endDate;
-            return this;
-        }
-
-        /**
-         * Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
-         * Attempts to use the key for any other purpose will be rejected.
-         *
-         * <p>This must be specified for all keys. There is no default.
-         *
-         * <p>If the set of purposes for which the key can be used does not contain
-         * {@link KeyStoreKeyProperties#PURPOSE_SIGN}, the self-signed certificate generated by
-         * {@link KeyPairGenerator} of {@code AndroidKeyStore} provider will contain an invalid
-         * signature. This is OK if the certificate is only used for obtaining the public key from
-         * Android KeyStore.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
-         */
-        @NonNull
-        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
-            mPurposes = purposes;
-            return this;
-        }
-
-        /**
-         * Sets the set of digests algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which
-         * the key can be used when signing/verifying. Attempts to use the key with any other digest
-         * algorithm will be rejected.
-         *
-         * <p>This must be specified for keys which are used for signing/verification.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @see KeyStoreKeyProperties.Digest
-         */
-        @NonNull
-        public Builder setDigests(@KeyStoreKeyProperties.DigestEnum String... digests) {
-            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
-            return this;
-        }
-
-        /**
-         * Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS1Padding},
-         * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to
-         * use the key with any other padding scheme will be rejected.
-         *
-         * <p>This must be specified for keys which are used for encryption/decryption.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
-         */
-        @NonNull
-        public Builder setEncryptionPaddings(
-                @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) {
-            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
-            return this;
-        }
-
-        /**
-         * Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
-         * can be used when signing/verifying. Attempts to use the key with any other padding scheme
-         * will be rejected.
-         *
-         * <p>This must be specified for RSA keys which are used for signing/verification.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
-         */
-        @NonNull
-        public Builder setSignaturePaddings(
-                @KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) {
-            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
-            return this;
-        }
-
-        /**
-         * Sets the set of block modes (e.g., {@code ECB}, {@code CBC}, {@code CTR}) with which the
-         * key can be used when encrypting/decrypting. Attempts to use the key with any other block
-         * modes will be rejected.
-         *
-         * <p>This must be specified for encryption/decryption keys.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
-         */
-        @NonNull
-        public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) {
-            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
-            return this;
-        }
-
-        /**
-         * Sets whether encryption using this key must be sufficiently randomized to produce
-         * different ciphertexts for the same plaintext every time. The formal cryptographic
-         * property being required is <em>indistinguishability under chosen-plaintext attack
-         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
-         * of 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.
-         *
-         * <p>By default, {@code IND-CPA} is required.
-         *
-         * <p>When {@code IND-CPA} is required, encryption/decryption transformations which do not
-         * offer {@code IND-CPA}, such as RSA without padding, are prohibited.
-         *
-         * <p>Before disabling this requirement, consider the following approaches instead:
-         * <ul>
-         * <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>
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         */
-        @NonNull
-        public Builder setRandomizedEncryptionRequired(boolean required) {
-            mRandomizedEncryptionRequired = required;
-            return this;
-        }
-
-        /**
-         * Sets whether user authentication is required to use this key.
-         *
-         * <p>By default, the key can be used without user authentication.
-         *
-         * <p>When user authentication is required, the user authorizes the use of the key by
-         * authenticating to this Android device using a subset of their secure lock screen
-         * credentials. Different authentication methods are used depending on whether the every
-         * use of the key must be authenticated (as specified by
-         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
-         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
-         * information</a>.
-         *
-         * <p>This restriction applies only to private key operations. Public key operations are not
-         * restricted.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @see #setUserAuthenticationValidityDurationSeconds(int)
-         */
-        @NonNull
-        public Builder setUserAuthenticationRequired(boolean required) {
-            mUserAuthenticationRequired = required;
-            return this;
-        }
-
-        /**
-         * Sets the duration of time (seconds) for which this key can be used after the user is
-         * successfully authenticated. This has effect only if user authentication is required.
-         *
-         * <p>By default, the user needs to authenticate for every use of the key.
-         *
-         * <p>This restriction applies only to private key operations. Public key operations are not
-         * restricted.
-         *
-         * <p><b>NOTE: This has currently no effect.</b>
-         *
-         * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
-         *        every use of the key.
-         *
-         * @see #setUserAuthenticationRequired(boolean)
-         */
-        @NonNull
-        public Builder setUserAuthenticationValidityDurationSeconds(
-                @IntRange(from = -1) int seconds) {
-            mUserAuthenticationValidityDurationSeconds = seconds;
-            return this;
-        }
-
-        /**
          * Builds the instance of the {@code KeyPairGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -965,18 +452,7 @@
                     mSerialNumber,
                     mStartDate,
                     mEndDate,
-                    mFlags,
-                    mKeyValidityStart,
-                    mKeyValidityForOriginationEnd,
-                    mKeyValidityForConsumptionEnd,
-                    mPurposes,
-                    mDigests,
-                    mEncryptionPaddings,
-                    mSignaturePaddings,
-                    mBlockModes,
-                    mRandomizedEncryptionRequired,
-                    mUserAuthenticationRequired,
-                    mUserAuthenticationValidityDurationSeconds);
+                    mFlags);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index caa4fec..72c74df 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -35,6 +35,11 @@
 import android.security.keymaster.KeymasterBlob;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keymaster.OperationResult;
+import android.security.keystore.KeyExpiredException;
+import android.security.keystore.KeyNotYetValidException;
+import android.security.keystore.KeyPermanentlyInvalidatedException;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.UserNotAuthenticatedException;
 import android.util.Log;
 
 import java.security.InvalidKeyException;
@@ -101,10 +106,10 @@
 
     private KeyStore(IKeystoreService binder) {
         mBinder = binder;
-        mContext = getContext();
+        mContext = getApplicationContext();
     }
 
-    private static Context getContext() {
+    static Context getApplicationContext() {
         ActivityThread activityThread = ActivityThread.currentActivityThread();
         if (activityThread == null) {
             throw new IllegalStateException(
@@ -131,10 +136,10 @@
         return mToken;
     }
 
-    static int getKeyTypeForAlgorithm(@KeyStoreKeyProperties.KeyAlgorithmEnum String keyType) {
-        if (KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) {
+    static int getKeyTypeForAlgorithm(@KeyProperties.KeyAlgorithmEnum String keyType) {
+        if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) {
             return NativeConstants.EVP_PKEY_RSA;
-        } else if (KeyStoreKeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) {
+        } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) {
             return NativeConstants.EVP_PKEY_EC;
         } else {
             return -1;
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 4eeca47..b0f1695 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -20,6 +20,7 @@
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keymaster.OperationResult;
+import android.security.keystore.KeyProperties;
 
 import java.security.AlgorithmParameters;
 import java.security.GeneralSecurityException;
@@ -496,7 +497,7 @@
         if ((mIv != null) && (mIv.length > 0)) {
             try {
                 AlgorithmParameters params =
-                        AlgorithmParameters.getInstance(KeyStoreKeyProperties.KEY_ALGORITHM_AES);
+                        AlgorithmParameters.getInstance(KeyProperties.KEY_ALGORITHM_AES);
                 params.init(new IvParameterSpec(mIv));
                 return params;
             } catch (NoSuchAlgorithmException e) {
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java
index 311278b..c9bdd41 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java
@@ -17,6 +17,7 @@
 package android.security;
 
 import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.UserNotAuthenticatedException;
 
 import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index d734d66..feec00f 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -19,11 +19,16 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import libcore.util.EmptyArray;
 
 import java.security.InvalidAlgorithmParameterException;
 import java.security.ProviderException;
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.Arrays;
 import java.util.Date;
 
 import javax.crypto.KeyGeneratorSpi;
@@ -96,13 +101,14 @@
     private final int mKeymasterDigest;
     private final int mDefaultKeySizeBits;
 
-    private KeyGeneratorSpec mSpec;
+    private KeyGenParameterSpec mSpec;
     private SecureRandom mRng;
 
     protected int mKeySizeBits;
     private int[] mKeymasterPurposes;
     private int[] mKeymasterBlockModes;
     private int[] mKeymasterPaddings;
+    private int[] mKeymasterDigests;
 
     protected KeyStoreKeyGeneratorSpi(
             int keymasterAlgorithm,
@@ -129,14 +135,14 @@
 
     @Override
     protected void engineInit(SecureRandom random) {
-        throw new UnsupportedOperationException("Cannot initialize without an "
-                + KeyGeneratorSpec.class.getName() + " parameter");
+        throw new UnsupportedOperationException("Cannot initialize without a "
+                + KeyGenParameterSpec.class.getName() + " parameter");
     }
 
     @Override
     protected void engineInit(int keySize, SecureRandom random) {
         throw new UnsupportedOperationException("Cannot initialize without a "
-                + KeyGeneratorSpec.class.getName() + " parameter");
+                + KeyGenParameterSpec.class.getName() + " parameter");
     }
 
     @Override
@@ -146,11 +152,11 @@
 
         boolean success = false;
         try {
-            if ((params == null) || (!(params instanceof KeyGeneratorSpec))) {
-                throw new InvalidAlgorithmParameterException("Cannot initialize without an "
-                        + KeyGeneratorSpec.class.getName() + " parameter");
+            if ((params == null) || (!(params instanceof KeyGenParameterSpec))) {
+                throw new InvalidAlgorithmParameterException("Cannot initialize without a "
+                        + KeyGenParameterSpec.class.getName() + " parameter");
             }
-            KeyGeneratorSpec spec = (KeyGeneratorSpec) params;
+            KeyGenParameterSpec spec = (KeyGenParameterSpec) params;
             if (spec.getKeystoreAlias() == null) {
                 throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
             }
@@ -168,13 +174,11 @@
             }
 
             try {
-                mKeymasterPurposes =
-                        KeyStoreKeyProperties.Purpose.allToKeymaster(spec.getPurposes());
-                mKeymasterPaddings = KeyStoreKeyProperties.EncryptionPadding.allToKeymaster(
+                mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
+                mKeymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
                         spec.getEncryptionPaddings());
-                mKeymasterBlockModes =
-                        KeyStoreKeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
-                if (((spec.getPurposes() & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0)
+                mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
+                if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
                         && (spec.isRandomizedEncryptionRequired())) {
                     for (int keymasterBlockMode : mKeymasterBlockModes) {
                         if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(
@@ -182,14 +186,55 @@
                             throw new InvalidAlgorithmParameterException(
                                     "Randomized encryption (IND-CPA) required but may be violated"
                                     + " by block mode: "
-                                    + KeyStoreKeyProperties.BlockMode.fromKeymaster(
-                                            keymasterBlockMode)
-                                    + ". See " + KeyGeneratorSpec.class.getName()
+                                    + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
+                                    + ". See " + KeyGenParameterSpec.class.getName()
                                     + " documentation.");
                         }
                     }
                 }
-            } catch (IllegalArgumentException e) {
+                if (spec.isDigestsSpecified()) {
+                    // Digest(s) explicitly specified in the spec
+                    mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
+                    if (mKeymasterDigest != -1) {
+                        // Key algorithm implies a digest -- ensure it's specified in the spec as
+                        // first digest.
+                        if (!com.android.internal.util.ArrayUtils.contains(
+                                mKeymasterDigests, mKeymasterDigest)) {
+                            throw new InvalidAlgorithmParameterException(
+                                    "Digests specified in algorithm parameters ("
+                                    + Arrays.asList(spec.getDigests()) + ") must include "
+                                    + " the digest "
+                                    + KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
+                                    + " implied by key algorithm");
+                        }
+                        if (mKeymasterDigests[0] != mKeymasterDigest) {
+                            // The first digest is not the one implied by the key algorithm.
+                            // Swap the implied digest with the first one.
+                            for (int i = 0; i < mKeymasterDigests.length; i++) {
+                                if (mKeymasterDigests[i] == mKeymasterDigest) {
+                                    mKeymasterDigests[i] = mKeymasterDigests[0];
+                                    mKeymasterDigests[0] = mKeymasterDigest;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    // No digest specified in the spec
+                    if (mKeymasterDigest != -1) {
+                        // Key algorithm implies a digest -- use that digest
+                        mKeymasterDigests = new int[] {mKeymasterDigest};
+                    } else {
+                        mKeymasterDigests = EmptyArray.INT;
+                    }
+                }
+                if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+                    if (mKeymasterDigests.length == 0) {
+                        throw new InvalidAlgorithmParameterException(
+                                "At least one digest algorithm must be specified");
+                    }
+                }
+            } catch (IllegalStateException | IllegalArgumentException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
 
@@ -212,29 +257,26 @@
 
     @Override
     protected SecretKey engineGenerateKey() {
-        KeyGeneratorSpec spec = mSpec;
+        KeyGenParameterSpec spec = mSpec;
         if (spec == null) {
             throw new IllegalStateException("Not initialized");
         }
 
-        if ((spec.isEncryptionRequired())
+        if ((spec.isEncryptionAtRestRequired())
                 && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
             throw new IllegalStateException(
-                    "Android KeyStore must be in initialized and unlocked state if encryption is"
-                    + " required");
+                    "Requested to import a key which must be encrypted at rest using secure lock"
+                    + " screen credential, but the credential hasn't yet been entered by the user");
         }
 
         KeymasterArguments args = new KeymasterArguments();
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
-        if (mKeymasterDigest != -1) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
-        }
         args.addInts(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
         args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
         args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
+        args.addInts(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
         KeymasterUtils.addUserAuthArgs(args,
-                spec.getContext(),
                 spec.isUserAuthenticationRequired(),
                 spec.getUserAuthenticationValidityDurationSeconds());
         args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
@@ -247,7 +289,7 @@
                 (spec.getKeyValidityForConsumptionEnd() != null)
                 ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
-        if (((spec.getPurposes() & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0)
+        if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
                 && (!spec.isRandomizedEncryptionRequired())) {
             // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
@@ -265,9 +307,9 @@
             throw new ProviderException(
                     "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
         }
-        @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
+        @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
         try {
-            keyAlgorithmJCA = KeyStoreKeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
+            keyAlgorithmJCA = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
                     mKeymasterAlgorithm, mKeymasterDigest);
         } catch (IllegalArgumentException e) {
             throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index a7fab80..174e03f 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -16,145 +16,51 @@
 
 package android.security;
 
-import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.content.Context;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProtection;
 
-import java.security.Key;
+import java.security.KeyPairGenerator;
 import java.security.KeyStore.ProtectionParameter;
-import java.security.cert.Certificate;
-import java.util.Date;
-
-import javax.crypto.Cipher;
 
 /**
- * Parameters specifying how to secure and restrict the use of a key or key pair being imported into
- * the <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class
- * specifies whether user authentication is required for using the key, what uses the key is
- * authorized for (e.g., only in {@code CTR} mode, or only for signing -- decryption not permitted),
- * whether the key should be encrypted at rest, the key's and validity start and end dates.
+ * This provides the optional parameters that can be specified for
+ * {@code KeyStore} entries that work with
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
+ * facility</a>. The Android KeyStore facility is accessed through a
+ * {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
+ * provider. The {@code context} passed in may be used to pop up some UI to ask
+ * the user to unlock or initialize the Android KeyStore facility.
+ * <p>
+ * Any entries placed in the {@code KeyStore} may be retrieved later. Note that
+ * there is only one logical instance of the {@code KeyStore} per application
+ * UID so apps using the {@code sharedUid} facility will also share a
+ * {@code KeyStore}.
+ * <p>
+ * Keys may be generated using the {@link KeyPairGenerator} facility with a
+ * {@link KeyPairGeneratorSpec} to specify the entry's {@code alias}. A
+ * self-signed X.509 certificate will be attached to generated entries, but that
+ * may be replaced at a later time by a certificate signed by a real Certificate
+ * Authority.
  *
- * <p>To import a key or key pair into the Android KeyStore, create an instance of this class using
- * the {@link Builder} and pass the instance into {@link java.security.KeyStore#setEntry(String, java.security.KeyStore.Entry, ProtectionParameter) KeyStore.setEntry}
- * with the key or key pair being imported.
- *
- * <p>To obtain the secret/symmetric or private key from the Android KeyStore use
- * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or
- * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}.
- * To obtain the public key from the Android KeyStore use
- * {@link java.security.KeyStore#getCertificate(String)} and then
- * {@link Certificate#getPublicKey()}.
- *
- * <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible.
- *
- * <p><h3>Example: Symmetric Key</h3>
- * The following example illustrates how to import an AES key into the Android KeyStore under alias
- * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7
- * padding. The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format.
- * <pre> {@code
- * SecretKey key = ...; // AES key
- *
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * keyStore.setEntry(
- *         "key1",
- *         new KeyStore.SecretKeyEntry(key),
- *         new KeyStoreParameter.Builder(context)
- *                 .setPurposes(KeyStoreKeyProperties.PURPOSE_ENCRYPT
- *                         | KeyStoreKeyProperties.PURPOSE_DECRYPT)
- *                 .setBlockMode(KeyStoreKeyProperties.BLOCK_MODE_CBC)
- *                 .setEncryptionPaddings(
- *                         KeyStoreKeyProperties.ENCRYPTION_PADDING_PKCS7)
- *                 .build());
- * // Key imported, obtain a reference to it.
- * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);
- * // The original key can now be thrown away.
- * }</pre>
- *
- * <p><h3>Example: Asymmetric Key Pair</h3>
- * The following example illustrates how to import an EC key pair into the Android KeyStore under
- * alias {@code key2} authorized to be used only for signing with SHA-256 digest and only if
- * the user has been authenticated within the last ten minutes. Both the private and the public key
- * must export their key material via {@link Key#getEncoded()} in {@code PKCS#8} and {@code X.509}
- * format respectively.
- * <pre> {@code
- * PrivateKey privateKey = ...;   // EC private key
- * Certificate[] certChain = ...; // Certificate chain with the first certificate
- *                                // containing the corresponding EC public key.
- *
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * keyStore.setEntry(
- *         "key2",
- *         new KeyStore.PrivateKeyEntry(privateKey, certChain),
- *         new KeyStoreParameter.Builder(context)
- *                 .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN)
- *                 .setDigests(KeyStoreKeyProperties.DIGEST_SHA256)
- *                 // Only permit this key to be used if the user
- *                 // authenticated within the last ten minutes.
- *                 .setUserAuthenticationRequired(true)
- *                 .setUserAuthenticationValidityDurationSeconds(10 * 60)
- *                 .build());
- * // Key pair imported, obtain a reference to it.
- * PrivateKey keyStorePrivateKey = (PrivateKey) keyStore.getKey("key2", null);
- * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey();
- * // The original private key can now be thrown away.
- * }</pre>
+ * @deprecated Use {@link KeyProtection} instead.
  */
+@Deprecated
 public final class KeyStoreParameter implements ProtectionParameter {
     private final Context mContext;
     private final int mFlags;
-    private final Date mKeyValidityStart;
-    private final Date mKeyValidityForOriginationEnd;
-    private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-    private final @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
-    private final @KeyStoreKeyProperties.DigestEnum String[] mDigests;
-    private final @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
-    private final boolean mRandomizedEncryptionRequired;
-    private final boolean mUserAuthenticationRequired;
-    private final int mUserAuthenticationValidityDurationSeconds;
 
     private KeyStoreParameter(
             Context context,
-            int flags,
-            Date keyValidityStart,
-            Date keyValidityForOriginationEnd,
-            Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyProperties.PurposeEnum int purposes,
-            @KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
-            @KeyStoreKeyProperties.SignaturePaddingEnum String[] signaturePaddings,
-            @KeyStoreKeyProperties.DigestEnum String[] digests,
-            @KeyStoreKeyProperties.BlockModeEnum String[] blockModes,
-            boolean randomizedEncryptionRequired,
-            boolean userAuthenticationRequired,
-            int userAuthenticationValidityDurationSeconds) {
+            int flags) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
-        } else if ((userAuthenticationValidityDurationSeconds < 0)
-                && (userAuthenticationValidityDurationSeconds != -1)) {
-            throw new IllegalArgumentException(
-                    "userAuthenticationValidityDurationSeconds must not be negative");
         }
 
         mContext = context;
         mFlags = flags;
-        mKeyValidityStart = keyValidityStart;
-        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
-        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
-        mPurposes = purposes;
-        mEncryptionPaddings =
-                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
-        mSignaturePaddings =
-                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
-        mDigests = ArrayUtils.cloneIfNotEmpty(digests);
-        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
-        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
-        mUserAuthenticationRequired = userAuthenticationRequired;
-        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
     }
 
     /**
@@ -175,151 +81,20 @@
      * Returns {@code true} if the {@link java.security.KeyStore} entry must be encrypted at rest.
      * This will protect the entry with the secure lock screen credential (e.g., password, PIN, or
      * pattern).
+     *
+     * <p>Note that encrypting the key at rest requires that the secure lock screen (e.g., password,
+     * PIN, pattern) is set up, otherwise key generation will fail. Moreover, this key will be
+     * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device
+     * Administrator). Finally, this key cannot be used until the user unlocks the secure lock
+     * screen after boot.
+     *
+     * @see KeyguardManager#isDeviceSecure()
      */
     public boolean isEncryptionRequired() {
         return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
     }
 
     /**
-     * Gets the time instant before which the key is not yet valid.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityStart() {
-        return mKeyValidityStart;
-    }
-
-    /**
-     * Gets the time instant after which the key is no long valid for decryption and verification.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityForConsumptionEnd() {
-        return mKeyValidityForConsumptionEnd;
-    }
-
-    /**
-     * Gets the time instant after which the key is no long valid for encryption and signing.
-     *
-     * @return instant or {@code null} if not restricted.
-     */
-    @Nullable
-    public Date getKeyValidityForOriginationEnd() {
-        return mKeyValidityForOriginationEnd;
-    }
-
-    /**
-     * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
-     * Attempts to use the key for any other purpose will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
-     */
-    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
-        return mPurposes;
-    }
-
-    /**
-     * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code PKCS1Padding},
-     * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
-     * the key with any other padding scheme will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
-        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
-    }
-
-    /**
-     * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
-     * can be used when signing/verifying. Attempts to use the key with any other padding scheme
-     * will be rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
-        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
-    }
-
-    /**
-     * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key
-     * can be used.
-     *
-     * @throws IllegalStateException if this set has not been specified.
-     *
-     * @see #isDigestsSpecified()
-     * @see KeyStoreKeyProperties.Digest
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.DigestEnum String[] getDigests() {
-        if (mDigests == null) {
-            throw new IllegalStateException("Digests not specified");
-        }
-        return ArrayUtils.cloneIfNotEmpty(mDigests);
-    }
-
-    /**
-     * Returns {@code true} if the set of digest algorithms with which the key can be used has been
-     * specified.
-     *
-     * @see #getDigests()
-     */
-    @NonNull
-    public boolean isDigestsSpecified() {
-        return mDigests != null;
-    }
-
-    /**
-     * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used
-     * when encrypting/decrypting. Attempts to use the key with any other block modes will be
-     * rejected.
-     *
-     * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
-     */
-    @NonNull
-    public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() {
-        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
-    }
-
-    /**
-     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
-     * different ciphertexts for the same plaintext every time. The formal cryptographic property
-     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
-     * IND-CPA})</em>. This property is important because it mitigates several classes of
-     * 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.
-     */
-    public boolean isRandomizedEncryptionRequired() {
-        return mRandomizedEncryptionRequired;
-    }
-
-    /**
-     * Returns {@code true} if user authentication is required for this key to be used.
-     *
-     * @see #getUserAuthenticationValidityDurationSeconds()
-     */
-    public boolean isUserAuthenticationRequired() {
-        return mUserAuthenticationRequired;
-    }
-
-    /**
-     * Gets the duration of time (seconds) for which this key can be used after the user is
-     * successfully authenticated. This has effect only if user authentication is required.
-     *
-     * @return duration in seconds or {@code -1} if authentication is required for every use of the
-     *         key.
-     *
-     * @see #isUserAuthenticationRequired()
-     */
-    public int getUserAuthenticationValidityDurationSeconds() {
-        return mUserAuthenticationValidityDurationSeconds;
-    }
-
-    /**
      * Builder class for {@link KeyStoreParameter} objects.
      * <p>
      * This will build protection parameters for use with the
@@ -332,24 +107,16 @@
      *
      * <pre class="prettyprint">
      * KeyStoreParameter params = new KeyStoreParameter.Builder(mContext)
-     *         .setEncryptionRequired(true)
+     *         .setEncryptionRequired()
      *         .build();
      * </pre>
+     *
+     *  @deprecated Use {@link KeyProtection.Builder} instead.
      */
+    @Deprecated
     public final static class Builder {
         private final Context mContext;
         private int mFlags;
-        private Date mKeyValidityStart;
-        private Date mKeyValidityForOriginationEnd;
-        private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-        private @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-        private @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
-        private @KeyStoreKeyProperties.DigestEnum String[] mDigests;
-        private @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
-        private boolean mRandomizedEncryptionRequired = true;
-        private boolean mUserAuthenticationRequired;
-        private int mUserAuthenticationValidityDurationSeconds = -1;
 
         /**
          * Creates a new instance of the {@code Builder} with the given
@@ -388,244 +155,6 @@
         }
 
         /**
-         * Sets the time instant before which the key is not yet valid.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @see #setKeyValidityEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityStart(Date startDate) {
-            mKeyValidityStart = startDate;
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @see #setKeyValidityStart(Date)
-         * @see #setKeyValidityForConsumptionEnd(Date)
-         * @see #setKeyValidityForOriginationEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityEnd(Date endDate) {
-            setKeyValidityForOriginationEnd(endDate);
-            setKeyValidityForConsumptionEnd(endDate);
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid for encryption and signing.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @see #setKeyValidityForConsumptionEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityForOriginationEnd(Date endDate) {
-            mKeyValidityForOriginationEnd = endDate;
-            return this;
-        }
-
-        /**
-         * Sets the time instant after which the key is no longer valid for decryption and
-         * verification.
-         *
-         * <p>By default, the key is valid at any instant.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @see #setKeyValidityForOriginationEnd(Date)
-         */
-        @NonNull
-        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
-            mKeyValidityForConsumptionEnd = endDate;
-            return this;
-        }
-
-        /**
-         * Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
-         * Attempts to use the key for any other purpose will be rejected.
-         *
-         * <p>This must be specified for all keys. There is no default.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
-         */
-        @NonNull
-        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
-            mPurposes = purposes;
-            return this;
-        }
-
-        /**
-         * Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS7Padding},
-         * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to
-         * use the key with any other padding scheme will be rejected.
-         *
-         * <p>This must be specified for keys which are used for encryption/decryption.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
-         */
-        @NonNull
-        public Builder setEncryptionPaddings(
-                @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) {
-            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
-            return this;
-        }
-
-        /**
-         * Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
-         * can be used when signing/verifying. Attempts to use the key with any other padding scheme
-         * will be rejected.
-         *
-         * <p>This must be specified for RSA keys which are used for signing/verification.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
-         */
-        @NonNull
-        public Builder setSignaturePaddings(
-                @KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) {
-            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
-            return this;
-        }
-
-
-        /**
-         * Sets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the
-         * key can be used when signing/verifying or generating MACs. Attempts to use the key with
-         * any other digest algorithm will be rejected.
-         *
-         * <p>For HMAC keys, the default is the digest algorithm specified in
-         * {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms
-         * must be specified.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @see KeyStoreKeyProperties.Digest
-         */
-        @NonNull
-        public Builder setDigests(@KeyStoreKeyProperties.DigestEnum String... digests) {
-            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
-            return this;
-        }
-
-        /**
-         * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}, {@code ECB}) with which the
-         * key can be used when encrypting/decrypting. Attempts to use the key with any other block
-         * modes will be rejected.
-         *
-         * <p>This must be specified for encryption/decryption keys.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
-         */
-        @NonNull
-        public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) {
-            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
-            return this;
-        }
-
-        /**
-         * Sets whether encryption using this key must be sufficiently randomized to produce
-         * different ciphertexts for the same plaintext every time. The formal cryptographic
-         * property being required is <em>indistinguishability under chosen-plaintext attack
-         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
-         * of 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.
-         *
-         * <p>By default, {@code IND-CPA} is required.
-         *
-         * <p>When {@code IND-CPA} is required:
-         * <ul>
-         * <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using
-         * {@code ECB} mode or RSA encryption without padding, are prohibited;</li>
-         * <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC},
-         * {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when
-         * encrypting, to ensure that only random IVs are used.</li>
-         *
-         * <p>Before disabling this requirement, consider the following approaches instead:
-         * <ul>
-         * <li>If you are generating a random IV for encryption and then initializing a {@code}
-         * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
-         * instead. This will occur if the {@code Cipher} is initialized for encryption without an
-         * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
-         * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
-         * random, such as the name of the file being encrypted, or transaction ID, or password,
-         * or a device identifier), consider changing your design to use a random IV which will then
-         * be provided in addition to the ciphertext to the entities which need to decrypt the
-         * ciphertext.</li>
-         * <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>
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         */
-        @NonNull
-        public Builder setRandomizedEncryptionRequired(boolean required) {
-            mRandomizedEncryptionRequired = required;
-            return this;
-        }
-
-        /**
-         * Sets whether user authentication is required to use this key.
-         *
-         * <p>By default, the key can be used without user authentication.
-         *
-         * <p>When user authentication is required, the user authorizes the use of the key by
-         * authenticating to this Android device using a subset of their secure lock screen
-         * credentials. Different authentication methods are used depending on whether the every
-         * use of the key must be authenticated (as specified by
-         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
-         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
-         * information</a>.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @see #setUserAuthenticationValidityDurationSeconds(int)
-         */
-        @NonNull
-        public Builder setUserAuthenticationRequired(boolean required) {
-            mUserAuthenticationRequired = required;
-            return this;
-        }
-
-        /**
-         * Sets the duration of time (seconds) for which this key can be used after the user is
-         * successfully authenticated. This has effect only if user authentication is required.
-         *
-         * <p>By default, the user needs to authenticate for every use of the key.
-         *
-         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
-         *
-         * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
-         *        every use of the key.
-         *
-         * @see #setUserAuthenticationRequired(boolean)
-         */
-        @NonNull
-        public Builder setUserAuthenticationValidityDurationSeconds(
-                @IntRange(from = -1) int seconds) {
-            mUserAuthenticationValidityDurationSeconds = seconds;
-            return this;
-        }
-
-        /**
          * Builds the instance of the {@code KeyStoreParameter}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -635,18 +164,7 @@
         public KeyStoreParameter build() {
             return new KeyStoreParameter(
                     mContext,
-                    mFlags,
-                    mKeyValidityStart,
-                    mKeyValidityForOriginationEnd,
-                    mKeyValidityForConsumptionEnd,
-                    mPurposes,
-                    mEncryptionPaddings,
-                    mSignaturePaddings,
-                    mDigests,
-                    mBlockModes,
-                    mRandomizedEncryptionRequired,
-                    mUserAuthenticationRequired,
-                    mUserAuthenticationValidityDurationSeconds);
+                    mFlags);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index 548296b..618ba47 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -18,6 +18,8 @@
 
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyInfo;
+import android.security.keystore.KeyProperties;
 
 import libcore.util.EmptyArray;
 
@@ -55,7 +57,7 @@
             throw new InvalidKeySpecException(
                     "Key material export of Android KeyStore keys is not supported");
         }
-        if (!KeyStoreKeySpec.class.equals(keySpecClass)) {
+        if (!KeyInfo.class.equals(keySpecClass)) {
             throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
         }
         String keyAliasInKeystore = ((KeyStoreSecretKey) key).getAlias();
@@ -75,22 +77,22 @@
         }
 
         boolean insideSecureHardware;
-        @KeyStoreKeyProperties.OriginEnum int origin;
+        @KeyProperties.OriginEnum int origin;
         int keySize;
-        @KeyStoreKeyProperties.PurposeEnum int purposes;
+        @KeyProperties.PurposeEnum int purposes;
         String[] encryptionPaddings;
-        @KeyStoreKeyProperties.DigestEnum String[] digests;
-        @KeyStoreKeyProperties.BlockModeEnum String[] blockModes;
+        @KeyProperties.DigestEnum String[] digests;
+        @KeyProperties.BlockModeEnum String[] blockModes;
         int keymasterSwEnforcedUserAuthenticators;
         int keymasterHwEnforcedUserAuthenticators;
         try {
             if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 insideSecureHardware = true;
-                origin = KeyStoreKeyProperties.Origin.fromKeymaster(
+                origin = KeyProperties.Origin.fromKeymaster(
                         keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
             } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 insideSecureHardware = false;
-                origin = KeyStoreKeyProperties.Origin.fromKeymaster(
+                origin = KeyProperties.Origin.fromKeymaster(
                         keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
             } else {
                 throw new InvalidKeySpecException("Key origin not available");
@@ -100,15 +102,14 @@
                 throw new InvalidKeySpecException("Key size not available");
             }
             keySize = keySizeInteger;
-            purposes = KeyStoreKeyProperties.Purpose.allFromKeymaster(
+            purposes = KeyProperties.Purpose.allFromKeymaster(
                     keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
 
             List<String> encryptionPaddingsList = new ArrayList<String>();
             for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
-                @KeyStoreKeyProperties.EncryptionPaddingEnum String jcaPadding;
+                @KeyProperties.EncryptionPaddingEnum String jcaPadding;
                 try {
-                    jcaPadding =
-                            KeyStoreKeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
+                    jcaPadding = KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
                 } catch (IllegalArgumentException e) {
                     throw new InvalidKeySpecException(
                             "Unsupported encryption padding: " + keymasterPadding);
@@ -118,9 +119,9 @@
             encryptionPaddings =
                     encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
 
-            digests = KeyStoreKeyProperties.Digest.allFromKeymaster(
+            digests = KeyProperties.Digest.allFromKeymaster(
                     keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
-            blockModes = KeyStoreKeyProperties.BlockMode.allFromKeymaster(
+            blockModes = KeyProperties.BlockMode.allFromKeymaster(
                     keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
             keymasterSwEnforcedUserAuthenticators =
                     keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
@@ -154,7 +155,7 @@
                 && (keymasterHwEnforcedUserAuthenticators != 0)
                 && (keymasterSwEnforcedUserAuthenticators == 0);
 
-        return new KeyStoreKeySpec(entryAlias,
+        return new KeyInfo(entryAlias,
                 insideSecureHardware,
                 origin,
                 keySize,
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index df67ae7..0f8f190 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -16,7 +16,6 @@
 
 package android.security;
 
-import android.content.Context;
 import android.hardware.fingerprint.FingerprintManager;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
@@ -73,7 +72,6 @@
      *        use of the key needs authorization.
      */
     public static void addUserAuthArgs(KeymasterArguments args,
-            Context context,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds) {
         if (!userAuthenticationRequired) {
@@ -85,7 +83,7 @@
             // Every use of this key needs to be authorized by the user. This currently means
             // fingerprint-only auth.
             FingerprintManager fingerprintManager =
-                    context.getSystemService(FingerprintManager.class);
+                    KeyStore.getApplicationContext().getSystemService(FingerprintManager.class);
             if ((fingerprintManager == null) || (!fingerprintManager.isHardwareDetected())) {
                 throw new IllegalStateException(
                         "This device does not support keys which require authentication for every"
diff --git a/keystore/java/android/security/KeyExpiredException.java b/keystore/java/android/security/keystore/KeyExpiredException.java
similarity index 97%
rename from keystore/java/android/security/KeyExpiredException.java
rename to keystore/java/android/security/keystore/KeyExpiredException.java
index f58e48a..15b8d67 100644
--- a/keystore/java/android/security/KeyExpiredException.java
+++ b/keystore/java/android/security/keystore/KeyExpiredException.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security;
+package android.security.keystore;
 
 import java.security.InvalidKeyException;
 
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
new file mode 100644
index 0000000..fa3b1cb
--- /dev/null
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -0,0 +1,857 @@
+/*
+ * Copyright (C) 2012 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.keystore;
+
+import android.app.KeyguardManager;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.security.ArrayUtils;
+import android.security.KeyStore;
+
+import java.math.BigInteger;
+import java.security.KeyPairGenerator;
+import java.security.cert.Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * {@link AlgorithmParameterSpec} for initializing a {@link KeyPairGenerator} or a
+ * {@link KeyGenerator} of the <a href="{@docRoot}training/articles/keystore.html">Android Keystore
+ * system</a>. The spec determines whether user authentication is required for using the key, what
+ * uses the key is authorized for (e.g., only for signing -- decryption not permitted), whether the
+ * key should be encrypted at rest, the key's and validity start and end dates.
+ *
+ * <p>To generate an asymmetric key pair or a symmetric key, create an instance of this class using
+ * the {@link Builder}, initialize a {@code KeyPairGenerator} or a {@code KeyGenerator} of the
+ * desired key type (e.g., {@code EC} or {@code AES} -- see
+ * {@link KeyProperties}.{@code KEY_ALGORITHM} constants) from the {@code AndroidKeyStore} provider
+ * with the {@code KeyPairGeneratorSpec} instance, and then generate a key or key pair using
+ * {@link KeyPairGenerator#generateKeyPair()}.
+ *
+ * <p>The generated key pair or key will be returned by the generator and also stored in the Android
+ * Keystore system under the alias specified in this spec. To obtain the secret or private key from
+ * the Android KeyStore use {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)}
+ * or {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}.
+ * To obtain the public key from the Android Keystore system use
+ * {@link java.security.KeyStore#getCertificate(String)} and then
+ * {@link Certificate#getPublicKey()}.
+ *
+ * <p>For asymmetric key pairs, a self-signed X.509 certificate will be also generated and stored in
+ * the Android KeyStore. This is because the {@link java.security.KeyStore} abstraction does not
+ * support storing key pairs without a certificate. The subject, serial number, and validity dates
+ * of the certificate can be customized in this spec. The self-signed certificate may be replaced at
+ * a later time by a certificate signed by a Certificate Authority (CA).
+ *
+ * <p>NOTE: The key material of the generated symmetric and private keys is not accessible. The key
+ * material of the public keys is accessible.
+ *
+ * <p><h3>Example: Asymmetric key pair</h3>
+ * The following example illustrates how to generate an EC key pair in the Android KeyStore system
+ * under alias {@code key1} authorized to be used only for signing using SHA-256, SHA-384,
+ * or SHA-512 digest and only if the user has been authenticated within the last five minutes.
+ * <pre> {@code
+ * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
+ *         KeyProperties.KEY_ALGORITHM_EC,
+ *         "AndroidKeyStore");
+ * keyPairGenerator.initialize(
+ *         new KeyGenParameterSpec.Builder("key1",
+ *                 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+ *                 .setDigests(KeyProperties.DIGEST_SHA256
+ *                         | KeyProperties.DIGEST_SHA384
+ *                         | KeyProperties.DIGEST_SHA512)
+ *                 // Only permit this key to be used if the user authenticated
+ *                 // within the last five minutes.
+ *                 .setUserAuthenticationRequired(true)
+ *                 .setUserAuthenticationValidityDurationSeconds(5 * 60)
+ *                 .build());
+ * KeyPair keyPair = keyPairGenerator.generateKeyPair();
+ *
+ * // The key pair can also be obtained from the Android Keystore any time as follows:
+ * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ * keyStore.load(null);
+ * PrivateKey privateKey = (PrivateKey) keyStore.getKey("key1", null);
+ * PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey();
+ * }</pre>
+ *
+ * <p><h3>Example: Symmetric key</h3>
+ * The following example illustrates how to generate an AES key in the Android KeyStore system under
+ * alias {@code key2} authorized to be used only for encryption/decryption in CTR mode.
+ * <pre> {@code
+ * KeyGenerator keyGenerator = KeyGenerator.getInstance(
+ *         KeyProperties.KEY_ALGORITHM_HMAC_SHA256,
+ *         "AndroidKeyStore");
+ * keyGenerator.initialize(
+ *         new KeyGenParameterSpec.Builder("key2",
+ *                 KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ *                 .setBlockModes(KeyProperties.BLOCK_MODE_CTR)
+ *                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ *                 .build());
+ * SecretKey key = keyGenerator.generateKey();
+ *
+ * // The key can also be obtained from the Android Keystore any time as follows:
+ * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ * keyStore.load(null);
+ * key = (SecretKey) keyStore.getKey("key2", null);
+ * }</pre>
+ */
+public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
+
+    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
+    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
+    private final String mKeystoreAlias;
+    private final int mKeySize;
+    private final AlgorithmParameterSpec mSpec;
+    private final X500Principal mCertificateSubject;
+    private final BigInteger mCertificateSerialNumber;
+    private final Date mCertificateNotBefore;
+    private final Date mCertificateNotAfter;
+    private final int mFlags;
+    private final Date mKeyValidityStart;
+    private final Date mKeyValidityForOriginationEnd;
+    private final Date mKeyValidityForConsumptionEnd;
+    private final @KeyProperties.PurposeEnum int mPurposes;
+    private final @KeyProperties.DigestEnum String[] mDigests;
+    private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
+    private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
+    private final @KeyProperties.BlockModeEnum String[] mBlockModes;
+    private final boolean mRandomizedEncryptionRequired;
+    private final boolean mUserAuthenticationRequired;
+    private final int mUserAuthenticationValidityDurationSeconds;
+
+    /**
+     * @hide should be built with Builder
+     */
+    public KeyGenParameterSpec(
+            String keyStoreAlias,
+            int keySize,
+            AlgorithmParameterSpec spec,
+            X500Principal certificateSubject,
+            BigInteger certificateSerialNumber,
+            Date certificateNotBefore,
+            Date certificateNotAfter,
+            int flags,
+            Date keyValidityStart,
+            Date keyValidityForOriginationEnd,
+            Date keyValidityForConsumptionEnd,
+            @KeyProperties.PurposeEnum int purposes,
+            @KeyProperties.DigestEnum String[] digests,
+            @KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
+            @KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
+            @KeyProperties.BlockModeEnum String[] blockModes,
+            boolean randomizedEncryptionRequired,
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
+        if (TextUtils.isEmpty(keyStoreAlias)) {
+            throw new IllegalArgumentException("keyStoreAlias must not be empty");
+        } else if ((userAuthenticationValidityDurationSeconds < 0)
+                && (userAuthenticationValidityDurationSeconds != -1)) {
+            throw new IllegalArgumentException(
+                    "userAuthenticationValidityDurationSeconds must not be negative");
+        }
+
+        if (certificateSubject == null) {
+            certificateSubject = DEFAULT_CERT_SUBJECT;
+        }
+        if (certificateNotBefore == null) {
+            certificateNotBefore = DEFAULT_CERT_NOT_BEFORE;
+        }
+        if (certificateNotAfter == null) {
+            certificateNotAfter = DEFAULT_CERT_NOT_AFTER;
+        }
+        if (certificateSerialNumber == null) {
+            certificateSerialNumber = DEFAULT_CERT_SERIAL_NUMBER;
+        }
+
+        if (certificateNotAfter.before(certificateNotBefore)) {
+            throw new IllegalArgumentException("certificateNotAfter < certificateNotBefore");
+        }
+
+        mKeystoreAlias = keyStoreAlias;
+        mKeySize = keySize;
+        mSpec = spec;
+        mCertificateSubject = certificateSubject;
+        mCertificateSerialNumber = certificateSerialNumber;
+        mCertificateNotBefore = certificateNotBefore;
+        mCertificateNotAfter = certificateNotAfter;
+        mFlags = flags;
+        mKeyValidityStart = keyValidityStart;
+        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
+        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mPurposes = purposes;
+        mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
+        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+        mUserAuthenticationRequired = userAuthenticationRequired;
+        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * Returns the alias that will be used in the {@code java.security.KeyStore}
+     * in conjunction with the {@code AndroidKeyStore}.
+     */
+    public String getKeystoreAlias() {
+        return mKeystoreAlias;
+    }
+
+    /**
+     * Returns the requested key size or {@code -1} if default size should be used.
+     */
+    public int getKeySize() {
+        return mKeySize;
+    }
+
+    /**
+     * Returns the {@link AlgorithmParameterSpec} that will be used for creation
+     * of the key pair.
+     */
+    @NonNull
+    public AlgorithmParameterSpec getAlgorithmParameterSpec() {
+        return mSpec;
+    }
+
+    /**
+     * Returns the subject distinguished name to be used on the X.509 certificate that will be put
+     * in the {@link java.security.KeyStore}.
+     */
+    @NonNull
+    public X500Principal getCertificateSubject() {
+        return mCertificateSubject;
+    }
+
+    /**
+     * Returns the serial number to be used on the X.509 certificate that will be put in the
+     * {@link java.security.KeyStore}.
+     */
+    @NonNull
+    public BigInteger getCertificateSerialNumber() {
+        return mCertificateSerialNumber;
+    }
+
+    /**
+     * Returns the start date to be used on the X.509 certificate that will be put in the
+     * {@link java.security.KeyStore}.
+     */
+    @NonNull
+    public Date getCertificateNotBefore() {
+        return mCertificateNotBefore;
+    }
+
+    /**
+     * Returns the end date to be used on the X.509 certificate that will be put in the
+     * {@link java.security.KeyStore}.
+     */
+    @NonNull
+    public Date getCertificateNotAfter() {
+        return mCertificateNotAfter;
+    }
+
+    /**
+     * @hide
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Returns {@code true} if the key must be encrypted at rest. This will protect the key with the
+     * secure lock screen credential (e.g., password, PIN, or pattern).
+     *
+     * <p>Note that encrypting the key at rest requires that the secure lock screen (e.g., password,
+     * PIN, pattern) is set up, otherwise key generation will fail. Moreover, this key will be
+     * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device
+     * Administrator). Finally, this key cannot be used until the user unlocks the secure lock
+     * screen after boot.
+     *
+     * @see KeyguardManager#isDeviceSecure()
+     */
+    public boolean isEncryptionAtRestRequired() {
+        return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
+    }
+
+    /**
+     * Returns the time instant before which the key is not yet valid or {@code null} if not
+     * restricted.
+     */
+    @Nullable
+    public Date getKeyValidityStart() {
+        return mKeyValidityStart;
+    }
+
+    /**
+     * Returns the time instant after which the key is no longer valid for decryption and
+     * verification or {@code null} if not restricted.
+     */
+    @Nullable
+    public Date getKeyValidityForConsumptionEnd() {
+        return mKeyValidityForConsumptionEnd;
+    }
+
+    /**
+     * Returns the time instant after which the key is no longer valid for encryption and signing
+     * or {@code null} if not restricted.
+     */
+    @Nullable
+    public Date getKeyValidityForOriginationEnd() {
+        return mKeyValidityForOriginationEnd;
+    }
+
+    /**
+     * Returns the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
+     * Attempts to use the key for any other purpose will be rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code PURPOSE} flags.
+     */
+    public @KeyProperties.PurposeEnum int getPurposes() {
+        return mPurposes;
+    }
+
+    /**
+     * Returns the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384} with which the
+     * key can be used or {@code null} if not specified.
+     *
+     * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+     *
+     * @throws IllegalStateException if this set has not been specified.
+     *
+     * @see #isDigestsSpecified()
+     */
+    @NonNull
+    public @KeyProperties.DigestEnum String[] getDigests() {
+        if (mDigests == null) {
+            throw new IllegalStateException("Digests not specified");
+        }
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
+    }
+
+    /**
+     * Returns {@code true} if the set of digest algorithms with which the key can be used has been
+     * specified.
+     *
+     * @see #getDigests()
+     */
+    @NonNull
+    public boolean isDigestsSpecified() {
+        return mDigests != null;
+    }
+
+    /**
+     * Returns the set of padding schemes (e.g., {@code PKCS7Padding}, {@code OEAPPadding},
+     * {@code PKCS1Padding}, {@code NoPadding}) with which the key can be used when
+     * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+     * rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
+     */
+    @NonNull
+    public @KeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
+    }
+
+    /**
+     * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
+     * can be used when signing/verifying. Attempts to use the key with any other padding scheme
+     * will be rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
+     */
+    @NonNull
+    public @KeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
+    }
+
+    /**
+     * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used
+     * when encrypting/decrypting. Attempts to use the key with any other block modes will be
+     * rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
+     */
+    @NonNull
+    public @KeyProperties.BlockModeEnum String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
+    }
+
+    /**
+     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+     * different ciphertexts for the same plaintext every time. The formal cryptographic property
+     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+     * IND-CPA})</em>. This property is important because it mitigates several classes of
+     * 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.
+     */
+    public boolean isRandomizedEncryptionRequired() {
+        return mRandomizedEncryptionRequired;
+    }
+
+    /**
+     * Returns {@code true} if user authentication is required for this key to be used.
+     *
+     * <p>This restriction applies only to private key operations. Public key operations are not
+     * restricted.
+     *
+     * @see #getUserAuthenticationValidityDurationSeconds()
+     */
+    public boolean isUserAuthenticationRequired() {
+        return mUserAuthenticationRequired;
+    }
+
+    /**
+     * Gets the duration of time (seconds) for which this key can be used after the user is
+     * successfully authenticated. This has effect only if user authentication is required.
+     *
+     * <p>This restriction applies only to private key operations. Public key operations are not
+     * restricted.
+     *
+     * @return duration in seconds or {@code -1} if authentication is required for every use of the
+     *         key.
+     *
+     * @see #isUserAuthenticationRequired()
+     */
+    public int getUserAuthenticationValidityDurationSeconds() {
+        return mUserAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * Builder of {@link KeyGenParameterSpec} instances.
+     */
+    public final static class Builder {
+        private final String mKeystoreAlias;
+        private @KeyProperties.PurposeEnum int mPurposes;
+
+        private int mKeySize = -1;
+        private AlgorithmParameterSpec mSpec;
+        private X500Principal mCertificateSubject;
+        private BigInteger mCertificateSerialNumber;
+        private Date mCertificateNotBefore;
+        private Date mCertificateNotAfter;
+        private int mFlags;
+        private Date mKeyValidityStart;
+        private Date mKeyValidityForOriginationEnd;
+        private Date mKeyValidityForConsumptionEnd;
+        private @KeyProperties.DigestEnum String[] mDigests;
+        private @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
+        private @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
+        private @KeyProperties.BlockModeEnum String[] mBlockModes;
+        private boolean mRandomizedEncryptionRequired = true;
+        private boolean mUserAuthenticationRequired;
+        private int mUserAuthenticationValidityDurationSeconds = -1;
+
+        /**
+         * Creates a new instance of the {@code Builder}.
+         *
+         * @param keystoreAlias alias of the entry in which the generated key will appear in
+         *        Android KeyStore.
+         * @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be
+         *        used. Attempts to use the key for any other purpose will be rejected.
+         *
+         *        <p>If the set of purposes for which the key can be used does not contain
+         *        {@link KeyProperties#PURPOSE_SIGN}, the self-signed certificate generated by
+         *        {@link KeyPairGenerator} of {@code AndroidKeyStore} provider will contain an
+         *        invalid signature. This is OK if the certificate is only used for obtaining the
+         *        public key from Android KeyStore.
+         *
+         *        <p><b>NOTE: The {@code purposes} parameter has currently no effect on asymmetric
+         *        key pairs.</b>
+         *
+         *        <p>See {@link KeyProperties}.{@code PURPOSE} flags.
+         */
+        public Builder(@NonNull String keystoreAlias, @KeyProperties.PurposeEnum int purposes) {
+            if (keystoreAlias == null) {
+                throw new NullPointerException("keystoreAlias == null");
+            }
+            mKeystoreAlias = keystoreAlias;
+            mPurposes = purposes;
+        }
+
+        /**
+         * Sets the size (in bits) of the key to be generated. For instance, for RSA keys this sets
+         * the modulus size, for EC keys this selects a curve with a matching field size, and for
+         * symmetric keys this sets the size of the bitstring which is their key material.
+         *
+         * <p>The default key size is specific to each key algorithm.
+         */
+        @NonNull
+        public Builder setKeySize(int keySize) {
+            if (keySize < 0) {
+                throw new IllegalArgumentException("keySize < 0");
+            }
+            mKeySize = keySize;
+            return this;
+        }
+
+        /**
+         * Sets the algorithm-specific key generation parameters. For example, for RSA keys this may
+         * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}.
+         */
+        public Builder setAlgorithmParameterSpec(@NonNull AlgorithmParameterSpec spec) {
+            if (spec == null) {
+                throw new NullPointerException("spec == null");
+            }
+            mSpec = spec;
+            return this;
+        }
+
+        /**
+         * Sets the subject used for the self-signed certificate of the generated key pair.
+         *
+         * <p>By default, the subject is {@code CN=fake}.
+         */
+        @NonNull
+        public Builder setCertificateSubject(@NonNull X500Principal subject) {
+            if (subject == null) {
+                throw new NullPointerException("subject == null");
+            }
+            mCertificateSubject = subject;
+            return this;
+        }
+
+        /**
+         * Sets the serial number used for the self-signed certificate of the generated key pair.
+         *
+         * <p>By default, the serial number is {@code 1}.
+         */
+        @NonNull
+        public Builder setCertificateSerialNumber(@NonNull BigInteger serialNumber) {
+            if (serialNumber == null) {
+                throw new NullPointerException("serialNumber == null");
+            }
+            mCertificateSerialNumber = serialNumber;
+            return this;
+        }
+
+        /**
+         * Sets the start of the validity period for the self-signed certificate of the generated
+         * key pair.
+         *
+         * <p>By default, this date is {@code Jan 1 1970}.
+         */
+        @NonNull
+        public Builder setCertificateNotBefore(@NonNull Date date) {
+            if (date == null) {
+                throw new NullPointerException("date == null");
+            }
+            mCertificateNotBefore = date;
+            return this;
+        }
+
+        /**
+         * Sets the end of the validity period for the self-signed certificate of the generated key
+         * pair.
+         *
+         * <p>By default, this date is {@code Jan 1 2048}.
+         */
+        @NonNull
+        public Builder setCertificateNotAfter(@NonNull Date date) {
+            if (date == null) {
+                throw new NullPointerException("date == null");
+            }
+            mCertificateNotAfter = date;
+            return this;
+        }
+
+        /**
+         * Sets whether this key pair or key must be encrypted at rest. This will protect the key
+         * pair or key with the secure lock screen credential (e.g., password, PIN, or pattern).
+         *
+         * <p>Note that enabling this feature requires that the secure lock screen (e.g., password,
+         * PIN, pattern) is set up, otherwise key generation will fail. Moreover, this key will be
+         * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device
+         * Administrator). Finally, this key cannot be used until the user unlocks the secure lock
+         * screen after boot.
+         *
+         * @see KeyguardManager#isDeviceSecure()
+         */
+        @NonNull
+        public Builder setEncryptionAtRestRequired(boolean required) {
+            if (required) {
+                mFlags |= KeyStore.FLAG_ENCRYPTED;
+            } else {
+                mFlags &= ~KeyStore.FLAG_ENCRYPTED;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the time instant before which the key is not yet valid.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityStart(Date startDate) {
+            mKeyValidityStart = startDate;
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityStart(Date)
+         * @see #setKeyValidityForConsumptionEnd(Date)
+         * @see #setKeyValidityForOriginationEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityEnd(Date endDate) {
+            setKeyValidityForOriginationEnd(endDate);
+            setKeyValidityForConsumptionEnd(endDate);
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid for encryption and signing.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityForConsumptionEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityForOriginationEnd(Date endDate) {
+            mKeyValidityForOriginationEnd = endDate;
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid for decryption and
+         * verification.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityForOriginationEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
+            mKeyValidityForConsumptionEnd = endDate;
+            return this;
+        }
+
+        /**
+         * Sets the set of digests algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which
+         * the key can be used when signing/verifying. Attempts to use the key with any other digest
+         * algorithm will be rejected.
+         *
+         * <p>This must be specified for keys which are used for signing/verification. For HMAC
+         * keys, the set of digests defaults to the digest associated with the key algorithm (e.g.,
+         * {@code SHA-256} for key algorithm {@code HmacSHA256}
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see KeyProperties.Digest
+         */
+        @NonNull
+        public Builder setDigests(@KeyProperties.DigestEnum String... digests) {
+            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+            return this;
+        }
+
+        /**
+         * Sets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code OAEPPadding},
+         * {@code PKCS1Padding}, {@code NoPadding}) with which the key can be used when
+         * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+         * rejected.
+         *
+         * <p>This must be specified for keys which are used for encryption/decryption.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
+         */
+        @NonNull
+        public Builder setEncryptionPaddings(
+                @KeyProperties.EncryptionPaddingEnum String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+        /**
+         * Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
+         * can be used when signing/verifying. Attempts to use the key with any other padding scheme
+         * will be rejected.
+         *
+         * <p>This must be specified for RSA keys which are used for signing/verification.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
+         */
+        @NonNull
+        public Builder setSignaturePaddings(
+                @KeyProperties.SignaturePaddingEnum String... paddings) {
+            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+        /**
+         * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}, {@code ECB}) with which the
+         * key can be used when encrypting/decrypting. Attempts to use the key with any other block
+         * modes will be rejected.
+         *
+         * <p>This must be specified for encryption/decryption keys.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
+         */
+        @NonNull
+        public Builder setBlockModes(@KeyProperties.BlockModeEnum String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
+            return this;
+        }
+
+        /**
+         * Sets whether encryption using this key must be sufficiently randomized to produce
+         * different ciphertexts for the same plaintext every time. The formal cryptographic
+         * property being required is <em>indistinguishability under chosen-plaintext attack
+         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+         * of 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.
+         *
+         * <p>By default, {@code IND-CPA} is required.
+         *
+         * <p>When {@code IND-CPA} is required:
+         * <ul>
+         * <li>encryption/decryption transformation which do not offer {@code IND-CPA}, such as
+         * {@code ECB} with a symmetric encryption algorithm, or RSA encryption/decryption without
+         * padding, are prohibited;</li>
+         * <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM},
+         * caller-provided IVs are rejected when encrypting, to ensure that only random IVs are
+         * used.</li>
+         * </ul>
+         *
+         * <p>Before disabling this requirement, consider the following approaches instead:
+         * <ul>
+         * <li>If you are generating a random IV for encryption and then initializing a {@code}
+         * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
+         * instead. This will occur if the {@code Cipher} is initialized for encryption without an
+         * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
+         * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
+         * random, such as the name of the file being encrypted, or transaction ID, or password,
+         * or a device identifier), consider changing your design to use a random IV which will then
+         * be provided in addition to the ciphertext to the entities which need to decrypt the
+         * ciphertext.</li>
+         * <li>If you are using RSA encryption without padding, consider switching to encryption
+         * padding schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
+         * </ul>
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         */
+        @NonNull
+        public Builder setRandomizedEncryptionRequired(boolean required) {
+            mRandomizedEncryptionRequired = required;
+            return this;
+        }
+
+        /**
+         * Sets whether user authentication is required to use this key.
+         *
+         * <p>By default, the key can be used without user authentication.
+         *
+         * <p>When user authentication is required, the user authorizes the use of the key by
+         * authenticating to this Android device using a subset of their secure lock screen
+         * credentials. Different authentication methods are used depending on whether the every
+         * use of the key must be authenticated (as specified by
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
+         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
+         * information</a>.
+         *
+         * <p>This restriction applies only to private key operations. Public key operations are not
+         * restricted.
+         *
+         * <p><b>NOTE: This has currently no effect.</b>
+         *
+         * @see #setUserAuthenticationValidityDurationSeconds(int)
+         */
+        @NonNull
+        public Builder setUserAuthenticationRequired(boolean required) {
+            mUserAuthenticationRequired = required;
+            return this;
+        }
+
+        /**
+         * Sets the duration of time (seconds) for which this key can be used after the user is
+         * successfully authenticated. This has effect only if user authentication is required.
+         *
+         * <p>By default, the user needs to authenticate for every use of the key.
+         *
+         * <p><b>NOTE: This has currently no effect.</b>
+         *
+         * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
+         *        every use of the key.
+         *
+         * @see #setUserAuthenticationRequired(boolean)
+         */
+        @NonNull
+        public Builder setUserAuthenticationValidityDurationSeconds(
+                @IntRange(from = -1) int seconds) {
+            mUserAuthenticationValidityDurationSeconds = seconds;
+            return this;
+        }
+
+        /**
+         * Builds an instance of {@code KeyGenParameterSpec}.
+         *
+         * @throws IllegalArgumentException if a required field is missing
+         */
+        @NonNull
+        public KeyGenParameterSpec build() {
+            return new KeyGenParameterSpec(
+                    mKeystoreAlias,
+                    mKeySize,
+                    mSpec,
+                    mCertificateSubject,
+                    mCertificateSerialNumber,
+                    mCertificateNotBefore,
+                    mCertificateNotAfter,
+                    mFlags,
+                    mKeyValidityStart,
+                    mKeyValidityForOriginationEnd,
+                    mKeyValidityForConsumptionEnd,
+                    mPurposes,
+                    mDigests,
+                    mEncryptionPaddings,
+                    mSignaturePaddings,
+                    mBlockModes,
+                    mRandomizedEncryptionRequired,
+                    mUserAuthenticationRequired,
+                    mUserAuthenticationValidityDurationSeconds);
+        }
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/keystore/KeyInfo.java
similarity index 76%
rename from keystore/java/android/security/KeyStoreKeySpec.java
rename to keystore/java/android/security/keystore/KeyInfo.java
index 4c43f89..aec2512 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.security;
+package android.security.keystore;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.security.ArrayUtils;
 
 import java.security.PrivateKey;
 import java.security.spec.KeySpec;
@@ -27,55 +28,55 @@
 
 /**
  * Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
- * KeyStore</a>. This class describes whether the key material is available in
+ * Keystore system</a>. This class describes whether the key material is available in
  * plaintext outside of secure hardware, whether user authentication is required for using the key
  * and whether this requirement is enforced by secure hardware, the key's origin, what uses the key
  * is authorized for (e.g., only in {@code CBC} mode, or signing only), whether the key should be
  * encrypted at rest, the key's and validity start and end dates.
  *
  * <p><h3>Example: Symmetric Key</h3>
- * The following example illustrates how to obtain a {@link KeyStoreKeySpec} describing the provided
- * Android KeyStore {@link SecretKey}.
+ * The following example illustrates how to obtain a {@code KeyInfo} describing the provided Android
+ * Keystore {@link SecretKey}.
  * <pre> {@code
- * SecretKey key = ...; // Android KeyStore key
+ * SecretKey key = ...; // Android Keystore key
  *
  * SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
- * KeyStoreKeySpec spec;
+ * KeyInfo keyInfo;
  * try &#123;
- *     spec = (KeyStoreKeySpec) factory.getKeySpec(key, KeyStoreKeySpec.class);
+ *     keyInfo = (KeyInfo) factory.getKeySpec(key, KeyInfo.class);
  * &#125; catch (InvalidKeySpecException e) &#123;
  *     // Not an Android KeyStore key.
  * &#125;
  * }</pre>
  *
  * <p><h3>Example: Private Key</h3>
- * The following example illustrates how to obtain a {@link KeyStoreKeySpec} describing the provided
+ * The following example illustrates how to obtain a {@code KeyInfo} describing the provided
  * Android KeyStore {@link PrivateKey}.
  * <pre> {@code
  * PrivateKey key = ...; // Android KeyStore key
  *
  * KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
- * KeyStoreKeySpec spec;
+ * KeyInfo keyInfo;
  * try &#123;
- *     spec = factory.getKeySpec(key, KeyStoreKeySpec.class);
+ *     keyInfo = factory.getKeySpec(key, KeyInfo.class);
  * &#125; catch (InvalidKeySpecException e) &#123;
  *     // Not an Android KeyStore key.
  * &#125;
  * }</pre>
  */
-public class KeyStoreKeySpec implements KeySpec {
+public class KeyInfo implements KeySpec {
     private final String mKeystoreAlias;
     private final int mKeySize;
     private final boolean mInsideSecureHardware;
-    private final @KeyStoreKeyProperties.OriginEnum int mOrigin;
+    private final @KeyProperties.OriginEnum int mOrigin;
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
-    private final @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
-    private final @KeyStoreKeyProperties.DigestEnum String[] mDigests;
-    private final @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
+    private final @KeyProperties.PurposeEnum int mPurposes;
+    private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
+    private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
+    private final @KeyProperties.DigestEnum String[] mDigests;
+    private final @KeyProperties.BlockModeEnum String[] mBlockModes;
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
@@ -83,18 +84,18 @@
     /**
      * @hide
      */
-    KeyStoreKeySpec(String keystoreKeyAlias,
+    public KeyInfo(String keystoreKeyAlias,
             boolean insideSecureHardware,
-            @KeyStoreKeyProperties.OriginEnum int origin,
+            @KeyProperties.OriginEnum int origin,
             int keySize,
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyProperties.PurposeEnum int purposes,
-            @KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
-            @KeyStoreKeyProperties.SignaturePaddingEnum String[] signaturePaddings,
-            @KeyStoreKeyProperties.DigestEnum String[] digests,
-            @KeyStoreKeyProperties.BlockModeEnum String[] blockModes,
+            @KeyProperties.PurposeEnum int purposes,
+            @KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
+            @KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
+            @KeyProperties.DigestEnum String[] digests,
+            @KeyProperties.BlockModeEnum String[] blockModes,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
             boolean userAuthenticationRequirementEnforcedBySecureHardware) {
@@ -135,9 +136,9 @@
     }
 
     /**
-     * Gets the origin of the key. See {@link KeyStoreKeyProperties}.{@code ORIGIN} constants.
+     * Gets the origin of the key. See {@link KeyProperties}.{@code ORIGIN} constants.
      */
-    public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
+    public @KeyProperties.OriginEnum int getOrigin() {
         return mOrigin;
     }
 
@@ -182,9 +183,9 @@
      * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
      * Attempts to use the key for any other purpose will be rejected.
      *
-     * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
+     * <p>See {@link KeyProperties}.{@code PURPOSE} flags.
      */
-    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
+    public @KeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
@@ -193,10 +194,10 @@
      * when encrypting/decrypting. Attempts to use the key with any other block modes will be
      * rejected.
      *
-     * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
+     * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
      */
     @NonNull
-    public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() {
+    public @KeyProperties.BlockModeEnum String[] getBlockModes() {
         return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
@@ -205,10 +206,10 @@
      * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
      * the key with any other padding scheme will be rejected.
      *
-     * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
+     * <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
      */
     @NonNull
-    public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
+    public @KeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
         return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
@@ -217,10 +218,10 @@
      * can be used when signing/verifying. Attempts to use the key with any other padding scheme
      * will be rejected.
      *
-     * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
+     * <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
      */
     @NonNull
-    public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
+    public @KeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
         return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
     }
 
@@ -228,10 +229,10 @@
      * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key
      * can be used.
      *
-     * @see KeyStoreKeyProperties.Digest
+     * <p>See {@link KeyProperties}.{@code DIGEST} constants.
      */
     @NonNull
-    public @KeyStoreKeyProperties.DigestEnum String[] getDigests() {
+    public @KeyProperties.DigestEnum String[] getDigests() {
         return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
diff --git a/keystore/java/android/security/KeyNotYetValidException.java b/keystore/java/android/security/keystore/KeyNotYetValidException.java
similarity index 97%
rename from keystore/java/android/security/KeyNotYetValidException.java
rename to keystore/java/android/security/keystore/KeyNotYetValidException.java
index 4ea27ef..2cec77d 100644
--- a/keystore/java/android/security/KeyNotYetValidException.java
+++ b/keystore/java/android/security/keystore/KeyNotYetValidException.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security;
+package android.security.keystore;
 
 import java.security.InvalidKeyException;
 
diff --git a/keystore/java/android/security/KeyPermanentlyInvalidatedException.java b/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java
similarity index 98%
rename from keystore/java/android/security/KeyPermanentlyInvalidatedException.java
rename to keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java
index 229eab0..e320c9c 100644
--- a/keystore/java/android/security/KeyPermanentlyInvalidatedException.java
+++ b/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security;
+package android.security.keystore;
 
 import java.security.InvalidKeyException;
 
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
similarity index 89%
rename from keystore/java/android/security/KeyStoreKeyProperties.java
rename to keystore/java/android/security/keystore/KeyProperties.java
index b58a7dd..e3c2d1d 100644
--- a/keystore/java/android/security/KeyStoreKeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security;
+package android.security.keystore;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -30,10 +30,10 @@
 import java.util.Locale;
 
 /**
- * Properties of {@code AndroidKeyStore} keys.
+ * Properties of <a href="{@docRoot}training/articles/keystore.html">Android Keystore</a> keys.
  */
-public abstract class KeyStoreKeyProperties {
-    private KeyStoreKeyProperties() {}
+public abstract class KeyProperties {
+    private KeyProperties() {}
 
     /**
      * @hide
@@ -68,10 +68,13 @@
      */
     public static final int PURPOSE_VERIFY = 1 << 3;
 
-    static abstract class Purpose {
+    /**
+     * @hide
+     */
+    public static abstract class Purpose {
         private Purpose() {}
 
-        static int toKeymaster(@PurposeEnum int purpose) {
+        public static int toKeymaster(@PurposeEnum int purpose) {
             switch (purpose) {
                 case PURPOSE_ENCRYPT:
                     return KeymasterDefs.KM_PURPOSE_ENCRYPT;
@@ -86,7 +89,7 @@
             }
         }
 
-        static @PurposeEnum int fromKeymaster(int purpose) {
+        public static @PurposeEnum int fromKeymaster(int purpose) {
             switch (purpose) {
                 case KeymasterDefs.KM_PURPOSE_ENCRYPT:
                     return PURPOSE_ENCRYPT;
@@ -102,7 +105,7 @@
         }
 
         @NonNull
-        static int[] allToKeymaster(@PurposeEnum int purposes) {
+        public static int[] allToKeymaster(@PurposeEnum int purposes) {
             int[] result = getSetFlags(purposes);
             for (int i = 0; i < result.length; i++) {
                 result[i] = toKeymaster(result[i]);
@@ -110,7 +113,7 @@
             return result;
         }
 
-        static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) {
+        public static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) {
             @PurposeEnum int result = 0;
             for (int keymasterPurpose : purposes) {
                 result |= fromKeymaster(keymasterPurpose);
@@ -159,10 +162,14 @@
     /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */
     public static final String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512";
 
-    static abstract class KeyAlgorithm {
+    /**
+     * @hide
+     */
+    public static abstract class KeyAlgorithm {
         private KeyAlgorithm() {}
 
-        static int toKeymasterSecretKeyAlgorithm(@NonNull @KeyAlgorithmEnum String algorithm) {
+        public static int toKeymasterSecretKeyAlgorithm(
+                @NonNull @KeyAlgorithmEnum String algorithm) {
             if (KEY_ALGORITHM_AES.equalsIgnoreCase(algorithm)) {
                 return KeymasterDefs.KM_ALGORITHM_AES;
             } else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
@@ -174,7 +181,7 @@
         }
 
         @NonNull
-        static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm(
+        public static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm(
                 int keymasterAlgorithm, int keymasterDigest) {
             switch (keymasterAlgorithm) {
                 case KeymasterDefs.KM_ALGORITHM_AES:
@@ -210,7 +217,7 @@
          *
          * @return keymaster digest or {@code -1} if the algorithm does not involve a digest.
          */
-        static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) {
+        public static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) {
             String algorithmUpper = algorithm.toUpperCase(Locale.US);
             if (algorithmUpper.startsWith("HMAC")) {
                 String digestUpper = algorithmUpper.substring("HMAC".length());
@@ -259,10 +266,13 @@
     /** Galois/Counter Mode (GCM) block mode. */
     public static final String BLOCK_MODE_GCM = "GCM";
 
-    static abstract class BlockMode {
+    /**
+     * @hide
+     */
+    public static abstract class BlockMode {
         private BlockMode() {}
 
-        static int toKeymaster(@NonNull @BlockModeEnum String blockMode) {
+        public static int toKeymaster(@NonNull @BlockModeEnum String blockMode) {
             if (BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) {
                 return KeymasterDefs.KM_MODE_ECB;
             } else if (BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) {
@@ -277,7 +287,7 @@
         }
 
         @NonNull
-        static @BlockModeEnum String fromKeymaster(int blockMode) {
+        public static @BlockModeEnum String fromKeymaster(int blockMode) {
             switch (blockMode) {
                 case KeymasterDefs.KM_MODE_ECB:
                     return BLOCK_MODE_ECB;
@@ -293,7 +303,8 @@
         }
 
         @NonNull
-        static @BlockModeEnum String[] allFromKeymaster(@NonNull Collection<Integer> blockModes) {
+        public static @BlockModeEnum String[] allFromKeymaster(
+                @NonNull Collection<Integer> blockModes) {
             if ((blockModes == null) || (blockModes.isEmpty())) {
                 return EmptyArray.STRING;
             }
@@ -306,7 +317,7 @@
             return result;
         }
 
-        static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) {
+        public static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) {
             if ((blockModes == null) || (blockModes.length == 0)) {
                 return EmptyArray.INT;
             }
@@ -350,10 +361,13 @@
      */
     public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding";
 
-    static abstract class EncryptionPadding {
+    /**
+     * @hide
+     */
+    public static abstract class EncryptionPadding {
         private EncryptionPadding() {}
 
-        static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) {
+        public static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) {
             if (ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
                 return KeymasterDefs.KM_PAD_NONE;
             } else if (ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
@@ -369,7 +383,7 @@
         }
 
         @NonNull
-        static @EncryptionPaddingEnum String fromKeymaster(int padding) {
+        public static @EncryptionPaddingEnum String fromKeymaster(int padding) {
             switch (padding) {
                 case KeymasterDefs.KM_PAD_NONE:
                     return ENCRYPTION_PADDING_NONE;
@@ -386,7 +400,7 @@
         }
 
         @NonNull
-        static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) {
+        public static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) {
             if ((paddings == null) || (paddings.length == 0)) {
                 return EmptyArray.INT;
             }
@@ -508,10 +522,13 @@
      */
     public static final String DIGEST_SHA512 = "SHA-512";
 
-    static abstract class Digest {
+    /**
+     * @hide
+     */
+    public static abstract class Digest {
         private Digest() {}
 
-        static int toKeymaster(@NonNull @DigestEnum String digest) {
+        public static int toKeymaster(@NonNull @DigestEnum String digest) {
             switch (digest.toUpperCase(Locale.US)) {
                 case DIGEST_SHA1:
                     return KeymasterDefs.KM_DIGEST_SHA1;
@@ -533,7 +550,7 @@
         }
 
         @NonNull
-        static @DigestEnum String fromKeymaster(int digest) {
+        public static @DigestEnum String fromKeymaster(int digest) {
             switch (digest) {
                 case KeymasterDefs.KM_DIGEST_NONE:
                     return DIGEST_NONE;
@@ -555,7 +572,7 @@
         }
 
         @NonNull
-        static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) {
+        public static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) {
             if (digests.isEmpty()) {
                 return EmptyArray.STRING;
             }
@@ -569,7 +586,7 @@
         }
 
         @NonNull
-        static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) {
+        public static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) {
             if ((digests == null) || (digests.length == 0)) {
                 return EmptyArray.INT;
             }
@@ -606,10 +623,13 @@
      */
     public static final int ORIGIN_UNKNOWN = 1 << 2;
 
-    static abstract class Origin {
+    /**
+     * @hide
+     */
+    public static abstract class Origin {
         private Origin() {}
 
-        static @OriginEnum int fromKeymaster(int origin) {
+        public static @OriginEnum int fromKeymaster(int origin) {
             switch (origin) {
                 case KeymasterDefs.KM_ORIGIN_GENERATED:
                     return ORIGIN_GENERATED;
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
new file mode 100644
index 0000000..113159d
--- /dev/null
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -0,0 +1,608 @@
+/*
+ * 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.keystore;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.security.ArrayUtils;
+import android.security.KeyStore;
+
+import java.security.Key;
+import java.security.KeyStore.ProtectionParameter;
+import java.security.cert.Certificate;
+import java.util.Date;
+
+import javax.crypto.Cipher;
+
+/**
+ * Specification of how a key or key pair is secured when imported into the
+ * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class
+ * specifies parameters such as whether user authentication is required for using the key, what uses
+ * the key is authorized for (e.g., only in {@code CTR} mode, or only for signing -- decryption not
+ * permitted), whether the key should be encrypted at rest, the key's and validity start and end
+ * dates.
+ *
+ * <p>To import a key or key pair into the Android KeyStore, create an instance of this class using
+ * the {@link Builder} and pass the instance into {@link java.security.KeyStore#setEntry(String, java.security.KeyStore.Entry, ProtectionParameter) KeyStore.setEntry}
+ * with the key or key pair being imported.
+ *
+ * <p>To obtain the secret/symmetric or private key from the Android KeyStore use
+ * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or
+ * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}.
+ * To obtain the public key from the Android KeyStore use
+ * {@link java.security.KeyStore#getCertificate(String)} and then
+ * {@link Certificate#getPublicKey()}.
+ *
+ * <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible.
+ *
+ * <p><h3>Example: Symmetric Key</h3>
+ * The following example illustrates how to import an AES key into the Android KeyStore under alias
+ * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7
+ * padding. The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format.
+ * <pre> {@code
+ * SecretKey key = ...; // AES key
+ *
+ * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ * keyStore.load(null);
+ * keyStore.setEntry(
+ *         "key1",
+ *         new KeyStore.SecretKeyEntry(key),
+ *         new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ *                 .setBlockMode(KeyProperties.BLOCK_MODE_CBC)
+ *                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
+ *                 .build());
+ * // Key imported, obtain a reference to it.
+ * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);
+ * // The original key can now be thrown away.
+ * }</pre>
+ *
+ * <p><h3>Example: Asymmetric Key Pair</h3>
+ * The following example illustrates how to import an EC key pair into the Android KeyStore under
+ * alias {@code key2} authorized to be used only for signing with SHA-256 digest and only if
+ * the user has been authenticated within the last ten minutes. Both the private and the public key
+ * must export their key material via {@link Key#getEncoded()} in {@code PKCS#8} and {@code X.509}
+ * format respectively.
+ * <pre> {@code
+ * PrivateKey privateKey = ...;   // EC private key
+ * Certificate[] certChain = ...; // Certificate chain with the first certificate
+ *                                // containing the corresponding EC public key.
+ *
+ * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ * keyStore.load(null);
+ * keyStore.setEntry(
+ *         "key2",
+ *         new KeyStore.PrivateKeyEntry(privateKey, certChain),
+ *         new KeyProtection.Builder(KeyProperties.PURPOSE_SIGN)
+ *                 .setDigests(KeyProperties.DIGEST_SHA256)
+ *                 // Only permit this key to be used if the user
+ *                 // authenticated within the last ten minutes.
+ *                 .setUserAuthenticationRequired(true)
+ *                 .setUserAuthenticationValidityDurationSeconds(10 * 60)
+ *                 .build());
+ * // Key pair imported, obtain a reference to it.
+ * PrivateKey keyStorePrivateKey = (PrivateKey) keyStore.getKey("key2", null);
+ * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey();
+ * // The original private key can now be thrown away.
+ * }</pre>
+ */
+public final class KeyProtection implements ProtectionParameter {
+    private final int mFlags;
+    private final Date mKeyValidityStart;
+    private final Date mKeyValidityForOriginationEnd;
+    private final Date mKeyValidityForConsumptionEnd;
+    private final @KeyProperties.PurposeEnum int mPurposes;
+    private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
+    private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
+    private final @KeyProperties.DigestEnum String[] mDigests;
+    private final @KeyProperties.BlockModeEnum String[] mBlockModes;
+    private final boolean mRandomizedEncryptionRequired;
+    private final boolean mUserAuthenticationRequired;
+    private final int mUserAuthenticationValidityDurationSeconds;
+
+    private KeyProtection(
+            int flags,
+            Date keyValidityStart,
+            Date keyValidityForOriginationEnd,
+            Date keyValidityForConsumptionEnd,
+            @KeyProperties.PurposeEnum int purposes,
+            @KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
+            @KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
+            @KeyProperties.DigestEnum String[] digests,
+            @KeyProperties.BlockModeEnum String[] blockModes,
+            boolean randomizedEncryptionRequired,
+            boolean userAuthenticationRequired,
+            int userAuthenticationValidityDurationSeconds) {
+        if ((userAuthenticationValidityDurationSeconds < 0)
+                && (userAuthenticationValidityDurationSeconds != -1)) {
+            throw new IllegalArgumentException(
+                    "userAuthenticationValidityDurationSeconds must not be negative");
+        }
+
+        mFlags = flags;
+        mKeyValidityStart = keyValidityStart;
+        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
+        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mPurposes = purposes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
+        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+        mUserAuthenticationRequired = userAuthenticationRequired;
+        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * @hide
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
+     * Returns {@code true} if the {@link java.security.KeyStore} entry must be encrypted at rest.
+     * This will protect the entry with the secure lock screen credential (e.g., password, PIN, or
+     * pattern).
+     */
+    public boolean isEncryptionAtRestRequired() {
+        return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
+    }
+
+    /**
+     * Gets the time instant before which the key is not yet valid.
+     *
+     * @return instant or {@code null} if not restricted.
+     */
+    @Nullable
+    public Date getKeyValidityStart() {
+        return mKeyValidityStart;
+    }
+
+    /**
+     * Gets the time instant after which the key is no long valid for decryption and verification.
+     *
+     * @return instant or {@code null} if not restricted.
+     */
+    @Nullable
+    public Date getKeyValidityForConsumptionEnd() {
+        return mKeyValidityForConsumptionEnd;
+    }
+
+    /**
+     * Gets the time instant after which the key is no long valid for encryption and signing.
+     *
+     * @return instant or {@code null} if not restricted.
+     */
+    @Nullable
+    public Date getKeyValidityForOriginationEnd() {
+        return mKeyValidityForOriginationEnd;
+    }
+
+    /**
+     * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
+     * Attempts to use the key for any other purpose will be rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code PURPOSE} flags.
+     */
+    public @KeyProperties.PurposeEnum int getPurposes() {
+        return mPurposes;
+    }
+
+    /**
+     * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code PKCS1Padding},
+     * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
+     * the key with any other padding scheme will be rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
+     */
+    @NonNull
+    public @KeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
+    }
+
+    /**
+     * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
+     * can be used when signing/verifying. Attempts to use the key with any other padding scheme
+     * will be rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
+     */
+    @NonNull
+    public @KeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
+    }
+
+    /**
+     * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key
+     * can be used.
+     *
+     * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+     *
+     * @throws IllegalStateException if this set has not been specified.
+     *
+     * @see #isDigestsSpecified()
+     */
+    @NonNull
+    public @KeyProperties.DigestEnum String[] getDigests() {
+        if (mDigests == null) {
+            throw new IllegalStateException("Digests not specified");
+        }
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
+    }
+
+    /**
+     * Returns {@code true} if the set of digest algorithms with which the key can be used has been
+     * specified.
+     *
+     * @see #getDigests()
+     */
+    public boolean isDigestsSpecified() {
+        return mDigests != null;
+    }
+
+    /**
+     * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used
+     * when encrypting/decrypting. Attempts to use the key with any other block modes will be
+     * rejected.
+     *
+     * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
+     */
+    @NonNull
+    public @KeyProperties.BlockModeEnum String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
+    }
+
+    /**
+     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+     * different ciphertexts for the same plaintext every time. The formal cryptographic property
+     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+     * IND-CPA})</em>. This property is important because it mitigates several classes of
+     * 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.
+     */
+    public boolean isRandomizedEncryptionRequired() {
+        return mRandomizedEncryptionRequired;
+    }
+
+    /**
+     * Returns {@code true} if user authentication is required for this key to be used.
+     *
+     * @see #getUserAuthenticationValidityDurationSeconds()
+     */
+    public boolean isUserAuthenticationRequired() {
+        return mUserAuthenticationRequired;
+    }
+
+    /**
+     * Gets the duration of time (seconds) for which this key can be used after the user is
+     * successfully authenticated. This has effect only if user authentication is required.
+     *
+     * @return duration in seconds or {@code -1} if authentication is required for every use of the
+     *         key.
+     *
+     * @see #isUserAuthenticationRequired()
+     */
+    public int getUserAuthenticationValidityDurationSeconds() {
+        return mUserAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * Builder of {@link KeyProtection} instances.
+     */
+    public final static class Builder {
+        private @KeyProperties.PurposeEnum int mPurposes;
+
+        private int mFlags;
+        private Date mKeyValidityStart;
+        private Date mKeyValidityForOriginationEnd;
+        private Date mKeyValidityForConsumptionEnd;
+        private @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
+        private @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
+        private @KeyProperties.DigestEnum String[] mDigests;
+        private @KeyProperties.BlockModeEnum String[] mBlockModes;
+        private boolean mRandomizedEncryptionRequired = true;
+        private boolean mUserAuthenticationRequired;
+        private int mUserAuthenticationValidityDurationSeconds = -1;
+
+        /**
+         * Creates a new instance of the {@code Builder}.
+         *
+         * @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be
+         *        used. Attempts to use the key for any other purpose will be rejected.
+         *
+         *        <p><b>NOTE: The {@code purposes} parameter has currently no effect on asymmetric
+         *        key pairs.</b>
+         *
+         *        <p>See {@link KeyProperties}.{@code PURPOSE} flags.
+         */
+        public Builder(@KeyProperties.PurposeEnum int purposes) {
+            mPurposes = purposes;
+        }
+
+        /**
+         * Sets whether this {@link java.security.KeyStore} entry must be encrypted at rest.
+         * Encryption at rest will protect the entry with the secure lock screen credential (e.g.,
+         * password, PIN, or pattern).
+         *
+         * <p>Note that enabling this feature requires that the secure lock screen (e.g., password,
+         * PIN, pattern) is set up, otherwise setting the {@code KeyStore} entry will fail.
+         * Moreover, this entry will be deleted when the secure lock screen is disabled or reset
+         * (e.g., by the user or a Device Administrator). Finally, this entry cannot be used until
+         * the user unlocks the secure lock screen after boot.
+         *
+         * @see KeyguardManager#isDeviceSecure()
+         */
+        @NonNull
+        public Builder setEncryptionAtRestRequired(boolean required) {
+            if (required) {
+                mFlags |= KeyStore.FLAG_ENCRYPTED;
+            } else {
+                mFlags &= ~KeyStore.FLAG_ENCRYPTED;
+            }
+            return this;
+        }
+
+        /**
+         * Sets the time instant before which the key is not yet valid.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityStart(Date startDate) {
+            mKeyValidityStart = startDate;
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityStart(Date)
+         * @see #setKeyValidityForConsumptionEnd(Date)
+         * @see #setKeyValidityForOriginationEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityEnd(Date endDate) {
+            setKeyValidityForOriginationEnd(endDate);
+            setKeyValidityForConsumptionEnd(endDate);
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid for encryption and signing.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityForConsumptionEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityForOriginationEnd(Date endDate) {
+            mKeyValidityForOriginationEnd = endDate;
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid for decryption and
+         * verification.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setKeyValidityForOriginationEnd(Date)
+         */
+        @NonNull
+        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
+            mKeyValidityForConsumptionEnd = endDate;
+            return this;
+        }
+
+        /**
+         * Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS7Padding},
+         * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to
+         * use the key with any other padding scheme will be rejected.
+         *
+         * <p>This must be specified for keys which are used for encryption/decryption.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
+         */
+        @NonNull
+        public Builder setEncryptionPaddings(
+                @KeyProperties.EncryptionPaddingEnum String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+        /**
+         * Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
+         * can be used when signing/verifying. Attempts to use the key with any other padding scheme
+         * will be rejected.
+         *
+         * <p>This must be specified for RSA keys which are used for signing/verification.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
+         */
+        @NonNull
+        public Builder setSignaturePaddings(
+                @KeyProperties.SignaturePaddingEnum String... paddings) {
+            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+        /**
+         * Sets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the
+         * key can be used when signing/verifying or generating MACs. Attempts to use the key with
+         * any other digest algorithm will be rejected.
+         *
+         * <p>For HMAC keys, the default is the digest algorithm specified in
+         * {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms
+         * must be specified.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code DIGEST} constants.
+         */
+        @NonNull
+        public Builder setDigests(@KeyProperties.DigestEnum String... digests) {
+            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+            return this;
+        }
+
+        /**
+         * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}, {@code ECB}) with which the
+         * key can be used when encrypting/decrypting. Attempts to use the key with any other block
+         * modes will be rejected.
+         *
+         * <p>This must be specified for encryption/decryption keys.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
+         */
+        @NonNull
+        public Builder setBlockModes(@KeyProperties.BlockModeEnum String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
+            return this;
+        }
+
+        /**
+         * Sets whether encryption using this key must be sufficiently randomized to produce
+         * different ciphertexts for the same plaintext every time. The formal cryptographic
+         * property being required is <em>indistinguishability under chosen-plaintext attack
+         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+         * of 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.
+         *
+         * <p>By default, {@code IND-CPA} is required.
+         *
+         * <p>When {@code IND-CPA} is required:
+         * <ul>
+         * <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using
+         * {@code ECB} mode or RSA encryption without padding, are prohibited;</li>
+         * <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC},
+         * {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when
+         * encrypting, to ensure that only random IVs are used.</li>
+         *
+         * <p>Before disabling this requirement, consider the following approaches instead:
+         * <ul>
+         * <li>If you are generating a random IV for encryption and then initializing a {@code}
+         * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
+         * instead. This will occur if the {@code Cipher} is initialized for encryption without an
+         * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
+         * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
+         * random, such as the name of the file being encrypted, or transaction ID, or password,
+         * or a device identifier), consider changing your design to use a random IV which will then
+         * be provided in addition to the ciphertext to the entities which need to decrypt the
+         * ciphertext.</li>
+         * <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>
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         */
+        @NonNull
+        public Builder setRandomizedEncryptionRequired(boolean required) {
+            mRandomizedEncryptionRequired = required;
+            return this;
+        }
+
+        /**
+         * Sets whether user authentication is required to use this key.
+         *
+         * <p>By default, the key can be used without user authentication.
+         *
+         * <p>When user authentication is required, the user authorizes the use of the key by
+         * authenticating to this Android device using a subset of their secure lock screen
+         * credentials. Different authentication methods are used depending on whether the every
+         * use of the key must be authenticated (as specified by
+         * {@link #setUserAuthenticationValidityDurationSeconds(int)}).
+         * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
+         * information</a>.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @see #setUserAuthenticationValidityDurationSeconds(int)
+         */
+        @NonNull
+        public Builder setUserAuthenticationRequired(boolean required) {
+            mUserAuthenticationRequired = required;
+            return this;
+        }
+
+        /**
+         * Sets the duration of time (seconds) for which this key can be used after the user is
+         * successfully authenticated. This has effect only if user authentication is required.
+         *
+         * <p>By default, the user needs to authenticate for every use of the key.
+         *
+         * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
+         *
+         * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
+         *        every use of the key.
+         *
+         * @see #setUserAuthenticationRequired(boolean)
+         */
+        @NonNull
+        public Builder setUserAuthenticationValidityDurationSeconds(
+                @IntRange(from = -1) int seconds) {
+            mUserAuthenticationValidityDurationSeconds = seconds;
+            return this;
+        }
+
+        /**
+         * Builds an instance of {@link KeyProtection}.
+         *
+         * @throws IllegalArgumentException if a required field is missing
+         */
+        @NonNull
+        public KeyProtection build() {
+            return new KeyProtection(
+                    mFlags,
+                    mKeyValidityStart,
+                    mKeyValidityForOriginationEnd,
+                    mKeyValidityForConsumptionEnd,
+                    mPurposes,
+                    mEncryptionPaddings,
+                    mSignaturePaddings,
+                    mDigests,
+                    mBlockModes,
+                    mRandomizedEncryptionRequired,
+                    mUserAuthenticationRequired,
+                    mUserAuthenticationValidityDurationSeconds);
+        }
+    }
+}
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/keystore/UserNotAuthenticatedException.java
similarity index 97%
rename from keystore/java/android/security/UserNotAuthenticatedException.java
rename to keystore/java/android/security/keystore/UserNotAuthenticatedException.java
index 2954fa7..21f861c 100644
--- a/keystore/java/android/security/UserNotAuthenticatedException.java
+++ b/keystore/java/android/security/keystore/UserNotAuthenticatedException.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.security;
+package android.security.keystore;
 
 import java.security.InvalidKeyException;
 
diff --git a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
index 681a9ff..bc8dd13 100644
--- a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
@@ -24,11 +24,6 @@
 import javax.security.auth.x500.X500Principal;
 
 public class KeyPairGeneratorSpecTest extends AndroidTestCase {
-    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
-    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
-    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1980
-    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
-
     private static final String TEST_ALIAS_1 = "test1";
 
     private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
@@ -110,37 +105,46 @@
         }
     }
 
-    public void testConstructor_NullSubjectDN_Success() throws Exception {
-        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
-                getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS, 0);
-        assertEquals(DEFAULT_CERT_SUBJECT, spec.getSubjectDN());
+    public void testConstructor_NullSubjectDN_Failure() throws Exception {
+        try {
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS, 0);
+            fail("Should throw IllegalArgumentException when subjectDN is null");
+        } catch (IllegalArgumentException success) {
+        }
     }
 
-    public void testConstructor_NullSerial_Success() throws Exception {
-        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
-                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
-                NOW_PLUS_10_YEARS, 0);
-        assertEquals(DEFAULT_CERT_SERIAL_NUMBER, spec.getSerialNumber());
+    public void testConstructor_NullSerial_Failure() throws Exception {
+        try {
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
+                    NOW_PLUS_10_YEARS, 0);
+            fail("Should throw IllegalArgumentException when startDate is null");
+        } catch (IllegalArgumentException success) {
+        }
     }
 
-    public void testConstructor_NullStartDate_Success() throws Exception {
-        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
-                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, null,
-                NOW_PLUS_10_YEARS, 0);
-        assertEquals(DEFAULT_CERT_NOT_BEFORE, spec.getStartDate());
+    public void testConstructor_NullStartDate_Failure() throws Exception {
+        try {
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
+                    null, NOW_PLUS_10_YEARS, 0);
+            fail("Should throw IllegalArgumentException when startDate is null");
+        } catch (IllegalArgumentException success) {
+        }
     }
 
-    public void testConstructor_NullEndDate_Success() throws Exception {
-        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
-                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, null, 0);
-        assertEquals(DEFAULT_CERT_NOT_AFTER, spec.getEndDate());
+    public void testConstructor_NullEndDate_Failure() throws Exception {
+        try {
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
+                    NOW, null, 0);
+            fail("Should throw IllegalArgumentException when keystoreAlias is null");
+        } catch (IllegalArgumentException success) {
+        }
     }
 
     public void testConstructor_EndBeforeStart_Failure() throws Exception {
         try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1,
-                    SERIAL_1, NOW_PLUS_10_YEARS, NOW, 0);
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
+                    NOW_PLUS_10_YEARS, NOW, 0);
             fail("Should throw IllegalArgumentException when end is before start");
         } catch (IllegalArgumentException success) {
         }
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index d138c24..7421120 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -21,7 +21,6 @@
 import android.os.IBinder;
 import android.os.Process;
 import android.os.ServiceManager;
-import android.security.KeyStore;
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;