This adds MD5, SHA-1, SHA-224, SHA-384, and SHA-512. SHA-256 was already there. MD5 is not exposed for HMAC on purpose, because MD5 has been deprecated for years. Bug: 18088752 Change-Id: I4df3d3f6cf10805c7910a1bdb577a91c85055945
809 lines
24 KiB
Java
809 lines
24 KiB
Java
/*
|
|
* 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})
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
@IntDef(flag = true,
|
|
value = {Padding.NONE, Padding.PKCS7})
|
|
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;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public static int toKeymaster(int padding) {
|
|
switch (padding) {
|
|
case NONE:
|
|
return KeymasterDefs.KM_PAD_NONE;
|
|
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_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 PKCS7:
|
|
return "PKCS#7";
|
|
default:
|
|
throw new IllegalArgumentException("Unknown padding: " + padding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
public static @PaddingEnum int fromJCAPadding(String padding) {
|
|
String paddingLower = padding.toLowerCase(Locale.US);
|
|
if ("nopadding".equals(paddingLower)) {
|
|
return NONE;
|
|
} else if ("pkcs7padding".equals(paddingLower)) {
|
|
return PKCS7;
|
|
} 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;
|
|
|
|
/**
|
|
* @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 @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;
|
|
}
|
|
}
|