* commit '9c0f257f0080aba0743f34fb6202215fca295146': Add SecretKeyFactory backed by AndroidKeyStore.
This commit is contained in:
@ -40,6 +40,10 @@ public class AndroidKeyStoreProvider extends Provider {
|
|||||||
put("KeyGenerator.AES", KeyStoreKeyGeneratorSpi.AES.class.getName());
|
put("KeyGenerator.AES", KeyStoreKeyGeneratorSpi.AES.class.getName());
|
||||||
put("KeyGenerator.HmacSHA256", KeyStoreKeyGeneratorSpi.HmacSHA256.class.getName());
|
put("KeyGenerator.HmacSHA256", KeyStoreKeyGeneratorSpi.HmacSHA256.class.getName());
|
||||||
|
|
||||||
|
// java.security.SecretKeyFactory
|
||||||
|
put("SecretKeyFactory.AES", KeyStoreSecretKeyFactorySpi.class.getName());
|
||||||
|
put("SecretKeyFactory.HmacSHA256", KeyStoreSecretKeyFactorySpi.class.getName());
|
||||||
|
|
||||||
// javax.crypto.Mac
|
// javax.crypto.Mac
|
||||||
putMacImpl("HmacSHA256", KeyStoreHmacSpi.HmacSHA256.class.getName());
|
putMacImpl("HmacSHA256", KeyStoreHmacSpi.HmacSHA256.class.getName());
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the set of purposes for which the key can be used to the provided set of purposes.
|
* Gets the set of purposes for which the key can be used.
|
||||||
*
|
*
|
||||||
* @return set of purposes or {@code null} if the key can be used for any purpose.
|
* @return set of purposes or {@code null} if the key can be used for any purpose.
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
package android.security;
|
||||||
|
|
||||||
|
import android.annotation.IntDef;
|
||||||
|
import android.security.keymaster.KeymasterDefs;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Characteristics of {@code AndroidKeyStore} keys.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public abstract class KeyStoreKeyCharacteristics {
|
||||||
|
private KeyStoreKeyCharacteristics() {}
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
@IntDef({Origin.GENERATED_INSIDE_TEE, Origin.GENERATED_OUTSIDE_OF_TEE, Origin.IMPORTED})
|
||||||
|
public @interface OriginEnum {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Origin of the key.
|
||||||
|
*/
|
||||||
|
public static abstract class Origin {
|
||||||
|
private Origin() {}
|
||||||
|
|
||||||
|
/** Key was generated inside a TEE. */
|
||||||
|
public static final int GENERATED_INSIDE_TEE = 1;
|
||||||
|
|
||||||
|
/** Key was generated outside of a TEE. */
|
||||||
|
public static final int GENERATED_OUTSIDE_OF_TEE = 2;
|
||||||
|
|
||||||
|
/** Key was imported. */
|
||||||
|
public static final int IMPORTED = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static @OriginEnum int fromKeymaster(int origin) {
|
||||||
|
switch (origin) {
|
||||||
|
case KeymasterDefs.KM_ORIGIN_HARDWARE:
|
||||||
|
return GENERATED_INSIDE_TEE;
|
||||||
|
case KeymasterDefs.KM_ORIGIN_SOFTWARE:
|
||||||
|
return GENERATED_OUTSIDE_OF_TEE;
|
||||||
|
case KeymasterDefs.KM_ORIGIN_IMPORTED:
|
||||||
|
return IMPORTED;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unknown origin: " + origin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
210
keystore/java/android/security/KeyStoreKeySpec.java
Normal file
210
keystore/java/android/security/KeyStoreKeySpec.java
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
package android.security;
|
||||||
|
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
|
||||||
|
* KeyStore</a>.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class KeyStoreKeySpec implements KeySpec {
|
||||||
|
private final String mKeystoreAlias;
|
||||||
|
private final int mKeySize;
|
||||||
|
private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
|
||||||
|
private final Date mKeyValidityStart;
|
||||||
|
private final Date mKeyValidityForOriginationEnd;
|
||||||
|
private final Date mKeyValidityForConsumptionEnd;
|
||||||
|
private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||||
|
private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
|
||||||
|
private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
|
||||||
|
private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
|
||||||
|
private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
|
||||||
|
private final Integer mMinSecondsBetweenOperations;
|
||||||
|
private final Integer mMaxUsesPerBoot;
|
||||||
|
private final Set<Integer> mUserAuthenticators;
|
||||||
|
private final Set<Integer> mTeeBackedUserAuthenticators;
|
||||||
|
private final Integer mUserAuthenticationValidityDurationSeconds;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
KeyStoreKeySpec(String keystoreKeyAlias,
|
||||||
|
@KeyStoreKeyCharacteristics.OriginEnum int origin,
|
||||||
|
int keySize, Date keyValidityStart, Date keyValidityForOriginationEnd,
|
||||||
|
Date keyValidityForConsumptionEnd,
|
||||||
|
@KeyStoreKeyConstraints.PurposeEnum int purposes,
|
||||||
|
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
|
||||||
|
@KeyStoreKeyConstraints.PaddingEnum Integer padding,
|
||||||
|
@KeyStoreKeyConstraints.DigestEnum Integer digest,
|
||||||
|
@KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
|
||||||
|
Integer minSecondsBetweenOperations,
|
||||||
|
Integer maxUsesPerBoot,
|
||||||
|
Set<Integer> userAuthenticators,
|
||||||
|
Set<Integer> teeBackedUserAuthenticators,
|
||||||
|
Integer userAuthenticationValidityDurationSeconds) {
|
||||||
|
mKeystoreAlias = keystoreKeyAlias;
|
||||||
|
mOrigin = origin;
|
||||||
|
mKeySize = keySize;
|
||||||
|
mKeyValidityStart = keyValidityStart;
|
||||||
|
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
|
||||||
|
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
|
||||||
|
mPurposes = purposes;
|
||||||
|
mAlgorithm = algorithm;
|
||||||
|
mPadding = padding;
|
||||||
|
mDigest = digest;
|
||||||
|
mBlockMode = blockMode;
|
||||||
|
mMinSecondsBetweenOperations = minSecondsBetweenOperations;
|
||||||
|
mMaxUsesPerBoot = maxUsesPerBoot;
|
||||||
|
mUserAuthenticators = (userAuthenticators != null)
|
||||||
|
? new HashSet<Integer>(userAuthenticators)
|
||||||
|
: Collections.<Integer>emptySet();
|
||||||
|
mTeeBackedUserAuthenticators = (teeBackedUserAuthenticators != null)
|
||||||
|
? new HashSet<Integer>(teeBackedUserAuthenticators)
|
||||||
|
: Collections.<Integer>emptySet();
|
||||||
|
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the entry alias under which the key is stored in the {@code AndroidKeyStore}.
|
||||||
|
*/
|
||||||
|
public String getKeystoreAlias() {
|
||||||
|
return mKeystoreAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the origin of the key.
|
||||||
|
*/
|
||||||
|
public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
|
||||||
|
return mOrigin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the key's size in bits.
|
||||||
|
*/
|
||||||
|
public int getKeySize() {
|
||||||
|
return mKeySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the time instant before which the key is not yet valid.
|
||||||
|
*
|
||||||
|
* @return instant or {@code null} if not restricted.
|
||||||
|
*/
|
||||||
|
public Date getKeyValidityStart() {
|
||||||
|
return mKeyValidityStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the time instant after which the key is no long valid for decryption and verification.
|
||||||
|
*
|
||||||
|
* @return instant or {@code null} if not restricted.
|
||||||
|
*/
|
||||||
|
public Date getKeyValidityForConsumptionEnd() {
|
||||||
|
return mKeyValidityForConsumptionEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the time instant after which the key is no long valid for encryption and signing.
|
||||||
|
*
|
||||||
|
* @return instant or {@code null} if not restricted.
|
||||||
|
*/
|
||||||
|
public Date getKeyValidityForOriginationEnd() {
|
||||||
|
return mKeyValidityForOriginationEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the set of purposes for which the key can be used.
|
||||||
|
*/
|
||||||
|
public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
|
||||||
|
return mPurposes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the algorithm of the key.
|
||||||
|
*/
|
||||||
|
public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
|
||||||
|
return mAlgorithm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the only block mode with which the key can be used.
|
||||||
|
*
|
||||||
|
* @return block mode or {@code null} if the block mode is not restricted.
|
||||||
|
*/
|
||||||
|
public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
|
||||||
|
return mBlockMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the only padding mode with which the key can be used.
|
||||||
|
*
|
||||||
|
* @return padding mode or {@code null} if the padding mode is not restricted.
|
||||||
|
*/
|
||||||
|
public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
|
||||||
|
return mPadding;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the only digest algorithm with which the key can be used.
|
||||||
|
*
|
||||||
|
* @return digest algorithm or {@code null} if the digest algorithm is not restricted.
|
||||||
|
*/
|
||||||
|
public @KeyStoreKeyConstraints.DigestEnum Integer getDigest() {
|
||||||
|
return mDigest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the minimum number of seconds that must expire since the most recent use of the key
|
||||||
|
* before it can be used again.
|
||||||
|
*
|
||||||
|
* @return number of seconds or {@code null} if there is no restriction on how frequently a key
|
||||||
|
* can be used.
|
||||||
|
*/
|
||||||
|
public Integer getMinSecondsBetweenOperations() {
|
||||||
|
return mMinSecondsBetweenOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of times the key can be used without rebooting the device.
|
||||||
|
*
|
||||||
|
* @return maximum number of times or {@code null} if there is no restriction.
|
||||||
|
*/
|
||||||
|
public Integer getMaxUsesPerBoot() {
|
||||||
|
return mMaxUsesPerBoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the user authenticators which protect access to the key. The key can only be used iff
|
||||||
|
* the user has authenticated to at least one of these user authenticators.
|
||||||
|
*
|
||||||
|
* @return user authenticators or empty set if the key can be used without user authentication.
|
||||||
|
*/
|
||||||
|
public Set<Integer> getUserAuthenticators() {
|
||||||
|
return new HashSet<Integer>(mUserAuthenticators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the TEE-backed user authenticators which protect access to the key. This is a subset of
|
||||||
|
* the user authentications returned by {@link #getUserAuthenticators()}.
|
||||||
|
*/
|
||||||
|
public Set<Integer> getTeeBackedUserAuthenticators() {
|
||||||
|
return new HashSet<Integer>(mTeeBackedUserAuthenticators);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the duration of time (seconds) for which the key can be used after the user
|
||||||
|
* successfully authenticates to one of the associated user authenticators.
|
||||||
|
*
|
||||||
|
* @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
|
||||||
|
* is required for every use of the key.
|
||||||
|
*/
|
||||||
|
public Integer getUserAuthenticationValidityDurationSeconds() {
|
||||||
|
return mUserAuthenticationValidityDurationSeconds;
|
||||||
|
}
|
||||||
|
}
|
140
keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
Normal file
140
keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package android.security;
|
||||||
|
|
||||||
|
import android.security.keymaster.KeyCharacteristics;
|
||||||
|
import android.security.keymaster.KeymasterDefs;
|
||||||
|
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.spec.InvalidKeySpecException;
|
||||||
|
import java.security.spec.KeySpec;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.SecretKeyFactorySpi;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SecretKeyFactorySpi} backed by Android KeyStore.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||||
|
|
||||||
|
private final KeyStore mKeyStore = KeyStore.getInstance();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected KeySpec engineGetKeySpec(SecretKey key,
|
||||||
|
@SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
|
||||||
|
if (keySpecClass == null) {
|
||||||
|
throw new InvalidKeySpecException("keySpecClass == null");
|
||||||
|
}
|
||||||
|
if (!(key instanceof KeyStoreSecretKey)) {
|
||||||
|
throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
|
||||||
|
((key != null) ? key.getClass().getName() : "null"));
|
||||||
|
}
|
||||||
|
if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
|
||||||
|
throw new InvalidKeySpecException(
|
||||||
|
"Key material export of Android KeyStore keys is not supported");
|
||||||
|
}
|
||||||
|
if (!KeyStoreKeySpec.class.equals(keySpecClass)) {
|
||||||
|
throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
|
||||||
|
}
|
||||||
|
String keyAliasInKeystore = ((KeyStoreSecretKey) key).getAlias();
|
||||||
|
String entryAlias;
|
||||||
|
if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
|
||||||
|
entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
|
||||||
|
} else {
|
||||||
|
throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
|
||||||
|
int errorCode =
|
||||||
|
mKeyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
|
||||||
|
if (errorCode != KeyStore.NO_ERROR) {
|
||||||
|
throw new InvalidKeySpecException("Failed to obtain information about key."
|
||||||
|
+ " Keystore error: " + errorCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@KeyStoreKeyCharacteristics.OriginEnum Integer origin;
|
||||||
|
int keySize;
|
||||||
|
@KeyStoreKeyConstraints.PurposeEnum int purposes;
|
||||||
|
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
|
||||||
|
@KeyStoreKeyConstraints.PaddingEnum Integer padding;
|
||||||
|
@KeyStoreKeyConstraints.DigestEnum Integer digest;
|
||||||
|
@KeyStoreKeyConstraints.BlockModeEnum Integer blockMode;
|
||||||
|
try {
|
||||||
|
origin = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ORIGIN);
|
||||||
|
if (origin == null) {
|
||||||
|
throw new InvalidKeySpecException("Key origin not available");
|
||||||
|
}
|
||||||
|
origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(origin);
|
||||||
|
Integer keySizeInteger =
|
||||||
|
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
|
||||||
|
if (keySizeInteger == null) {
|
||||||
|
throw new InvalidKeySpecException("Key size not available");
|
||||||
|
}
|
||||||
|
keySize = keySizeInteger;
|
||||||
|
purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
|
||||||
|
KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
|
||||||
|
Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
|
||||||
|
if (alg == null) {
|
||||||
|
throw new InvalidKeySpecException("Key algorithm not available");
|
||||||
|
}
|
||||||
|
algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
|
||||||
|
padding = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING);
|
||||||
|
if (padding != null) {
|
||||||
|
padding = KeyStoreKeyConstraints.Padding.fromKeymaster(padding);
|
||||||
|
}
|
||||||
|
digest = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST);
|
||||||
|
if (digest != null) {
|
||||||
|
digest = KeyStoreKeyConstraints.Digest.fromKeymaster(digest);
|
||||||
|
}
|
||||||
|
blockMode = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE);
|
||||||
|
if (blockMode != null) {
|
||||||
|
blockMode = KeyStoreKeyConstraints.BlockMode.fromKeymaster(blockMode);
|
||||||
|
}
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
throw new InvalidKeySpecException("Unsupported key characteristic", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Read user authentication IDs once the Keymaster API has stabilized
|
||||||
|
Set<Integer> userAuthenticators = Collections.emptySet();
|
||||||
|
Set<Integer> teeBackedUserAuthenticators = Collections.emptySet();
|
||||||
|
// Set<Integer> userAuthenticators = new HashSet<Integer>(
|
||||||
|
// getInts(keyCharacteristics, KeymasterDefs.KM_TAG_USER_AUTH_ID));
|
||||||
|
// Set<Integer> teeBackedUserAuthenticators = new HashSet<Integer>(
|
||||||
|
// keyCharacteristics.hwEnforced.getInts(KeymasterDefs.KM_TAG_USER_AUTH_ID));
|
||||||
|
|
||||||
|
return new KeyStoreKeySpec(entryAlias,
|
||||||
|
origin,
|
||||||
|
keySize,
|
||||||
|
KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME),
|
||||||
|
KeymasterUtils.getDate(keyCharacteristics,
|
||||||
|
KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME),
|
||||||
|
KeymasterUtils.getDate(keyCharacteristics,
|
||||||
|
KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME),
|
||||||
|
purposes,
|
||||||
|
algorithm,
|
||||||
|
padding,
|
||||||
|
digest,
|
||||||
|
blockMode,
|
||||||
|
KeymasterUtils.getInt(keyCharacteristics,
|
||||||
|
KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS),
|
||||||
|
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT),
|
||||||
|
userAuthenticators,
|
||||||
|
teeBackedUserAuthenticators,
|
||||||
|
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Key import into Android KeyStore is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Key import into Android KeyStore is not supported");
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,12 @@
|
|||||||
package android.security;
|
package android.security;
|
||||||
|
|
||||||
|
import android.security.keymaster.KeyCharacteristics;
|
||||||
import android.security.keymaster.KeymasterDefs;
|
import android.security.keymaster.KeymasterDefs;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@ -20,4 +25,37 @@ public abstract class KeymasterUtils {
|
|||||||
KeymasterDefs.getErrorMessage(keymasterErrorCode));
|
KeymasterDefs.getErrorMessage(keymasterErrorCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
|
||||||
|
Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
|
||||||
|
if (result == null) {
|
||||||
|
result = keyCharacteristics.swEnforced.getDate(tag, null);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user