Use JCA names for block modes, paddings, and digests.
This replaces int-based enums from KeyStoreKeyConstraints with
String values commonly used in JCA API.
As part of under the hood refactoring:
* KeyStoreKeyCharacteristics and KeyStoreKeyConstraints have been
merged into KeyStoreKeyProperties.
* KeymasterUtils methods operating on KeymasterArguments and
KeymasterCharacteristics have been moved to their respective
classes.
Bug: 18088752
Change-Id: I9c8b984cb3c28184adb617e34d87f2837bd1d3a1
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 55a8b4f..fcee9fc 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -19,6 +19,8 @@
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.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 @@
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 @@
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 @@
}
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 @@
// 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);
diff --git a/keystore/java/android/security/ArrayUtils.java b/keystore/java/android/security/ArrayUtils.java
new file mode 100644
index 0000000..2047d3f
--- /dev/null
+++ b/keystore/java/android/security/ArrayUtils.java
@@ -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;
+ }
+ }
+}
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 4dcabd0..a22c31c 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -49,11 +49,11 @@
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 @@
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 @@
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 @@
/**
* 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 @@
*
* @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 @@
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 @@
}
/**
- * 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 @@
* @see #setUserAuthenticationValidityDurationSeconds(int)
*/
public Builder setUserAuthenticators(
- @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
mUserAuthenticators = userAuthenticators;
return this;
}
@@ -447,7 +449,7 @@
mKeyValidityForOriginationEnd,
mKeyValidityForConsumptionEnd,
mPurposes,
- mPaddings,
+ mEncryptionPaddings,
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticators,
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index db310ea..9d6701a 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -78,17 +78,19 @@
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 @@
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 @@
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 @@
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 @@
*
* @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 @@
*
* @hide
*/
- public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
return mUserAuthenticators;
}
@@ -458,17 +474,19 @@
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 @@
}
/**
- * 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 @@
* @hide
*/
public Builder setUserAuthenticators(
- @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
mUserAuthenticators = userAuthenticators;
return this;
}
@@ -800,7 +833,8 @@
mKeyValidityForConsumptionEnd,
mPurposes,
mDigests,
- mPaddings,
+ mEncryptionPaddings,
+ mSignaturePaddings,
mBlockModes,
mRandomizedEncryptionRequired,
mUserAuthenticators,
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index 487eac0..7bc6378 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -48,68 +48,67 @@
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 @@
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 @@
}
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();
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index 1f8b7e4..aafd2fa 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -19,6 +19,8 @@
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 @@
// 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 @@
} 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 @@
// 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 @@
throw KeyStore.getKeyStoreException(opResult.resultCode);
}
- return concat(output, opResult.output);
+ return ArrayUtils.concat(output, opResult.output);
}
/**
@@ -215,11 +217,11 @@
*/
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 @@
+ " . 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;
}
/**
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index f69e7d1..a19bbda 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -37,36 +37,36 @@
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 @@
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 @@
}
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,
diff --git a/keystore/java/android/security/KeyStoreKeyCharacteristics.java b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
deleted file mode 100644
index 1f5d400..0000000
--- a/keystore/java/android/security/KeyStoreKeyCharacteristics.java
+++ /dev/null
@@ -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);
- }
- }
- }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
deleted file mode 100644
index 055b702..0000000
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ /dev/null
@@ -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;
- }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index a500786..87e7ee6 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -37,68 +37,68 @@
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 @@
}
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 @@
(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 @@
throw KeyStore.getCryptoOperationException(errorCode);
}
String keyAlgorithmJCA =
- KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
+ KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
}
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
new file mode 100644
index 0000000..d8ad1d3
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -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;
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index 27b444e..861ed34 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -29,17 +29,17 @@
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 @@
*/
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 @@
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 @@
/**
* Gets the origin of the key.
*/
- public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
+ public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
return mOrigin;
}
@@ -137,36 +139,36 @@
/**
* 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 @@
*
* @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 @@
* 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;
}
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index fb534b4..9fce177 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -43,24 +43,26 @@
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 @@
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 @@
*
* @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 @@
}
/**
- * 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 @@
*
* @hide
*/
- public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
return mUserAuthenticators;
}
@@ -244,12 +260,13 @@
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 @@
}
/**
- * 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 @@
* @hide
*/
public Builder setUserAuthenticators(
- @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
mUserAuthenticators = userAuthenticators;
return this;
}
@@ -484,7 +516,8 @@
mKeyValidityForOriginationEnd,
mKeyValidityForConsumptionEnd,
mPurposes,
- mPaddings,
+ mEncryptionPaddings,
+ mSignaturePaddings,
mDigests,
mBlockModes,
mRandomizedEncryptionRequired,
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index 99a8168..33073a4 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -19,10 +19,14 @@
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 @@
}
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 @@
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
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 3143d4d..67f75c2 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -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;
}
}