diff options
Diffstat (limited to 'keystore/java/android/security/KeyStoreKeyConstraints.java')
-rw-r--r-- | keystore/java/android/security/KeyStoreKeyConstraints.java | 429 |
1 files changed, 429 insertions, 0 deletions
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java new file mode 100644 index 0000000..01e6dcd --- /dev/null +++ b/keystore/java/android/security/KeyStoreKeyConstraints.java @@ -0,0 +1,429 @@ +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.Arrays; +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; + + /** + * Number of flags defined above. Needs to be kept in sync with the flags above. + */ + private static final int VALUE_COUNT = 4; + + /** + * @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(int purposes) { + int[] result = new int[VALUE_COUNT]; + int resultCount = 0; + int purpose = 1; + for (int i = 0; i < 32; i++) { + if ((purposes & 1) != 0) { + result[resultCount] = toKeymaster(purpose); + resultCount++; + } + purposes >>>= 1; + purpose <<= 1; + if (purposes == 0) { + break; + } + } + return Arrays.copyOf(result, resultCount); + } + + /** + * @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}) + public @interface AlgorithmEnum {} + + /** + * Key algorithm. + */ + public static abstract class Algorithm { + private Algorithm() {} + + /** + * Key algorithm: AES. + */ + public static final int AES = 0; + + /** + * Key algorithm: HMAC. + */ + public static final int HMAC = 1; + + /** + * @hide + */ + public static int toKeymaster(@AlgorithmEnum int algorithm) { + switch (algorithm) { + case AES: + return KeymasterDefs.KM_ALGORITHM_AES; + case HMAC: + return KeymasterDefs.KM_ALGORITHM_HMAC; + 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; + 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"; + 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.SHA256: + return "HmacSHA256"; + 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) { + default: + throw new IllegalArgumentException("Unsupported key alorithm: " + algorithm); + } + } + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({Padding.NONE, Padding.ZERO, Padding.PKCS7}) + public @interface PaddingEnum {} + + /** + * Padding for signing and encryption. + */ + public static abstract class Padding { + private Padding() {} + + /** + * No padding. + */ + public static final int NONE = 0; + + /** + * Pad with zeros. + */ + public static final int ZERO = 1; + + /** + * PKCS#7 padding. + */ + public static final int PKCS7 = 2; + + /** + * @hide + */ + public static int toKeymaster(int padding) { + switch (padding) { + case NONE: + return KeymasterDefs.KM_PAD_NONE; + case ZERO: + return KeymasterDefs.KM_PAD_ZERO; + case PKCS7: + return KeymasterDefs.KM_PAD_PKCS7; + 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_ZERO: + return ZERO; + case KeymasterDefs.KM_PAD_PKCS7: + return PKCS7; + default: + throw new IllegalArgumentException("Unknown padding: " + padding); + } + } + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({Digest.NONE, Digest.SHA256}) + 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 = 0; + + /** + * SHA-256 digest. + */ + public static final int SHA256 = 1; + + /** + * @hide + */ + public static String toString(@DigestEnum int digest) { + switch (digest) { + case NONE: + return "NONE"; + case SHA256: + return "SHA256"; + default: + throw new IllegalArgumentException("Unknown digest: " + digest); + } + } + + /** + * @hide + */ + public static int toKeymaster(@DigestEnum int digest) { + switch (digest) { + case NONE: + return KeymasterDefs.KM_DIGEST_NONE; + case SHA256: + return KeymasterDefs.KM_DIGEST_SHA_2_256; + 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_SHA_2_256: + return SHA256; + default: + throw new IllegalArgumentException("Unknown digest: " + digest); + } + } + + /** + * @hide + */ + public static @DigestEnum Integer fromJCASecretKeyAlgorithm(String algorithm) { + String algorithmLower = algorithm.toLowerCase(Locale.US); + if (algorithmLower.startsWith("hmac")) { + if ("hmacsha256".equals(algorithmLower)) { + return SHA256; + } else { + throw new IllegalArgumentException("Unsupported digest: " + + algorithmLower.substring("hmac".length())); + } + } else { + return null; + } + } + + /** + * @hide + */ + public static String toJCASignatureAlgorithmDigest(@DigestEnum int digest) { + switch (digest) { + case NONE: + return "NONE"; + case SHA256: + return "SHA256"; + default: + throw new IllegalArgumentException("Unknown digest: " + digest); + } + } + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({BlockMode.ECB}) + 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 = 0; + + /** + * @hide + */ + public static int toKeymaster(@BlockModeEnum int mode) { + switch (mode) { + case ECB: + return KeymasterDefs.KM_MODE_ECB; + 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; + default: + throw new IllegalArgumentException("Unknown block mode: " + mode); + } + } + } +} |