Use JCA names for block modes, paddings, and digests.

This replaces int-based enums from KeyStoreKeyConstraints with
String values commonly used in JCA API.

As part of under the hood refactoring:
* KeyStoreKeyCharacteristics and KeyStoreKeyConstraints have been
  merged into KeyStoreKeyProperties.
* KeymasterUtils methods operating on KeymasterArguments and
  KeymasterCharacteristics have been moved to their respective
  classes.

Bug: 18088752
Change-Id: I9c8b984cb3c28184adb617e34d87f2837bd1d3a1
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index b803a1b..b3a3aad 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -30,10 +32,12 @@
 
     public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new
             Parcelable.Creator<KeyCharacteristics>() {
+                @Override
                 public KeyCharacteristics createFromParcel(Parcel in) {
                     return new KeyCharacteristics(in);
                 }
 
+                @Override
                 public KeyCharacteristics[] newArray(int length) {
                     return new KeyCharacteristics[length];
                 }
@@ -50,6 +54,7 @@
         return 0;
     }
 
+    @Override
     public void writeToParcel(Parcel out, int flags) {
         swEnforced.writeToParcel(out, flags);
         hwEnforced.writeToParcel(out, flags);
@@ -59,5 +64,53 @@
         swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
         hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
     }
+
+    public Integer getInteger(int tag) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getInt(tag, -1);
+        } else if (swEnforced.containsTag(tag)) {
+            return swEnforced.getInt(tag, -1);
+        } else {
+            return null;
+        }
+    }
+
+    public int getInt(int tag, int defaultValue) {
+        Integer result = getInteger(tag);
+        return (result != null) ? result : defaultValue;
+    }
+
+    public List<Integer> getInts(int tag) {
+        List<Integer> result = new ArrayList<Integer>();
+        result.addAll(hwEnforced.getInts(tag));
+        result.addAll(swEnforced.getInts(tag));
+        return result;
+    }
+
+    public Date getDate(int tag) {
+        Date result = hwEnforced.getDate(tag, null);
+        if (result == null) {
+            result = swEnforced.getDate(tag, null);
+        }
+        return result;
+    }
+
+    public Date getDate(int tag, Date defaultValue) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getDate(tag, null);
+        } else if (hwEnforced.containsTag(tag)) {
+            return swEnforced.getDate(tag, null);
+        } else {
+            return defaultValue;
+        }
+    }
+
+    public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
+        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+            return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+        } else {
+            return keyCharacteristics.swEnforced.getBoolean(tag, false);
+        }
+    }
 }
 
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index b5fd4bd..8ed288c 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -34,9 +34,12 @@
 
     public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
             Parcelable.Creator<KeymasterArguments>() {
+                @Override
                 public KeymasterArguments createFromParcel(Parcel in) {
                     return new KeymasterArguments(in);
                 }
+
+                @Override
                 public KeymasterArguments[] newArray(int size) {
                     return new KeymasterArguments[size];
                 }
@@ -54,6 +57,12 @@
         mArguments.add(new KeymasterIntArgument(tag, value));
     }
 
+    public void addInts(int tag, int... values) {
+        for (int value : values) {
+            addInt(tag, value);
+        }
+    }
+
     public void addBoolean(int tag) {
         mArguments.add(new KeymasterBooleanArgument(tag));
     }
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 55a8b4f..fcee9fc 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -19,6 +19,8 @@
 import com.android.org.conscrypt.OpenSSLEngine;
 import com.android.org.conscrypt.OpenSSLKeyHolder;
 
+import libcore.util.EmptyArray;
+
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
@@ -46,6 +48,7 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
@@ -112,13 +115,6 @@
             if (keymasterAlgorithm == -1) {
                 throw new UnrecoverableKeyException("Key algorithm unknown");
             }
-            @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
-            try {
-                keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(keymasterAlgorithm);
-            } catch (IllegalArgumentException e) {
-                throw (UnrecoverableKeyException)
-                        new UnrecoverableKeyException("Unsupported key algorithm").initCause(e);
-            }
 
             int keymasterDigest =
                     keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
@@ -126,20 +122,11 @@
                 keymasterDigest =
                         keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
             }
-            @KeyStoreKeyConstraints.DigestEnum Integer digest = null;
-            if (keymasterDigest != -1) {
-                try {
-                    digest = KeyStoreKeyConstraints.Digest.fromKeymaster(keymasterDigest);
-                } catch (IllegalArgumentException e) {
-                    throw (UnrecoverableKeyException)
-                            new UnrecoverableKeyException("Unsupported digest").initCause(e);
-                }
-            }
 
             String keyAlgorithmString;
             try {
-                keyAlgorithmString = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(
-                    keyAlgorithm, digest);
+                keyAlgorithmString = KeymasterUtils.getJcaSecretKeyAlgorithm(
+                        keymasterAlgorithm, keymasterDigest);
             } catch (IllegalArgumentException e) {
                 throw (UnrecoverableKeyException)
                         new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
@@ -456,90 +443,92 @@
         }
 
         String keyAlgorithmString = key.getAlgorithm();
-        @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
-        @KeyStoreKeyConstraints.DigestEnum Integer digest;
+        int keymasterAlgorithm;
+        int keymasterDigest;
         try {
-            keyAlgorithm =
-                    KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString);
-            digest = KeyStoreKeyConstraints.Digest.fromJCASecretKeyAlgorithm(keyAlgorithmString);
+            keymasterAlgorithm = KeymasterUtils.getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(
+                    keyAlgorithmString);
+            keymasterDigest =
+                    KeymasterUtils.getKeymasterDigestfromJcaSecretKeyAlgorithm(keyAlgorithmString);
         } catch (IllegalArgumentException e) {
             throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
         }
 
         KeymasterArguments args = new KeymasterArguments();
-        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
-                KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm));
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
 
-        @KeyStoreKeyConstraints.DigestEnum int digests;
+        int[] keymasterDigests;
         if (params.isDigestsSpecified()) {
             // Digest(s) specified in parameters
-            if (digest != null) {
+            keymasterDigests =
+                    KeymasterUtils.getKeymasterDigestsFromJcaDigestAlgorithms(params.getDigests());
+            if (keymasterDigest != -1) {
                 // Digest also specified in the JCA key algorithm name.
-                if ((params.getDigests() & digest) != digest) {
+                if (!com.android.internal.util.ArrayUtils.contains(
+                        keymasterDigests, keymasterDigest)) {
                     throw new KeyStoreException("Key digest mismatch"
                             + ". Key: " + keyAlgorithmString
-                            + ", parameter spec: "
-                            + KeyStoreKeyConstraints.Digest.allToString(params.getDigests()));
+                            + ", parameter spec: " + Arrays.asList(params.getDigests()));
                 }
             }
-            digests = params.getDigests();
         } else {
             // No digest specified in parameters
-            if (digest != null) {
+            if (keymasterDigest != -1) {
                 // Digest specified in the JCA key algorithm name.
-                digests = digest;
+                keymasterDigests = new int[] {keymasterDigest};
             } else {
-                digests = 0;
+                keymasterDigests = EmptyArray.INT;
             }
         }
-        for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest);
-        }
-        if (digests != 0) {
+        args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
+        if (keymasterDigests.length > 0) {
             // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
             // This code will blow up if mode than one digest is specified.
-            Integer digestOutputSizeBytes =
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
-            if (digestOutputSizeBytes != null) {
+            int digestOutputSizeBytes =
+                    KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]);
+            if (digestOutputSizeBytes != -1) {
                 // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
                 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
             }
         }
-        if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
-            if (digests == 0) {
+        if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+            if (keymasterDigests.length == 0) {
                 throw new KeyStoreException("At least one digest algorithm must be specified"
                         + " for key algorithm " + keyAlgorithmString);
             }
         }
 
-        @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes();
-        @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes();
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes();
+        int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
+                params.getBlockModes());
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (params.isRandomizedEncryptionRequired())) {
-            @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
-                    blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
-            if (incompatibleBlockModes != 0) {
-                throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be"
-                        + " violated by block mode(s): "
-                        + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
-                        + ". See KeyStoreParameter documentation.");
+            for (int keymasterBlockMode : keymasterBlockModes) {
+                if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
+                    throw new KeyStoreException(
+                            "Randomized encryption (IND-CPA) required but may be violated by block"
+                            + " mode: "
+                            + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
+                                    keymasterBlockMode)
+                            + ". See KeyStoreParameter documentation.");
+                }
             }
         }
-        for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
+        for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
-        for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
-            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
-        }
-        for (int keymasterPadding :
-            KeyStoreKeyConstraints.Padding.allToKeymaster(params.getPaddings())) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
-        }
+        args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+        int[] keymasterPaddings = ArrayUtils.concat(
+                KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
+                        params.getEncryptionPaddings()),
+                KeymasterUtils.getKeymasterPaddingsFromJcaSignaturePaddings(
+                        params.getSignaturePaddings()));
+        args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
         if (params.getUserAuthenticators() == 0) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
             args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
-                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                    KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
                             params.getUserAuthenticators()));
         }
         if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
@@ -559,7 +548,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 & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (!params.isRandomizedEncryptionRequired())) {
             // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
diff --git a/keystore/java/android/security/ArrayUtils.java b/keystore/java/android/security/ArrayUtils.java
new file mode 100644
index 0000000..2047d3f
--- /dev/null
+++ b/keystore/java/android/security/ArrayUtils.java
@@ -0,0 +1,62 @@
+package android.security;
+
+import libcore.util.EmptyArray;
+
+/**
+ * @hide
+ */
+abstract class ArrayUtils {
+    private ArrayUtils() {}
+
+    public static String[] nullToEmpty(String[] array) {
+        return (array != null) ? array : EmptyArray.STRING;
+    }
+
+    public static String[] cloneIfNotEmpty(String[] array) {
+        return ((array != null) && (array.length > 0)) ? array.clone() : array;
+    }
+
+    public static byte[] concat(byte[] arr1, byte[] arr2) {
+        return concat(arr1, 0, (arr1 != null) ? arr1.length : 0,
+                arr2, 0, (arr2 != null) ? arr2.length : 0);
+    }
+
+    public static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
+            int len2) {
+        if (len1 == 0) {
+            return subarray(arr2, offset2, len2);
+        } else if (len2 == 0) {
+            return subarray(arr1, offset1, len1);
+        } else {
+            byte[] result = new byte[len1 + len2];
+            System.arraycopy(arr1, offset1, result, 0, len1);
+            System.arraycopy(arr2, offset2, result, len1, len2);
+            return result;
+        }
+    }
+
+    public static byte[] subarray(byte[] arr, int offset, int len) {
+        if (len == 0) {
+            return EmptyArray.BYTE;
+        }
+        if ((offset == 0) && (len == arr.length)) {
+            return arr;
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(arr, offset, result, 0, len);
+        return result;
+    }
+
+    public static int[] concat(int[] arr1, int[] arr2) {
+        if ((arr1 == null) || (arr1.length == 0)) {
+            return arr2;
+        } else if ((arr2 == null) || (arr2.length == 0)) {
+            return arr1;
+        } else {
+            int[] result = new int[arr1.length + arr2.length];
+            System.arraycopy(arr1, 0, result, 0, arr1.length);
+            System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
+            return result;
+        }
+    }
+}
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 4dcabd0..a22c31c 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -49,11 +49,11 @@
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+    private final String[] mEncryptionPaddings;
+    private final String[] mBlockModes;
     private final boolean mRandomizedEncryptionRequired;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
     private final int mUserAuthenticationValidityDurationSeconds;
 
     private KeyGeneratorSpec(
@@ -64,11 +64,11 @@
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] encryptionPaddings,
+            String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
             int userAuthenticationValidityDurationSeconds) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
@@ -88,8 +88,9 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mPaddings = paddings;
-        mBlockModes = blockModes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -154,22 +155,22 @@
     /**
      * Gets the set of purposes for which the key can be used.
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the set of padding schemes to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
     /**
-     * Gets the set of block modes to which the key is restricted.
+     * Gets the set of block modes with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
@@ -191,7 +192,7 @@
      *
      * @return user authenticators or {@code 0} if the key can be used without user authentication.
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -221,11 +222,11 @@
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
         private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+        private String[] mEncryptionPaddings;
+        private String[] mBlockModes;
         private boolean mRandomizedEncryptionRequired = true;
-        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
         private int mUserAuthenticationValidityDurationSeconds = -1;
 
         /**
@@ -332,34 +333,35 @@
         }
 
         /**
-         * Restricts the key to being used only for the provided set of purposes.
+         * Sets the set of purposes for which the key can be used.
          *
-         * <p>This restriction must be specified. There is no default.
+         * <p>This must be specified for all keys. There is no default.
          */
-        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
             mPurposes = purposes;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided padding schemes. Attempts to use
-         * the key with any other padding will be rejected.
+         * Sets the set of padding schemes 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 restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for keys which are used for encryption/decryption.
          */
-        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
-            mPaddings = paddings;
+        public Builder setEncryptionPaddings(String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block modes. Attempts to use the
-         * key with any other block modes will be rejected.
+         * Sets the set of block modes 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 restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for encryption/decryption keys.
          */
-        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
-            mBlockModes = blockModes;
+        public Builder setBlockModes(String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
             return this;
         }
 
@@ -412,7 +414,7 @@
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          */
         public Builder setUserAuthenticators(
-                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
             mUserAuthenticators = userAuthenticators;
             return this;
         }
@@ -447,7 +449,7 @@
                     mKeyValidityForOriginationEnd,
                     mKeyValidityForConsumptionEnd,
                     mPurposes,
-                    mPaddings,
+                    mEncryptionPaddings,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
                     mUserAuthenticators,
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index db310ea..9d6701a 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -78,17 +78,19 @@
 
     private final Date mKeyValidityForConsumptionEnd;
 
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
 
-    private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
+    private final String[] mDigests;
 
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+    private final String[] mEncryptionPaddings;
 
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final String[] mSignaturePaddings;
+
+    private final String[] mBlockModes;
 
     private final boolean mRandomizedEncryptionRequired;
 
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
 
     private final int mUserAuthenticationValidityDurationSeconds;
 
@@ -130,12 +132,13 @@
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.DigestEnum int digests,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] digests,
+            String[] encryptionPaddings,
+            String[] signaturePaddings,
+            String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
             int userAuthenticationValidityDurationSeconds) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
@@ -171,9 +174,11 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mDigests = digests;
-        mPaddings = paddings;
-        mBlockModes = blockModes;
+        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;
         mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -199,13 +204,15 @@
                 startDate,
                 endDate,
                 endDate,
-                0,
-                0,
-                0,
-                0,
-                true,
-                0,
-                -1);
+                0, // purposes
+                null, // digests
+                null, // encryption paddings
+                null, // signature paddings
+                null, // block modes
+                false, // randomized encryption required
+                0, // user authenticators
+                -1 // user authentication validity duration (seconds)
+                );
     }
 
     /**
@@ -333,35 +340,44 @@
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the set of digests to which the key is restricted.
+     * Gets the set of digest algorithms with which the key can be used.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
-        return mDigests;
+    public String[] getDigests() {
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
     /**
-     * Gets the set of padding schemes to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
     /**
-     * Gets the set of block modes to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when signing/verifying.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
+    }
+
+    /**
+     * Gets the set of block modes with which the key can be used.
+     *
+     * @hide
+     */
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
@@ -390,7 +406,7 @@
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -458,17 +474,19 @@
 
         private Date mKeyValidityForConsumptionEnd;
 
-        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
 
-        private @KeyStoreKeyConstraints.DigestEnum int mDigests;
+        private String[] mDigests;
 
-        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+        private String[] mEncryptionPaddings;
 
-        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private String[] mSignaturePaddings;
+
+        private String[] mBlockModes;
 
         private boolean mRandomizedEncryptionRequired = true;
 
-        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
 
         private int mUserAuthenticationValidityDurationSeconds = -1;
 
@@ -658,53 +676,68 @@
         }
 
         /**
-         * Restricts the key to being used only for the provided set of purposes.
+         * Sets the set of purposes for which the key can be used.
          *
-         * <p>This restriction must be specified. There is no default.
+         * <p>This must be specified for all keys. There is no default.
          *
          * @hide
          */
-        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
             mPurposes = purposes;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided digests. Attempts to use the key
-         * with any other digests be rejected.
+         * Sets the set of digests with which the key can be used when signing/verifying. Attempts
+         * to use the key with any other digest will be rejected.
          *
-         * <p>This restriction must be specified for keys which are used for signing/verification.
+         * <p>This must be specified for keys which are used for signing/verification.
          *
          * @hide
          */
-        public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
-            mDigests = digests;
+        public Builder setDigests(String... digests) {
+            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided padding schemes. Attempts to use
-         * the key with any other padding will be rejected.
+         * Sets the set of padding schemes 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 restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for keys which are used for encryption/decryption.
          *
          * @hide
          */
-        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
-            mPaddings = paddings;
+        public Builder setEncryptionPaddings(String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block mode when encrypting or
-         * decrypting. Attempts to use the key with any other block modes will be rejected.
+         * Sets the set of padding schemes 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 restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for RSA keys which are used for signing/verification.
          *
          * @hide
          */
-        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
-            mBlockModes = blockModes;
+        public Builder setSignaturePaddings(String... paddings) {
+            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+        /**
+         * Sets the set of block modes 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.
+         *
+         * @hide
+         */
+        public Builder setBlockModes(String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
             return this;
         }
 
@@ -752,7 +785,7 @@
          * @hide
          */
         public Builder setUserAuthenticators(
-                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
             mUserAuthenticators = userAuthenticators;
             return this;
         }
@@ -800,7 +833,8 @@
                     mKeyValidityForConsumptionEnd,
                     mPurposes,
                     mDigests,
-                    mPaddings,
+                    mEncryptionPaddings,
+                    mSignaturePaddings,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
                     mUserAuthenticators,
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 487eac0..7bc6378 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -48,68 +48,67 @@
 public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
 
     public abstract static class AES extends KeyStoreCipherSpi {
-        protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
-                @KeyStoreKeyConstraints.PaddingEnum int padding, boolean ivUsed) {
-            super(KeyStoreKeyConstraints.Algorithm.AES,
-                    blockMode,
-                    padding,
+        protected AES(int keymasterBlockMode, int keymasterPadding, boolean ivUsed) {
+            super(KeymasterDefs.KM_ALGORITHM_AES,
+                    keymasterBlockMode,
+                    keymasterPadding,
                     16,
                     ivUsed);
         }
 
         public abstract static class ECB extends AES {
-            protected ECB(@KeyStoreKeyConstraints.PaddingEnum int padding) {
-                super(KeyStoreKeyConstraints.BlockMode.ECB, padding, false);
+            protected ECB(int keymasterPadding) {
+                super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
             }
 
             public static class NoPadding extends ECB {
                 public NoPadding() {
-                    super(KeyStoreKeyConstraints.Padding.NONE);
+                    super(KeymasterDefs.KM_PAD_NONE);
                 }
             }
 
             public static class PKCS7Padding extends ECB {
                 public PKCS7Padding() {
-                    super(KeyStoreKeyConstraints.Padding.PKCS7);
+                    super(KeymasterDefs.KM_PAD_PKCS7);
                 }
             }
         }
 
         public abstract static class CBC extends AES {
-            protected CBC(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
-                super(KeyStoreKeyConstraints.BlockMode.CBC, padding, true);
+            protected CBC(int keymasterPadding) {
+                super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
             }
 
             public static class NoPadding extends CBC {
                 public NoPadding() {
-                    super(KeyStoreKeyConstraints.Padding.NONE);
+                    super(KeymasterDefs.KM_PAD_NONE);
                 }
             }
 
             public static class PKCS7Padding extends CBC {
                 public PKCS7Padding() {
-                    super(KeyStoreKeyConstraints.Padding.PKCS7);
+                    super(KeymasterDefs.KM_PAD_PKCS7);
                 }
             }
         }
 
         public abstract static class CTR extends AES {
-            protected CTR(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
-                super(KeyStoreKeyConstraints.BlockMode.CTR, padding, true);
+            protected CTR(int keymasterPadding) {
+                super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
             }
 
             public static class NoPadding extends CTR {
                 public NoPadding() {
-                    super(KeyStoreKeyConstraints.Padding.NONE);
+                    super(KeymasterDefs.KM_PAD_NONE);
                 }
             }
         }
     }
 
     private final KeyStore mKeyStore;
-    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPadding;
+    private final int mKeymasterAlgorithm;
+    private final int mKeymasterBlockMode;
+    private final int mKeymasterPadding;
     private final int mBlockSizeBytes;
 
     /** Whether this transformation requires an IV. */
@@ -138,15 +137,15 @@
     private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
 
     protected KeyStoreCipherSpi(
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockMode,
-            @KeyStoreKeyConstraints.PaddingEnum int padding,
+            int keymasterAlgorithm,
+            int keymasterBlockMode,
+            int keymasterPadding,
             int blockSizeBytes,
             boolean ivUsed) {
         mKeyStore = KeyStore.getInstance();
-        mAlgorithm = algorithm;
-        mBlockMode = blockMode;
-        mPadding = padding;
+        mKeymasterAlgorithm = keymasterAlgorithm;
+        mKeymasterBlockMode = keymasterBlockMode;
+        mKeymasterPadding = keymasterPadding;
         mBlockSizeBytes = blockSizeBytes;
         mIvRequired = ivUsed;
     }
@@ -236,9 +235,9 @@
         }
 
         KeymasterArguments keymasterInputArgs = new KeymasterArguments();
-        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm);
-        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mBlockMode);
-        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mPadding);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
         addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
 
         KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index 1f8b7e4..aafd2fa 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -19,6 +19,8 @@
 import android.os.IBinder;
 import android.security.keymaster.OperationResult;
 
+import libcore.util.EmptyArray;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
@@ -95,7 +97,7 @@
                 // Too much input for one chunk -- extract one max-sized chunk and feed it into the
                 // update operation.
                 inputBytesInChunk = mMaxChunkSize - mBufferedLength;
-                chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+                chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
                         input, inputOffset, inputBytesInChunk);
             } else {
                 // All of available input fits into one chunk.
@@ -108,7 +110,7 @@
                 } else {
                     // Need to combine buffered data with input data into one array.
                     inputBytesInChunk = inputLength;
-                    chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+                    chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
                             input, inputOffset, inputBytesInChunk);
                 }
             }
@@ -197,7 +199,7 @@
 
         // Flush all buffered input and provided input into keystore/keymaster.
         byte[] output = update(input, inputOffset, inputLength);
-        output = concat(output, flush());
+        output = ArrayUtils.concat(output, flush());
 
         OperationResult opResult = mKeyStoreStream.finish();
         if (opResult == null) {
@@ -206,7 +208,7 @@
             throw KeyStore.getKeyStoreException(opResult.resultCode);
         }
 
-        return concat(output, opResult.output);
+        return ArrayUtils.concat(output, opResult.output);
     }
 
     /**
@@ -215,11 +217,11 @@
      */
     public byte[] flush() throws KeyStoreException {
         if (mBufferedLength <= 0) {
-            return EMPTY_BYTE_ARRAY;
+            return EmptyArray.BYTE;
         }
 
-        byte[] chunk = subarray(mBuffered, mBufferedOffset, mBufferedLength);
-        mBuffered = EMPTY_BYTE_ARRAY;
+        byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
+        mBuffered = EmptyArray.BYTE;
         mBufferedLength = 0;
         mBufferedOffset = 0;
 
@@ -238,46 +240,7 @@
                     + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
         }
 
-        return (opResult.output != null) ? opResult.output : EMPTY_BYTE_ARRAY;
-    }
-
-    private static byte[] concat(byte[] arr1, byte[] arr2) {
-        if ((arr1 == null) || (arr1.length == 0)) {
-            return arr2;
-        } else if ((arr2 == null) || (arr2.length == 0)) {
-            return arr1;
-        } else {
-            byte[] result = new byte[arr1.length + arr2.length];
-            System.arraycopy(arr1, 0, result, 0, arr1.length);
-            System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
-            return result;
-        }
-    }
-
-    private static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
-            int len2) {
-        if (len1 == 0) {
-            return subarray(arr2, offset2, len2);
-        } else if (len2 == 0) {
-            return subarray(arr1, offset1, len1);
-        } else {
-            byte[] result = new byte[len1 + len2];
-            System.arraycopy(arr1, offset1, result, 0, len1);
-            System.arraycopy(arr2, offset2, result, len1, len2);
-            return result;
-        }
-    }
-
-    private static byte[] subarray(byte[] arr, int offset, int len) {
-        if (len == 0) {
-            return EMPTY_BYTE_ARRAY;
-        }
-        if ((offset == 0) && (len == arr.length)) {
-            return arr;
-        }
-        byte[] result = new byte[len];
-        System.arraycopy(arr, offset, result, 0, len);
-        return result;
+        return (opResult.output != null) ? opResult.output : EmptyArray.BYTE;
     }
 
     /**
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index f69e7d1..a19bbda 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -37,36 +37,36 @@
 
     public static class HmacSHA1 extends KeyStoreHmacSpi {
         public HmacSHA1() {
-            super(KeyStoreKeyConstraints.Digest.SHA1);
+            super(KeymasterDefs.KM_DIGEST_SHA1);
         }
     }
 
     public static class HmacSHA224 extends KeyStoreHmacSpi {
         public HmacSHA224() {
-            super(KeyStoreKeyConstraints.Digest.SHA224);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
     }
 
     public static class HmacSHA256 extends KeyStoreHmacSpi {
         public HmacSHA256() {
-            super(KeyStoreKeyConstraints.Digest.SHA256);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
     }
 
     public static class HmacSHA384 extends KeyStoreHmacSpi {
         public HmacSHA384() {
-            super(KeyStoreKeyConstraints.Digest.SHA384);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
     }
 
     public static class HmacSHA512 extends KeyStoreHmacSpi {
         public HmacSHA512() {
-            super(KeyStoreKeyConstraints.Digest.SHA512);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
     }
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
-    private final @KeyStoreKeyConstraints.DigestEnum int mDigest;
+    private final int mKeymasterDigest;
     private final int mMacSizeBytes;
 
     private String mKeyAliasInKeyStore;
@@ -76,9 +76,9 @@
     private IBinder mOperationToken;
     private Long mOperationHandle;
 
-    protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest) {
-        mDigest = digest;
-        mMacSizeBytes = KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
+    protected KeyStoreHmacSpi(int keymasterDigest) {
+        mKeymasterDigest = keymasterDigest;
+        mMacSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest);
     }
 
     @Override
@@ -129,8 +129,8 @@
         }
 
         KeymasterArguments keymasterArgs = new KeymasterArguments();
-        keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.HMAC);
-        keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mDigest);
+        keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
+        keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
 
         OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
                 KeymasterDefs.KM_PURPOSE_SIGN,
diff --git a/keystore/java/android/security/KeyStoreKeyCharacteristics.java b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
deleted file mode 100644
index 1f5d400..0000000
--- a/keystore/java/android/security/KeyStoreKeyCharacteristics.java
+++ /dev/null
@@ -1,63 +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.IntDef;
-import android.security.keymaster.KeymasterDefs;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Characteristics of {@code AndroidKeyStore} keys.
- *
- * @hide
- */
-public abstract class KeyStoreKeyCharacteristics {
-    private KeyStoreKeyCharacteristics() {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Origin.GENERATED, Origin.IMPORTED})
-    public @interface OriginEnum {}
-
-    /**
-     * Origin of the key.
-     */
-    public static abstract class Origin {
-        private Origin() {}
-
-        /** Key was generated inside AndroidKeyStore. */
-        public static final int GENERATED = 1 << 0;
-
-        /** Key was imported into AndroidKeyStore. */
-        public static final int IMPORTED = 1 << 1;
-
-        /**
-         * @hide
-         */
-        public static @OriginEnum int fromKeymaster(int origin) {
-            switch (origin) {
-                case KeymasterDefs.KM_ORIGIN_HARDWARE:
-                    return GENERATED;
-                case KeymasterDefs.KM_ORIGIN_IMPORTED:
-                    return IMPORTED;
-                default:
-                    throw new IllegalArgumentException("Unknown origin: " + origin);
-            }
-        }
-    }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
deleted file mode 100644
index 055b702..0000000
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ /dev/null
@@ -1,937 +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.IntDef;
-import android.security.keymaster.KeymasterDefs;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collection;
-import java.util.Locale;
-
-/**
- * Constraints for {@code AndroidKeyStore} keys.
- *
- * @hide
- */
-public abstract class KeyStoreKeyConstraints {
-    private KeyStoreKeyConstraints() {}
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
-    public @interface PurposeEnum {}
-
-    /**
-     * Purpose of key.
-     */
-    public static abstract class Purpose {
-        private Purpose() {}
-
-        /**
-         * Purpose: encryption.
-         */
-        public static final int ENCRYPT = 1 << 0;
-
-        /**
-         * Purpose: decryption.
-         */
-        public static final int DECRYPT = 1 << 1;
-
-        /**
-         * Purpose: signing.
-         */
-        public static final int SIGN = 1 << 2;
-
-        /**
-         * Purpose: signature verification.
-         */
-        public static final int VERIFY = 1 << 3;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@PurposeEnum int purpose) {
-            switch (purpose) {
-                case ENCRYPT:
-                    return KeymasterDefs.KM_PURPOSE_ENCRYPT;
-                case DECRYPT:
-                    return KeymasterDefs.KM_PURPOSE_DECRYPT;
-                case SIGN:
-                    return KeymasterDefs.KM_PURPOSE_SIGN;
-                case VERIFY:
-                    return KeymasterDefs.KM_PURPOSE_VERIFY;
-                default:
-                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @PurposeEnum int fromKeymaster(int purpose) {
-            switch (purpose) {
-                case KeymasterDefs.KM_PURPOSE_ENCRYPT:
-                    return ENCRYPT;
-                case KeymasterDefs.KM_PURPOSE_DECRYPT:
-                    return DECRYPT;
-                case KeymasterDefs.KM_PURPOSE_SIGN:
-                    return SIGN;
-                case KeymasterDefs.KM_PURPOSE_VERIFY:
-                    return VERIFY;
-                default:
-                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@PurposeEnum int purposes) {
-            int[] result = getSetFlags(purposes);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) {
-            @PurposeEnum int result = 0;
-            for (int keymasterPurpose : purposes) {
-                result |= fromKeymaster(keymasterPurpose);
-            }
-            return result;
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Algorithm.AES, Algorithm.HMAC, Algorithm.RSA, Algorithm.EC})
-    public @interface AlgorithmEnum {}
-
-    /**
-     * Key algorithm.
-     */
-    public static abstract class Algorithm {
-        private Algorithm() {}
-
-        /**
-         * Key algorithm: AES.
-         */
-        public static final int AES = 1 << 0;
-
-        /**
-         * Key algorithm: HMAC.
-         */
-        public static final int HMAC = 1 << 1;
-
-        /**
-         * Key algorithm: RSA.
-         */
-        public static final int RSA = 1 << 2;
-
-        /**
-         * Key algorithm: EC.
-         */
-        public static final int EC = 1 << 3;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@AlgorithmEnum int algorithm) {
-            switch (algorithm) {
-                case AES:
-                    return KeymasterDefs.KM_ALGORITHM_AES;
-                case HMAC:
-                    return KeymasterDefs.KM_ALGORITHM_HMAC;
-                case RSA:
-                    return KeymasterDefs.KM_ALGORITHM_RSA;
-                case EC:
-                    return KeymasterDefs.KM_ALGORITHM_EC;
-                default:
-                    throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @AlgorithmEnum int fromKeymaster(int algorithm) {
-            switch (algorithm) {
-                case KeymasterDefs.KM_ALGORITHM_AES:
-                    return AES;
-                case KeymasterDefs.KM_ALGORITHM_HMAC:
-                    return HMAC;
-                case KeymasterDefs.KM_ALGORITHM_RSA:
-                    return RSA;
-                case KeymasterDefs.KM_ALGORITHM_EC:
-                    return EC;
-                default:
-                    throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@AlgorithmEnum int algorithm) {
-            switch (algorithm) {
-                case AES:
-                    return "AES";
-                case HMAC:
-                    return "HMAC";
-                case RSA:
-                    return "RSA";
-                case EC:
-                    return "EC";
-                default:
-                    throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @AlgorithmEnum int fromJCASecretKeyAlgorithm(String algorithm) {
-            if (algorithm == null) {
-                throw new NullPointerException("algorithm == null");
-            } else  if ("AES".equalsIgnoreCase(algorithm)) {
-                return AES;
-            } else if (algorithm.toLowerCase(Locale.US).startsWith("hmac")) {
-                return HMAC;
-            } else {
-                throw new IllegalArgumentException(
-                        "Unsupported secret key algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toJCASecretKeyAlgorithm(@AlgorithmEnum int algorithm,
-                @DigestEnum Integer digest) {
-            switch (algorithm) {
-                case AES:
-                    return "AES";
-                case HMAC:
-                    if (digest == null) {
-                        throw new IllegalArgumentException("HMAC digest not specified");
-                    }
-                    switch (digest) {
-                        case Digest.MD5:
-                            return "HmacMD5";
-                        case Digest.SHA1:
-                            return "HmacSHA1";
-                        case Digest.SHA224:
-                            return "HmacSHA224";
-                        case Digest.SHA256:
-                            return "HmacSHA256";
-                        case Digest.SHA384:
-                            return "HmacSHA384";
-                        case Digest.SHA512:
-                            return "HmacSHA512";
-                        default:
-                            throw new IllegalArgumentException(
-                                    "Unsupported HMAC digest: " + digest);
-                    }
-                default:
-                    throw new IllegalArgumentException("Unsupported key algorithm: " + algorithm);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toJCAKeyPairAlgorithm(@AlgorithmEnum int algorithm) {
-            switch (algorithm) {
-                case RSA:
-                    return "RSA";
-                case EC:
-                    return "EC";
-                default:
-                    throw new IllegalArgumentException("Unsupported key alorithm: " + algorithm);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {
-                Padding.NONE,
-                Padding.PKCS7,
-                Padding.RSA_PKCS1_ENCRYPTION,
-                Padding.RSA_PKCS1_SIGNATURE,
-                Padding.RSA_OAEP,
-                Padding.RSA_PSS,
-                })
-    public @interface PaddingEnum {}
-
-    /**
-     * Padding for signing and encryption.
-     */
-    public static abstract class Padding {
-        private Padding() {}
-
-        /**
-         * No padding.
-         */
-        public static final int NONE = 1 << 0;
-
-        /**
-         * PKCS#7 padding.
-         */
-        public static final int PKCS7 = 1 << 1;
-
-        /**
-         * RSA PKCS#1 v1.5 padding for encryption/decryption.
-         */
-        public static final int RSA_PKCS1_ENCRYPTION = 1 << 2;
-
-        /**
-         * RSA PKCS#1 v1.5 padding for signatures.
-         */
-        public static final int RSA_PKCS1_SIGNATURE = 1 << 3;
-
-        /**
-         * RSA Optimal Asymmetric Encryption Padding (OAEP).
-         */
-        public static final int RSA_OAEP = 1 << 4;
-
-        /**
-         * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding.
-         */
-        public static final int RSA_PSS = 1 << 5;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(int padding) {
-            switch (padding) {
-                case NONE:
-                    return KeymasterDefs.KM_PAD_NONE;
-                case PKCS7:
-                    return KeymasterDefs.KM_PAD_PKCS7;
-                case RSA_PKCS1_ENCRYPTION:
-                    return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
-                case RSA_PKCS1_SIGNATURE:
-                    return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
-                case RSA_OAEP:
-                    return KeymasterDefs.KM_PAD_RSA_OAEP;
-                case RSA_PSS:
-                    return KeymasterDefs.KM_PAD_RSA_PSS;
-                default:
-                    throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @PaddingEnum int fromKeymaster(int padding) {
-            switch (padding) {
-                case KeymasterDefs.KM_PAD_NONE:
-                    return NONE;
-                case KeymasterDefs.KM_PAD_PKCS7:
-                    return PKCS7;
-                case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
-                    return RSA_PKCS1_ENCRYPTION;
-                case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
-                    return RSA_PKCS1_SIGNATURE;
-                case KeymasterDefs.KM_PAD_RSA_OAEP:
-                    return RSA_OAEP;
-                case KeymasterDefs.KM_PAD_RSA_PSS:
-                    return RSA_PSS;
-                default:
-                    throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@PaddingEnum int padding) {
-            switch (padding) {
-                case NONE:
-                    return "NONE";
-                case PKCS7:
-                    return "PKCS#7";
-                case RSA_PKCS1_ENCRYPTION:
-                    return "RSA PKCS#1 (encryption)";
-                case RSA_PKCS1_SIGNATURE:
-                    return "RSA PKCS#1 (signature)";
-                case RSA_OAEP:
-                    return "RSA OAEP";
-                case RSA_PSS:
-                    return "RSA PSS";
-                default:
-                    throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @PaddingEnum int fromJCACipherPadding(String padding) {
-            String paddingLower = padding.toLowerCase(Locale.US);
-            if ("nopadding".equals(paddingLower)) {
-                return NONE;
-            } else if ("pkcs7padding".equals(paddingLower)) {
-                return PKCS7;
-            } else if ("pkcs1padding".equals(paddingLower)) {
-                return RSA_PKCS1_ENCRYPTION;
-            } else if (("oaeppadding".equals(paddingLower))
-                    || ((paddingLower.startsWith("oaepwith"))
-                            && (paddingLower.endsWith("padding")))) {
-                return RSA_OAEP;
-            } else {
-                throw new IllegalArgumentException("Unknown padding: " + padding);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@PaddingEnum int paddings) {
-            int[] result = getSetFlags(paddings);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @PaddingEnum int allFromKeymaster(Collection<Integer> paddings) {
-            @PaddingEnum int result = 0;
-            for (int keymasterPadding : paddings) {
-                result |= fromKeymaster(keymasterPadding);
-            }
-            return result;
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {
-                Digest.NONE,
-                Digest.MD5,
-                Digest.SHA1,
-                Digest.SHA224,
-                Digest.SHA256,
-                Digest.SHA384,
-                Digest.SHA512,
-                })
-    public @interface DigestEnum {}
-
-    /**
-     * Digests that can be used with a key when signing or generating Message Authentication
-     * Codes (MACs).
-     */
-    public static abstract class Digest {
-        private Digest() {}
-
-        /**
-         * No digest: sign/authenticate the raw message.
-         */
-        public static final int NONE = 1 << 0;
-
-        /**
-         * MD5 digest.
-         */
-        public static final int MD5 = 1 << 1;
-
-        /**
-         * SHA-1 digest.
-         */
-        public static final int SHA1 = 1 << 2;
-
-        /**
-         * SHA-2 224 (aka SHA-224) digest.
-         */
-        public static final int SHA224 = 1 << 3;
-
-        /**
-         * SHA-2 256 (aka SHA-256) digest.
-         */
-        public static final int SHA256 = 1 << 4;
-
-        /**
-         * SHA-2 384 (aka SHA-384) digest.
-         */
-        public static final int SHA384 = 1 << 5;
-
-        /**
-         * SHA-2 512 (aka SHA-512) digest.
-         */
-        public static final int SHA512 = 1 << 6;
-
-        /**
-         * @hide
-         */
-        public static String toString(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return "NONE";
-                case MD5:
-                    return "MD5";
-                case SHA1:
-                    return "SHA-1";
-                case SHA224:
-                    return "SHA-224";
-                case SHA256:
-                    return "SHA-256";
-                case SHA384:
-                    return "SHA-384";
-                case SHA512:
-                    return "SHA-512";
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String allToString(@DigestEnum int digests) {
-            StringBuilder result = new StringBuilder("[");
-            boolean firstValue = true;
-            for (@DigestEnum int digest : getSetFlags(digests)) {
-                if (firstValue) {
-                    firstValue = false;
-                } else {
-                    result.append(", ");
-                }
-                result.append(toString(digest));
-            }
-            result.append(']');
-            return result.toString();
-        }
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return KeymasterDefs.KM_DIGEST_NONE;
-                case MD5:
-                    return KeymasterDefs.KM_DIGEST_MD5;
-                case SHA1:
-                    return KeymasterDefs.KM_DIGEST_SHA1;
-                case SHA224:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_224;
-                case SHA256:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_256;
-                case SHA384:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_384;
-                case SHA512:
-                    return KeymasterDefs.KM_DIGEST_SHA_2_512;
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @DigestEnum int fromKeymaster(int digest) {
-            switch (digest) {
-                case KeymasterDefs.KM_DIGEST_NONE:
-                    return NONE;
-                case KeymasterDefs.KM_DIGEST_MD5:
-                    return MD5;
-                case KeymasterDefs.KM_DIGEST_SHA1:
-                    return SHA1;
-                case KeymasterDefs.KM_DIGEST_SHA_2_224:
-                    return SHA224;
-                case KeymasterDefs.KM_DIGEST_SHA_2_256:
-                    return SHA256;
-                case KeymasterDefs.KM_DIGEST_SHA_2_384:
-                    return SHA384;
-                case KeymasterDefs.KM_DIGEST_SHA_2_512:
-                    return SHA512;
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@DigestEnum int digests) {
-            int[] result = getSetFlags(digests);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @DigestEnum int allFromKeymaster(Collection<Integer> digests) {
-            @DigestEnum int result = 0;
-            for (int keymasterDigest : digests) {
-                result |= fromKeymaster(keymasterDigest);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @DigestEnum Integer fromJCASecretKeyAlgorithm(String algorithm) {
-            String algorithmLower = algorithm.toLowerCase(Locale.US);
-            if (algorithmLower.startsWith("hmac")) {
-                String digestLower = algorithmLower.substring("hmac".length());
-                if ("md5".equals(digestLower)) {
-                    return MD5;
-                } else if ("sha1".equals(digestLower)) {
-                    return SHA1;
-                } else if ("sha224".equals(digestLower)) {
-                    return SHA224;
-                } else if ("sha256".equals(digestLower)) {
-                    return SHA256;
-                } else if ("sha384".equals(digestLower)) {
-                    return SHA384;
-                } else if ("sha512".equals(digestLower)) {
-                    return SHA512;
-                } else {
-                    throw new IllegalArgumentException("Unsupported digest: " + digestLower);
-                }
-            } else {
-                return null;
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String toJCASignatureAlgorithmDigest(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return "NONE";
-                case MD5:
-                    return "MD5";
-                case SHA1:
-                    return "SHA1";
-                case SHA224:
-                    return "SHA224";
-                case SHA256:
-                    return "SHA256";
-                case SHA384:
-                    return "SHA384";
-                case SHA512:
-                    return "SHA512";
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static Integer getOutputSizeBytes(@DigestEnum int digest) {
-            switch (digest) {
-                case NONE:
-                    return null;
-                case MD5:
-                    return 128 / 8;
-                case SHA1:
-                    return 160 / 8;
-                case SHA224:
-                    return 224 / 8;
-                case SHA256:
-                    return 256 / 8;
-                case SHA384:
-                    return 384 / 8;
-                case SHA512:
-                    return 512 / 8;
-                default:
-                    throw new IllegalArgumentException("Unknown digest: " + digest);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {BlockMode.ECB, BlockMode.CBC, BlockMode.CTR, BlockMode.GCM})
-    public @interface BlockModeEnum {}
-
-    /**
-     * Block modes that can be used when encrypting/decrypting using a key.
-     */
-    public static abstract class BlockMode {
-        private BlockMode() {}
-
-        /** Electronic Codebook (ECB) block mode. */
-        public static final int ECB = 1 << 0;
-
-        /** Cipher Block Chaining (CBC) block mode. */
-        public static final int CBC = 1 << 1;
-
-        /** Counter (CTR) block mode. */
-        public static final int CTR = 1 << 2;
-
-        /** Galois/Counter Mode (GCM) block mode. */
-        public static final int GCM = 1 << 3;
-
-        /**
-         * Set of block modes compatible with IND-CPA if used correctly.
-         *
-         * @hide
-         */
-        public static final @BlockModeEnum int IND_CPA_COMPATIBLE_MODES =
-                CBC | CTR | GCM;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@BlockModeEnum int mode) {
-            switch (mode) {
-                case ECB:
-                    return KeymasterDefs.KM_MODE_ECB;
-                case CBC:
-                    return KeymasterDefs.KM_MODE_CBC;
-                case CTR:
-                    return KeymasterDefs.KM_MODE_CTR;
-                case GCM:
-                    return KeymasterDefs.KM_MODE_GCM;
-                default:
-                    throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @BlockModeEnum int fromKeymaster(int mode) {
-            switch (mode) {
-                case KeymasterDefs.KM_MODE_ECB:
-                    return ECB;
-                case KeymasterDefs.KM_MODE_CBC:
-                    return CBC;
-                case KeymasterDefs.KM_MODE_CTR:
-                    return CTR;
-                case KeymasterDefs.KM_MODE_GCM:
-                    return GCM;
-                default:
-                    throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int[] allToKeymaster(@BlockModeEnum int modes) {
-            int[] result = getSetFlags(modes);
-            for (int i = 0; i < result.length; i++) {
-                result[i] = toKeymaster(result[i]);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @BlockModeEnum int allFromKeymaster(Collection<Integer> modes) {
-            @BlockModeEnum int result = 0;
-            for (int keymasterMode : modes) {
-                result |= fromKeymaster(keymasterMode);
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@BlockModeEnum int mode) {
-            switch (mode) {
-                case ECB:
-                    return "ECB";
-                case CBC:
-                    return "CBC";
-                case CTR:
-                    return "CTR";
-                case GCM:
-                    return "GCM";
-                default:
-                    throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static String allToString(@BlockModeEnum int modes) {
-            StringBuilder result = new StringBuilder("[");
-            boolean firstValue = true;
-            for (@BlockModeEnum int mode : getSetFlags(modes)) {
-                if (firstValue) {
-                    firstValue = false;
-                } else {
-                    result.append(", ");
-                }
-                result.append(toString(mode));
-            }
-            result.append(']');
-            return result.toString();
-        }
-
-        /**
-         * @hide
-         */
-        public static @BlockModeEnum int fromJCAMode(String mode) {
-            String modeLower = mode.toLowerCase(Locale.US);
-            if ("ecb".equals(modeLower)) {
-                return ECB;
-            } else if ("cbc".equals(modeLower)) {
-                return CBC;
-            } else if ("ctr".equals(modeLower)) {
-                return CTR;
-            } else if ("gcm".equals(modeLower)) {
-                return GCM;
-            } else {
-                throw new IllegalArgumentException("Unknown block mode: " + mode);
-            }
-        }
-    }
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag = true,
-            value = {UserAuthenticator.LOCK_SCREEN})
-    public @interface UserAuthenticatorEnum {}
-
-    /**
-     * User authenticators which can be used to restrict/protect access to keys.
-     */
-    public static abstract class UserAuthenticator {
-        private UserAuthenticator() {}
-
-        /** Lock screen. */
-        public static final int LOCK_SCREEN = 1 << 0;
-
-        /**
-         * @hide
-         */
-        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
-            switch (userAuthenticator) {
-                case LOCK_SCREEN:
-                    return KeymasterDefs.HW_AUTH_PASSWORD;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
-            switch (userAuthenticator) {
-                case KeymasterDefs.HW_AUTH_PASSWORD:
-                    return LOCK_SCREEN;
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
-            int result = 0;
-            int userAuthenticator = 1;
-            while (userAuthenticators != 0) {
-                if ((userAuthenticators & 1) != 0) {
-                    result |= toKeymaster(userAuthenticator);
-                }
-                userAuthenticators >>>= 1;
-                userAuthenticator <<= 1;
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
-            @UserAuthenticatorEnum int result = 0;
-            int userAuthenticator = 1;
-            while (userAuthenticators != 0) {
-                if ((userAuthenticators & 1) != 0) {
-                    result |= fromKeymaster(userAuthenticator);
-                }
-                userAuthenticators >>>= 1;
-                userAuthenticator <<= 1;
-            }
-            return result;
-        }
-
-        /**
-         * @hide
-         */
-        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
-            switch (userAuthenticator) {
-                case LOCK_SCREEN:
-                    return "LOCK_SCREEN";
-                default:
-                    throw new IllegalArgumentException(
-                            "Unknown user authenticator: " + userAuthenticator);
-            }
-        }
-    }
-
-    private static final int[] EMPTY_INT_ARRAY = new int[0];
-
-    private static int[] getSetFlags(int flags) {
-        if (flags == 0) {
-            return EMPTY_INT_ARRAY;
-        }
-        int result[] = new int[getSetBitCount(flags)];
-        int resultOffset = 0;
-        int flag = 1;
-        while (flags != 0) {
-            if ((flags & 1) != 0) {
-                result[resultOffset] = flag;
-                resultOffset++;
-            }
-            flags >>>= 1;
-            flag <<= 1;
-        }
-        return result;
-    }
-
-    private static int getSetBitCount(int value) {
-        if (value == 0) {
-            return 0;
-        }
-        int result = 0;
-        while (value != 0) {
-            if ((value & 1) != 0) {
-                result++;
-            }
-            value >>>= 1;
-        }
-        return result;
-    }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index a500786..87e7ee6 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -37,68 +37,68 @@
 
     public static class AES extends KeyStoreKeyGeneratorSpi {
         public AES() {
-            super(KeyStoreKeyConstraints.Algorithm.AES, 128);
+            super(KeymasterDefs.KM_ALGORITHM_AES, 128);
         }
     }
 
     protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi {
-        protected HmacBase(@KeyStoreKeyConstraints.DigestEnum int digest) {
-            super(KeyStoreKeyConstraints.Algorithm.HMAC,
-                    digest,
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest) * 8);
+        protected HmacBase(int keymasterDigest) {
+            super(KeymasterDefs.KM_ALGORITHM_HMAC,
+                    keymasterDigest,
+                    KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest) * 8);
         }
     }
 
     public static class HmacSHA1 extends HmacBase {
         public HmacSHA1() {
-            super(KeyStoreKeyConstraints.Digest.SHA1);
+            super(KeymasterDefs.KM_DIGEST_SHA1);
         }
     }
 
     public static class HmacSHA224 extends HmacBase {
         public HmacSHA224() {
-            super(KeyStoreKeyConstraints.Digest.SHA224);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_224);
         }
     }
 
     public static class HmacSHA256 extends HmacBase {
         public HmacSHA256() {
-            super(KeyStoreKeyConstraints.Digest.SHA256);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_256);
         }
     }
 
     public static class HmacSHA384 extends HmacBase {
         public HmacSHA384() {
-            super(KeyStoreKeyConstraints.Digest.SHA384);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_384);
         }
     }
 
     public static class HmacSHA512 extends HmacBase {
         public HmacSHA512() {
-            super(KeyStoreKeyConstraints.Digest.SHA512);
+            super(KeymasterDefs.KM_DIGEST_SHA_2_512);
         }
     }
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
-    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
+    private final int mKeymasterAlgorithm;
+    private final int mKeymasterDigest;
     private final int mDefaultKeySizeBits;
 
     private KeyGeneratorSpec mSpec;
     private SecureRandom mRng;
 
     protected KeyStoreKeyGeneratorSpi(
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+            int keymasterAlgorithm,
             int defaultKeySizeBits) {
-        this(algorithm, null, defaultKeySizeBits);
+        this(keymasterAlgorithm, -1, defaultKeySizeBits);
     }
 
     protected KeyStoreKeyGeneratorSpi(
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
-            @KeyStoreKeyConstraints.DigestEnum Integer digest,
+            int keymasterAlgorithm,
+            int keymasterDigest,
             int defaultKeySizeBits) {
-        mAlgorithm = algorithm;
-        mDigest = digest;
+        mKeymasterAlgorithm = keymasterAlgorithm;
+        mKeymasterDigest = keymasterDigest;
         mDefaultKeySizeBits = defaultKeySizeBits;
     }
 
@@ -117,58 +117,55 @@
         }
 
         KeymasterArguments args = new KeymasterArguments();
-        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
-                KeyStoreKeyConstraints.Algorithm.toKeymaster(mAlgorithm));
-        if (mDigest != null) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST,
-                    KeyStoreKeyConstraints.Digest.toKeymaster(mDigest));
-            Integer digestOutputSizeBytes =
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(mDigest);
-            if (digestOutputSizeBytes != null) {
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
+        if (mKeymasterDigest != -1) {
+            args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
+            int digestOutputSizeBytes =
+                    KeymasterUtils.getDigestOutputSizeBytes(mKeymasterDigest);
+            if (digestOutputSizeBytes != -1) {
                 // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
                 // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
                 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
             }
         }
-        if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
-            if (mDigest == null) {
-                throw new IllegalStateException("Digest algorithm must be specified for key"
-                        + " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
+        if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+            if (mKeymasterDigest == -1) {
+                throw new IllegalStateException("Digest algorithm must be specified for HMAC key");
             }
         }
         int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
-        @KeyStoreKeyConstraints.PurposeEnum int purposes = spec.getPurposes();
-        @KeyStoreKeyConstraints.BlockModeEnum int blockModes = spec.getBlockModes();
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        @KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes();
+        int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
+                spec.getBlockModes());
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (spec.isRandomizedEncryptionRequired())) {
-            @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
-                    blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
-            if (incompatibleBlockModes != 0) {
-                throw new IllegalStateException(
-                        "Randomized encryption (IND-CPA) required but may be violated by block"
-                        + " mode(s): "
-                        + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
-                        + ". See KeyGeneratorSpec documentation.");
+            for (int keymasterBlockMode : keymasterBlockModes) {
+                if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
+                    throw new IllegalStateException(
+                            "Randomized encryption (IND-CPA) required but may be violated by block"
+                            + " mode: "
+                            + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
+                                    keymasterBlockMode)
+                            + ". See KeyGeneratorSpec documentation.");
+                }
             }
         }
 
         for (int keymasterPurpose :
-            KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
+            KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
-        for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
-            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
-        }
-        for (int keymasterPadding :
-            KeyStoreKeyConstraints.Padding.allToKeymaster(spec.getPaddings())) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
-        }
+        args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+        args.addInts(
+                KeymasterDefs.KM_TAG_PADDING,
+                KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
+                        spec.getEncryptionPaddings()));
         if (spec.getUserAuthenticators() == 0) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
             args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
-                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                    KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
                             spec.getUserAuthenticators()));
         }
         if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
@@ -185,7 +182,7 @@
                 (spec.getKeyValidityForConsumptionEnd() != null)
                 ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
-        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+        if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
                 && (!spec.isRandomizedEncryptionRequired())) {
             // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
@@ -206,7 +203,7 @@
             throw KeyStore.getCryptoOperationException(errorCode);
         }
         String keyAlgorithmJCA =
-                KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
+                KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
         return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
     }
 
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
new file mode 100644
index 0000000..d8ad1d3
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -0,0 +1,274 @@
+/*
+ * 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.IntDef;
+import android.security.keymaster.KeymasterDefs;
+
+import libcore.util.EmptyArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+
+/**
+ * Properties of {@code AndroidKeyStore} keys.
+ *
+ * @hide
+ */
+public abstract class KeyStoreKeyProperties {
+    private KeyStoreKeyProperties() {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
+    public @interface PurposeEnum {}
+
+    /**
+     * Purpose of key.
+     */
+    public static abstract class Purpose {
+        private Purpose() {}
+
+        /**
+         * Purpose: encryption.
+         */
+        public static final int ENCRYPT = 1 << 0;
+
+        /**
+         * Purpose: decryption.
+         */
+        public static final int DECRYPT = 1 << 1;
+
+        /**
+         * Purpose: signing.
+         */
+        public static final int SIGN = 1 << 2;
+
+        /**
+         * Purpose: signature verification.
+         */
+        public static final int VERIFY = 1 << 3;
+
+        /**
+         * @hide
+         */
+        public static int toKeymaster(@PurposeEnum int purpose) {
+            switch (purpose) {
+                case ENCRYPT:
+                    return KeymasterDefs.KM_PURPOSE_ENCRYPT;
+                case DECRYPT:
+                    return KeymasterDefs.KM_PURPOSE_DECRYPT;
+                case SIGN:
+                    return KeymasterDefs.KM_PURPOSE_SIGN;
+                case VERIFY:
+                    return KeymasterDefs.KM_PURPOSE_VERIFY;
+                default:
+                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static @PurposeEnum int fromKeymaster(int purpose) {
+            switch (purpose) {
+                case KeymasterDefs.KM_PURPOSE_ENCRYPT:
+                    return ENCRYPT;
+                case KeymasterDefs.KM_PURPOSE_DECRYPT:
+                    return DECRYPT;
+                case KeymasterDefs.KM_PURPOSE_SIGN:
+                    return SIGN;
+                case KeymasterDefs.KM_PURPOSE_VERIFY:
+                    return VERIFY;
+                default:
+                    throw new IllegalArgumentException("Unknown purpose: " + purpose);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int[] allToKeymaster(@PurposeEnum int purposes) {
+            int[] result = getSetFlags(purposes);
+            for (int i = 0; i < result.length; i++) {
+                result[i] = toKeymaster(result[i]);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) {
+            @PurposeEnum int result = 0;
+            for (int keymasterPurpose : purposes) {
+                result |= fromKeymaster(keymasterPurpose);
+            }
+            return result;
+        }
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = {UserAuthenticator.LOCK_SCREEN})
+    public @interface UserAuthenticatorEnum {}
+
+    /**
+     * User authenticators which can be used to restrict/protect access to keys.
+     */
+    public static abstract class UserAuthenticator {
+        private UserAuthenticator() {}
+
+        /** Lock screen. */
+        public static final int LOCK_SCREEN = 1 << 0;
+
+        /**
+         * @hide
+         */
+        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return KeymasterDefs.HW_AUTH_PASSWORD;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
+            switch (userAuthenticator) {
+                case KeymasterDefs.HW_AUTH_PASSWORD:
+                    return LOCK_SCREEN;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
+            int result = 0;
+            int userAuthenticator = 1;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    result |= toKeymaster(userAuthenticator);
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
+            @UserAuthenticatorEnum int result = 0;
+            int userAuthenticator = 1;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    result |= fromKeymaster(userAuthenticator);
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return "LOCK_SCREEN";
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({Origin.GENERATED, Origin.IMPORTED})
+    public @interface OriginEnum {}
+
+    /**
+     * Origin of the key.
+     */
+    public static abstract class Origin {
+        private Origin() {}
+
+        /** Key was generated inside AndroidKeyStore. */
+        public static final int GENERATED = 1 << 0;
+
+        /** Key was imported into AndroidKeyStore. */
+        public static final int IMPORTED = 1 << 1;
+
+        /**
+         * @hide
+         */
+        public static @OriginEnum int fromKeymaster(int origin) {
+            switch (origin) {
+                case KeymasterDefs.KM_ORIGIN_HARDWARE:
+                    return GENERATED;
+                case KeymasterDefs.KM_ORIGIN_IMPORTED:
+                    return IMPORTED;
+                default:
+                    throw new IllegalArgumentException("Unknown origin: " + origin);
+            }
+        }
+    }
+
+    private static int[] getSetFlags(int flags) {
+        if (flags == 0) {
+            return EmptyArray.INT;
+        }
+        int result[] = new int[getSetBitCount(flags)];
+        int resultOffset = 0;
+        int flag = 1;
+        while (flags != 0) {
+            if ((flags & 1) != 0) {
+                result[resultOffset] = flag;
+                resultOffset++;
+            }
+            flags >>>= 1;
+            flag <<= 1;
+        }
+        return result;
+    }
+
+    private static int getSetBitCount(int value) {
+        if (value == 0) {
+            return 0;
+        }
+        int result = 0;
+        while (value != 0) {
+            if ((value & 1) != 0) {
+                result++;
+            }
+            value >>>= 1;
+        }
+        return result;
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index 27b444e..861ed34 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -29,17 +29,17 @@
     private final String mKeystoreAlias;
     private final int mKeySize;
     private final boolean mTeeBacked;
-    private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
+    private final @KeyStoreKeyProperties.OriginEnum int mOrigin;
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-    private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+    private final String[] mEncryptionPaddings;
+    private final String[] mSignaturePaddings;
+    private final String[] mDigests;
+    private final String[] mBlockModes;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
     private final int mUserAuthenticationValidityDurationSeconds;
 
 
@@ -48,18 +48,18 @@
      */
     KeyStoreKeySpec(String keystoreKeyAlias,
             boolean teeBacked,
-            @KeyStoreKeyCharacteristics.OriginEnum int origin,
+            @KeyStoreKeyProperties.OriginEnum int origin,
             int keySize,
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.DigestEnum int digests,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] encryptionPaddings,
+            String[] signaturePaddings,
+            String[] digests,
+            String[] blockModes,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
             int userAuthenticationValidityDurationSeconds) {
         mKeystoreAlias = keystoreKeyAlias;
         mTeeBacked = teeBacked;
@@ -69,10 +69,12 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mAlgorithm = algorithm;
-        mPaddings = paddings;
-        mDigests = digests;
-        mBlockModes = blockModes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mUserAuthenticators = userAuthenticators;
         mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -96,7 +98,7 @@
     /**
      * Gets the origin of the key.
      */
-    public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
+    public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
         return mOrigin;
     }
 
@@ -137,36 +139,36 @@
     /**
      * Gets the set of purposes for which the key can be used.
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the algorithm of the key.
-     */
-    public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
-        return mAlgorithm;
-    }
-
-    /**
      * Gets the set of block modes with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
-     * Gets the set of padding modes with which the key can be used.
+     * Gets the set of padding modes with which the key can be used when encrypting/decrypting.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
+    }
+
+    /**
+     * Gets the set of padding modes with which the key can be used when signing/verifying.
+     */
+    public String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
     }
 
     /**
      * Gets the set of digest algorithms with which the key can be used.
      */
-    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
-        return mDigests;
+    public String[] getDigests() {
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
     /**
@@ -175,7 +177,7 @@
      *
      * @return user authenticators or {@code 0} if the key can be used without user authentication.
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -184,7 +186,7 @@
      * key. This is a subset of the user authentications returned by
      * {@link #getUserAuthenticators()}.
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
         return mTeeEnforcedUserAuthenticators;
     }
 
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index fb534b4..9fce177 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -43,24 +43,26 @@
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
-    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+    private final String[] mEncryptionPaddings;
+    private final String[] mSignaturePaddings;
+    private final String[] mDigests;
+    private final String[] mBlockModes;
     private final boolean mRandomizedEncryptionRequired;
-    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
     private final int mUserAuthenticationValidityDurationSeconds;
 
     private KeyStoreParameter(int flags,
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum int purposes,
-            @KeyStoreKeyConstraints.PaddingEnum int paddings,
-            @KeyStoreKeyConstraints.DigestEnum Integer digests,
-            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyProperties.PurposeEnum int purposes,
+            String[] encryptionPaddings,
+            String[] signaturePaddings,
+            String[] digests,
+            String[] blockModes,
             boolean randomizedEncryptionRequired,
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
             int userAuthenticationValidityDurationSeconds) {
         if ((userAuthenticationValidityDurationSeconds < 0)
                 && (userAuthenticationValidityDurationSeconds != -1)) {
@@ -73,9 +75,12 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mPaddings = paddings;
-        mDigests = digests;
-        mBlockModes = blockModes;
+        mEncryptionPaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+        mSignaturePaddings =
+                ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+        mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+        mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
@@ -133,37 +138,48 @@
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+    public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the set of padding schemes to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
-        return mPaddings;
+    public String[] getEncryptionPaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
     }
 
     /**
-     * Gets the set of digests to which the key is restricted.
+     * Gets the set of padding schemes with which the key can be used when signing or verifying
+     * signatures.
      *
-     * @throws IllegalStateException if this restriction has not been specified.
+     * @hide
+     */
+    public String[] getSignaturePaddings() {
+        return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
+    }
+
+    /**
+     * Gets the set of digest algorithms with which the key can be used.
+     *
+     * @throws IllegalStateException if this set has not been specified.
      *
      * @see #isDigestsSpecified()
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
+    public String[] getDigests() {
         if (mDigests == null) {
             throw new IllegalStateException("Digests not specified");
         }
-        return mDigests;
+        return ArrayUtils.cloneIfNotEmpty(mDigests);
     }
 
     /**
-     * Returns {@code true} if digest restrictions have been specified.
+     * Returns {@code true} if the set of digest algorithms with which the key can be used has been
+     * specified.
      *
      * @see #getDigests()
      *
@@ -174,12 +190,12 @@
     }
 
     /**
-     * Gets the set of block modes to which the key is restricted.
+     * Gets the set of block modes with which the key can be used.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
-        return mBlockModes;
+    public String[] getBlockModes() {
+        return ArrayUtils.cloneIfNotEmpty(mBlockModes);
     }
 
     /**
@@ -205,7 +221,7 @@
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+    public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
         return mUserAuthenticators;
     }
 
@@ -244,12 +260,13 @@
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
         private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
-        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
-        private @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
-        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+        private String[] mEncryptionPaddings;
+        private String[] mSignaturePaddings;
+        private String[] mDigests;
+        private String[] mBlockModes;
         private boolean mRandomizedEncryptionRequired = true;
-        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
         private int mUserAuthenticationValidityDurationSeconds = -1;
 
         /**
@@ -342,55 +359,70 @@
         }
 
         /**
-         * Restricts the key to being used only for the provided set of purposes.
+         * Sets the set of purposes for which the key can be used.
          *
-         * <p>This restriction must be specified. There is no default.
+         * <p>This must be specified for all keys. There is no default.
          *
          * @hide
          */
-        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+        public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
             mPurposes = purposes;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided padding schemes. Attempts to use
-         * the key with any other padding will be rejected.
+         * Sets the set of padding schemes 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 restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This must be specified for keys which are used for encryption/decryption.
          *
          * @hide
          */
-        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
-            mPaddings = paddings;
+        public Builder setEncryptionPaddings(String... paddings) {
+            mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided digests when generating signatures
-         * or HMACs. Attempts to use the key with any other digest will be rejected.
+         * Sets the set of padding schemes with which the key can be used when
+         * signing/verifying. Attempts to use the key with any other padding scheme will be
+         * rejected.
          *
-         * <p>For HMAC keys, the default is to restrict to the digest specified in
-         * {@link Key#getAlgorithm()}. For asymmetric signing keys this constraint must be specified
-         * because there is no default.
+         * <p>This must be specified for RSA keys which are used for signing/verification.
          *
          * @hide
          */
-        public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
-            mDigests = digests;
+        public Builder setSignaturePaddings(String... paddings) {
+            mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
+            return this;
+        }
+
+
+        /**
+         * Sets the set of digests with which the key can be used when signing/verifying or
+         * generating MACs. Attempts to use the key with any other digest will be rejected.
+         *
+         * <p>For HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()}. For
+         * asymmetric signing keys this constraint must be specified.
+         *
+         * @hide
+         */
+        public Builder setDigests(String... digests) {
+            mDigests = ArrayUtils.cloneIfNotEmpty(digests);
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block modes. Attempts to use the
-         * key with any other block modes will be rejected.
+         * Sets the set of block modes 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 restriction must be specified for symmetric encryption/decryption keys.
+         * <p>This must be specified for encryption/decryption keys.
          *
          * @hide
          */
-        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
-            mBlockModes = blockModes;
+        public Builder setBlockModes(String... blockModes) {
+            mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
             return this;
         }
 
@@ -449,7 +481,7 @@
          * @hide
          */
         public Builder setUserAuthenticators(
-                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+                @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
             mUserAuthenticators = userAuthenticators;
             return this;
         }
@@ -484,7 +516,8 @@
                     mKeyValidityForOriginationEnd,
                     mKeyValidityForConsumptionEnd,
                     mPurposes,
-                    mPaddings,
+                    mEncryptionPaddings,
+                    mSignaturePaddings,
                     mDigests,
                     mBlockModes,
                     mRandomizedEncryptionRequired,
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index 99a8168..33073a4 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -19,10 +19,14 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterDefs;
 
+import libcore.util.EmptyArray;
+
 import java.security.InvalidKeyException;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.KeySpec;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactorySpi;
@@ -71,84 +75,90 @@
         }
 
         boolean teeBacked;
-        @KeyStoreKeyCharacteristics.OriginEnum int origin;
+        @KeyStoreKeyProperties.OriginEnum int origin;
         int keySize;
-        @KeyStoreKeyConstraints.PurposeEnum int purposes;
-        @KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
-        @KeyStoreKeyConstraints.PaddingEnum int paddings;
-        @KeyStoreKeyConstraints.DigestEnum int digests;
-        @KeyStoreKeyConstraints.BlockModeEnum int blockModes;
-        @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators;
-        @KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
+        @KeyStoreKeyProperties.PurposeEnum int purposes;
+        String[] encryptionPaddings;
+        String[] digests;
+        String[] blockModes;
+        @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators;
+        @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
         try {
             if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 teeBacked = true;
-                origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
+                origin = KeyStoreKeyProperties.Origin.fromKeymaster(
                         keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
             } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
                 teeBacked = false;
-                origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
+                origin = KeyStoreKeyProperties.Origin.fromKeymaster(
                         keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
             } else {
                 throw new InvalidKeySpecException("Key origin not available");
             }
-            Integer keySizeInteger =
-                    KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
+            Integer keySizeInteger = keyCharacteristics.getInteger(KeymasterDefs.KM_TAG_KEY_SIZE);
             if (keySizeInteger == null) {
                 throw new InvalidKeySpecException("Key size not available");
             }
             keySize = keySizeInteger;
-            purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
-            Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
-            if (alg == null) {
-                throw new InvalidKeySpecException("Key algorithm not available");
-            }
-            algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
-            paddings = KeyStoreKeyConstraints.Padding.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING));
-            digests = KeyStoreKeyConstraints.Digest.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST));
-            blockModes = KeyStoreKeyConstraints.BlockMode.allFromKeymaster(
-                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE));
+            purposes = KeyStoreKeyProperties.Purpose.allFromKeymaster(
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
 
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            List<String> encryptionPaddingsList = new ArrayList<String>();
+            for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
+                String jcaPadding;
+                try {
+                    jcaPadding = KeymasterUtils.getJcaEncryptionPaddingFromKeymasterPadding(
+                            keymasterPadding);
+                } catch (IllegalArgumentException e) {
+                    throw new InvalidKeySpecException(
+                            "Unsupported encryption padding: " + keymasterPadding);
+                }
+                encryptionPaddingsList.add(jcaPadding);
+            }
+            encryptionPaddings =
+                    encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
+
+            digests = KeymasterUtils.getJcaDigestAlgorithmsFromKeymasterDigests(
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
+            blockModes = KeymasterUtils.getJcaBlockModesFromKeymasterBlockModes(
+                    keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
+
+            @KeyStoreKeyProperties.UserAuthenticatorEnum
             int swEnforcedKeymasterUserAuthenticators =
                     keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            @KeyStoreKeyProperties.UserAuthenticatorEnum
             int hwEnforcedKeymasterUserAuthenticators =
                     keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
-            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            @KeyStoreKeyProperties.UserAuthenticatorEnum
             int keymasterUserAuthenticators =
                     swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators;
-            userAuthenticators = KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+            userAuthenticators = KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
                     keymasterUserAuthenticators);
             teeEnforcedUserAuthenticators =
-                    KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+                    KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
                             hwEnforcedKeymasterUserAuthenticators);
         } catch (IllegalArgumentException e) {
             throw new InvalidKeySpecException("Unsupported key characteristic", e);
         }
 
-        Date keyValidityStart =
-                KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+        Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
         if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
             keyValidityStart = null;
         }
-        Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
-                KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+        Date keyValidityForOriginationEnd =
+                keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
         if ((keyValidityForOriginationEnd != null)
                 && (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
             keyValidityForOriginationEnd = null;
         }
-        Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
-                KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+        Date keyValidityForConsumptionEnd =
+                keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
         if ((keyValidityForConsumptionEnd != null)
                 && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
             keyValidityForConsumptionEnd = null;
         }
-        Integer userAuthenticationValidityDurationSeconds =
-                KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT);
+        int userAuthenticationValidityDurationSeconds =
+                keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
 
         return new KeyStoreKeySpec(entryAlias,
                 teeBacked,
@@ -158,14 +168,13 @@
                 keyValidityForOriginationEnd,
                 keyValidityForConsumptionEnd,
                 purposes,
-                algorithm,
-                paddings,
+                encryptionPaddings,
+                EmptyArray.STRING, // no signature paddings -- this is symmetric crypto
                 digests,
                 blockModes,
                 userAuthenticators,
                 teeEnforcedUserAuthenticators,
-                ((userAuthenticationValidityDurationSeconds != null)
-                        ? userAuthenticationValidityDurationSeconds : -1));
+                userAuthenticationValidityDurationSeconds);
     }
 
     @Override
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 3143d4d..67f75c2 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -16,48 +16,327 @@
 
 package android.security;
 
-import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
 
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import libcore.util.EmptyArray;
+
+import java.util.Collection;
+import java.util.Locale;
 
 /**
  * @hide
  */
 public abstract class KeymasterUtils {
+
     private KeymasterUtils() {}
 
-    public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
-        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
-            return keyCharacteristics.hwEnforced.getInt(tag, -1);
-        } else if (keyCharacteristics.swEnforced.containsTag(tag)) {
-            return keyCharacteristics.swEnforced.getInt(tag, -1);
+    public static int getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
+        if ("AES".equalsIgnoreCase(jcaKeyAlgorithm)) {
+            return KeymasterDefs.KM_ALGORITHM_AES;
+        } else if (jcaKeyAlgorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
+            return KeymasterDefs.KM_ALGORITHM_HMAC;
         } else {
-            return null;
+            throw new IllegalArgumentException(
+                    "Unsupported secret key algorithm: " + jcaKeyAlgorithm);
         }
     }
 
-    public static List<Integer> getInts(KeyCharacteristics keyCharacteristics, int tag) {
-        List<Integer> result = new ArrayList<Integer>();
-        result.addAll(keyCharacteristics.hwEnforced.getInts(tag));
-        result.addAll(keyCharacteristics.swEnforced.getInts(tag));
-        return result;
+    public static String getJcaSecretKeyAlgorithm(int keymasterAlgorithm, int keymasterDigest) {
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_AES:
+                if (keymasterDigest != -1) {
+                    throw new IllegalArgumentException(
+                            "Digest not supported for AES key: " + keymasterDigest);
+                }
+                return "AES";
+            case KeymasterDefs.KM_ALGORITHM_HMAC:
+                switch (keymasterDigest) {
+                    case KeymasterDefs.KM_DIGEST_SHA1:
+                        return "HmacSHA1";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                        return "HmacSHA224";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                        return "HmacSHA256";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                        return "HmacSHA384";
+                    case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                        return "HmacSHA512";
+                    default:
+                        throw new IllegalArgumentException(
+                                "Unsupported HMAC digest: " + keymasterDigest);
+                }
+            default:
+                throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
+        }
     }
 
-    public static Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
-        Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
-        if (result == null) {
-            result = keyCharacteristics.swEnforced.getDate(tag, null);
+    public static String getJcaKeyPairAlgorithmFromKeymasterAlgorithm(int keymasterAlgorithm) {
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_RSA:
+                return "RSA";
+            case KeymasterDefs.KM_ALGORITHM_EC:
+                return "EC";
+            default:
+                throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
+        }
+    }
+
+    public static int getKeymasterDigestfromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
+        String algorithmUpper = jcaKeyAlgorithm.toUpperCase(Locale.US);
+        if (algorithmUpper.startsWith("HMAC")) {
+            String digestUpper = algorithmUpper.substring("HMAC".length());
+            switch (digestUpper) {
+                case "MD5":
+                    return KeymasterDefs.KM_DIGEST_MD5;
+                case "SHA1":
+                    return KeymasterDefs.KM_DIGEST_SHA1;
+                case "SHA224":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_224;
+                case "SHA256":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_256;
+                case "SHA384":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_384;
+                case "SHA512":
+                    return KeymasterDefs.KM_DIGEST_SHA_2_512;
+                default:
+                    throw new IllegalArgumentException("Unsupported HMAC digest: " + digestUpper);
+            }
+        } else {
+            return -1;
+        }
+    }
+
+    public static int getKeymasterDigestFromJcaDigestAlgorithm(String jcaDigestAlgorithm) {
+        if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-1")) {
+            return KeymasterDefs.KM_DIGEST_SHA1;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-224")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_224;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-256")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_256;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-384")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_384;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-512")) {
+            return KeymasterDefs.KM_DIGEST_SHA_2_512;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("NONE")) {
+            return KeymasterDefs.KM_DIGEST_NONE;
+        } else if (jcaDigestAlgorithm.equalsIgnoreCase("MD5")) {
+            return KeymasterDefs.KM_DIGEST_MD5;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported digest algorithm: " + jcaDigestAlgorithm);
+        }
+    }
+
+    public static String getJcaDigestAlgorithmFromKeymasterDigest(int keymasterDigest) {
+        switch (keymasterDigest) {
+            case KeymasterDefs.KM_DIGEST_NONE:
+                return "NONE";
+            case KeymasterDefs.KM_DIGEST_MD5:
+                return "MD5";
+            case KeymasterDefs.KM_DIGEST_SHA1:
+                return "SHA-1";
+            case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                return "SHA-224";
+            case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                return "SHA-256";
+            case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                return "SHA-384";
+            case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                return "SHA-512";
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported digest algorithm: " + keymasterDigest);
+        }
+    }
+
+    public static String[] getJcaDigestAlgorithmsFromKeymasterDigests(
+            Collection<Integer> keymasterDigests) {
+        if (keymasterDigests.isEmpty()) {
+            return EmptyArray.STRING;
+        }
+        String[] result = new String[keymasterDigests.size()];
+        int offset = 0;
+        for (int keymasterDigest : keymasterDigests) {
+            result[offset] = getJcaDigestAlgorithmFromKeymasterDigest(keymasterDigest);
+            offset++;
         }
         return result;
     }
 
-    public static boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
-        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
-            return keyCharacteristics.hwEnforced.getBoolean(tag, false);
-        } else {
-            return keyCharacteristics.swEnforced.getBoolean(tag, false);
+    public static int[] getKeymasterDigestsFromJcaDigestAlgorithms(String[] jcaDigestAlgorithms) {
+        if ((jcaDigestAlgorithms == null) || (jcaDigestAlgorithms.length == 0)) {
+            return EmptyArray.INT;
         }
+        int[] result = new int[jcaDigestAlgorithms.length];
+        int offset = 0;
+        for (String jcaDigestAlgorithm : jcaDigestAlgorithms) {
+            result[offset] = getKeymasterDigestFromJcaDigestAlgorithm(jcaDigestAlgorithm);
+            offset++;
+        }
+        return result;
+    }
+
+    public static int getDigestOutputSizeBytes(int keymasterDigest) {
+        switch (keymasterDigest) {
+            case KeymasterDefs.KM_DIGEST_NONE:
+                return -1;
+            case KeymasterDefs.KM_DIGEST_MD5:
+                return 128 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA1:
+                return 160 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                return 224 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_256:
+                return 256 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                return 384 / 8;
+            case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                return 512 / 8;
+            default:
+                throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
+        }
+    }
+
+    public static int getKeymasterBlockModeFromJcaBlockMode(String jcaBlockMode) {
+        if ("ECB".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_ECB;
+        } else if ("CBC".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_CBC;
+        } else if ("CTR".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_CTR;
+        } else if ("GCM".equalsIgnoreCase(jcaBlockMode)) {
+            return KeymasterDefs.KM_MODE_GCM;
+        } else {
+            throw new IllegalArgumentException("Unsupported block mode: " + jcaBlockMode);
+        }
+    }
+
+    public static String getJcaBlockModeFromKeymasterBlockMode(int keymasterBlockMode) {
+        switch (keymasterBlockMode) {
+            case KeymasterDefs.KM_MODE_ECB:
+                return "ECB";
+            case KeymasterDefs.KM_MODE_CBC:
+                return "CBC";
+            case KeymasterDefs.KM_MODE_CTR:
+                return "CTR";
+            case KeymasterDefs.KM_MODE_GCM:
+                return "GCM";
+            default:
+                throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+        }
+    }
+
+    public static String[] getJcaBlockModesFromKeymasterBlockModes(
+            Collection<Integer> keymasterBlockModes) {
+        if ((keymasterBlockModes == null) || (keymasterBlockModes.isEmpty())) {
+            return EmptyArray.STRING;
+        }
+        String[] result = new String[keymasterBlockModes.size()];
+        int offset = 0;
+        for (int keymasterBlockMode : keymasterBlockModes) {
+            result[offset] = getJcaBlockModeFromKeymasterBlockMode(keymasterBlockMode);
+            offset++;
+        }
+        return result;
+    }
+
+    public static int[] getKeymasterBlockModesFromJcaBlockModes(String[] jcaBlockModes) {
+        if ((jcaBlockModes == null) || (jcaBlockModes.length == 0)) {
+            return EmptyArray.INT;
+        }
+        int[] result = new int[jcaBlockModes.length];
+        for (int i = 0; i < jcaBlockModes.length; i++) {
+            result[i] = getKeymasterBlockModeFromJcaBlockMode(jcaBlockModes[i]);
+        }
+        return result;
+    }
+
+    public static boolean isKeymasterBlockModeIndCpaCompatible(int keymasterBlockMode) {
+        switch (keymasterBlockMode) {
+            case KeymasterDefs.KM_MODE_ECB:
+                return false;
+            case KeymasterDefs.KM_MODE_CBC:
+            case KeymasterDefs.KM_MODE_CTR:
+            case KeymasterDefs.KM_MODE_GCM:
+                return true;
+            default:
+                throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+        }
+    }
+
+    public static int getKeymasterPaddingFromJcaEncryptionPadding(String jcaPadding) {
+        if ("NoPadding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_NONE;
+        } else if ("PKCS7Padding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_PKCS7;
+        } else if ("PKCS1Padding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+        } else if ("OEAPPadding".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_OAEP;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported encryption padding scheme: " + jcaPadding);
+        }
+    }
+
+    public static String getJcaEncryptionPaddingFromKeymasterPadding(int keymasterPadding) {
+        switch (keymasterPadding) {
+            case KeymasterDefs.KM_PAD_NONE:
+                return "NoPadding";
+            case KeymasterDefs.KM_PAD_PKCS7:
+                return "PKCS7Padding";
+            case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+                return "PKCS1Padding";
+            case KeymasterDefs.KM_PAD_RSA_OAEP:
+                return "OEAPPadding";
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported encryption padding: " + keymasterPadding);
+        }
+    }
+
+    public static int getKeymasterPaddingFromJcaSignaturePadding(String jcaPadding) {
+        if ("PKCS#1".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
+        } if ("PSS".equalsIgnoreCase(jcaPadding)) {
+            return KeymasterDefs.KM_PAD_RSA_PSS;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported signature padding scheme: " + jcaPadding);
+        }
+    }
+
+    public static String getJcaSignaturePaddingFromKeymasterPadding(int keymasterPadding) {
+        switch (keymasterPadding) {
+            case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
+                return "PKCS#1";
+            case KeymasterDefs.KM_PAD_RSA_PSS:
+                return "PSS";
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported signature padding: " + keymasterPadding);
+        }
+    }
+
+    public static int[] getKeymasterPaddingsFromJcaEncryptionPaddings(String[] jcaPaddings) {
+        if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
+            return EmptyArray.INT;
+        }
+        int[] result = new int[jcaPaddings.length];
+        for (int i = 0; i < jcaPaddings.length; i++) {
+            result[i] = getKeymasterPaddingFromJcaEncryptionPadding(jcaPaddings[i]);
+        }
+        return result;
+    }
+
+    public static int[] getKeymasterPaddingsFromJcaSignaturePaddings(String[] jcaPaddings) {
+        if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
+            return EmptyArray.INT;
+        }
+        int[] result = new int[jcaPaddings.length];
+        for (int i = 0; i < jcaPaddings.length; i++) {
+            result[i] = getKeymasterPaddingFromJcaSignaturePadding(jcaPaddings[i]);
+        }
+        return result;
     }
 }