Loading core/java/android/security/keymaster/KeyCharacteristics.java +53 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.security.keymaster; import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; import java.util.Date; import java.util.List; /** Loading @@ -30,10 +32,12 @@ public class KeyCharacteristics implements Parcelable { public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new Parcelable.Creator<KeyCharacteristics>() { @Override public KeyCharacteristics createFromParcel(Parcel in) { return new KeyCharacteristics(in); } @Override public KeyCharacteristics[] newArray(int length) { return new KeyCharacteristics[length]; } Loading @@ -50,6 +54,7 @@ public class KeyCharacteristics implements Parcelable { return 0; } @Override public void writeToParcel(Parcel out, int flags) { swEnforced.writeToParcel(out, flags); hwEnforced.writeToParcel(out, flags); Loading @@ -59,5 +64,53 @@ public class KeyCharacteristics implements Parcelable { swEnforced = KeymasterArguments.CREATOR.createFromParcel(in); hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in); } public Integer getInteger(int tag) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getInt(tag, -1); } else if (swEnforced.containsTag(tag)) { return swEnforced.getInt(tag, -1); } else { return null; } } public int getInt(int tag, int defaultValue) { Integer result = getInteger(tag); return (result != null) ? result : defaultValue; } public List<Integer> getInts(int tag) { List<Integer> result = new ArrayList<Integer>(); result.addAll(hwEnforced.getInts(tag)); result.addAll(swEnforced.getInts(tag)); return result; } public Date getDate(int tag) { Date result = hwEnforced.getDate(tag, null); if (result == null) { result = swEnforced.getDate(tag, null); } return result; } public Date getDate(int tag, Date defaultValue) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getDate(tag, null); } else if (hwEnforced.containsTag(tag)) { return swEnforced.getDate(tag, null); } else { return defaultValue; } } public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) { if (keyCharacteristics.hwEnforced.containsTag(tag)) { return keyCharacteristics.hwEnforced.getBoolean(tag, false); } else { return keyCharacteristics.swEnforced.getBoolean(tag, false); } } } core/java/android/security/keymaster/KeymasterArguments.java +9 −0 Original line number Diff line number Diff line Loading @@ -34,9 +34,12 @@ public class KeymasterArguments implements Parcelable { public static final Parcelable.Creator<KeymasterArguments> CREATOR = new Parcelable.Creator<KeymasterArguments>() { @Override public KeymasterArguments createFromParcel(Parcel in) { return new KeymasterArguments(in); } @Override public KeymasterArguments[] newArray(int size) { return new KeymasterArguments[size]; } Loading @@ -54,6 +57,12 @@ public class KeymasterArguments implements Parcelable { mArguments.add(new KeymasterIntArgument(tag, value)); } public void addInts(int tag, int... values) { for (int value : values) { addInt(tag, value); } } public void addBoolean(int tag) { mArguments.add(new KeymasterBooleanArgument(tag)); } Loading keystore/java/android/security/AndroidKeyStore.java +52 −63 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.security; import com.android.org.conscrypt.OpenSSLEngine; import com.android.org.conscrypt.OpenSSLKeyHolder; import libcore.util.EmptyArray; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; Loading Loading @@ -46,6 +48,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; Loading Loading @@ -112,13 +115,6 @@ public class AndroidKeyStore extends KeyStoreSpi { if (keymasterAlgorithm == -1) { throw new UnrecoverableKeyException("Key algorithm unknown"); } @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm; try { keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(keymasterAlgorithm); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported key algorithm").initCause(e); } int keymasterDigest = keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1); Loading @@ -126,20 +122,11 @@ public class AndroidKeyStore extends KeyStoreSpi { keymasterDigest = keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1); } @KeyStoreKeyConstraints.DigestEnum Integer digest = null; if (keymasterDigest != -1) { try { digest = KeyStoreKeyConstraints.Digest.fromKeymaster(keymasterDigest); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported digest").initCause(e); } } String keyAlgorithmString; try { keyAlgorithmString = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm( keyAlgorithm, digest); keyAlgorithmString = KeymasterUtils.getJcaSecretKeyAlgorithm( keymasterAlgorithm, keymasterDigest); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported secret key type").initCause(e); Loading Loading @@ -456,90 +443,92 @@ public class AndroidKeyStore extends KeyStoreSpi { } String keyAlgorithmString = key.getAlgorithm(); @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm; @KeyStoreKeyConstraints.DigestEnum Integer digest; int keymasterAlgorithm; int keymasterDigest; try { keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString); digest = KeyStoreKeyConstraints.Digest.fromJCASecretKeyAlgorithm(keyAlgorithmString); keymasterAlgorithm = KeymasterUtils.getKeymasterAlgorithmFromJcaSecretKeyAlgorithm( keyAlgorithmString); keymasterDigest = KeymasterUtils.getKeymasterDigestfromJcaSecretKeyAlgorithm(keyAlgorithmString); } catch (IllegalArgumentException e) { throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString); } KeymasterArguments args = new KeymasterArguments(); args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm)); args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm); @KeyStoreKeyConstraints.DigestEnum int digests; int[] keymasterDigests; if (params.isDigestsSpecified()) { // Digest(s) specified in parameters if (digest != null) { keymasterDigests = KeymasterUtils.getKeymasterDigestsFromJcaDigestAlgorithms(params.getDigests()); if (keymasterDigest != -1) { // Digest also specified in the JCA key algorithm name. if ((params.getDigests() & digest) != digest) { if (!com.android.internal.util.ArrayUtils.contains( keymasterDigests, keymasterDigest)) { throw new KeyStoreException("Key digest mismatch" + ". Key: " + keyAlgorithmString + ", parameter spec: " + KeyStoreKeyConstraints.Digest.allToString(params.getDigests())); + ", parameter spec: " + Arrays.asList(params.getDigests())); } } digests = params.getDigests(); } else { // No digest specified in parameters if (digest != null) { if (keymasterDigest != -1) { // Digest specified in the JCA key algorithm name. digests = digest; keymasterDigests = new int[] {keymasterDigest}; } else { digests = 0; } keymasterDigests = EmptyArray.INT; } for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) { args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest); } if (digests != 0) { args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests); if (keymasterDigests.length > 0) { // TODO: Remove MAC length constraint once Keymaster API no longer requires it. // This code will blow up if mode than one digest is specified. Integer digestOutputSizeBytes = KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest); if (digestOutputSizeBytes != null) { int digestOutputSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]); if (digestOutputSizeBytes != -1) { // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes); } } if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) { if (digests == 0) { if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { if (keymasterDigests.length == 0) { throw new KeyStoreException("At least one digest algorithm must be specified" + " for key algorithm " + keyAlgorithmString); } } @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes(); @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes(); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes(); int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes( params.getBlockModes()); if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) { @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes = blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES; if (incompatibleBlockModes != 0) { throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be" + " violated by block mode(s): " + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes) 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)) { 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); for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } 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) { Loading @@ -559,7 +548,7 @@ public class AndroidKeyStore extends KeyStoreSpi { // TODO: Remove this once keymaster does not require us to specify the size of imported key. args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) && (!params.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); Loading keystore/java/android/security/ArrayUtils.java 0 → 100644 +62 −0 Original line number Diff line number Diff line 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; } } } keystore/java/android/security/KeyGeneratorSpec.java +39 −37 Original line number Diff line number Diff line Loading @@ -49,11 +49,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private final Date mKeyValidityStart; private final Date mKeyValidityForOriginationEnd; private final Date mKeyValidityForConsumptionEnd; private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private final @KeyStoreKeyProperties.PurposeEnum int mPurposes; private final String[] mEncryptionPaddings; private final String[] mBlockModes; private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; private KeyGeneratorSpec( Loading @@ -64,11 +64,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { Date keyValidityStart, Date keyValidityForOriginationEnd, Date keyValidityForConsumptionEnd, @KeyStoreKeyConstraints.PurposeEnum int purposes, @KeyStoreKeyConstraints.PaddingEnum int paddings, @KeyStoreKeyConstraints.BlockModeEnum int blockModes, @KeyStoreKeyProperties.PurposeEnum int purposes, String[] encryptionPaddings, String[] blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators, @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, int userAuthenticationValidityDurationSeconds) { if (context == null) { throw new IllegalArgumentException("context == null"); Loading @@ -88,8 +88,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; mPurposes = purposes; mPaddings = paddings; mBlockModes = blockModes; mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; Loading Loading @@ -154,22 +155,22 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { /** * Gets the set of purposes for which the key can be used. */ public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() { public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { return mPurposes; } /** * Gets the set of padding schemes to which the key is restricted. * Gets the set of padding schemes with which the key can be used when encrypting/decrypting. */ public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() { return mPaddings; public String[] getEncryptionPaddings() { return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); } /** * Gets the set of block modes to which the key is restricted. * Gets the set of block modes with which the key can be used. */ public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() { return mBlockModes; public String[] getBlockModes() { return ArrayUtils.cloneIfNotEmpty(mBlockModes); } /** Loading @@ -191,7 +192,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @return user authenticators or {@code 0} if the key can be used without user authentication. */ public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() { public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() { return mUserAuthenticators; } Loading Loading @@ -221,11 +222,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private Date mKeyValidityStart; private Date mKeyValidityForOriginationEnd; private Date mKeyValidityForConsumptionEnd; private @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private @KeyStoreKeyProperties.PurposeEnum int mPurposes; private String[] mEncryptionPaddings; private String[] mBlockModes; private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; /** Loading Loading @@ -332,34 +333,35 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** * Restricts the key to being used only for the provided set of purposes. * Sets the set of purposes for which the key can be used. * * <p>This restriction must be specified. There is no default. * <p>This must be specified for all keys. There is no default. */ public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) { public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { mPurposes = purposes; return this; } /** * Restricts the key to being used only with the provided padding schemes. Attempts to use * the key with any other padding will be rejected. * Sets the set of padding schemes with which the key can be used when * encrypting/decrypting. Attempts to use the key with any other padding scheme will be * rejected. * * <p>This restriction must be specified for keys which are used for encryption/decryption. * <p>This must be specified for keys which are used for encryption/decryption. */ public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) { mPaddings = paddings; public Builder setEncryptionPaddings(String... paddings) { mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); return this; } /** * Restricts the key to being used only with the provided block modes. Attempts to use the * key with any other block modes will be rejected. * Sets the set of block modes with which the key can be used when encrypting/decrypting. * Attempts to use the key with any other block modes will be rejected. * * <p>This restriction must be specified for keys which are used for encryption/decryption. * <p>This must be specified for encryption/decryption keys. */ public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) { mBlockModes = blockModes; public Builder setBlockModes(String... blockModes) { mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); return this; } Loading Loading @@ -412,7 +414,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * @see #setUserAuthenticationValidityDurationSeconds(int) */ public Builder setUserAuthenticators( @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) { @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) { mUserAuthenticators = userAuthenticators; return this; } Loading Loading @@ -447,7 +449,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd, mPurposes, mPaddings, mEncryptionPaddings, mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, Loading Loading
core/java/android/security/keymaster/KeyCharacteristics.java +53 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.security.keymaster; import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; import java.util.Date; import java.util.List; /** Loading @@ -30,10 +32,12 @@ public class KeyCharacteristics implements Parcelable { public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new Parcelable.Creator<KeyCharacteristics>() { @Override public KeyCharacteristics createFromParcel(Parcel in) { return new KeyCharacteristics(in); } @Override public KeyCharacteristics[] newArray(int length) { return new KeyCharacteristics[length]; } Loading @@ -50,6 +54,7 @@ public class KeyCharacteristics implements Parcelable { return 0; } @Override public void writeToParcel(Parcel out, int flags) { swEnforced.writeToParcel(out, flags); hwEnforced.writeToParcel(out, flags); Loading @@ -59,5 +64,53 @@ public class KeyCharacteristics implements Parcelable { swEnforced = KeymasterArguments.CREATOR.createFromParcel(in); hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in); } public Integer getInteger(int tag) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getInt(tag, -1); } else if (swEnforced.containsTag(tag)) { return swEnforced.getInt(tag, -1); } else { return null; } } public int getInt(int tag, int defaultValue) { Integer result = getInteger(tag); return (result != null) ? result : defaultValue; } public List<Integer> getInts(int tag) { List<Integer> result = new ArrayList<Integer>(); result.addAll(hwEnforced.getInts(tag)); result.addAll(swEnforced.getInts(tag)); return result; } public Date getDate(int tag) { Date result = hwEnforced.getDate(tag, null); if (result == null) { result = swEnforced.getDate(tag, null); } return result; } public Date getDate(int tag, Date defaultValue) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getDate(tag, null); } else if (hwEnforced.containsTag(tag)) { return swEnforced.getDate(tag, null); } else { return defaultValue; } } public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) { if (keyCharacteristics.hwEnforced.containsTag(tag)) { return keyCharacteristics.hwEnforced.getBoolean(tag, false); } else { return keyCharacteristics.swEnforced.getBoolean(tag, false); } } }
core/java/android/security/keymaster/KeymasterArguments.java +9 −0 Original line number Diff line number Diff line Loading @@ -34,9 +34,12 @@ public class KeymasterArguments implements Parcelable { public static final Parcelable.Creator<KeymasterArguments> CREATOR = new Parcelable.Creator<KeymasterArguments>() { @Override public KeymasterArguments createFromParcel(Parcel in) { return new KeymasterArguments(in); } @Override public KeymasterArguments[] newArray(int size) { return new KeymasterArguments[size]; } Loading @@ -54,6 +57,12 @@ public class KeymasterArguments implements Parcelable { mArguments.add(new KeymasterIntArgument(tag, value)); } public void addInts(int tag, int... values) { for (int value : values) { addInt(tag, value); } } public void addBoolean(int tag) { mArguments.add(new KeymasterBooleanArgument(tag)); } Loading
keystore/java/android/security/AndroidKeyStore.java +52 −63 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.security; import com.android.org.conscrypt.OpenSSLEngine; import com.android.org.conscrypt.OpenSSLKeyHolder; import libcore.util.EmptyArray; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; Loading Loading @@ -46,6 +48,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; Loading Loading @@ -112,13 +115,6 @@ public class AndroidKeyStore extends KeyStoreSpi { if (keymasterAlgorithm == -1) { throw new UnrecoverableKeyException("Key algorithm unknown"); } @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm; try { keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(keymasterAlgorithm); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported key algorithm").initCause(e); } int keymasterDigest = keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1); Loading @@ -126,20 +122,11 @@ public class AndroidKeyStore extends KeyStoreSpi { keymasterDigest = keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1); } @KeyStoreKeyConstraints.DigestEnum Integer digest = null; if (keymasterDigest != -1) { try { digest = KeyStoreKeyConstraints.Digest.fromKeymaster(keymasterDigest); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported digest").initCause(e); } } String keyAlgorithmString; try { keyAlgorithmString = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm( keyAlgorithm, digest); keyAlgorithmString = KeymasterUtils.getJcaSecretKeyAlgorithm( keymasterAlgorithm, keymasterDigest); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported secret key type").initCause(e); Loading Loading @@ -456,90 +443,92 @@ public class AndroidKeyStore extends KeyStoreSpi { } String keyAlgorithmString = key.getAlgorithm(); @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm; @KeyStoreKeyConstraints.DigestEnum Integer digest; int keymasterAlgorithm; int keymasterDigest; try { keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString); digest = KeyStoreKeyConstraints.Digest.fromJCASecretKeyAlgorithm(keyAlgorithmString); keymasterAlgorithm = KeymasterUtils.getKeymasterAlgorithmFromJcaSecretKeyAlgorithm( keyAlgorithmString); keymasterDigest = KeymasterUtils.getKeymasterDigestfromJcaSecretKeyAlgorithm(keyAlgorithmString); } catch (IllegalArgumentException e) { throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString); } KeymasterArguments args = new KeymasterArguments(); args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm)); args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm); @KeyStoreKeyConstraints.DigestEnum int digests; int[] keymasterDigests; if (params.isDigestsSpecified()) { // Digest(s) specified in parameters if (digest != null) { keymasterDigests = KeymasterUtils.getKeymasterDigestsFromJcaDigestAlgorithms(params.getDigests()); if (keymasterDigest != -1) { // Digest also specified in the JCA key algorithm name. if ((params.getDigests() & digest) != digest) { if (!com.android.internal.util.ArrayUtils.contains( keymasterDigests, keymasterDigest)) { throw new KeyStoreException("Key digest mismatch" + ". Key: " + keyAlgorithmString + ", parameter spec: " + KeyStoreKeyConstraints.Digest.allToString(params.getDigests())); + ", parameter spec: " + Arrays.asList(params.getDigests())); } } digests = params.getDigests(); } else { // No digest specified in parameters if (digest != null) { if (keymasterDigest != -1) { // Digest specified in the JCA key algorithm name. digests = digest; keymasterDigests = new int[] {keymasterDigest}; } else { digests = 0; } keymasterDigests = EmptyArray.INT; } for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) { args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest); } if (digests != 0) { args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests); if (keymasterDigests.length > 0) { // TODO: Remove MAC length constraint once Keymaster API no longer requires it. // This code will blow up if mode than one digest is specified. Integer digestOutputSizeBytes = KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest); if (digestOutputSizeBytes != null) { int digestOutputSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]); if (digestOutputSizeBytes != -1) { // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes); } } if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) { if (digests == 0) { if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { if (keymasterDigests.length == 0) { throw new KeyStoreException("At least one digest algorithm must be specified" + " for key algorithm " + keyAlgorithmString); } } @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes(); @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes(); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes(); int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes( params.getBlockModes()); if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) { @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes = blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES; if (incompatibleBlockModes != 0) { throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be" + " violated by block mode(s): " + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes) 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)) { 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); for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } 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) { Loading @@ -559,7 +548,7 @@ public class AndroidKeyStore extends KeyStoreSpi { // TODO: Remove this once keymaster does not require us to specify the size of imported key. args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) && (!params.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); Loading
keystore/java/android/security/ArrayUtils.java 0 → 100644 +62 −0 Original line number Diff line number Diff line 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; } } }
keystore/java/android/security/KeyGeneratorSpec.java +39 −37 Original line number Diff line number Diff line Loading @@ -49,11 +49,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private final Date mKeyValidityStart; private final Date mKeyValidityForOriginationEnd; private final Date mKeyValidityForConsumptionEnd; private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private final @KeyStoreKeyProperties.PurposeEnum int mPurposes; private final String[] mEncryptionPaddings; private final String[] mBlockModes; private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; private KeyGeneratorSpec( Loading @@ -64,11 +64,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { Date keyValidityStart, Date keyValidityForOriginationEnd, Date keyValidityForConsumptionEnd, @KeyStoreKeyConstraints.PurposeEnum int purposes, @KeyStoreKeyConstraints.PaddingEnum int paddings, @KeyStoreKeyConstraints.BlockModeEnum int blockModes, @KeyStoreKeyProperties.PurposeEnum int purposes, String[] encryptionPaddings, String[] blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators, @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators, int userAuthenticationValidityDurationSeconds) { if (context == null) { throw new IllegalArgumentException("context == null"); Loading @@ -88,8 +88,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; mPurposes = purposes; mPaddings = paddings; mBlockModes = blockModes; mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; Loading Loading @@ -154,22 +155,22 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { /** * Gets the set of purposes for which the key can be used. */ public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() { public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { return mPurposes; } /** * Gets the set of padding schemes to which the key is restricted. * Gets the set of padding schemes with which the key can be used when encrypting/decrypting. */ public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() { return mPaddings; public String[] getEncryptionPaddings() { return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); } /** * Gets the set of block modes to which the key is restricted. * Gets the set of block modes with which the key can be used. */ public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() { return mBlockModes; public String[] getBlockModes() { return ArrayUtils.cloneIfNotEmpty(mBlockModes); } /** Loading @@ -191,7 +192,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @return user authenticators or {@code 0} if the key can be used without user authentication. */ public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() { public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() { return mUserAuthenticators; } Loading Loading @@ -221,11 +222,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private Date mKeyValidityStart; private Date mKeyValidityForOriginationEnd; private Date mKeyValidityForConsumptionEnd; private @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private @KeyStoreKeyProperties.PurposeEnum int mPurposes; private String[] mEncryptionPaddings; private String[] mBlockModes; private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; /** Loading Loading @@ -332,34 +333,35 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** * Restricts the key to being used only for the provided set of purposes. * Sets the set of purposes for which the key can be used. * * <p>This restriction must be specified. There is no default. * <p>This must be specified for all keys. There is no default. */ public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) { public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { mPurposes = purposes; return this; } /** * Restricts the key to being used only with the provided padding schemes. Attempts to use * the key with any other padding will be rejected. * Sets the set of padding schemes with which the key can be used when * encrypting/decrypting. Attempts to use the key with any other padding scheme will be * rejected. * * <p>This restriction must be specified for keys which are used for encryption/decryption. * <p>This must be specified for keys which are used for encryption/decryption. */ public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) { mPaddings = paddings; public Builder setEncryptionPaddings(String... paddings) { mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); return this; } /** * Restricts the key to being used only with the provided block modes. Attempts to use the * key with any other block modes will be rejected. * Sets the set of block modes with which the key can be used when encrypting/decrypting. * Attempts to use the key with any other block modes will be rejected. * * <p>This restriction must be specified for keys which are used for encryption/decryption. * <p>This must be specified for encryption/decryption keys. */ public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) { mBlockModes = blockModes; public Builder setBlockModes(String... blockModes) { mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); return this; } Loading Loading @@ -412,7 +414,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * @see #setUserAuthenticationValidityDurationSeconds(int) */ public Builder setUserAuthenticators( @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) { @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) { mUserAuthenticators = userAuthenticators; return this; } Loading Loading @@ -447,7 +449,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd, mPurposes, mPaddings, mEncryptionPaddings, mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, Loading