blob: 47bb1ccbbeb7ba061188b7b110c5536dd833f794 [file] [log] [blame]
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);
}
}
/**
* @hide
*/
public static String toString(@PaddingEnum int padding) {
switch (padding) {
case NONE:
return "NONE";
case ZERO:
return "ZERO";
case PKCS7:
return "PKCS#7";
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);
}
}
/**
* @hide
*/
public static String toString(@BlockModeEnum int mode) {
switch (mode) {
case ECB:
return "ECB";
default:
throw new IllegalArgumentException("Unknown block mode: " + mode);
}
}
}
}