summaryrefslogtreecommitdiffstats
path: root/keystore/java/android/security/KeyStoreKeyProperties.java
diff options
context:
space:
mode:
Diffstat (limited to 'keystore/java/android/security/KeyStoreKeyProperties.java')
-rw-r--r--keystore/java/android/security/KeyStoreKeyProperties.java520
1 files changed, 519 insertions, 1 deletions
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
index b85ec53..1c3e300 100644
--- a/keystore/java/android/security/KeyStoreKeyProperties.java
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -17,13 +17,23 @@
package android.security;
import android.annotation.IntDef;
+import android.annotation.StringDef;
import android.security.keymaster.KeymasterDefs;
import libcore.util.EmptyArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
import java.util.Collection;
+import java.util.Locale;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKeyFactory;
/**
* Properties of {@code AndroidKeyStore} keys.
@@ -37,7 +47,7 @@ public abstract class KeyStoreKeyProperties {
public @interface PurposeEnum {}
/**
- * Purpose of key.
+ * Purposes of key.
*/
public static abstract class Purpose {
private Purpose() {}
@@ -122,6 +132,514 @@ public abstract class KeyStoreKeyProperties {
}
@Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ Algorithm.RSA,
+ Algorithm.EC,
+ Algorithm.AES,
+ Algorithm.HMAC_SHA1,
+ Algorithm.HMAC_SHA224,
+ Algorithm.HMAC_SHA256,
+ Algorithm.HMAC_SHA384,
+ Algorithm.HMAC_SHA512,
+ })
+ public @interface AlgorithmEnum {}
+
+ /**
+ * Key algorithms.
+ *
+ * <p>These are standard names which can be used to obtain instances of {@link KeyGenerator},
+ * {@link KeyPairGenerator}, {@link Cipher} (as part of the transformation string), {@link Mac},
+ * {@link KeyFactory}, {@link SecretKeyFactory}. These are also the names used by
+ * {@link Key#getAlgorithm()}.
+ */
+ public static abstract class Algorithm {
+ private Algorithm() {}
+
+ /** Rivest Shamir Adleman (RSA) key. */
+ public static final String RSA = "RSA";
+
+ /** Elliptic Curve (EC) key. */
+ public static final String EC = "EC";
+
+ /** Advanced Encryption Standard (AES) key. */
+ public static final String AES = "AES";
+
+ /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-1 as the hash. */
+ public static final String HMAC_SHA1 = "HmacSHA1";
+
+ /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-224 as the hash. */
+ public static final String HMAC_SHA224 = "HmacSHA224";
+
+ /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-256 as the hash. */
+ public static final String HMAC_SHA256 = "HmacSHA256";
+
+ /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-384 as the hash. */
+ public static final String HMAC_SHA384 = "HmacSHA384";
+
+ /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */
+ public static final String HMAC_SHA512 = "HmacSHA512";
+
+ /**
+ * @hide
+ */
+ static int toKeymasterSecretKeyAlgorithm(@AlgorithmEnum String algorithm) {
+ if (AES.equalsIgnoreCase(algorithm)) {
+ return KeymasterDefs.KM_ALGORITHM_AES;
+ } else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
+ return KeymasterDefs.KM_ALGORITHM_HMAC;
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported secret key algorithm: " + algorithm);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @AlgorithmEnum String fromKeymasterSecretKeyAlgorithm(
+ int keymasterAlgorithm, int keymasterDigest) {
+ switch (keymasterAlgorithm) {
+ case KeymasterDefs.KM_ALGORITHM_AES:
+ if (keymasterDigest != -1) {
+ throw new IllegalArgumentException("Digest not supported for AES key: "
+ + Digest.fromKeymaster(keymasterDigest));
+ }
+ return AES;
+ case KeymasterDefs.KM_ALGORITHM_HMAC:
+ switch (keymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return HMAC_SHA1;
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return HMAC_SHA224;
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return HMAC_SHA256;
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return HMAC_SHA384;
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return HMAC_SHA512;
+ default:
+ throw new IllegalArgumentException("Unsupported HMAC digest: "
+ + Digest.fromKeymaster(keymasterDigest));
+ }
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported algorithm: " + keymasterAlgorithm);
+ }
+ }
+
+ /**
+ * @hide
+ *
+ * @return keymaster digest or {@code -1} if the algorithm does not involve a digest.
+ */
+ static int toKeymasterDigest(@AlgorithmEnum String algorithm) {
+ String algorithmUpper = algorithm.toUpperCase(Locale.US);
+ if (algorithmUpper.startsWith("HMAC")) {
+ String digestUpper = algorithmUpper.substring("HMAC".length());
+ switch (digestUpper) {
+ 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;
+ }
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ 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 String ECB = "ECB";
+
+ /** Cipher Block Chaining (CBC) block mode. */
+ public static final String CBC = "CBC";
+
+ /** Counter (CTR) block mode. */
+ public static final String CTR = "CTR";
+
+ /** Galois/Counter Mode (GCM) block mode. */
+ public static final String GCM = "GCM";
+
+ /**
+ * @hide
+ */
+ static int toKeymaster(@BlockModeEnum String blockMode) {
+ if (ECB.equalsIgnoreCase(blockMode)) {
+ return KeymasterDefs.KM_MODE_ECB;
+ } else if (CBC.equalsIgnoreCase(blockMode)) {
+ return KeymasterDefs.KM_MODE_CBC;
+ } else if (CTR.equalsIgnoreCase(blockMode)) {
+ return KeymasterDefs.KM_MODE_CTR;
+ } else if (GCM.equalsIgnoreCase(blockMode)) {
+ return KeymasterDefs.KM_MODE_GCM;
+ } else {
+ throw new IllegalArgumentException("Unsupported block mode: " + blockMode);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @BlockModeEnum String fromKeymaster(int blockMode) {
+ switch (blockMode) {
+ 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: " + blockMode);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @BlockModeEnum String[] allFromKeymaster(Collection<Integer> blockModes) {
+ if ((blockModes == null) || (blockModes.isEmpty())) {
+ return EmptyArray.STRING;
+ }
+ @BlockModeEnum String[] result = new String[blockModes.size()];
+ int offset = 0;
+ for (int blockMode : blockModes) {
+ result[offset] = fromKeymaster(blockMode);
+ offset++;
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ static int[] allToKeymaster(@BlockModeEnum String[] blockModes) {
+ if ((blockModes == null) || (blockModes.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[blockModes.length];
+ for (int i = 0; i < blockModes.length; i++) {
+ result[i] = toKeymaster(blockModes[i]);
+ }
+ return result;
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ EncryptionPadding.NONE,
+ EncryptionPadding.PKCS7,
+ EncryptionPadding.RSA_PKCS1,
+ EncryptionPadding.RSA_OAEP,
+ })
+ public @interface EncryptionPaddingEnum {}
+
+ /**
+ * Padding schemes for encryption/decryption.
+ */
+ public static abstract class EncryptionPadding {
+ private EncryptionPadding() {}
+
+ /**
+ * No padding.
+ */
+ public static final String NONE = "NoPadding";
+
+ /**
+ * PKCS#7 padding.
+ */
+ public static final String PKCS7 = "PKCS7Padding";
+
+ /**
+ * RSA PKCS#1 v1.5 padding for encryption/decryption.
+ */
+ public static final String RSA_PKCS1 = "PKCS1Padding";
+
+ /**
+ * RSA Optimal Asymmetric Encryption Padding (OAEP).
+ */
+ public static final String RSA_OAEP = "OAEPPadding";
+
+ /**
+ * @hide
+ */
+ static int toKeymaster(@EncryptionPaddingEnum String padding) {
+ if (NONE.equalsIgnoreCase(padding)) {
+ return KeymasterDefs.KM_PAD_NONE;
+ } else if (PKCS7.equalsIgnoreCase(padding)) {
+ return KeymasterDefs.KM_PAD_PKCS7;
+ } else if (RSA_PKCS1.equalsIgnoreCase(padding)) {
+ return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+ } else if (RSA_OAEP.equalsIgnoreCase(padding)) {
+ return KeymasterDefs.KM_PAD_RSA_OAEP;
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported encryption padding scheme: " + padding);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @EncryptionPaddingEnum String 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;
+ case KeymasterDefs.KM_PAD_RSA_OAEP:
+ return RSA_OAEP;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported encryption padding: " + padding);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static int[] allToKeymaster(@EncryptionPaddingEnum String[] paddings) {
+ if ((paddings == null) || (paddings.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[paddings.length];
+ for (int i = 0; i < paddings.length; i++) {
+ result[i] = toKeymaster(paddings[i]);
+ }
+ return result;
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ SignaturePadding.RSA_PKCS1,
+ SignaturePadding.RSA_PSS,
+ })
+ public @interface SignaturePaddingEnum {}
+
+ /**
+ * Padding schemes for signing/verification.
+ */
+ public static abstract class SignaturePadding {
+ private SignaturePadding() {}
+
+ /**
+ * RSA PKCS#1 v1.5 padding for signatures.
+ */
+ public static final String RSA_PKCS1 = "PKCS1";
+
+ /**
+ * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding.
+ */
+ public static final String RSA_PSS = "PSS";
+
+ /**
+ * @hide
+ */
+ static int toKeymaster(@SignaturePaddingEnum String padding) {
+ switch (padding.toUpperCase(Locale.US)) {
+ case RSA_PKCS1:
+ return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
+ case RSA_PSS:
+ return KeymasterDefs.KM_PAD_RSA_PSS;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported signature padding scheme: " + padding);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @SignaturePaddingEnum String fromKeymaster(int padding) {
+ switch (padding) {
+ case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
+ return RSA_PKCS1;
+ case KeymasterDefs.KM_PAD_RSA_PSS:
+ return RSA_PSS;
+ default:
+ throw new IllegalArgumentException("Unsupported signature padding: " + padding);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static int[] allToKeymaster(@SignaturePaddingEnum String[] paddings) {
+ if ((paddings == null) || (paddings.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[paddings.length];
+ for (int i = 0; i < paddings.length; i++) {
+ result[i] = toKeymaster(paddings[i]);
+ }
+ return result;
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ 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 String NONE = "NONE";
+
+ /**
+ * MD5 digest.
+ */
+ public static final String MD5 = "MD5";
+
+ /**
+ * SHA-1 digest.
+ */
+ public static final String SHA1 = "SHA-1";
+
+ /**
+ * SHA-2 224 (aka SHA-224) digest.
+ */
+ public static final String SHA224 = "SHA-224";
+
+ /**
+ * SHA-2 256 (aka SHA-256) digest.
+ */
+ public static final String SHA256 = "SHA-256";
+
+ /**
+ * SHA-2 384 (aka SHA-384) digest.
+ */
+ public static final String SHA384 = "SHA-384";
+
+ /**
+ * SHA-2 512 (aka SHA-512) digest.
+ */
+ public static final String SHA512 = "SHA-512";
+
+ /**
+ * @hide
+ */
+ static int toKeymaster(@DigestEnum String digest) {
+ switch (digest.toUpperCase(Locale.US)) {
+ 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;
+ case NONE:
+ return KeymasterDefs.KM_DIGEST_NONE;
+ case MD5:
+ return KeymasterDefs.KM_DIGEST_MD5;
+ default:
+ throw new IllegalArgumentException("Unsupported digest algorithm: " + digest);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @DigestEnum String 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("Unsupported digest algorithm: " + digest);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ static @DigestEnum String[] allFromKeymaster(Collection<Integer> digests) {
+ if (digests.isEmpty()) {
+ return EmptyArray.STRING;
+ }
+ String[] result = new String[digests.size()];
+ int offset = 0;
+ for (int digest : digests) {
+ result[offset] = fromKeymaster(digest);
+ offset++;
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ static int[] allToKeymaster(@DigestEnum String[] digests) {
+ if ((digests == null) || (digests.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[digests.length];
+ int offset = 0;
+ for (@DigestEnum String digest : digests) {
+ result[offset] = toKeymaster(digest);
+ offset++;
+ }
+ return result;
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
@IntDef({Origin.GENERATED, Origin.IMPORTED, Origin.UNKNOWN})
public @interface OriginEnum {}