Merge "Use JCA names for block modes, paddings, and digests."

This commit is contained in:
Alex Klyubin
2015-04-13 17:01:28 +00:00
committed by Gerrit Code Review
17 changed files with 1156 additions and 1451 deletions

View File

@@ -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);
}
}
}

View File

@@ -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));
}

View File

@@ -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);

View 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;
}
}
}

View File

@@ -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,

View File

@@ -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,

View File

@@ -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();

View File

@@ -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;
}
/**

View File

@@ -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,

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View 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;
}
}

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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

View File

@@ -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;
}
}