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/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;
     }
 }