Merge "Use JCA names for block modes, paddings, and digests."
This commit is contained in:
@@ -19,6 +19,8 @@ package android.security.keymaster;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -30,10 +32,12 @@ public class KeyCharacteristics implements Parcelable {
|
||||
|
||||
public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new
|
||||
Parcelable.Creator<KeyCharacteristics>() {
|
||||
@Override
|
||||
public KeyCharacteristics createFromParcel(Parcel in) {
|
||||
return new KeyCharacteristics(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyCharacteristics[] newArray(int length) {
|
||||
return new KeyCharacteristics[length];
|
||||
}
|
||||
@@ -50,6 +54,7 @@ public class KeyCharacteristics implements Parcelable {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
swEnforced.writeToParcel(out, flags);
|
||||
hwEnforced.writeToParcel(out, flags);
|
||||
@@ -59,5 +64,53 @@ public class KeyCharacteristics implements Parcelable {
|
||||
swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
|
||||
hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
|
||||
}
|
||||
|
||||
public Integer getInteger(int tag) {
|
||||
if (hwEnforced.containsTag(tag)) {
|
||||
return hwEnforced.getInt(tag, -1);
|
||||
} else if (swEnforced.containsTag(tag)) {
|
||||
return swEnforced.getInt(tag, -1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(int tag, int defaultValue) {
|
||||
Integer result = getInteger(tag);
|
||||
return (result != null) ? result : defaultValue;
|
||||
}
|
||||
|
||||
public List<Integer> getInts(int tag) {
|
||||
List<Integer> result = new ArrayList<Integer>();
|
||||
result.addAll(hwEnforced.getInts(tag));
|
||||
result.addAll(swEnforced.getInts(tag));
|
||||
return result;
|
||||
}
|
||||
|
||||
public Date getDate(int tag) {
|
||||
Date result = hwEnforced.getDate(tag, null);
|
||||
if (result == null) {
|
||||
result = swEnforced.getDate(tag, null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Date getDate(int tag, Date defaultValue) {
|
||||
if (hwEnforced.containsTag(tag)) {
|
||||
return hwEnforced.getDate(tag, null);
|
||||
} else if (hwEnforced.containsTag(tag)) {
|
||||
return swEnforced.getDate(tag, null);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
|
||||
if (keyCharacteristics.hwEnforced.containsTag(tag)) {
|
||||
return keyCharacteristics.hwEnforced.getBoolean(tag, false);
|
||||
} else {
|
||||
return keyCharacteristics.swEnforced.getBoolean(tag, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,12 @@ public class KeymasterArguments implements Parcelable {
|
||||
|
||||
public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
|
||||
Parcelable.Creator<KeymasterArguments>() {
|
||||
@Override
|
||||
public KeymasterArguments createFromParcel(Parcel in) {
|
||||
return new KeymasterArguments(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeymasterArguments[] newArray(int size) {
|
||||
return new KeymasterArguments[size];
|
||||
}
|
||||
@@ -54,6 +57,12 @@ public class KeymasterArguments implements Parcelable {
|
||||
mArguments.add(new KeymasterIntArgument(tag, value));
|
||||
}
|
||||
|
||||
public void addInts(int tag, int... values) {
|
||||
for (int value : values) {
|
||||
addInt(tag, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void addBoolean(int tag) {
|
||||
mArguments.add(new KeymasterBooleanArgument(tag));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package android.security;
|
||||
import com.android.org.conscrypt.OpenSSLEngine;
|
||||
import com.android.org.conscrypt.OpenSSLKeyHolder;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import android.security.keymaster.KeyCharacteristics;
|
||||
import android.security.keymaster.KeymasterArguments;
|
||||
import android.security.keymaster.KeymasterDefs;
|
||||
@@ -46,6 +48,7 @@ import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -112,13 +115,6 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
||||
if (keymasterAlgorithm == -1) {
|
||||
throw new UnrecoverableKeyException("Key algorithm unknown");
|
||||
}
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
|
||||
try {
|
||||
keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(keymasterAlgorithm);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw (UnrecoverableKeyException)
|
||||
new UnrecoverableKeyException("Unsupported key algorithm").initCause(e);
|
||||
}
|
||||
|
||||
int keymasterDigest =
|
||||
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
|
||||
@@ -126,20 +122,11 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
||||
keymasterDigest =
|
||||
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
|
||||
}
|
||||
@KeyStoreKeyConstraints.DigestEnum Integer digest = null;
|
||||
if (keymasterDigest != -1) {
|
||||
try {
|
||||
digest = KeyStoreKeyConstraints.Digest.fromKeymaster(keymasterDigest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw (UnrecoverableKeyException)
|
||||
new UnrecoverableKeyException("Unsupported digest").initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
String keyAlgorithmString;
|
||||
try {
|
||||
keyAlgorithmString = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(
|
||||
keyAlgorithm, digest);
|
||||
keyAlgorithmString = KeymasterUtils.getJcaSecretKeyAlgorithm(
|
||||
keymasterAlgorithm, keymasterDigest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw (UnrecoverableKeyException)
|
||||
new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
|
||||
@@ -456,90 +443,92 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
||||
}
|
||||
|
||||
String keyAlgorithmString = key.getAlgorithm();
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
|
||||
@KeyStoreKeyConstraints.DigestEnum Integer digest;
|
||||
int keymasterAlgorithm;
|
||||
int keymasterDigest;
|
||||
try {
|
||||
keyAlgorithm =
|
||||
KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString);
|
||||
digest = KeyStoreKeyConstraints.Digest.fromJCASecretKeyAlgorithm(keyAlgorithmString);
|
||||
keymasterAlgorithm = KeymasterUtils.getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(
|
||||
keyAlgorithmString);
|
||||
keymasterDigest =
|
||||
KeymasterUtils.getKeymasterDigestfromJcaSecretKeyAlgorithm(keyAlgorithmString);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
|
||||
}
|
||||
|
||||
KeymasterArguments args = new KeymasterArguments();
|
||||
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
|
||||
KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm));
|
||||
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
|
||||
|
||||
@KeyStoreKeyConstraints.DigestEnum int digests;
|
||||
int[] keymasterDigests;
|
||||
if (params.isDigestsSpecified()) {
|
||||
// Digest(s) specified in parameters
|
||||
if (digest != null) {
|
||||
keymasterDigests =
|
||||
KeymasterUtils.getKeymasterDigestsFromJcaDigestAlgorithms(params.getDigests());
|
||||
if (keymasterDigest != -1) {
|
||||
// Digest also specified in the JCA key algorithm name.
|
||||
if ((params.getDigests() & digest) != digest) {
|
||||
if (!com.android.internal.util.ArrayUtils.contains(
|
||||
keymasterDigests, keymasterDigest)) {
|
||||
throw new KeyStoreException("Key digest mismatch"
|
||||
+ ". Key: " + keyAlgorithmString
|
||||
+ ", parameter spec: "
|
||||
+ KeyStoreKeyConstraints.Digest.allToString(params.getDigests()));
|
||||
+ ", parameter spec: " + Arrays.asList(params.getDigests()));
|
||||
}
|
||||
}
|
||||
digests = params.getDigests();
|
||||
} else {
|
||||
// No digest specified in parameters
|
||||
if (digest != null) {
|
||||
if (keymasterDigest != -1) {
|
||||
// Digest specified in the JCA key algorithm name.
|
||||
digests = digest;
|
||||
keymasterDigests = new int[] {keymasterDigest};
|
||||
} else {
|
||||
digests = 0;
|
||||
keymasterDigests = EmptyArray.INT;
|
||||
}
|
||||
}
|
||||
for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest);
|
||||
}
|
||||
if (digests != 0) {
|
||||
args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
|
||||
if (keymasterDigests.length > 0) {
|
||||
// TODO: Remove MAC length constraint once Keymaster API no longer requires it.
|
||||
// This code will blow up if mode than one digest is specified.
|
||||
Integer digestOutputSizeBytes =
|
||||
KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
|
||||
if (digestOutputSizeBytes != null) {
|
||||
int digestOutputSizeBytes =
|
||||
KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]);
|
||||
if (digestOutputSizeBytes != -1) {
|
||||
// TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
|
||||
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
|
||||
}
|
||||
}
|
||||
if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
|
||||
if (digests == 0) {
|
||||
if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
|
||||
if (keymasterDigests.length == 0) {
|
||||
throw new KeyStoreException("At least one digest algorithm must be specified"
|
||||
+ " for key algorithm " + keyAlgorithmString);
|
||||
}
|
||||
}
|
||||
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes();
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes();
|
||||
if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes();
|
||||
int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
|
||||
params.getBlockModes());
|
||||
if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
|
||||
&& (params.isRandomizedEncryptionRequired())) {
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
|
||||
blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
|
||||
if (incompatibleBlockModes != 0) {
|
||||
throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be"
|
||||
+ " violated by block mode(s): "
|
||||
+ KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
|
||||
+ ". See KeyStoreParameter documentation.");
|
||||
for (int keymasterBlockMode : keymasterBlockModes) {
|
||||
if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
|
||||
throw new KeyStoreException(
|
||||
"Randomized encryption (IND-CPA) required but may be violated by block"
|
||||
+ " mode: "
|
||||
+ KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
|
||||
keymasterBlockMode)
|
||||
+ ". See KeyStoreParameter documentation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
|
||||
for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
|
||||
}
|
||||
for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
|
||||
}
|
||||
for (int keymasterPadding :
|
||||
KeyStoreKeyConstraints.Padding.allToKeymaster(params.getPaddings())) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
|
||||
}
|
||||
args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
|
||||
int[] keymasterPaddings = ArrayUtils.concat(
|
||||
KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
|
||||
params.getEncryptionPaddings()),
|
||||
KeymasterUtils.getKeymasterPaddingsFromJcaSignaturePaddings(
|
||||
params.getSignaturePaddings()));
|
||||
args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
|
||||
if (params.getUserAuthenticators() == 0) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
||||
} else {
|
||||
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
|
||||
KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
|
||||
KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
|
||||
params.getUserAuthenticators()));
|
||||
}
|
||||
if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
|
||||
@@ -559,7 +548,7 @@ public class AndroidKeyStore extends KeyStoreSpi {
|
||||
// TODO: Remove this once keymaster does not require us to specify the size of imported key.
|
||||
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
|
||||
|
||||
if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
|
||||
if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
|
||||
&& (!params.isRandomizedEncryptionRequired())) {
|
||||
// Permit caller-provided IV when encrypting with this key
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
|
||||
|
||||
62
keystore/java/android/security/ArrayUtils.java
Normal file
62
keystore/java/android/security/ArrayUtils.java
Normal file
@@ -0,0 +1,62 @@
|
||||
package android.security;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
abstract class ArrayUtils {
|
||||
private ArrayUtils() {}
|
||||
|
||||
public static String[] nullToEmpty(String[] array) {
|
||||
return (array != null) ? array : EmptyArray.STRING;
|
||||
}
|
||||
|
||||
public static String[] cloneIfNotEmpty(String[] array) {
|
||||
return ((array != null) && (array.length > 0)) ? array.clone() : array;
|
||||
}
|
||||
|
||||
public static byte[] concat(byte[] arr1, byte[] arr2) {
|
||||
return concat(arr1, 0, (arr1 != null) ? arr1.length : 0,
|
||||
arr2, 0, (arr2 != null) ? arr2.length : 0);
|
||||
}
|
||||
|
||||
public static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
|
||||
int len2) {
|
||||
if (len1 == 0) {
|
||||
return subarray(arr2, offset2, len2);
|
||||
} else if (len2 == 0) {
|
||||
return subarray(arr1, offset1, len1);
|
||||
} else {
|
||||
byte[] result = new byte[len1 + len2];
|
||||
System.arraycopy(arr1, offset1, result, 0, len1);
|
||||
System.arraycopy(arr2, offset2, result, len1, len2);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] subarray(byte[] arr, int offset, int len) {
|
||||
if (len == 0) {
|
||||
return EmptyArray.BYTE;
|
||||
}
|
||||
if ((offset == 0) && (len == arr.length)) {
|
||||
return arr;
|
||||
}
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(arr, offset, result, 0, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] concat(int[] arr1, int[] arr2) {
|
||||
if ((arr1 == null) || (arr1.length == 0)) {
|
||||
return arr2;
|
||||
} else if ((arr2 == null) || (arr2.length == 0)) {
|
||||
return arr1;
|
||||
} else {
|
||||
int[] result = new int[arr1.length + arr2.length];
|
||||
System.arraycopy(arr1, 0, result, 0, arr1.length);
|
||||
System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,11 +49,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
private final Date mKeyValidityStart;
|
||||
private final Date mKeyValidityForOriginationEnd;
|
||||
private final Date mKeyValidityForConsumptionEnd;
|
||||
private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||
private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
|
||||
private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
private final String[] mEncryptionPaddings;
|
||||
private final String[] mBlockModes;
|
||||
private final boolean mRandomizedEncryptionRequired;
|
||||
private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
|
||||
private KeyGeneratorSpec(
|
||||
@@ -64,11 +64,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
Date keyValidityStart,
|
||||
Date keyValidityForOriginationEnd,
|
||||
Date keyValidityForConsumptionEnd,
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes,
|
||||
@KeyStoreKeyConstraints.PaddingEnum int paddings,
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes,
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes,
|
||||
String[] encryptionPaddings,
|
||||
String[] blockModes,
|
||||
boolean randomizedEncryptionRequired,
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("context == null");
|
||||
@@ -88,8 +88,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
|
||||
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
|
||||
mPurposes = purposes;
|
||||
mPaddings = paddings;
|
||||
mBlockModes = blockModes;
|
||||
mEncryptionPaddings =
|
||||
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
|
||||
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
|
||||
@@ -154,22 +155,22 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
/**
|
||||
* Gets the set of purposes for which the key can be used.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
|
||||
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of padding schemes to which the key is restricted.
|
||||
* Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
|
||||
return mPaddings;
|
||||
public String[] getEncryptionPaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of block modes to which the key is restricted.
|
||||
* Gets the set of block modes with which the key can be used.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
|
||||
return mBlockModes;
|
||||
public String[] getBlockModes() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,7 +192,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* @return user authenticators or {@code 0} if the key can be used without user authentication.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
return mUserAuthenticators;
|
||||
}
|
||||
|
||||
@@ -221,11 +222,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
private Date mKeyValidityStart;
|
||||
private Date mKeyValidityForOriginationEnd;
|
||||
private Date mKeyValidityForConsumptionEnd;
|
||||
private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||
private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
|
||||
private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
private String[] mEncryptionPaddings;
|
||||
private String[] mBlockModes;
|
||||
private boolean mRandomizedEncryptionRequired = true;
|
||||
private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private int mUserAuthenticationValidityDurationSeconds = -1;
|
||||
|
||||
/**
|
||||
@@ -332,34 +333,35 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only for the provided set of purposes.
|
||||
* Sets the set of purposes for which the key can be used.
|
||||
*
|
||||
* <p>This restriction must be specified. There is no default.
|
||||
* <p>This must be specified for all keys. There is no default.
|
||||
*/
|
||||
public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
|
||||
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided padding schemes. Attempts to use
|
||||
* the key with any other padding will be rejected.
|
||||
* Sets the set of padding schemes with which the key can be used when
|
||||
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for keys which are used for encryption/decryption.
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*/
|
||||
public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
|
||||
mPaddings = paddings;
|
||||
public Builder setEncryptionPaddings(String... paddings) {
|
||||
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided block modes. Attempts to use the
|
||||
* key with any other block modes will be rejected.
|
||||
* Sets the set of block modes with which the key can be used when encrypting/decrypting.
|
||||
* Attempts to use the key with any other block modes will be rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for keys which are used for encryption/decryption.
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*/
|
||||
public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
|
||||
mBlockModes = blockModes;
|
||||
public Builder setBlockModes(String... blockModes) {
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -412,7 +414,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
* @see #setUserAuthenticationValidityDurationSeconds(int)
|
||||
*/
|
||||
public Builder setUserAuthenticators(
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
return this;
|
||||
}
|
||||
@@ -447,7 +449,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
mKeyValidityForOriginationEnd,
|
||||
mKeyValidityForConsumptionEnd,
|
||||
mPurposes,
|
||||
mPaddings,
|
||||
mEncryptionPaddings,
|
||||
mBlockModes,
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticators,
|
||||
|
||||
@@ -78,17 +78,19 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
|
||||
private final Date mKeyValidityForConsumptionEnd;
|
||||
|
||||
private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||
private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
|
||||
private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
|
||||
private final String[] mDigests;
|
||||
|
||||
private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
|
||||
private final String[] mEncryptionPaddings;
|
||||
|
||||
private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private final String[] mSignaturePaddings;
|
||||
|
||||
private final String[] mBlockModes;
|
||||
|
||||
private final boolean mRandomizedEncryptionRequired;
|
||||
|
||||
private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
|
||||
@@ -130,12 +132,13 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
Date keyValidityStart,
|
||||
Date keyValidityForOriginationEnd,
|
||||
Date keyValidityForConsumptionEnd,
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes,
|
||||
@KeyStoreKeyConstraints.DigestEnum int digests,
|
||||
@KeyStoreKeyConstraints.PaddingEnum int paddings,
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes,
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes,
|
||||
String[] digests,
|
||||
String[] encryptionPaddings,
|
||||
String[] signaturePaddings,
|
||||
String[] blockModes,
|
||||
boolean randomizedEncryptionRequired,
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
if (context == null) {
|
||||
throw new IllegalArgumentException("context == null");
|
||||
@@ -171,9 +174,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
|
||||
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
|
||||
mPurposes = purposes;
|
||||
mDigests = digests;
|
||||
mPaddings = paddings;
|
||||
mBlockModes = blockModes;
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
|
||||
mEncryptionPaddings =
|
||||
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
|
||||
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
|
||||
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
|
||||
@@ -199,13 +204,15 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
startDate,
|
||||
endDate,
|
||||
endDate,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
true,
|
||||
0,
|
||||
-1);
|
||||
0, // purposes
|
||||
null, // digests
|
||||
null, // encryption paddings
|
||||
null, // signature paddings
|
||||
null, // block modes
|
||||
false, // randomized encryption required
|
||||
0, // user authenticators
|
||||
-1 // user authentication validity duration (seconds)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,35 +340,44 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
|
||||
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of digests to which the key is restricted.
|
||||
* Gets the set of digest algorithms with which the key can be used.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
|
||||
return mDigests;
|
||||
public String[] getDigests() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mDigests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of padding schemes to which the key is restricted.
|
||||
* Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
|
||||
return mPaddings;
|
||||
public String[] getEncryptionPaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of block modes to which the key is restricted.
|
||||
* Gets the set of padding schemes with which the key can be used when signing/verifying.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
|
||||
return mBlockModes;
|
||||
public String[] getSignaturePaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of block modes with which the key can be used.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public String[] getBlockModes() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,7 +406,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
return mUserAuthenticators;
|
||||
}
|
||||
|
||||
@@ -458,17 +474,19 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
|
||||
private Date mKeyValidityForConsumptionEnd;
|
||||
|
||||
private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||
private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
|
||||
private @KeyStoreKeyConstraints.DigestEnum int mDigests;
|
||||
private String[] mDigests;
|
||||
|
||||
private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
|
||||
private String[] mEncryptionPaddings;
|
||||
|
||||
private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private String[] mSignaturePaddings;
|
||||
|
||||
private String[] mBlockModes;
|
||||
|
||||
private boolean mRandomizedEncryptionRequired = true;
|
||||
|
||||
private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
|
||||
private int mUserAuthenticationValidityDurationSeconds = -1;
|
||||
|
||||
@@ -658,53 +676,68 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only for the provided set of purposes.
|
||||
* Sets the set of purposes for which the key can be used.
|
||||
*
|
||||
* <p>This restriction must be specified. There is no default.
|
||||
* <p>This must be specified for all keys. There is no default.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
|
||||
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided digests. Attempts to use the key
|
||||
* with any other digests be rejected.
|
||||
* Sets the set of digests with which the key can be used when signing/verifying. Attempts
|
||||
* to use the key with any other digest will be rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for keys which are used for signing/verification.
|
||||
* <p>This must be specified for keys which are used for signing/verification.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
|
||||
mDigests = digests;
|
||||
public Builder setDigests(String... digests) {
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided padding schemes. Attempts to use
|
||||
* the key with any other padding will be rejected.
|
||||
* Sets the set of padding schemes with which the key can be used when
|
||||
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for keys which are used for encryption/decryption.
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
|
||||
mPaddings = paddings;
|
||||
public Builder setEncryptionPaddings(String... paddings) {
|
||||
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided block mode when encrypting or
|
||||
* decrypting. Attempts to use the key with any other block modes will be rejected.
|
||||
* Sets the set of padding schemes with which the key can be used when
|
||||
* signing/verifying. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for keys which are used for encryption/decryption.
|
||||
* <p>This must be specified for RSA keys which are used for signing/verification.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
|
||||
mBlockModes = blockModes;
|
||||
public Builder setSignaturePaddings(String... paddings) {
|
||||
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of block modes with which the key can be used when encrypting/decrypting.
|
||||
* Attempts to use the key with any other block modes will be rejected.
|
||||
*
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setBlockModes(String... blockModes) {
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -752,7 +785,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
* @hide
|
||||
*/
|
||||
public Builder setUserAuthenticators(
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
return this;
|
||||
}
|
||||
@@ -800,7 +833,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
|
||||
mKeyValidityForConsumptionEnd,
|
||||
mPurposes,
|
||||
mDigests,
|
||||
mPaddings,
|
||||
mEncryptionPaddings,
|
||||
mSignaturePaddings,
|
||||
mBlockModes,
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticators,
|
||||
|
||||
@@ -48,68 +48,67 @@ import javax.crypto.spec.IvParameterSpec;
|
||||
public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
|
||||
|
||||
public abstract static class AES extends KeyStoreCipherSpi {
|
||||
protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
|
||||
@KeyStoreKeyConstraints.PaddingEnum int padding, boolean ivUsed) {
|
||||
super(KeyStoreKeyConstraints.Algorithm.AES,
|
||||
blockMode,
|
||||
padding,
|
||||
protected AES(int keymasterBlockMode, int keymasterPadding, boolean ivUsed) {
|
||||
super(KeymasterDefs.KM_ALGORITHM_AES,
|
||||
keymasterBlockMode,
|
||||
keymasterPadding,
|
||||
16,
|
||||
ivUsed);
|
||||
}
|
||||
|
||||
public abstract static class ECB extends AES {
|
||||
protected ECB(@KeyStoreKeyConstraints.PaddingEnum int padding) {
|
||||
super(KeyStoreKeyConstraints.BlockMode.ECB, padding, false);
|
||||
protected ECB(int keymasterPadding) {
|
||||
super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
|
||||
}
|
||||
|
||||
public static class NoPadding extends ECB {
|
||||
public NoPadding() {
|
||||
super(KeyStoreKeyConstraints.Padding.NONE);
|
||||
super(KeymasterDefs.KM_PAD_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PKCS7Padding extends ECB {
|
||||
public PKCS7Padding() {
|
||||
super(KeyStoreKeyConstraints.Padding.PKCS7);
|
||||
super(KeymasterDefs.KM_PAD_PKCS7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class CBC extends AES {
|
||||
protected CBC(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
|
||||
super(KeyStoreKeyConstraints.BlockMode.CBC, padding, true);
|
||||
protected CBC(int keymasterPadding) {
|
||||
super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
|
||||
}
|
||||
|
||||
public static class NoPadding extends CBC {
|
||||
public NoPadding() {
|
||||
super(KeyStoreKeyConstraints.Padding.NONE);
|
||||
super(KeymasterDefs.KM_PAD_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PKCS7Padding extends CBC {
|
||||
public PKCS7Padding() {
|
||||
super(KeyStoreKeyConstraints.Padding.PKCS7);
|
||||
super(KeymasterDefs.KM_PAD_PKCS7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class CTR extends AES {
|
||||
protected CTR(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
|
||||
super(KeyStoreKeyConstraints.BlockMode.CTR, padding, true);
|
||||
protected CTR(int keymasterPadding) {
|
||||
super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
|
||||
}
|
||||
|
||||
public static class NoPadding extends CTR {
|
||||
public NoPadding() {
|
||||
super(KeyStoreKeyConstraints.Padding.NONE);
|
||||
super(KeymasterDefs.KM_PAD_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final KeyStore mKeyStore;
|
||||
private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
|
||||
private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode;
|
||||
private final @KeyStoreKeyConstraints.PaddingEnum int mPadding;
|
||||
private final int mKeymasterAlgorithm;
|
||||
private final int mKeymasterBlockMode;
|
||||
private final int mKeymasterPadding;
|
||||
private final int mBlockSizeBytes;
|
||||
|
||||
/** Whether this transformation requires an IV. */
|
||||
@@ -138,15 +137,15 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
|
||||
private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
|
||||
|
||||
protected KeyStoreCipherSpi(
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
|
||||
@KeyStoreKeyConstraints.PaddingEnum int padding,
|
||||
int keymasterAlgorithm,
|
||||
int keymasterBlockMode,
|
||||
int keymasterPadding,
|
||||
int blockSizeBytes,
|
||||
boolean ivUsed) {
|
||||
mKeyStore = KeyStore.getInstance();
|
||||
mAlgorithm = algorithm;
|
||||
mBlockMode = blockMode;
|
||||
mPadding = padding;
|
||||
mKeymasterAlgorithm = keymasterAlgorithm;
|
||||
mKeymasterBlockMode = keymasterBlockMode;
|
||||
mKeymasterPadding = keymasterPadding;
|
||||
mBlockSizeBytes = blockSizeBytes;
|
||||
mIvRequired = ivUsed;
|
||||
}
|
||||
@@ -236,9 +235,9 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
|
||||
}
|
||||
|
||||
KeymasterArguments keymasterInputArgs = new KeymasterArguments();
|
||||
keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm);
|
||||
keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mBlockMode);
|
||||
keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mPadding);
|
||||
keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
|
||||
keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
|
||||
keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
|
||||
addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
|
||||
|
||||
KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
|
||||
|
||||
@@ -19,6 +19,8 @@ package android.security;
|
||||
import android.os.IBinder;
|
||||
import android.security.keymaster.OperationResult;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -95,7 +97,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
||||
// Too much input for one chunk -- extract one max-sized chunk and feed it into the
|
||||
// update operation.
|
||||
inputBytesInChunk = mMaxChunkSize - mBufferedLength;
|
||||
chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
|
||||
chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
|
||||
input, inputOffset, inputBytesInChunk);
|
||||
} else {
|
||||
// All of available input fits into one chunk.
|
||||
@@ -108,7 +110,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
||||
} else {
|
||||
// Need to combine buffered data with input data into one array.
|
||||
inputBytesInChunk = inputLength;
|
||||
chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
|
||||
chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
|
||||
input, inputOffset, inputBytesInChunk);
|
||||
}
|
||||
}
|
||||
@@ -197,7 +199,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
||||
|
||||
// Flush all buffered input and provided input into keystore/keymaster.
|
||||
byte[] output = update(input, inputOffset, inputLength);
|
||||
output = concat(output, flush());
|
||||
output = ArrayUtils.concat(output, flush());
|
||||
|
||||
OperationResult opResult = mKeyStoreStream.finish();
|
||||
if (opResult == null) {
|
||||
@@ -206,7 +208,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
||||
throw KeyStore.getKeyStoreException(opResult.resultCode);
|
||||
}
|
||||
|
||||
return concat(output, opResult.output);
|
||||
return ArrayUtils.concat(output, opResult.output);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,11 +217,11 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
||||
*/
|
||||
public byte[] flush() throws KeyStoreException {
|
||||
if (mBufferedLength <= 0) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
return EmptyArray.BYTE;
|
||||
}
|
||||
|
||||
byte[] chunk = subarray(mBuffered, mBufferedOffset, mBufferedLength);
|
||||
mBuffered = EMPTY_BYTE_ARRAY;
|
||||
byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
|
||||
mBuffered = EmptyArray.BYTE;
|
||||
mBufferedLength = 0;
|
||||
mBufferedOffset = 0;
|
||||
|
||||
@@ -238,46 +240,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
|
||||
+ " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
|
||||
}
|
||||
|
||||
return (opResult.output != null) ? opResult.output : EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
|
||||
private static byte[] concat(byte[] arr1, byte[] arr2) {
|
||||
if ((arr1 == null) || (arr1.length == 0)) {
|
||||
return arr2;
|
||||
} else if ((arr2 == null) || (arr2.length == 0)) {
|
||||
return arr1;
|
||||
} else {
|
||||
byte[] result = new byte[arr1.length + arr2.length];
|
||||
System.arraycopy(arr1, 0, result, 0, arr1.length);
|
||||
System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
|
||||
int len2) {
|
||||
if (len1 == 0) {
|
||||
return subarray(arr2, offset2, len2);
|
||||
} else if (len2 == 0) {
|
||||
return subarray(arr1, offset1, len1);
|
||||
} else {
|
||||
byte[] result = new byte[len1 + len2];
|
||||
System.arraycopy(arr1, offset1, result, 0, len1);
|
||||
System.arraycopy(arr2, offset2, result, len1, len2);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] subarray(byte[] arr, int offset, int len) {
|
||||
if (len == 0) {
|
||||
return EMPTY_BYTE_ARRAY;
|
||||
}
|
||||
if ((offset == 0) && (len == arr.length)) {
|
||||
return arr;
|
||||
}
|
||||
byte[] result = new byte[len];
|
||||
System.arraycopy(arr, offset, result, 0, len);
|
||||
return result;
|
||||
return (opResult.output != null) ? opResult.output : EmptyArray.BYTE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,36 +37,36 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
|
||||
|
||||
public static class HmacSHA1 extends KeyStoreHmacSpi {
|
||||
public HmacSHA1() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA1);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA1);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA224 extends KeyStoreHmacSpi {
|
||||
public HmacSHA224() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA224);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_224);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA256 extends KeyStoreHmacSpi {
|
||||
public HmacSHA256() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA256);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_256);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA384 extends KeyStoreHmacSpi {
|
||||
public HmacSHA384() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA384);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_384);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA512 extends KeyStoreHmacSpi {
|
||||
public HmacSHA512() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA512);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_512);
|
||||
}
|
||||
}
|
||||
|
||||
private final KeyStore mKeyStore = KeyStore.getInstance();
|
||||
private final @KeyStoreKeyConstraints.DigestEnum int mDigest;
|
||||
private final int mKeymasterDigest;
|
||||
private final int mMacSizeBytes;
|
||||
|
||||
private String mKeyAliasInKeyStore;
|
||||
@@ -76,9 +76,9 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
|
||||
private IBinder mOperationToken;
|
||||
private Long mOperationHandle;
|
||||
|
||||
protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest) {
|
||||
mDigest = digest;
|
||||
mMacSizeBytes = KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
|
||||
protected KeyStoreHmacSpi(int keymasterDigest) {
|
||||
mKeymasterDigest = keymasterDigest;
|
||||
mMacSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,8 +129,8 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
|
||||
}
|
||||
|
||||
KeymasterArguments keymasterArgs = new KeymasterArguments();
|
||||
keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.HMAC);
|
||||
keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mDigest);
|
||||
keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
|
||||
keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
|
||||
|
||||
OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
|
||||
KeymasterDefs.KM_PURPOSE_SIGN,
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Characteristics of {@code AndroidKeyStore} keys.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class KeyStoreKeyCharacteristics {
|
||||
private KeyStoreKeyCharacteristics() {}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({Origin.GENERATED, Origin.IMPORTED})
|
||||
public @interface OriginEnum {}
|
||||
|
||||
/**
|
||||
* Origin of the key.
|
||||
*/
|
||||
public static abstract class Origin {
|
||||
private Origin() {}
|
||||
|
||||
/** Key was generated inside AndroidKeyStore. */
|
||||
public static final int GENERATED = 1 << 0;
|
||||
|
||||
/** Key was imported into AndroidKeyStore. */
|
||||
public static final int IMPORTED = 1 << 1;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static @OriginEnum int fromKeymaster(int origin) {
|
||||
switch (origin) {
|
||||
case KeymasterDefs.KM_ORIGIN_HARDWARE:
|
||||
return GENERATED;
|
||||
case KeymasterDefs.KM_ORIGIN_IMPORTED:
|
||||
return IMPORTED;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown origin: " + origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,937 +0,0 @@
|
||||
/*
|
||||
* 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, Algorithm.RSA, Algorithm.EC})
|
||||
public @interface AlgorithmEnum {}
|
||||
|
||||
/**
|
||||
* Key algorithm.
|
||||
*/
|
||||
public static abstract class Algorithm {
|
||||
private Algorithm() {}
|
||||
|
||||
/**
|
||||
* Key algorithm: AES.
|
||||
*/
|
||||
public static final int AES = 1 << 0;
|
||||
|
||||
/**
|
||||
* Key algorithm: HMAC.
|
||||
*/
|
||||
public static final int HMAC = 1 << 1;
|
||||
|
||||
/**
|
||||
* Key algorithm: RSA.
|
||||
*/
|
||||
public static final int RSA = 1 << 2;
|
||||
|
||||
/**
|
||||
* Key algorithm: EC.
|
||||
*/
|
||||
public static final int EC = 1 << 3;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static int toKeymaster(@AlgorithmEnum int algorithm) {
|
||||
switch (algorithm) {
|
||||
case AES:
|
||||
return KeymasterDefs.KM_ALGORITHM_AES;
|
||||
case HMAC:
|
||||
return KeymasterDefs.KM_ALGORITHM_HMAC;
|
||||
case RSA:
|
||||
return KeymasterDefs.KM_ALGORITHM_RSA;
|
||||
case EC:
|
||||
return KeymasterDefs.KM_ALGORITHM_EC;
|
||||
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;
|
||||
case KeymasterDefs.KM_ALGORITHM_RSA:
|
||||
return RSA;
|
||||
case KeymasterDefs.KM_ALGORITHM_EC:
|
||||
return EC;
|
||||
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";
|
||||
case RSA:
|
||||
return "RSA";
|
||||
case EC:
|
||||
return "EC";
|
||||
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.MD5:
|
||||
return "HmacMD5";
|
||||
case Digest.SHA1:
|
||||
return "HmacSHA1";
|
||||
case Digest.SHA224:
|
||||
return "HmacSHA224";
|
||||
case Digest.SHA256:
|
||||
return "HmacSHA256";
|
||||
case Digest.SHA384:
|
||||
return "HmacSHA384";
|
||||
case Digest.SHA512:
|
||||
return "HmacSHA512";
|
||||
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) {
|
||||
case RSA:
|
||||
return "RSA";
|
||||
case EC:
|
||||
return "EC";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported key alorithm: " + algorithm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
Padding.NONE,
|
||||
Padding.PKCS7,
|
||||
Padding.RSA_PKCS1_ENCRYPTION,
|
||||
Padding.RSA_PKCS1_SIGNATURE,
|
||||
Padding.RSA_OAEP,
|
||||
Padding.RSA_PSS,
|
||||
})
|
||||
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;
|
||||
|
||||
/**
|
||||
* RSA PKCS#1 v1.5 padding for encryption/decryption.
|
||||
*/
|
||||
public static final int RSA_PKCS1_ENCRYPTION = 1 << 2;
|
||||
|
||||
/**
|
||||
* RSA PKCS#1 v1.5 padding for signatures.
|
||||
*/
|
||||
public static final int RSA_PKCS1_SIGNATURE = 1 << 3;
|
||||
|
||||
/**
|
||||
* RSA Optimal Asymmetric Encryption Padding (OAEP).
|
||||
*/
|
||||
public static final int RSA_OAEP = 1 << 4;
|
||||
|
||||
/**
|
||||
* RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding.
|
||||
*/
|
||||
public static final int RSA_PSS = 1 << 5;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static int toKeymaster(int padding) {
|
||||
switch (padding) {
|
||||
case NONE:
|
||||
return KeymasterDefs.KM_PAD_NONE;
|
||||
case PKCS7:
|
||||
return KeymasterDefs.KM_PAD_PKCS7;
|
||||
case RSA_PKCS1_ENCRYPTION:
|
||||
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
|
||||
case RSA_PKCS1_SIGNATURE:
|
||||
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
|
||||
case RSA_OAEP:
|
||||
return KeymasterDefs.KM_PAD_RSA_OAEP;
|
||||
case RSA_PSS:
|
||||
return KeymasterDefs.KM_PAD_RSA_PSS;
|
||||
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;
|
||||
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
|
||||
return RSA_PKCS1_ENCRYPTION;
|
||||
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
|
||||
return RSA_PKCS1_SIGNATURE;
|
||||
case KeymasterDefs.KM_PAD_RSA_OAEP:
|
||||
return RSA_OAEP;
|
||||
case KeymasterDefs.KM_PAD_RSA_PSS:
|
||||
return RSA_PSS;
|
||||
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";
|
||||
case RSA_PKCS1_ENCRYPTION:
|
||||
return "RSA PKCS#1 (encryption)";
|
||||
case RSA_PKCS1_SIGNATURE:
|
||||
return "RSA PKCS#1 (signature)";
|
||||
case RSA_OAEP:
|
||||
return "RSA OAEP";
|
||||
case RSA_PSS:
|
||||
return "RSA PSS";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown padding: " + padding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static @PaddingEnum int fromJCACipherPadding(String padding) {
|
||||
String paddingLower = padding.toLowerCase(Locale.US);
|
||||
if ("nopadding".equals(paddingLower)) {
|
||||
return NONE;
|
||||
} else if ("pkcs7padding".equals(paddingLower)) {
|
||||
return PKCS7;
|
||||
} else if ("pkcs1padding".equals(paddingLower)) {
|
||||
return RSA_PKCS1_ENCRYPTION;
|
||||
} else if (("oaeppadding".equals(paddingLower))
|
||||
|| ((paddingLower.startsWith("oaepwith"))
|
||||
&& (paddingLower.endsWith("padding")))) {
|
||||
return RSA_OAEP;
|
||||
} 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;
|
||||
|
||||
/**
|
||||
* Set of block modes compatible with IND-CPA if used correctly.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final @BlockModeEnum int IND_CPA_COMPATIBLE_MODES =
|
||||
CBC | CTR | GCM;
|
||||
|
||||
/**
|
||||
* @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 String allToString(@BlockModeEnum int modes) {
|
||||
StringBuilder result = new StringBuilder("[");
|
||||
boolean firstValue = true;
|
||||
for (@BlockModeEnum int mode : getSetFlags(modes)) {
|
||||
if (firstValue) {
|
||||
firstValue = false;
|
||||
} else {
|
||||
result.append(", ");
|
||||
}
|
||||
result.append(toString(mode));
|
||||
}
|
||||
result.append(']');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -37,68 +37,68 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
|
||||
public static class AES extends KeyStoreKeyGeneratorSpi {
|
||||
public AES() {
|
||||
super(KeyStoreKeyConstraints.Algorithm.AES, 128);
|
||||
super(KeymasterDefs.KM_ALGORITHM_AES, 128);
|
||||
}
|
||||
}
|
||||
|
||||
protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi {
|
||||
protected HmacBase(@KeyStoreKeyConstraints.DigestEnum int digest) {
|
||||
super(KeyStoreKeyConstraints.Algorithm.HMAC,
|
||||
digest,
|
||||
KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest) * 8);
|
||||
protected HmacBase(int keymasterDigest) {
|
||||
super(KeymasterDefs.KM_ALGORITHM_HMAC,
|
||||
keymasterDigest,
|
||||
KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA1 extends HmacBase {
|
||||
public HmacSHA1() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA1);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA1);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA224 extends HmacBase {
|
||||
public HmacSHA224() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA224);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_224);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA256 extends HmacBase {
|
||||
public HmacSHA256() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA256);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_256);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA384 extends HmacBase {
|
||||
public HmacSHA384() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA384);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_384);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HmacSHA512 extends HmacBase {
|
||||
public HmacSHA512() {
|
||||
super(KeyStoreKeyConstraints.Digest.SHA512);
|
||||
super(KeymasterDefs.KM_DIGEST_SHA_2_512);
|
||||
}
|
||||
}
|
||||
|
||||
private final KeyStore mKeyStore = KeyStore.getInstance();
|
||||
private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
|
||||
private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
|
||||
private final int mKeymasterAlgorithm;
|
||||
private final int mKeymasterDigest;
|
||||
private final int mDefaultKeySizeBits;
|
||||
|
||||
private KeyGeneratorSpec mSpec;
|
||||
private SecureRandom mRng;
|
||||
|
||||
protected KeyStoreKeyGeneratorSpi(
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
|
||||
int keymasterAlgorithm,
|
||||
int defaultKeySizeBits) {
|
||||
this(algorithm, null, defaultKeySizeBits);
|
||||
this(keymasterAlgorithm, -1, defaultKeySizeBits);
|
||||
}
|
||||
|
||||
protected KeyStoreKeyGeneratorSpi(
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
|
||||
@KeyStoreKeyConstraints.DigestEnum Integer digest,
|
||||
int keymasterAlgorithm,
|
||||
int keymasterDigest,
|
||||
int defaultKeySizeBits) {
|
||||
mAlgorithm = algorithm;
|
||||
mDigest = digest;
|
||||
mKeymasterAlgorithm = keymasterAlgorithm;
|
||||
mKeymasterDigest = keymasterDigest;
|
||||
mDefaultKeySizeBits = defaultKeySizeBits;
|
||||
}
|
||||
|
||||
@@ -117,58 +117,55 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
}
|
||||
|
||||
KeymasterArguments args = new KeymasterArguments();
|
||||
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
|
||||
KeyStoreKeyConstraints.Algorithm.toKeymaster(mAlgorithm));
|
||||
if (mDigest != null) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_DIGEST,
|
||||
KeyStoreKeyConstraints.Digest.toKeymaster(mDigest));
|
||||
Integer digestOutputSizeBytes =
|
||||
KeyStoreKeyConstraints.Digest.getOutputSizeBytes(mDigest);
|
||||
if (digestOutputSizeBytes != null) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
|
||||
if (mKeymasterDigest != -1) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
|
||||
int digestOutputSizeBytes =
|
||||
KeymasterUtils.getDigestOutputSizeBytes(mKeymasterDigest);
|
||||
if (digestOutputSizeBytes != -1) {
|
||||
// TODO: Remove MAC length constraint once Keymaster API no longer requires it.
|
||||
// TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
|
||||
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
|
||||
}
|
||||
}
|
||||
if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
|
||||
if (mDigest == null) {
|
||||
throw new IllegalStateException("Digest algorithm must be specified for key"
|
||||
+ " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
|
||||
if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
|
||||
if (mKeymasterDigest == -1) {
|
||||
throw new IllegalStateException("Digest algorithm must be specified for HMAC key");
|
||||
}
|
||||
}
|
||||
int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
|
||||
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes = spec.getPurposes();
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes = spec.getBlockModes();
|
||||
if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes();
|
||||
int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
|
||||
spec.getBlockModes());
|
||||
if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
|
||||
&& (spec.isRandomizedEncryptionRequired())) {
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
|
||||
blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
|
||||
if (incompatibleBlockModes != 0) {
|
||||
throw new IllegalStateException(
|
||||
"Randomized encryption (IND-CPA) required but may be violated by block"
|
||||
+ " mode(s): "
|
||||
+ KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
|
||||
+ ". See KeyGeneratorSpec documentation.");
|
||||
for (int keymasterBlockMode : keymasterBlockModes) {
|
||||
if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
|
||||
throw new IllegalStateException(
|
||||
"Randomized encryption (IND-CPA) required but may be violated by block"
|
||||
+ " mode: "
|
||||
+ KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
|
||||
keymasterBlockMode)
|
||||
+ ". See KeyGeneratorSpec documentation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int keymasterPurpose :
|
||||
KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
|
||||
KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
|
||||
}
|
||||
for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
|
||||
}
|
||||
for (int keymasterPadding :
|
||||
KeyStoreKeyConstraints.Padding.allToKeymaster(spec.getPaddings())) {
|
||||
args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
|
||||
}
|
||||
args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
|
||||
args.addInts(
|
||||
KeymasterDefs.KM_TAG_PADDING,
|
||||
KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
|
||||
spec.getEncryptionPaddings()));
|
||||
if (spec.getUserAuthenticators() == 0) {
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
|
||||
} else {
|
||||
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
|
||||
KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
|
||||
KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
|
||||
spec.getUserAuthenticators()));
|
||||
}
|
||||
if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
|
||||
@@ -185,7 +182,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
(spec.getKeyValidityForConsumptionEnd() != null)
|
||||
? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
|
||||
|
||||
if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
|
||||
if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
|
||||
&& (!spec.isRandomizedEncryptionRequired())) {
|
||||
// Permit caller-provided IV when encrypting with this key
|
||||
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
|
||||
@@ -206,7 +203,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
|
||||
throw KeyStore.getCryptoOperationException(errorCode);
|
||||
}
|
||||
String keyAlgorithmJCA =
|
||||
KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
|
||||
KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
|
||||
return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
|
||||
}
|
||||
|
||||
|
||||
274
keystore/java/android/security/KeyStoreKeyProperties.java
Normal file
274
keystore/java/android/security/KeyStoreKeyProperties.java
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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 libcore.util.EmptyArray;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Properties of {@code AndroidKeyStore} keys.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class KeyStoreKeyProperties {
|
||||
private KeyStoreKeyProperties() {}
|
||||
|
||||
@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(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({Origin.GENERATED, Origin.IMPORTED})
|
||||
public @interface OriginEnum {}
|
||||
|
||||
/**
|
||||
* Origin of the key.
|
||||
*/
|
||||
public static abstract class Origin {
|
||||
private Origin() {}
|
||||
|
||||
/** Key was generated inside AndroidKeyStore. */
|
||||
public static final int GENERATED = 1 << 0;
|
||||
|
||||
/** Key was imported into AndroidKeyStore. */
|
||||
public static final int IMPORTED = 1 << 1;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static @OriginEnum int fromKeymaster(int origin) {
|
||||
switch (origin) {
|
||||
case KeymasterDefs.KM_ORIGIN_HARDWARE:
|
||||
return GENERATED;
|
||||
case KeymasterDefs.KM_ORIGIN_IMPORTED:
|
||||
return IMPORTED;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown origin: " + origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] getSetFlags(int flags) {
|
||||
if (flags == 0) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -29,17 +29,17 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
private final String mKeystoreAlias;
|
||||
private final int mKeySize;
|
||||
private final boolean mTeeBacked;
|
||||
private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
|
||||
private final @KeyStoreKeyProperties.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 int mPaddings;
|
||||
private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
|
||||
private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
|
||||
private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
private final String[] mEncryptionPaddings;
|
||||
private final String[] mSignaturePaddings;
|
||||
private final String[] mDigests;
|
||||
private final String[] mBlockModes;
|
||||
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
|
||||
|
||||
@@ -48,18 +48,18 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
*/
|
||||
KeyStoreKeySpec(String keystoreKeyAlias,
|
||||
boolean teeBacked,
|
||||
@KeyStoreKeyCharacteristics.OriginEnum int origin,
|
||||
@KeyStoreKeyProperties.OriginEnum int origin,
|
||||
int keySize,
|
||||
Date keyValidityStart,
|
||||
Date keyValidityForOriginationEnd,
|
||||
Date keyValidityForConsumptionEnd,
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes,
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
|
||||
@KeyStoreKeyConstraints.PaddingEnum int paddings,
|
||||
@KeyStoreKeyConstraints.DigestEnum int digests,
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes,
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes,
|
||||
String[] encryptionPaddings,
|
||||
String[] signaturePaddings,
|
||||
String[] digests,
|
||||
String[] blockModes,
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
mKeystoreAlias = keystoreKeyAlias;
|
||||
mTeeBacked = teeBacked;
|
||||
@@ -69,10 +69,12 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
|
||||
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
|
||||
mPurposes = purposes;
|
||||
mAlgorithm = algorithm;
|
||||
mPaddings = paddings;
|
||||
mDigests = digests;
|
||||
mBlockModes = blockModes;
|
||||
mEncryptionPaddings =
|
||||
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
|
||||
mSignaturePaddings =
|
||||
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
|
||||
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
|
||||
@@ -96,7 +98,7 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
/**
|
||||
* Gets the origin of the key.
|
||||
*/
|
||||
public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
|
||||
public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
@@ -137,36 +139,36 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
/**
|
||||
* Gets the set of purposes for which the key can be used.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
|
||||
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the algorithm of the key.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
|
||||
return mAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of block modes with which the key can be used.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
|
||||
return mBlockModes;
|
||||
public String[] getBlockModes() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of padding modes with which the key can be used.
|
||||
* Gets the set of padding modes with which the key can be used when encrypting/decrypting.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
|
||||
return mPaddings;
|
||||
public String[] getEncryptionPaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of padding modes with which the key can be used when signing/verifying.
|
||||
*/
|
||||
public String[] getSignaturePaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of digest algorithms with which the key can be used.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
|
||||
return mDigests;
|
||||
public String[] getDigests() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mDigests);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +177,7 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
*
|
||||
* @return user authenticators or {@code 0} if the key can be used without user authentication.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
return mUserAuthenticators;
|
||||
}
|
||||
|
||||
@@ -184,7 +186,7 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
* key. This is a subset of the user authentications returned by
|
||||
* {@link #getUserAuthenticators()}.
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
|
||||
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
|
||||
return mTeeEnforcedUserAuthenticators;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,24 +43,26 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
private final Date mKeyValidityStart;
|
||||
private final Date mKeyValidityForOriginationEnd;
|
||||
private final Date mKeyValidityForConsumptionEnd;
|
||||
private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||
private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
|
||||
private final @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
|
||||
private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
private final String[] mEncryptionPaddings;
|
||||
private final String[] mSignaturePaddings;
|
||||
private final String[] mDigests;
|
||||
private final String[] mBlockModes;
|
||||
private final boolean mRandomizedEncryptionRequired;
|
||||
private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
|
||||
private KeyStoreParameter(int flags,
|
||||
Date keyValidityStart,
|
||||
Date keyValidityForOriginationEnd,
|
||||
Date keyValidityForConsumptionEnd,
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes,
|
||||
@KeyStoreKeyConstraints.PaddingEnum int paddings,
|
||||
@KeyStoreKeyConstraints.DigestEnum Integer digests,
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes,
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes,
|
||||
String[] encryptionPaddings,
|
||||
String[] signaturePaddings,
|
||||
String[] digests,
|
||||
String[] blockModes,
|
||||
boolean randomizedEncryptionRequired,
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
if ((userAuthenticationValidityDurationSeconds < 0)
|
||||
&& (userAuthenticationValidityDurationSeconds != -1)) {
|
||||
@@ -73,9 +75,12 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
|
||||
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
|
||||
mPurposes = purposes;
|
||||
mPaddings = paddings;
|
||||
mDigests = digests;
|
||||
mBlockModes = blockModes;
|
||||
mEncryptionPaddings =
|
||||
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
|
||||
mSignaturePaddings =
|
||||
ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
|
||||
mRandomizedEncryptionRequired = randomizedEncryptionRequired;
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
|
||||
@@ -133,37 +138,48 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
|
||||
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of padding schemes to which the key is restricted.
|
||||
* Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
|
||||
return mPaddings;
|
||||
public String[] getEncryptionPaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of digests to which the key is restricted.
|
||||
* Gets the set of padding schemes with which the key can be used when signing or verifying
|
||||
* signatures.
|
||||
*
|
||||
* @throws IllegalStateException if this restriction has not been specified.
|
||||
* @hide
|
||||
*/
|
||||
public String[] getSignaturePaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of digest algorithms with which the key can be used.
|
||||
*
|
||||
* @throws IllegalStateException if this set has not been specified.
|
||||
*
|
||||
* @see #isDigestsSpecified()
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
|
||||
public String[] getDigests() {
|
||||
if (mDigests == null) {
|
||||
throw new IllegalStateException("Digests not specified");
|
||||
}
|
||||
return mDigests;
|
||||
return ArrayUtils.cloneIfNotEmpty(mDigests);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if digest restrictions have been specified.
|
||||
* Returns {@code true} if the set of digest algorithms with which the key can be used has been
|
||||
* specified.
|
||||
*
|
||||
* @see #getDigests()
|
||||
*
|
||||
@@ -174,12 +190,12 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of block modes to which the key is restricted.
|
||||
* Gets the set of block modes with which the key can be used.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
|
||||
return mBlockModes;
|
||||
public String[] getBlockModes() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,7 +221,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
|
||||
return mUserAuthenticators;
|
||||
}
|
||||
|
||||
@@ -244,12 +260,13 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
private Date mKeyValidityStart;
|
||||
private Date mKeyValidityForOriginationEnd;
|
||||
private Date mKeyValidityForConsumptionEnd;
|
||||
private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
|
||||
private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
|
||||
private @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
|
||||
private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
|
||||
private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
private String[] mEncryptionPaddings;
|
||||
private String[] mSignaturePaddings;
|
||||
private String[] mDigests;
|
||||
private String[] mBlockModes;
|
||||
private boolean mRandomizedEncryptionRequired = true;
|
||||
private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
|
||||
private int mUserAuthenticationValidityDurationSeconds = -1;
|
||||
|
||||
/**
|
||||
@@ -342,55 +359,70 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only for the provided set of purposes.
|
||||
* Sets the set of purposes for which the key can be used.
|
||||
*
|
||||
* <p>This restriction must be specified. There is no default.
|
||||
* <p>This must be specified for all keys. There is no default.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
|
||||
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided padding schemes. Attempts to use
|
||||
* the key with any other padding will be rejected.
|
||||
* Sets the set of padding schemes with which the key can be used when
|
||||
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for keys which are used for encryption/decryption.
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
|
||||
mPaddings = paddings;
|
||||
public Builder setEncryptionPaddings(String... paddings) {
|
||||
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided digests when generating signatures
|
||||
* or HMACs. Attempts to use the key with any other digest will be rejected.
|
||||
* Sets the set of padding schemes with which the key can be used when
|
||||
* signing/verifying. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>For HMAC keys, the default is to restrict to the digest specified in
|
||||
* {@link Key#getAlgorithm()}. For asymmetric signing keys this constraint must be specified
|
||||
* because there is no default.
|
||||
* <p>This must be specified for RSA keys which are used for signing/verification.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
|
||||
mDigests = digests;
|
||||
public Builder setSignaturePaddings(String... paddings) {
|
||||
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the set of digests with which the key can be used when signing/verifying or
|
||||
* generating MACs. Attempts to use the key with any other digest will be rejected.
|
||||
*
|
||||
* <p>For HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()}. For
|
||||
* asymmetric signing keys this constraint must be specified.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setDigests(String... digests) {
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts the key to being used only with the provided block modes. Attempts to use the
|
||||
* key with any other block modes will be rejected.
|
||||
* Sets the set of block modes with which the key can be used when encrypting/decrypting.
|
||||
* Attempts to use the key with any other block modes will be rejected.
|
||||
*
|
||||
* <p>This restriction must be specified for symmetric encryption/decryption keys.
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
|
||||
mBlockModes = blockModes;
|
||||
public Builder setBlockModes(String... blockModes) {
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -449,7 +481,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
* @hide
|
||||
*/
|
||||
public Builder setUserAuthenticators(
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
|
||||
mUserAuthenticators = userAuthenticators;
|
||||
return this;
|
||||
}
|
||||
@@ -484,7 +516,8 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
mKeyValidityForOriginationEnd,
|
||||
mKeyValidityForConsumptionEnd,
|
||||
mPurposes,
|
||||
mPaddings,
|
||||
mEncryptionPaddings,
|
||||
mSignaturePaddings,
|
||||
mDigests,
|
||||
mBlockModes,
|
||||
mRandomizedEncryptionRequired,
|
||||
|
||||
@@ -19,10 +19,14 @@ package android.security;
|
||||
import android.security.keymaster.KeyCharacteristics;
|
||||
import android.security.keymaster.KeymasterDefs;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.KeySpec;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.SecretKeyFactorySpi;
|
||||
@@ -71,84 +75,90 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
}
|
||||
|
||||
boolean teeBacked;
|
||||
@KeyStoreKeyCharacteristics.OriginEnum int origin;
|
||||
@KeyStoreKeyProperties.OriginEnum int origin;
|
||||
int keySize;
|
||||
@KeyStoreKeyConstraints.PurposeEnum int purposes;
|
||||
@KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
|
||||
@KeyStoreKeyConstraints.PaddingEnum int paddings;
|
||||
@KeyStoreKeyConstraints.DigestEnum int digests;
|
||||
@KeyStoreKeyConstraints.BlockModeEnum int blockModes;
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators;
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes;
|
||||
String[] encryptionPaddings;
|
||||
String[] digests;
|
||||
String[] blockModes;
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators;
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
|
||||
try {
|
||||
if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
|
||||
teeBacked = true;
|
||||
origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
|
||||
origin = KeyStoreKeyProperties.Origin.fromKeymaster(
|
||||
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
|
||||
} else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
|
||||
teeBacked = false;
|
||||
origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
|
||||
origin = KeyStoreKeyProperties.Origin.fromKeymaster(
|
||||
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Key origin not available");
|
||||
}
|
||||
Integer keySizeInteger =
|
||||
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
|
||||
Integer keySizeInteger = keyCharacteristics.getInteger(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);
|
||||
paddings = KeyStoreKeyConstraints.Padding.allFromKeymaster(
|
||||
KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING));
|
||||
digests = KeyStoreKeyConstraints.Digest.allFromKeymaster(
|
||||
KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST));
|
||||
blockModes = KeyStoreKeyConstraints.BlockMode.allFromKeymaster(
|
||||
KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE));
|
||||
purposes = KeyStoreKeyProperties.Purpose.allFromKeymaster(
|
||||
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
|
||||
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum
|
||||
List<String> encryptionPaddingsList = new ArrayList<String>();
|
||||
for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
|
||||
String jcaPadding;
|
||||
try {
|
||||
jcaPadding = KeymasterUtils.getJcaEncryptionPaddingFromKeymasterPadding(
|
||||
keymasterPadding);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidKeySpecException(
|
||||
"Unsupported encryption padding: " + keymasterPadding);
|
||||
}
|
||||
encryptionPaddingsList.add(jcaPadding);
|
||||
}
|
||||
encryptionPaddings =
|
||||
encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
|
||||
|
||||
digests = KeymasterUtils.getJcaDigestAlgorithmsFromKeymasterDigests(
|
||||
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
|
||||
blockModes = KeymasterUtils.getJcaBlockModesFromKeymasterBlockModes(
|
||||
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
|
||||
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum
|
||||
int swEnforcedKeymasterUserAuthenticators =
|
||||
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum
|
||||
int hwEnforcedKeymasterUserAuthenticators =
|
||||
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||
@KeyStoreKeyConstraints.UserAuthenticatorEnum
|
||||
@KeyStoreKeyProperties.UserAuthenticatorEnum
|
||||
int keymasterUserAuthenticators =
|
||||
swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators;
|
||||
userAuthenticators = KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
|
||||
userAuthenticators = KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
|
||||
keymasterUserAuthenticators);
|
||||
teeEnforcedUserAuthenticators =
|
||||
KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
|
||||
KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
|
||||
hwEnforcedKeymasterUserAuthenticators);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidKeySpecException("Unsupported key characteristic", e);
|
||||
}
|
||||
|
||||
Date keyValidityStart =
|
||||
KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
|
||||
Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
|
||||
if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
|
||||
keyValidityStart = null;
|
||||
}
|
||||
Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
|
||||
KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
|
||||
Date keyValidityForOriginationEnd =
|
||||
keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
|
||||
if ((keyValidityForOriginationEnd != null)
|
||||
&& (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
|
||||
keyValidityForOriginationEnd = null;
|
||||
}
|
||||
Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
|
||||
KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
|
||||
Date keyValidityForConsumptionEnd =
|
||||
keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
|
||||
if ((keyValidityForConsumptionEnd != null)
|
||||
&& (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
|
||||
keyValidityForConsumptionEnd = null;
|
||||
}
|
||||
Integer userAuthenticationValidityDurationSeconds =
|
||||
KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT);
|
||||
int userAuthenticationValidityDurationSeconds =
|
||||
keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
|
||||
|
||||
return new KeyStoreKeySpec(entryAlias,
|
||||
teeBacked,
|
||||
@@ -158,14 +168,13 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
keyValidityForOriginationEnd,
|
||||
keyValidityForConsumptionEnd,
|
||||
purposes,
|
||||
algorithm,
|
||||
paddings,
|
||||
encryptionPaddings,
|
||||
EmptyArray.STRING, // no signature paddings -- this is symmetric crypto
|
||||
digests,
|
||||
blockModes,
|
||||
userAuthenticators,
|
||||
teeEnforcedUserAuthenticators,
|
||||
((userAuthenticationValidityDurationSeconds != null)
|
||||
? userAuthenticationValidityDurationSeconds : -1));
|
||||
userAuthenticationValidityDurationSeconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,48 +16,327 @@
|
||||
|
||||
package android.security;
|
||||
|
||||
import android.security.keymaster.KeyCharacteristics;
|
||||
import android.security.keymaster.KeymasterDefs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public abstract class KeymasterUtils {
|
||||
|
||||
private KeymasterUtils() {}
|
||||
|
||||
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);
|
||||
public static int getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
|
||||
if ("AES".equalsIgnoreCase(jcaKeyAlgorithm)) {
|
||||
return KeymasterDefs.KM_ALGORITHM_AES;
|
||||
} else if (jcaKeyAlgorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
|
||||
return KeymasterDefs.KM_ALGORITHM_HMAC;
|
||||
} else {
|
||||
return null;
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported secret key algorithm: " + jcaKeyAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
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 String getJcaSecretKeyAlgorithm(int keymasterAlgorithm, int keymasterDigest) {
|
||||
switch (keymasterAlgorithm) {
|
||||
case KeymasterDefs.KM_ALGORITHM_AES:
|
||||
if (keymasterDigest != -1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Digest not supported for AES key: " + keymasterDigest);
|
||||
}
|
||||
return "AES";
|
||||
case KeymasterDefs.KM_ALGORITHM_HMAC:
|
||||
switch (keymasterDigest) {
|
||||
case KeymasterDefs.KM_DIGEST_SHA1:
|
||||
return "HmacSHA1";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_224:
|
||||
return "HmacSHA224";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_256:
|
||||
return "HmacSHA256";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_384:
|
||||
return "HmacSHA384";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_512:
|
||||
return "HmacSHA512";
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported HMAC digest: " + keymasterDigest);
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
|
||||
Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
|
||||
if (result == null) {
|
||||
result = keyCharacteristics.swEnforced.getDate(tag, null);
|
||||
public static String getJcaKeyPairAlgorithmFromKeymasterAlgorithm(int keymasterAlgorithm) {
|
||||
switch (keymasterAlgorithm) {
|
||||
case KeymasterDefs.KM_ALGORITHM_RSA:
|
||||
return "RSA";
|
||||
case KeymasterDefs.KM_ALGORITHM_EC:
|
||||
return "EC";
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKeymasterDigestfromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
|
||||
String algorithmUpper = jcaKeyAlgorithm.toUpperCase(Locale.US);
|
||||
if (algorithmUpper.startsWith("HMAC")) {
|
||||
String digestUpper = algorithmUpper.substring("HMAC".length());
|
||||
switch (digestUpper) {
|
||||
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("Unsupported HMAC digest: " + digestUpper);
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKeymasterDigestFromJcaDigestAlgorithm(String jcaDigestAlgorithm) {
|
||||
if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-1")) {
|
||||
return KeymasterDefs.KM_DIGEST_SHA1;
|
||||
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-224")) {
|
||||
return KeymasterDefs.KM_DIGEST_SHA_2_224;
|
||||
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-256")) {
|
||||
return KeymasterDefs.KM_DIGEST_SHA_2_256;
|
||||
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-384")) {
|
||||
return KeymasterDefs.KM_DIGEST_SHA_2_384;
|
||||
} else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-512")) {
|
||||
return KeymasterDefs.KM_DIGEST_SHA_2_512;
|
||||
} else if (jcaDigestAlgorithm.equalsIgnoreCase("NONE")) {
|
||||
return KeymasterDefs.KM_DIGEST_NONE;
|
||||
} else if (jcaDigestAlgorithm.equalsIgnoreCase("MD5")) {
|
||||
return KeymasterDefs.KM_DIGEST_MD5;
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported digest algorithm: " + jcaDigestAlgorithm);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getJcaDigestAlgorithmFromKeymasterDigest(int keymasterDigest) {
|
||||
switch (keymasterDigest) {
|
||||
case KeymasterDefs.KM_DIGEST_NONE:
|
||||
return "NONE";
|
||||
case KeymasterDefs.KM_DIGEST_MD5:
|
||||
return "MD5";
|
||||
case KeymasterDefs.KM_DIGEST_SHA1:
|
||||
return "SHA-1";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_224:
|
||||
return "SHA-224";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_256:
|
||||
return "SHA-256";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_384:
|
||||
return "SHA-384";
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_512:
|
||||
return "SHA-512";
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported digest algorithm: " + keymasterDigest);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getJcaDigestAlgorithmsFromKeymasterDigests(
|
||||
Collection<Integer> keymasterDigests) {
|
||||
if (keymasterDigests.isEmpty()) {
|
||||
return EmptyArray.STRING;
|
||||
}
|
||||
String[] result = new String[keymasterDigests.size()];
|
||||
int offset = 0;
|
||||
for (int keymasterDigest : keymasterDigests) {
|
||||
result[offset] = getJcaDigestAlgorithmFromKeymasterDigest(keymasterDigest);
|
||||
offset++;
|
||||
}
|
||||
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);
|
||||
public static int[] getKeymasterDigestsFromJcaDigestAlgorithms(String[] jcaDigestAlgorithms) {
|
||||
if ((jcaDigestAlgorithms == null) || (jcaDigestAlgorithms.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
int[] result = new int[jcaDigestAlgorithms.length];
|
||||
int offset = 0;
|
||||
for (String jcaDigestAlgorithm : jcaDigestAlgorithms) {
|
||||
result[offset] = getKeymasterDigestFromJcaDigestAlgorithm(jcaDigestAlgorithm);
|
||||
offset++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int getDigestOutputSizeBytes(int keymasterDigest) {
|
||||
switch (keymasterDigest) {
|
||||
case KeymasterDefs.KM_DIGEST_NONE:
|
||||
return -1;
|
||||
case KeymasterDefs.KM_DIGEST_MD5:
|
||||
return 128 / 8;
|
||||
case KeymasterDefs.KM_DIGEST_SHA1:
|
||||
return 160 / 8;
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_224:
|
||||
return 224 / 8;
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_256:
|
||||
return 256 / 8;
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_384:
|
||||
return 384 / 8;
|
||||
case KeymasterDefs.KM_DIGEST_SHA_2_512:
|
||||
return 512 / 8;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKeymasterBlockModeFromJcaBlockMode(String jcaBlockMode) {
|
||||
if ("ECB".equalsIgnoreCase(jcaBlockMode)) {
|
||||
return KeymasterDefs.KM_MODE_ECB;
|
||||
} else if ("CBC".equalsIgnoreCase(jcaBlockMode)) {
|
||||
return KeymasterDefs.KM_MODE_CBC;
|
||||
} else if ("CTR".equalsIgnoreCase(jcaBlockMode)) {
|
||||
return KeymasterDefs.KM_MODE_CTR;
|
||||
} else if ("GCM".equalsIgnoreCase(jcaBlockMode)) {
|
||||
return KeymasterDefs.KM_MODE_GCM;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported block mode: " + jcaBlockMode);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getJcaBlockModeFromKeymasterBlockMode(int keymasterBlockMode) {
|
||||
switch (keymasterBlockMode) {
|
||||
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: " + keymasterBlockMode);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getJcaBlockModesFromKeymasterBlockModes(
|
||||
Collection<Integer> keymasterBlockModes) {
|
||||
if ((keymasterBlockModes == null) || (keymasterBlockModes.isEmpty())) {
|
||||
return EmptyArray.STRING;
|
||||
}
|
||||
String[] result = new String[keymasterBlockModes.size()];
|
||||
int offset = 0;
|
||||
for (int keymasterBlockMode : keymasterBlockModes) {
|
||||
result[offset] = getJcaBlockModeFromKeymasterBlockMode(keymasterBlockMode);
|
||||
offset++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] getKeymasterBlockModesFromJcaBlockModes(String[] jcaBlockModes) {
|
||||
if ((jcaBlockModes == null) || (jcaBlockModes.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
int[] result = new int[jcaBlockModes.length];
|
||||
for (int i = 0; i < jcaBlockModes.length; i++) {
|
||||
result[i] = getKeymasterBlockModeFromJcaBlockMode(jcaBlockModes[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isKeymasterBlockModeIndCpaCompatible(int keymasterBlockMode) {
|
||||
switch (keymasterBlockMode) {
|
||||
case KeymasterDefs.KM_MODE_ECB:
|
||||
return false;
|
||||
case KeymasterDefs.KM_MODE_CBC:
|
||||
case KeymasterDefs.KM_MODE_CTR:
|
||||
case KeymasterDefs.KM_MODE_GCM:
|
||||
return true;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKeymasterPaddingFromJcaEncryptionPadding(String jcaPadding) {
|
||||
if ("NoPadding".equalsIgnoreCase(jcaPadding)) {
|
||||
return KeymasterDefs.KM_PAD_NONE;
|
||||
} else if ("PKCS7Padding".equalsIgnoreCase(jcaPadding)) {
|
||||
return KeymasterDefs.KM_PAD_PKCS7;
|
||||
} else if ("PKCS1Padding".equalsIgnoreCase(jcaPadding)) {
|
||||
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
|
||||
} else if ("OEAPPadding".equalsIgnoreCase(jcaPadding)) {
|
||||
return KeymasterDefs.KM_PAD_RSA_OAEP;
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported encryption padding scheme: " + jcaPadding);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getJcaEncryptionPaddingFromKeymasterPadding(int keymasterPadding) {
|
||||
switch (keymasterPadding) {
|
||||
case KeymasterDefs.KM_PAD_NONE:
|
||||
return "NoPadding";
|
||||
case KeymasterDefs.KM_PAD_PKCS7:
|
||||
return "PKCS7Padding";
|
||||
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
|
||||
return "PKCS1Padding";
|
||||
case KeymasterDefs.KM_PAD_RSA_OAEP:
|
||||
return "OEAPPadding";
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported encryption padding: " + keymasterPadding);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKeymasterPaddingFromJcaSignaturePadding(String jcaPadding) {
|
||||
if ("PKCS#1".equalsIgnoreCase(jcaPadding)) {
|
||||
return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
|
||||
} if ("PSS".equalsIgnoreCase(jcaPadding)) {
|
||||
return KeymasterDefs.KM_PAD_RSA_PSS;
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported signature padding scheme: " + jcaPadding);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getJcaSignaturePaddingFromKeymasterPadding(int keymasterPadding) {
|
||||
switch (keymasterPadding) {
|
||||
case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
|
||||
return "PKCS#1";
|
||||
case KeymasterDefs.KM_PAD_RSA_PSS:
|
||||
return "PSS";
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported signature padding: " + keymasterPadding);
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] getKeymasterPaddingsFromJcaEncryptionPaddings(String[] jcaPaddings) {
|
||||
if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
int[] result = new int[jcaPaddings.length];
|
||||
for (int i = 0; i < jcaPaddings.length; i++) {
|
||||
result[i] = getKeymasterPaddingFromJcaEncryptionPadding(jcaPaddings[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int[] getKeymasterPaddingsFromJcaSignaturePaddings(String[] jcaPaddings) {
|
||||
if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
int[] result = new int[jcaPaddings.length];
|
||||
for (int i = 0; i < jcaPaddings.length; i++) {
|
||||
result[i] = getKeymasterPaddingFromJcaSignaturePadding(jcaPaddings[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user