diff options
Diffstat (limited to 'keystore/java')
13 files changed, 649 insertions, 485 deletions
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java index 3f29c6a..ea90ca3 100644 --- a/keystore/java/android/security/AndroidKeyPairGenerator.java +++ b/keystore/java/android/security/AndroidKeyPairGenerator.java @@ -54,13 +54,13 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { public static class RSA extends AndroidKeyPairGenerator { public RSA() { - super(KeyStoreKeyProperties.Algorithm.RSA); + super(KeyStoreKeyProperties.KEY_ALGORITHM_RSA); } } public static class EC extends AndroidKeyPairGenerator { public EC() { - super(KeyStoreKeyProperties.Algorithm.EC); + super(KeyStoreKeyProperties.KEY_ALGORITHM_EC); } } @@ -83,15 +83,15 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { private android.security.KeyStore mKeyStore; private KeyPairGeneratorSpec mSpec; - private @KeyStoreKeyProperties.AlgorithmEnum String mKeyAlgorithm; + private @KeyStoreKeyProperties.KeyAlgorithmEnum String mKeyAlgorithm; private int mKeyType; private int mKeySize; - protected AndroidKeyPairGenerator(@KeyStoreKeyProperties.AlgorithmEnum String algorithm) { + protected AndroidKeyPairGenerator(@KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { mAlgorithm = algorithm; } - public @KeyStoreKeyProperties.AlgorithmEnum String getAlgorithm() { + @KeyStoreKeyProperties.KeyAlgorithmEnum String getAlgorithm() { return mAlgorithm; } @@ -197,7 +197,8 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { return certGen.generate(privateKey); } - private @KeyStoreKeyProperties.AlgorithmEnum String getKeyAlgorithm(KeyPairGeneratorSpec spec) { + private @KeyStoreKeyProperties.KeyAlgorithmEnum String getKeyAlgorithm( + KeyPairGeneratorSpec spec) { String result = spec.getKeyType(); if (result != null) { return result; @@ -249,10 +250,10 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { } private static String getDefaultSignatureAlgorithmForKeyAlgorithm( - @KeyStoreKeyProperties.AlgorithmEnum String algorithm) { - if (KeyStoreKeyProperties.Algorithm.RSA.equalsIgnoreCase(algorithm)) { + @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { + if (KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { return "sha256WithRSA"; - } else if (KeyStoreKeyProperties.Algorithm.EC.equalsIgnoreCase(algorithm)) { + } else if (KeyStoreKeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) { return "sha256WithECDSA"; } else { throw new IllegalArgumentException("Unsupported key type " + algorithm); @@ -288,7 +289,7 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { } KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params; - @KeyStoreKeyProperties.AlgorithmEnum String keyAlgorithm = getKeyAlgorithm(spec); + @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithm = getKeyAlgorithm(spec); int keyType = KeyStore.getKeyTypeForAlgorithm(keyAlgorithm); if (keyType == -1) { throw new InvalidAlgorithmParameterException( diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java index 69d80e6..7ac236a 100644 --- a/keystore/java/android/security/AndroidKeyStore.java +++ b/keystore/java/android/security/AndroidKeyStore.java @@ -129,10 +129,10 @@ public class AndroidKeyStore extends KeyStoreSpi { keymasterDigest = keymasterDigests.get(0); } - @KeyStoreKeyProperties.AlgorithmEnum String keyAlgorithmString; + @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithmString; try { keyAlgorithmString = - KeyStoreKeyProperties.Algorithm.fromKeymasterSecretKeyAlgorithm( + KeyStoreKeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( keymasterAlgorithm, keymasterDigest); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) @@ -453,10 +453,10 @@ public class AndroidKeyStore extends KeyStoreSpi { int keymasterAlgorithm; int keymasterDigest; try { - keymasterAlgorithm = KeyStoreKeyProperties.Algorithm.toKeymasterSecretKeyAlgorithm( + keymasterAlgorithm = KeyStoreKeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm( keyAlgorithmString); keymasterDigest = - KeyStoreKeyProperties.Algorithm.toKeymasterDigest(keyAlgorithmString); + KeyStoreKeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString); } catch (IllegalArgumentException e) { throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString); } @@ -497,7 +497,7 @@ public class AndroidKeyStore extends KeyStoreSpi { @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes(); int[] keymasterBlockModes = KeyStoreKeyProperties.BlockMode.allToKeymaster(params.getBlockModes()); - if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) + if (((purposes & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) { for (int keymasterBlockMode : keymasterBlockModes) { if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) { @@ -536,7 +536,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 & KeyStoreKeyProperties.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/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java index a3e5aec..1cd8784 100644 --- a/keystore/java/android/security/EcIesParameterSpec.java +++ b/keystore/java/android/security/EcIesParameterSpec.java @@ -1,6 +1,8 @@ package android.security; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -49,45 +51,44 @@ import javax.crypto.Mac; */ public class EcIesParameterSpec implements AlgorithmParameterSpec { + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) - @IntDef(value = {PointFormat.UNCOMPRESSED, PointFormat.COMPRESSED}) + @IntDef({ + POINT_FORMAT_UNSPECIFIED, + POINT_FORMAT_UNCOMPRESSED, + POINT_FORMAT_COMPRESSED, + }) public @interface PointFormatEnum {} + /** Unspecified EC point format. */ + public static final int POINT_FORMAT_UNSPECIFIED = -1; + /** - * Wire format of the EC point. + * Uncompressed EC point format: both coordinates are stored separately. + * + * <p>The wire format is byte {@code 0x04} followed by binary representation of the {@code x} + * coordinate followed by binary representation of the {@code y} coordinate. See + * {@code ISO 18033-2} section {@code 5.4.3}. */ - public static abstract class PointFormat { - - private PointFormat() {} + public static final int POINT_FORMAT_UNCOMPRESSED = 0; - /** Unspecified point format. */ - public static final int UNSPECIFIED = -1; - - /** - * Uncompressed point format: both coordinates are stored separately. - * - * <p>The wire format is byte {@code 0x04} followed by binary representation of the - * {@code x} coordinate followed by binary representation of the {@code y} coordinate. See - * {@code ISO 18033-2} section {@code 5.4.3}. - */ - public static final int UNCOMPRESSED = 0; - - /** - * Compressed point format: only one coordinate is stored. - * - * <p>The wire format is byte {@code 0x02} or {@code 0x03} (depending on the value of the - * stored coordinate) followed by the binary representation of the {@code x} coordinate. - * See {@code ISO 18033-2} section {@code 5.4.3}. - */ - public static final int COMPRESSED = 1; - } + /** + * Compressed EC point format: only one coordinate is stored. + * + * <p>The wire format is byte {@code 0x02} or {@code 0x03} (depending on the value of the stored + * coordinate) followed by the binary representation of the {@code x} coordinate. See + * {@code ISO 18033-2} section {@code 5.4.3}. + */ + public static final int POINT_FORMAT_COMPRESSED = 1; /** * Default parameter spec: compressed point format, {@code HKDFwithSHA256}, DEM uses 128-bit AES * GCM. */ public static final EcIesParameterSpec DEFAULT = new EcIesParameterSpec( - PointFormat.COMPRESSED, + POINT_FORMAT_COMPRESSED, "HKDFwithSHA256", "AES/GCM/NoPadding", 128, @@ -117,7 +118,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { } /** - * Returns KEM EC point wire format or {@link PointFormat#UNSPECIFIED} if not specified. + * Returns KEM EC point wire format or {@link #POINT_FORMAT_UNSPECIFIED} if not specified. */ public @PointFormatEnum int getKemPointFormat() { return mKemPointFormat; @@ -127,6 +128,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * Returns KEM KDF algorithm (e.g., {@code HKDFwithSHA256} or {@code KDF1withSHA1}) or * {@code null} if not specified. */ + @Nullable public String getKemKdfAlgorithm() { return mKemKdfAlgorithm; } @@ -138,6 +140,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * @see Cipher#getInstance(String) * @see #getDemCipherKeySize() */ + @Nullable public String getDemCipherTransformation() { return mDemCipherTransformation; } @@ -158,6 +161,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * @see Mac#getInstance(String) * @see #getDemMacKeySize() */ + @Nullable public String getDemMacAlgorithm() { return mDemMacAlgorithm; } @@ -175,7 +179,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * Builder of {@link EcIesParameterSpec}. */ public static class Builder { - private @PointFormatEnum int mKemPointFormat = PointFormat.UNSPECIFIED; + private @PointFormatEnum int mKemPointFormat = POINT_FORMAT_UNSPECIFIED; private String mKemKdfAlgorithm; private String mDemCipherTransformation; private int mDemCipherKeySize = 128; @@ -194,7 +198,8 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * Sets KEM KDF algorithm. For example, {@code HKDFwithSHA256}, {@code KDF2withSHA256}, or * {@code KDF1withSHA1}. */ - public Builder setKemKdfAlgorithm(String algorithm) { + @NonNull + public Builder setKemKdfAlgorithm(@Nullable String algorithm) { mKemKdfAlgorithm = algorithm; return this; } @@ -205,7 +210,8 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * * @see Cipher#getInstance(String) */ - public Builder setDemCipherTransformation(String transformation) { + @NonNull + public Builder setDemCipherTransformation(@Nullable String transformation) { mDemCipherTransformation = transformation; return this; } @@ -217,6 +223,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * * @see #setDemCipherTransformation(String) */ + @NonNull public Builder setDemCipherKeySize(int sizeBits) { mDemCipherKeySize = sizeBits; return this; @@ -227,7 +234,8 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * * @see Mac#getInstance(String) */ - public Builder setDemMacAlgorithm(String algorithm) { + @NonNull + public Builder setDemMacAlgorithm(@Nullable String algorithm) { mDemMacAlgorithm = algorithm; return this; } @@ -239,6 +247,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { * * @see #setDemCipherKeySize(int) */ + @NonNull public Builder setDemMacKeySize(int sizeBits) { mDemMacKeySize = sizeBits; return this; @@ -247,6 +256,7 @@ public class EcIesParameterSpec implements AlgorithmParameterSpec { /** * Returns a new {@link EcIesParameterSpec} based on the current state of this builder. */ + @NonNull public EcIesParameterSpec build() { int demMacKeySize = (mDemMacKeySize != -1) ? mDemMacKeySize : mDemCipherKeySize; return new EcIesParameterSpec( diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 8e27dc3..3853eca 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -15,6 +15,8 @@ */ package android.security; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Activity; import android.app.PendingIntent; import android.content.ComponentName; @@ -217,6 +219,7 @@ public final class KeyChain { * successfully installed, otherwise {@link * Activity#RESULT_CANCELED} will be returned. */ + @NonNull public static Intent createInstallIntent() { Intent intent = new Intent(ACTION_INSTALL); intent.setClassName(CERT_INSTALLER_PACKAGE, @@ -261,9 +264,10 @@ public final class KeyChain { * @param alias The alias to preselect if available, or null if * unavailable. */ - public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response, - @KeyStoreKeyProperties.AlgorithmEnum String[] keyTypes, Principal[] issuers, - String host, int port, String alias) { + public static void choosePrivateKeyAlias(@NonNull Activity activity, + @NonNull KeyChainAliasCallback response, + @KeyStoreKeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, + @Nullable String host, int port, @Nullable String alias) { choosePrivateKeyAlias(activity, response, keyTypes, issuers, host, port, null, alias); } @@ -306,9 +310,10 @@ public final class KeyChain { * @param alias The alias to preselect if available, or null if * unavailable. */ - public static void choosePrivateKeyAlias(Activity activity, KeyChainAliasCallback response, - @KeyStoreKeyProperties.AlgorithmEnum String[] keyTypes, Principal[] issuers, - String host, int port, String url, String alias) { + public static void choosePrivateKeyAlias(@NonNull Activity activity, + @NonNull KeyChainAliasCallback response, + @KeyStoreKeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, + @Nullable String host, int port, @Nullable String url, @Nullable String alias) { /* * TODO currently keyTypes, issuers are unused. They are meant * to follow the semantics and purpose of X509KeyManager @@ -361,7 +366,8 @@ public final class KeyChain { * returned via {@link KeyChainAliasCallback#alias}. * @throws KeyChainException if the alias was valid but there was some problem accessing it. */ - public static PrivateKey getPrivateKey(Context context, String alias) + @Nullable + public static PrivateKey getPrivateKey(@NonNull Context context, @NonNull String alias) throws KeyChainException, InterruptedException { if (alias == null) { throw new NullPointerException("alias == null"); @@ -396,8 +402,9 @@ public final class KeyChain { * returned via {@link KeyChainAliasCallback#alias}. * @throws KeyChainException if the alias was valid but there was some problem accessing it. */ - public static X509Certificate[] getCertificateChain(Context context, String alias) - throws KeyChainException, InterruptedException { + @Nullable + public static X509Certificate[] getCertificateChain(@NonNull Context context, + @NonNull String alias) throws KeyChainException, InterruptedException { if (alias == null) { throw new NullPointerException("alias == null"); } @@ -432,10 +439,10 @@ public final class KeyChain { * "RSA"). */ public static boolean isKeyAlgorithmSupported( - @KeyStoreKeyProperties.AlgorithmEnum String algorithm) { + @NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { final String algUpper = algorithm.toUpperCase(Locale.US); - return KeyStoreKeyProperties.Algorithm.EC.equals(algUpper) - || KeyStoreKeyProperties.Algorithm.RSA.equals(algUpper); + return KeyStoreKeyProperties.KEY_ALGORITHM_EC.equals(algUpper) + || KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equals(algUpper); } /** @@ -446,7 +453,7 @@ public final class KeyChain { * that makes it non-exportable. */ public static boolean isBoundKeyAlgorithm( - @KeyStoreKeyProperties.AlgorithmEnum String algorithm) { + @NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { if (!isKeyAlgorithmSupported(algorithm)) { return false; } @@ -455,7 +462,8 @@ public final class KeyChain { } /** @hide */ - public static X509Certificate toCertificate(byte[] bytes) { + @NonNull + public static X509Certificate toCertificate(@NonNull byte[] bytes) { if (bytes == null) { throw new IllegalArgumentException("bytes == null"); } @@ -496,14 +504,14 @@ public final class KeyChain { * * Caller should call unbindService on the result when finished. */ - public static KeyChainConnection bind(Context context) throws InterruptedException { + public static KeyChainConnection bind(@NonNull Context context) throws InterruptedException { return bindAsUser(context, Process.myUserHandle()); } /** * @hide */ - public static KeyChainConnection bindAsUser(Context context, UserHandle user) + public static KeyChainConnection bindAsUser(@NonNull Context context, UserHandle user) throws InterruptedException { if (context == null) { throw new NullPointerException("context == null"); @@ -537,7 +545,7 @@ public final class KeyChain { return new KeyChainConnection(context, keyChainServiceConnection, q.take()); } - private static void ensureNotOnMainThread(Context context) { + private static void ensureNotOnMainThread(@NonNull Context context) { Looper looper = Looper.myLooper(); if (looper != null && looper == context.getMainLooper()) { throw new IllegalStateException( diff --git a/keystore/java/android/security/KeyChainAliasCallback.java b/keystore/java/android/security/KeyChainAliasCallback.java index 2500863..8e41377 100644 --- a/keystore/java/android/security/KeyChainAliasCallback.java +++ b/keystore/java/android/security/KeyChainAliasCallback.java @@ -15,6 +15,8 @@ */ package android.security; +import android.annotation.Nullable; + /** * The KeyChainAliasCallback is the callback for {@link * KeyChain#choosePrivateKeyAlias}. @@ -25,5 +27,5 @@ public interface KeyChainAliasCallback { * Called with the alias of the certificate chosen by the user, or * null if no value was chosen. */ - public void alias(String alias); + public void alias(@Nullable String alias); } diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java index 97e3a67..e63566b 100644 --- a/keystore/java/android/security/KeyGeneratorSpec.java +++ b/keystore/java/android/security/KeyGeneratorSpec.java @@ -16,6 +16,9 @@ package android.security; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; import android.text.TextUtils; @@ -53,13 +56,13 @@ import javax.crypto.KeyGenerator; * been authenticated within the last five minutes. * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( - * KeyStoreKeyProperties.Algorithm.HMAC_SHA256, + * KeyStoreKeyProperties.KEY_ALGORITHM_HMAC_SHA256, * "AndroidKeyStore"); * keyGenerator.initialize( * new KeyGeneratorSpec.Builder(context) * .setAlias("key1") - * .setPurposes(KeyStoreKeyProperties.Purpose.SIGN - * | KeyStoreKeyProperties.Purpose.VERIFY) + * .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN + * | KeyStoreKeyProperties.PURPOSE_VERIFY) * // Only permit this key to be used if the user authenticated * // within the last five minutes. * .setUserAuthenticationRequired(true) @@ -163,6 +166,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityStart() { return mKeyValidityStart; } @@ -172,6 +176,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForConsumptionEnd() { return mKeyValidityForConsumptionEnd; } @@ -181,27 +186,41 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForOriginationEnd() { return mKeyValidityForOriginationEnd; } /** - * Gets the set of purposes for which the key can be used. + * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { return mPurposes; } /** - * Gets the set of padding schemes with which the key can be used when encrypting/decrypting. + * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code NoPadding}) with + * which the key can be used when encrypting/decrypting. Attempts to use the key with any + * other padding scheme will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() { return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); } /** - * Gets the set of block modes with which the key can be used. + * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * when encrypting/decrypting. Attempts to use the key with any other block modes will be + * rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() { return ArrayUtils.cloneIfNotEmpty(mBlockModes); } @@ -269,7 +288,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * {@code context} passed in may be used to pop up some UI to ask the user to unlock or * initialize the Android KeyStore facility. */ - public Builder(Context context) { + public Builder(@NonNull Context context) { if (context == null) { throw new NullPointerException("context == null"); } @@ -282,7 +301,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * <p>The alias must be provided. There is no default. */ - public Builder setAlias(String alias) { + @NonNull + public Builder setAlias(@NonNull String alias) { if (alias == null) { throw new NullPointerException("alias == null"); } @@ -296,6 +316,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * <p>By default, the key size will be determines based on the key algorithm. For example, * for {@code HmacSHA256}, the key size will default to {@code 256}. */ + @NonNull public Builder setKeySize(int keySize) { mKeySize = keySize; return this; @@ -313,6 +334,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @see KeyguardManager#isDeviceSecure() */ + @NonNull public Builder setEncryptionRequired() { mFlags |= KeyStore.FLAG_ENCRYPTED; return this; @@ -325,6 +347,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @see #setKeyValidityEnd(Date) */ + @NonNull public Builder setKeyValidityStart(Date startDate) { mKeyValidityStart = startDate; return this; @@ -339,6 +362,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * @see #setKeyValidityForConsumptionEnd(Date) * @see #setKeyValidityForOriginationEnd(Date) */ + @NonNull public Builder setKeyValidityEnd(Date endDate) { setKeyValidityForOriginationEnd(endDate); setKeyValidityForConsumptionEnd(endDate); @@ -352,6 +376,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @see #setKeyValidityForConsumptionEnd(Date) */ + @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { mKeyValidityForOriginationEnd = endDate; return this; @@ -365,28 +390,36 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @see #setKeyValidityForOriginationEnd(Date) */ + @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { mKeyValidityForConsumptionEnd = endDate; return this; } /** - * Sets the set of purposes for which the key can be used. + * Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. * * <p>This must be specified for all keys. There is no default. + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ + @NonNull public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { mPurposes = purposes; return this; } /** - * 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. + * Sets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code NoPadding}) 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 must be specified for keys which are used for encryption/decryption. + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public Builder setEncryptionPaddings( @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) { mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); @@ -394,11 +427,15 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { } /** - * 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. + * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}) 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. + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) { mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); return this; @@ -436,6 +473,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * ciphertext.</li> * </ul> */ + @NonNull public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; @@ -456,6 +494,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @see #setUserAuthenticationValidityDurationSeconds(int) */ + @NonNull public Builder setUserAuthenticationRequired(boolean required) { mUserAuthenticationRequired = required; return this; @@ -472,7 +511,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @see #setUserAuthenticationRequired(boolean) */ - public Builder setUserAuthenticationValidityDurationSeconds(int seconds) { + @NonNull + public Builder setUserAuthenticationValidityDurationSeconds( + @IntRange(from = -1) int seconds) { mUserAuthenticationValidityDurationSeconds = seconds; return this; } @@ -482,6 +523,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { * * @throws IllegalArgumentException if a required field is missing or violates a constraint. */ + @NonNull public KeyGeneratorSpec build() { return new KeyGeneratorSpec(mContext, mKeystoreAlias, diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index 7fd5cb5..b07c052 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -17,6 +17,9 @@ package android.security; import android.app.KeyguardManager; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.text.TextUtils; @@ -66,16 +69,16 @@ import javax.security.auth.x500.X500Principal; * digest and only if the user has been authenticated within the last five minutes. * <pre> {@code * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( - * KeyStoreKeyProperties.Algorithm.EC, + * KeyStoreKeyProperties.KEY_ALGORITHM_EC, * "AndroidKeyStore"); * keyPairGenerator.initialize( * new KeyGeneratorSpec.Builder(context) * .setAlias("key2") - * .setPurposes(KeyStoreKeyProperties.Purpose.SIGN - * | KeyStoreKeyProperties.Purpose.VERIFY) - * .setDigests(KeyStoreKeyProperties.Digest.SHA256 - * | KeyStoreKeyProperties.Digest.SHA384 - * | KeyStoreKeyProperties.Digest.SHA512) + * .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN + * | KeyStoreKeyProperties.PURPOSE_VERIFY) + * .setDigests(KeyStoreKeyProperties.DIGEST_SHA256 + * | KeyStoreKeyProperties.DIGEST_SHA384 + * | KeyStoreKeyProperties.DIGEST_SHA512) * // Only permit this key to be used if the user authenticated * // within the last five minutes. * .setUserAuthenticationRequired(true) @@ -284,9 +287,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Returns the key type (e.g., "EC", "RSA") specified by this parameter. + * Returns the type of key pair (e.g., {@code EC}, {@code RSA}) to be generated. See + * {@link KeyStoreKeyProperties}.{@code KEY_ALGORITHM} constants. */ - public @KeyStoreKeyProperties.AlgorithmEnum String getKeyType() { + @Nullable + public @KeyStoreKeyProperties.KeyAlgorithmEnum String getKeyType() { return mKeyType; } @@ -303,6 +308,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * Returns the {@link AlgorithmParameterSpec} that will be used for creation * of the key pair. */ + @NonNull public AlgorithmParameterSpec getAlgorithmParameterSpec() { return mSpec; } @@ -311,6 +317,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * Gets the subject distinguished name to be used on the X.509 certificate * that will be put in the {@link java.security.KeyStore}. */ + @NonNull public X500Principal getSubjectDN() { return mSubjectDN; } @@ -319,6 +326,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * Gets the serial number to be used on the X.509 certificate that will be * put in the {@link java.security.KeyStore}. */ + @NonNull public BigInteger getSerialNumber() { return mSerialNumber; } @@ -327,6 +335,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * Gets the start date to be used on the X.509 certificate that will be put * in the {@link java.security.KeyStore}. */ + @NonNull public Date getStartDate() { return mStartDate; } @@ -335,6 +344,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * Gets the end date to be used on the X.509 certificate that will be put in * the {@link java.security.KeyStore}. */ + @NonNull public Date getEndDate() { return mEndDate; } @@ -359,6 +369,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityStart() { return mKeyValidityStart; } @@ -369,6 +380,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForConsumptionEnd() { return mKeyValidityForConsumptionEnd; } @@ -378,41 +390,64 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForOriginationEnd() { return mKeyValidityForOriginationEnd; } /** - * Gets the set of purposes for which the key can be used. + * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { return mPurposes; } /** - * Gets the set of digest algorithms with which the key can be used. + * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384} with which the key + * can be used. + * + * @see KeyStoreKeyProperties.Digest */ + @NonNull public @KeyStoreKeyProperties.DigestEnum String[] getDigests() { return ArrayUtils.cloneIfNotEmpty(mDigests); } /** - * Gets the set of padding schemes with which the key can be used when encrypting/decrypting. + * Gets the set of padding schemes (e.g., {@code OEAPPadding}, {@code PKCS1Padding}, + * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use + * the key with any other padding scheme will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() { return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); } /** - * Gets the set of padding schemes with which the key can be used when signing/verifying. + * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key + * can be used when signing/verifying. Attempts to use the key with any other padding scheme + * will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() { return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings); } /** - * Gets the set of block modes with which the key can be used. + * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * when encrypting/decrypting. Attempts to use the key with any other block modes will be + * rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() { return ArrayUtils.cloneIfNotEmpty(mBlockModes); } @@ -528,7 +563,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * some UI to ask the user to unlock or initialize the Android KeyStore * facility. */ - public Builder(Context context) { + public Builder(@NonNull Context context) { if (context == null) { throw new NullPointerException("context == null"); } @@ -540,7 +575,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * {@link java.security.KeyStore} instance using the * {@code AndroidKeyStore} provider. */ - public Builder setAlias(String alias) { + @NonNull + public Builder setAlias(@NonNull String alias) { if (alias == null) { throw new NullPointerException("alias == null"); } @@ -549,9 +585,12 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * Sets the key type (e.g., EC, RSA) of the keypair to be created. + * Sets the type of key pair (e.g., {@code EC}, {@code RSA}) of the key pair to be + * generated. See {@link KeyStoreKeyProperties}.{@code KEY_ALGORITHM} constants. + * */ - public Builder setKeyType(@KeyStoreKeyProperties.AlgorithmEnum String keyType) + @NonNull + public Builder setKeyType(@NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String keyType) throws NoSuchAlgorithmException { if (keyType == null) { throw new NullPointerException("keyType == null"); @@ -569,6 +608,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * key type of RSA this will set the modulus size and for a key type of * EC it will select a curve with a matching field size. */ + @NonNull public Builder setKeySize(int keySize) { if (keySize < 0) { throw new IllegalArgumentException("keySize < 0"); @@ -581,7 +621,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * Sets the algorithm-specific key generation parameters. For example, for RSA keys * this may be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}. */ - public Builder setAlgorithmParameterSpec(AlgorithmParameterSpec spec) { + public Builder setAlgorithmParameterSpec(@NonNull AlgorithmParameterSpec spec) { if (spec == null) { throw new NullPointerException("spec == null"); } @@ -597,7 +637,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On * newer platforms the subject defaults to {@code CN=fake} if not specified. */ - public Builder setSubject(X500Principal subject) { + @NonNull + public Builder setSubject(@NonNull X500Principal subject) { if (subject == null) { throw new NullPointerException("subject == null"); } @@ -613,7 +654,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On * newer platforms the serial number defaults to {@code 1} if not specified. */ - public Builder setSerialNumber(BigInteger serialNumber) { + @NonNull + public Builder setSerialNumber(@NonNull BigInteger serialNumber) { if (serialNumber == null) { throw new NullPointerException("serialNumber == null"); } @@ -629,7 +671,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On * newer platforms the date defaults to {@code Jan 1 1970} if not specified. */ - public Builder setStartDate(Date startDate) { + @NonNull + public Builder setStartDate(@NonNull Date startDate) { if (startDate == null) { throw new NullPointerException("startDate == null"); } @@ -645,7 +688,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On * newer platforms the date defaults to {@code Jan 1 2048} if not specified. */ - public Builder setEndDate(Date endDate) { + @NonNull + public Builder setEndDate(@NonNull Date endDate) { if (endDate == null) { throw new NullPointerException("endDate == null"); } @@ -665,6 +709,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * @see KeyguardManager#isDeviceSecure() */ + @NonNull public Builder setEncryptionRequired() { mFlags |= KeyStore.FLAG_ENCRYPTED; return this; @@ -675,10 +720,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> * * @see #setKeyValidityEnd(Date) */ + @NonNull public Builder setKeyValidityStart(Date startDate) { mKeyValidityStart = startDate; return this; @@ -689,12 +735,13 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> * * @see #setKeyValidityStart(Date) * @see #setKeyValidityForConsumptionEnd(Date) * @see #setKeyValidityForOriginationEnd(Date) */ + @NonNull public Builder setKeyValidityEnd(Date endDate) { setKeyValidityForOriginationEnd(endDate); setKeyValidityForConsumptionEnd(endDate); @@ -706,10 +753,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> * * @see #setKeyValidityForConsumptionEnd(Date) */ + @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { mKeyValidityForOriginationEnd = endDate; return this; @@ -721,55 +769,67 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> * * @see #setKeyValidityForOriginationEnd(Date) */ + @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { mKeyValidityForConsumptionEnd = endDate; return this; } /** - * Sets the set of purposes for which the key can be used. + * Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. * * <p>This must be specified for all keys. There is no default. * * <p>If the set of purposes for which the key can be used does not contain - * {@link KeyStoreKeyProperties.Purpose#SIGN}, the self-signed certificate generated by + * {@link KeyStoreKeyProperties#PURPOSE_SIGN}, the self-signed certificate generated by * {@link KeyPairGenerator} of {@code AndroidKeyStore} provider will contain an invalid * signature. This is OK if the certificate is only used for obtaining the public key from * Android KeyStore. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ + @NonNull public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { mPurposes = purposes; return this; } /** - * 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. + * Sets the set of digests algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which + * the key can be used when signing/verifying. Attempts to use the key with any other digest + * algorithm will be rejected. * * <p>This must be specified for keys which are used for signing/verification. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> + * + * @see KeyStoreKeyProperties.Digest */ + @NonNull public Builder setDigests(@KeyStoreKeyProperties.DigestEnum String... digests) { mDigests = ArrayUtils.cloneIfNotEmpty(digests); return this; } /** - * 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. + * Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS1Padding}, + * {@code NoPadding}) 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 must be specified for keys which are used for encryption/decryption. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public Builder setEncryptionPaddings( @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) { mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); @@ -777,14 +837,17 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * 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. + * Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) 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 must be specified for RSA keys which are used for signing/verification. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. */ + @NonNull public Builder setSignaturePaddings( @KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) { mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings); @@ -792,13 +855,17 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { } /** - * 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. + * Sets the set of block modes (e.g., {@code ECB}, {@code CBC}, {@code CTR}) 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. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) { mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); return this; @@ -824,8 +891,9 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li> * </ul> * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> */ + @NonNull public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; @@ -847,10 +915,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * <p>This restriction applies only to private key operations. Public key operations are not * restricted. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> * * @see #setUserAuthenticationValidityDurationSeconds(int) */ + @NonNull public Builder setUserAuthenticationRequired(boolean required) { mUserAuthenticationRequired = required; return this; @@ -865,14 +934,16 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * <p>This restriction applies only to private key operations. Public key operations are not * restricted. * - * <p><b>NOTE: This has currently no effect. + * <p><b>NOTE: This has currently no effect.</b> * * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for * every use of the key. * * @see #setUserAuthenticationRequired(boolean) */ - public Builder setUserAuthenticationValidityDurationSeconds(int seconds) { + @NonNull + public Builder setUserAuthenticationValidityDurationSeconds( + @IntRange(from = -1) int seconds) { mUserAuthenticationValidityDurationSeconds = seconds; return this; } @@ -883,6 +954,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * @throws IllegalArgumentException if a required field is missing * @return built instance of {@code KeyPairGeneratorSpec} */ + @NonNull public KeyPairGeneratorSpec build() { return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 3ed8899..7e3193d 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -131,10 +131,10 @@ public class KeyStore { return mToken; } - static int getKeyTypeForAlgorithm(@KeyStoreKeyProperties.AlgorithmEnum String keyType) { - if (KeyStoreKeyProperties.Algorithm.RSA.equalsIgnoreCase(keyType)) { + static int getKeyTypeForAlgorithm(@KeyStoreKeyProperties.KeyAlgorithmEnum String keyType) { + if (KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) { return NativeConstants.EVP_PKEY_RSA; - } else if (KeyStoreKeyProperties.Algorithm.EC.equalsIgnoreCase(keyType)) { + } else if (KeyStoreKeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) { return NativeConstants.EVP_PKEY_EC; } else { return -1; diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java index bd601bc..4eeca47 100644 --- a/keystore/java/android/security/KeyStoreCipherSpi.java +++ b/keystore/java/android/security/KeyStoreCipherSpi.java @@ -496,7 +496,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if ((mIv != null) && (mIv.length > 0)) { try { AlgorithmParameters params = - AlgorithmParameters.getInstance(KeyStoreKeyProperties.Algorithm.AES); + AlgorithmParameters.getInstance(KeyStoreKeyProperties.KEY_ALGORITHM_AES); params.init(new IvParameterSpec(mIv)); return params; } catch (NoSuchAlgorithmException e) { diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index 4b914c2..d734d66 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -174,7 +174,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { spec.getEncryptionPaddings()); mKeymasterBlockModes = KeyStoreKeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()); - if (((spec.getPurposes() & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) + if (((spec.getPurposes() & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0) && (spec.isRandomizedEncryptionRequired())) { for (int keymasterBlockMode : mKeymasterBlockModes) { if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible( @@ -247,7 +247,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { (spec.getKeyValidityForConsumptionEnd() != null) ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE)); - if (((spec.getPurposes() & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0) + if (((spec.getPurposes() & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0) && (!spec.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); @@ -265,9 +265,9 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { throw new ProviderException( "Keystore operation failed", KeyStore.getKeyStoreException(errorCode)); } - String keyAlgorithmJCA; + @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA; try { - keyAlgorithmJCA = KeyStoreKeyProperties.Algorithm.fromKeymasterSecretKeyAlgorithm( + keyAlgorithmJCA = KeyStoreKeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( mKeymasterAlgorithm, mKeymasterDigest); } catch (IllegalArgumentException e) { throw new ProviderException("Failed to obtain JCA secret key algorithm name", e); diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java index 1cf6a7a..b58a7dd 100644 --- a/keystore/java/android/security/KeyStoreKeyProperties.java +++ b/keystore/java/android/security/KeyStoreKeyProperties.java @@ -17,6 +17,8 @@ package android.security; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.StringDef; import android.security.keymaster.KeymasterDefs; @@ -24,94 +26,83 @@ import libcore.util.EmptyArray; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPairGenerator; import java.util.Collection; import java.util.Locale; -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.SecretKeyFactory; - /** * Properties of {@code AndroidKeyStore} keys. */ public abstract class KeyStoreKeyProperties { private KeyStoreKeyProperties() {} + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, - value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY}) + value = { + PURPOSE_ENCRYPT, + PURPOSE_DECRYPT, + PURPOSE_SIGN, + PURPOSE_VERIFY, + }) public @interface PurposeEnum {} /** - * Purposes of key. + * Purpose of key: encryption. */ - public static abstract class Purpose { - private Purpose() {} + public static final int PURPOSE_ENCRYPT = 1 << 0; - /** - * Purpose: encryption. - */ - public static final int ENCRYPT = 1 << 0; + /** + * Purpose of key: decryption. + */ + public static final int PURPOSE_DECRYPT = 1 << 1; - /** - * Purpose: decryption. - */ - public static final int DECRYPT = 1 << 1; + /** + * Purpose of key: signing or generating a Message Authentication Code (MAC). + */ + public static final int PURPOSE_SIGN = 1 << 2; - /** - * Purpose: signing. - */ - public static final int SIGN = 1 << 2; + /** + * Purpose of key: signature or Message Authentication Code (MAC) verification. + */ + public static final int PURPOSE_VERIFY = 1 << 3; - /** - * Purpose: signature verification. - */ - public static final int VERIFY = 1 << 3; + static abstract class Purpose { + private Purpose() {} - /** - * @hide - */ - public static int toKeymaster(@PurposeEnum int purpose) { + static int toKeymaster(@PurposeEnum int purpose) { switch (purpose) { - case ENCRYPT: + case PURPOSE_ENCRYPT: return KeymasterDefs.KM_PURPOSE_ENCRYPT; - case DECRYPT: + case PURPOSE_DECRYPT: return KeymasterDefs.KM_PURPOSE_DECRYPT; - case SIGN: + case PURPOSE_SIGN: return KeymasterDefs.KM_PURPOSE_SIGN; - case VERIFY: + case PURPOSE_VERIFY: return KeymasterDefs.KM_PURPOSE_VERIFY; default: throw new IllegalArgumentException("Unknown purpose: " + purpose); } } - /** - * @hide - */ - public static @PurposeEnum int fromKeymaster(int purpose) { + static @PurposeEnum int fromKeymaster(int purpose) { switch (purpose) { case KeymasterDefs.KM_PURPOSE_ENCRYPT: - return ENCRYPT; + return PURPOSE_ENCRYPT; case KeymasterDefs.KM_PURPOSE_DECRYPT: - return DECRYPT; + return PURPOSE_DECRYPT; case KeymasterDefs.KM_PURPOSE_SIGN: - return SIGN; + return PURPOSE_SIGN; case KeymasterDefs.KM_PURPOSE_VERIFY: - return VERIFY; + return PURPOSE_VERIFY; default: throw new IllegalArgumentException("Unknown purpose: " + purpose); } } - /** - * @hide - */ - public static int[] allToKeymaster(@PurposeEnum int purposes) { + @NonNull + static int[] allToKeymaster(@PurposeEnum int purposes) { int[] result = getSetFlags(purposes); for (int i = 0; i < result.length; i++) { result[i] = toKeymaster(result[i]); @@ -119,10 +110,7 @@ public abstract class KeyStoreKeyProperties { return result; } - /** - * @hide - */ - public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) { + static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) { @PurposeEnum int result = 0; for (int keymasterPurpose : purposes) { result |= fromKeymaster(keymasterPurpose); @@ -131,59 +119,51 @@ public abstract class KeyStoreKeyProperties { } } + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) @StringDef({ - Algorithm.RSA, - Algorithm.EC, - Algorithm.AES, - Algorithm.HMAC_SHA1, - Algorithm.HMAC_SHA224, - Algorithm.HMAC_SHA256, - Algorithm.HMAC_SHA384, - Algorithm.HMAC_SHA512, + KEY_ALGORITHM_RSA, + KEY_ALGORITHM_EC, + KEY_ALGORITHM_AES, + KEY_ALGORITHM_HMAC_SHA1, + KEY_ALGORITHM_HMAC_SHA224, + KEY_ALGORITHM_HMAC_SHA256, + KEY_ALGORITHM_HMAC_SHA384, + KEY_ALGORITHM_HMAC_SHA512, }) - public @interface AlgorithmEnum {} + public @interface KeyAlgorithmEnum {} - /** - * Key algorithms. - * - * <p>These are standard names which can be used to obtain instances of {@link KeyGenerator}, - * {@link KeyPairGenerator}, {@link Cipher} (as part of the transformation string), {@link Mac}, - * {@link KeyFactory}, {@link SecretKeyFactory}. These are also the names used by - * {@link Key#getAlgorithm()}. - */ - public static abstract class Algorithm { - private Algorithm() {} + /** Rivest Shamir Adleman (RSA) key. */ + public static final String KEY_ALGORITHM_RSA = "RSA"; - /** Rivest Shamir Adleman (RSA) key. */ - public static final String RSA = "RSA"; + /** Elliptic Curve (EC) Cryptography key. */ + public static final String KEY_ALGORITHM_EC = "EC"; - /** Elliptic Curve (EC) key. */ - public static final String EC = "EC"; + /** Advanced Encryption Standard (AES) key. */ + public static final String KEY_ALGORITHM_AES = "AES"; - /** Advanced Encryption Standard (AES) key. */ - public static final String AES = "AES"; + /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-1 as the hash. */ + public static final String KEY_ALGORITHM_HMAC_SHA1 = "HmacSHA1"; - /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-1 as the hash. */ - public static final String HMAC_SHA1 = "HmacSHA1"; + /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-224 as the hash. */ + public static final String KEY_ALGORITHM_HMAC_SHA224 = "HmacSHA224"; - /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-224 as the hash. */ - public static final String HMAC_SHA224 = "HmacSHA224"; + /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-256 as the hash. */ + public static final String KEY_ALGORITHM_HMAC_SHA256 = "HmacSHA256"; - /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-256 as the hash. */ - public static final String HMAC_SHA256 = "HmacSHA256"; + /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-384 as the hash. */ + public static final String KEY_ALGORITHM_HMAC_SHA384 = "HmacSHA384"; - /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-384 as the hash. */ - public static final String HMAC_SHA384 = "HmacSHA384"; + /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */ + public static final String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512"; - /** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */ - public static final String HMAC_SHA512 = "HmacSHA512"; + static abstract class KeyAlgorithm { + private KeyAlgorithm() {} - /** - * @hide - */ - static int toKeymasterSecretKeyAlgorithm(@AlgorithmEnum String algorithm) { - if (AES.equalsIgnoreCase(algorithm)) { + static int toKeymasterSecretKeyAlgorithm(@NonNull @KeyAlgorithmEnum String algorithm) { + if (KEY_ALGORITHM_AES.equalsIgnoreCase(algorithm)) { return KeymasterDefs.KM_ALGORITHM_AES; } else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) { return KeymasterDefs.KM_ALGORITHM_HMAC; @@ -193,10 +173,8 @@ public abstract class KeyStoreKeyProperties { } } - /** - * @hide - */ - static @AlgorithmEnum String fromKeymasterSecretKeyAlgorithm( + @NonNull + static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm( int keymasterAlgorithm, int keymasterDigest) { switch (keymasterAlgorithm) { case KeymasterDefs.KM_ALGORITHM_AES: @@ -204,26 +182,26 @@ public abstract class KeyStoreKeyProperties { throw new IllegalArgumentException("Digest not supported for AES key: " + Digest.fromKeymaster(keymasterDigest)); } - return AES; + return KEY_ALGORITHM_AES; case KeymasterDefs.KM_ALGORITHM_HMAC: switch (keymasterDigest) { case KeymasterDefs.KM_DIGEST_SHA1: - return HMAC_SHA1; + return KEY_ALGORITHM_HMAC_SHA1; case KeymasterDefs.KM_DIGEST_SHA_2_224: - return HMAC_SHA224; + return KEY_ALGORITHM_HMAC_SHA224; case KeymasterDefs.KM_DIGEST_SHA_2_256: - return HMAC_SHA256; + return KEY_ALGORITHM_HMAC_SHA256; case KeymasterDefs.KM_DIGEST_SHA_2_384: - return HMAC_SHA384; + return KEY_ALGORITHM_HMAC_SHA384; case KeymasterDefs.KM_DIGEST_SHA_2_512: - return HMAC_SHA512; + return KEY_ALGORITHM_HMAC_SHA512; default: throw new IllegalArgumentException("Unsupported HMAC digest: " + Digest.fromKeymaster(keymasterDigest)); } default: throw new IllegalArgumentException( - "Unsupported algorithm: " + keymasterAlgorithm); + "Unsupported key algorithm: " + keymasterAlgorithm); } } @@ -232,7 +210,7 @@ public abstract class KeyStoreKeyProperties { * * @return keymaster digest or {@code -1} if the algorithm does not involve a digest. */ - static int toKeymasterDigest(@AlgorithmEnum String algorithm) { + static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) { String algorithmUpper = algorithm.toUpperCase(Locale.US); if (algorithmUpper.startsWith("HMAC")) { String digestUpper = algorithmUpper.substring("HMAC".length()); @@ -257,72 +235,65 @@ public abstract class KeyStoreKeyProperties { } } + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) @StringDef({ - BlockMode.ECB, - BlockMode.CBC, - BlockMode.CTR, - BlockMode.GCM, + BLOCK_MODE_ECB, + BLOCK_MODE_CBC, + BLOCK_MODE_CTR, + BLOCK_MODE_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 String BLOCK_MODE_ECB = "ECB"; - /** Electronic Codebook (ECB) block mode. */ - public static final String ECB = "ECB"; + /** Cipher Block Chaining (CBC) block mode. */ + public static final String BLOCK_MODE_CBC = "CBC"; - /** Cipher Block Chaining (CBC) block mode. */ - public static final String CBC = "CBC"; + /** Counter (CTR) block mode. */ + public static final String BLOCK_MODE_CTR = "CTR"; - /** Counter (CTR) block mode. */ - public static final String CTR = "CTR"; + /** Galois/Counter Mode (GCM) block mode. */ + public static final String BLOCK_MODE_GCM = "GCM"; - /** Galois/Counter Mode (GCM) block mode. */ - public static final String GCM = "GCM"; + static abstract class BlockMode { + private BlockMode() {} - /** - * @hide - */ - static int toKeymaster(@BlockModeEnum String blockMode) { - if (ECB.equalsIgnoreCase(blockMode)) { + static int toKeymaster(@NonNull @BlockModeEnum String blockMode) { + if (BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) { return KeymasterDefs.KM_MODE_ECB; - } else if (CBC.equalsIgnoreCase(blockMode)) { + } else if (BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) { return KeymasterDefs.KM_MODE_CBC; - } else if (CTR.equalsIgnoreCase(blockMode)) { + } else if (BLOCK_MODE_CTR.equalsIgnoreCase(blockMode)) { return KeymasterDefs.KM_MODE_CTR; - } else if (GCM.equalsIgnoreCase(blockMode)) { + } else if (BLOCK_MODE_GCM.equalsIgnoreCase(blockMode)) { return KeymasterDefs.KM_MODE_GCM; } else { throw new IllegalArgumentException("Unsupported block mode: " + blockMode); } } - /** - * @hide - */ + @NonNull static @BlockModeEnum String fromKeymaster(int blockMode) { switch (blockMode) { case KeymasterDefs.KM_MODE_ECB: - return ECB; + return BLOCK_MODE_ECB; case KeymasterDefs.KM_MODE_CBC: - return CBC; + return BLOCK_MODE_CBC; case KeymasterDefs.KM_MODE_CTR: - return CTR; + return BLOCK_MODE_CTR; case KeymasterDefs.KM_MODE_GCM: - return GCM; + return BLOCK_MODE_GCM; default: throw new IllegalArgumentException("Unsupported block mode: " + blockMode); } } - /** - * @hide - */ - static @BlockModeEnum String[] allFromKeymaster(Collection<Integer> blockModes) { + @NonNull + static @BlockModeEnum String[] allFromKeymaster(@NonNull Collection<Integer> blockModes) { if ((blockModes == null) || (blockModes.isEmpty())) { return EmptyArray.STRING; } @@ -335,10 +306,7 @@ public abstract class KeyStoreKeyProperties { return result; } - /** - * @hide - */ - static int[] allToKeymaster(@BlockModeEnum String[] blockModes) { + static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) { if ((blockModes == null) || (blockModes.length == 0)) { return EmptyArray.INT; } @@ -350,52 +318,49 @@ public abstract class KeyStoreKeyProperties { } } + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) @StringDef({ - EncryptionPadding.NONE, - EncryptionPadding.PKCS7, - EncryptionPadding.RSA_PKCS1, - EncryptionPadding.RSA_OAEP, + ENCRYPTION_PADDING_NONE, + ENCRYPTION_PADDING_PKCS7, + ENCRYPTION_PADDING_RSA_PKCS1, + ENCRYPTION_PADDING_RSA_OAEP, }) public @interface EncryptionPaddingEnum {} /** - * Padding schemes for encryption/decryption. + * No encryption padding. */ - public static abstract class EncryptionPadding { - private EncryptionPadding() {} + public static final String ENCRYPTION_PADDING_NONE = "NoPadding"; - /** - * No padding. - */ - public static final String NONE = "NoPadding"; + /** + * PKCS#7 encryption padding scheme. + */ + public static final String ENCRYPTION_PADDING_PKCS7 = "PKCS7Padding"; - /** - * PKCS#7 padding. - */ - public static final String PKCS7 = "PKCS7Padding"; + /** + * RSA PKCS#1 v1.5 padding scheme for encryption. + */ + public static final String ENCRYPTION_PADDING_RSA_PKCS1 = "PKCS1Padding"; - /** - * RSA PKCS#1 v1.5 padding for encryption/decryption. - */ - public static final String RSA_PKCS1 = "PKCS1Padding"; + /** + * RSA Optimal Asymmetric Encryption Padding (OAEP) scheme. + */ + public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding"; - /** - * RSA Optimal Asymmetric Encryption Padding (OAEP). - */ - public static final String RSA_OAEP = "OAEPPadding"; + static abstract class EncryptionPadding { + private EncryptionPadding() {} - /** - * @hide - */ - static int toKeymaster(@EncryptionPaddingEnum String padding) { - if (NONE.equalsIgnoreCase(padding)) { + static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) { + if (ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) { return KeymasterDefs.KM_PAD_NONE; - } else if (PKCS7.equalsIgnoreCase(padding)) { + } else if (ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) { return KeymasterDefs.KM_PAD_PKCS7; - } else if (RSA_PKCS1.equalsIgnoreCase(padding)) { + } else if (ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) { return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT; - } else if (RSA_OAEP.equalsIgnoreCase(padding)) { + } else if (ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) { return KeymasterDefs.KM_PAD_RSA_OAEP; } else { throw new IllegalArgumentException( @@ -403,29 +368,25 @@ public abstract class KeyStoreKeyProperties { } } - /** - * @hide - */ + @NonNull static @EncryptionPaddingEnum String fromKeymaster(int padding) { switch (padding) { case KeymasterDefs.KM_PAD_NONE: - return NONE; + return ENCRYPTION_PADDING_NONE; case KeymasterDefs.KM_PAD_PKCS7: - return PKCS7; + return ENCRYPTION_PADDING_PKCS7; case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT: - return RSA_PKCS1; + return ENCRYPTION_PADDING_RSA_PKCS1; case KeymasterDefs.KM_PAD_RSA_OAEP: - return RSA_OAEP; + return ENCRYPTION_PADDING_RSA_OAEP; default: throw new IllegalArgumentException( "Unsupported encryption padding: " + padding); } } - /** - * @hide - */ - static int[] allToKeymaster(@EncryptionPaddingEnum String[] paddings) { + @NonNull + static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) { if ((paddings == null) || (paddings.length == 0)) { return EmptyArray.INT; } @@ -437,37 +398,34 @@ public abstract class KeyStoreKeyProperties { } } + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) @StringDef({ - SignaturePadding.RSA_PKCS1, - SignaturePadding.RSA_PSS, + SIGNATURE_PADDING_RSA_PKCS1, + SIGNATURE_PADDING_RSA_PSS, }) public @interface SignaturePaddingEnum {} /** - * Padding schemes for signing/verification. + * RSA PKCS#1 v1.5 padding for signatures. */ - public static abstract class SignaturePadding { - private SignaturePadding() {} + public static final String SIGNATURE_PADDING_RSA_PKCS1 = "PKCS1"; - /** - * RSA PKCS#1 v1.5 padding for signatures. - */ - public static final String RSA_PKCS1 = "PKCS1"; + /** + * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding. + */ + public static final String SIGNATURE_PADDING_RSA_PSS = "PSS"; - /** - * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding. - */ - public static final String RSA_PSS = "PSS"; + static abstract class SignaturePadding { + private SignaturePadding() {} - /** - * @hide - */ - static int toKeymaster(@SignaturePaddingEnum String padding) { + static int toKeymaster(@NonNull @SignaturePaddingEnum String padding) { switch (padding.toUpperCase(Locale.US)) { - case RSA_PKCS1: + case SIGNATURE_PADDING_RSA_PKCS1: return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN; - case RSA_PSS: + case SIGNATURE_PADDING_RSA_PSS: return KeymasterDefs.KM_PAD_RSA_PSS; default: throw new IllegalArgumentException( @@ -475,24 +433,20 @@ public abstract class KeyStoreKeyProperties { } } - /** - * @hide - */ + @NonNull static @SignaturePaddingEnum String fromKeymaster(int padding) { switch (padding) { case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN: - return RSA_PKCS1; + return SIGNATURE_PADDING_RSA_PKCS1; case KeymasterDefs.KM_PAD_RSA_PSS: - return RSA_PSS; + return SIGNATURE_PADDING_RSA_PSS; default: throw new IllegalArgumentException("Unsupported signature padding: " + padding); } } - /** - * @hide - */ - static int[] allToKeymaster(@SignaturePaddingEnum String[] paddings) { + @NonNull + static int[] allToKeymaster(@Nullable @SignaturePaddingEnum String[] paddings) { if ((paddings == null) || (paddings.length == 0)) { return EmptyArray.INT; } @@ -504,112 +458,104 @@ public abstract class KeyStoreKeyProperties { } } + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) @StringDef({ - Digest.NONE, - Digest.MD5, - Digest.SHA1, - Digest.SHA224, - Digest.SHA256, - Digest.SHA384, - Digest.SHA512, + 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). + * No digest: sign/authenticate the raw message. */ - public static abstract class Digest { - private Digest() {} + public static final String DIGEST_NONE = "NONE"; - /** - * No digest: sign/authenticate the raw message. - */ - public static final String NONE = "NONE"; + /** + * MD5 digest. + */ + public static final String DIGEST_MD5 = "MD5"; - /** - * MD5 digest. - */ - public static final String MD5 = "MD5"; + /** + * SHA-1 digest. + */ + public static final String DIGEST_SHA1 = "SHA-1"; - /** - * SHA-1 digest. - */ - public static final String SHA1 = "SHA-1"; + /** + * SHA-2 224 (aka SHA-224) digest. + */ + public static final String DIGEST_SHA224 = "SHA-224"; - /** - * SHA-2 224 (aka SHA-224) digest. - */ - public static final String SHA224 = "SHA-224"; + /** + * SHA-2 256 (aka SHA-256) digest. + */ + public static final String DIGEST_SHA256 = "SHA-256"; - /** - * SHA-2 256 (aka SHA-256) digest. - */ - public static final String SHA256 = "SHA-256"; + /** + * SHA-2 384 (aka SHA-384) digest. + */ + public static final String DIGEST_SHA384 = "SHA-384"; - /** - * SHA-2 384 (aka SHA-384) digest. - */ - public static final String SHA384 = "SHA-384"; + /** + * SHA-2 512 (aka SHA-512) digest. + */ + public static final String DIGEST_SHA512 = "SHA-512"; - /** - * SHA-2 512 (aka SHA-512) digest. - */ - public static final String SHA512 = "SHA-512"; + static abstract class Digest { + private Digest() {} - /** - * @hide - */ - static int toKeymaster(@DigestEnum String digest) { + static int toKeymaster(@NonNull @DigestEnum String digest) { switch (digest.toUpperCase(Locale.US)) { - case SHA1: + case DIGEST_SHA1: return KeymasterDefs.KM_DIGEST_SHA1; - case SHA224: + case DIGEST_SHA224: return KeymasterDefs.KM_DIGEST_SHA_2_224; - case SHA256: + case DIGEST_SHA256: return KeymasterDefs.KM_DIGEST_SHA_2_256; - case SHA384: + case DIGEST_SHA384: return KeymasterDefs.KM_DIGEST_SHA_2_384; - case SHA512: + case DIGEST_SHA512: return KeymasterDefs.KM_DIGEST_SHA_2_512; - case NONE: + case DIGEST_NONE: return KeymasterDefs.KM_DIGEST_NONE; - case MD5: + case DIGEST_MD5: return KeymasterDefs.KM_DIGEST_MD5; default: throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); } } - /** - * @hide - */ + @NonNull static @DigestEnum String fromKeymaster(int digest) { switch (digest) { case KeymasterDefs.KM_DIGEST_NONE: - return NONE; + return DIGEST_NONE; case KeymasterDefs.KM_DIGEST_MD5: - return MD5; + return DIGEST_MD5; case KeymasterDefs.KM_DIGEST_SHA1: - return SHA1; + return DIGEST_SHA1; case KeymasterDefs.KM_DIGEST_SHA_2_224: - return SHA224; + return DIGEST_SHA224; case KeymasterDefs.KM_DIGEST_SHA_2_256: - return SHA256; + return DIGEST_SHA256; case KeymasterDefs.KM_DIGEST_SHA_2_384: - return SHA384; + return DIGEST_SHA384; case KeymasterDefs.KM_DIGEST_SHA_2_512: - return SHA512; + return DIGEST_SHA512; default: throw new IllegalArgumentException("Unsupported digest algorithm: " + digest); } } - /** - * @hide - */ - static @DigestEnum String[] allFromKeymaster(Collection<Integer> digests) { + @NonNull + static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) { if (digests.isEmpty()) { return EmptyArray.STRING; } @@ -622,10 +568,8 @@ public abstract class KeyStoreKeyProperties { return result; } - /** - * @hide - */ - static int[] allToKeymaster(@DigestEnum String[] digests) { + @NonNull + static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) { if ((digests == null) || (digests.length == 0)) { return EmptyArray.INT; } @@ -639,39 +583,40 @@ public abstract class KeyStoreKeyProperties { } } + /** + * @hide + */ @Retention(RetentionPolicy.SOURCE) - @IntDef({Origin.GENERATED, Origin.IMPORTED, Origin.UNKNOWN}) + @IntDef({ + ORIGIN_GENERATED, + ORIGIN_IMPORTED, + ORIGIN_UNKNOWN, + }) public @interface OriginEnum {} - /** - * Origin of the key. - */ - public static abstract class Origin { - private Origin() {} + /** Key was generated inside AndroidKeyStore. */ + public static final int ORIGIN_GENERATED = 1 << 0; - /** Key was generated inside AndroidKeyStore. */ - public static final int GENERATED = 1 << 0; + /** Key was imported into AndroidKeyStore. */ + public static final int ORIGIN_IMPORTED = 1 << 1; - /** Key was imported into AndroidKeyStore. */ - public static final int IMPORTED = 1 << 1; + /** + * Origin of the key is unknown. This can occur only for keys backed by an old TEE-backed + * implementation which does not record origin information. + */ + public static final int ORIGIN_UNKNOWN = 1 << 2; - /** - * Origin of the key is unknown. This can occur only for keys backed by an old TEE-backed - * implementation which does not record origin information. - */ - public static final int UNKNOWN = 1 << 2; + static abstract class Origin { + private Origin() {} - /** - * @hide - */ - public static @OriginEnum int fromKeymaster(int origin) { + static @OriginEnum int fromKeymaster(int origin) { switch (origin) { case KeymasterDefs.KM_ORIGIN_GENERATED: - return GENERATED; + return ORIGIN_GENERATED; case KeymasterDefs.KM_ORIGIN_IMPORTED: - return IMPORTED; + return ORIGIN_IMPORTED; case KeymasterDefs.KM_ORIGIN_UNKNOWN: - return UNKNOWN; + return ORIGIN_UNKNOWN; default: throw new IllegalArgumentException("Unknown origin: " + origin); } diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java index 0a9acbb..4c43f89 100644 --- a/keystore/java/android/security/KeyStoreKeySpec.java +++ b/keystore/java/android/security/KeyStoreKeySpec.java @@ -16,6 +16,9 @@ package android.security; +import android.annotation.NonNull; +import android.annotation.Nullable; + import java.security.PrivateKey; import java.security.spec.KeySpec; import java.util.Date; @@ -132,7 +135,7 @@ public class KeyStoreKeySpec implements KeySpec { } /** - * Gets the origin of the key. + * Gets the origin of the key. See {@link KeyStoreKeyProperties}.{@code ORIGIN} constants. */ public @KeyStoreKeyProperties.OriginEnum int getOrigin() { return mOrigin; @@ -150,6 +153,7 @@ public class KeyStoreKeySpec implements KeySpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityStart() { return mKeyValidityStart; } @@ -159,6 +163,7 @@ public class KeyStoreKeySpec implements KeySpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForConsumptionEnd() { return mKeyValidityForConsumptionEnd; } @@ -168,41 +173,64 @@ public class KeyStoreKeySpec implements KeySpec { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForOriginationEnd() { return mKeyValidityForOriginationEnd; } /** - * Gets the set of purposes for which the key can be used. + * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { return mPurposes; } /** - * Gets the set of block modes with which the key can be used. + * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * when encrypting/decrypting. Attempts to use the key with any other block modes will be + * rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() { return ArrayUtils.cloneIfNotEmpty(mBlockModes); } /** - * Gets the set of padding modes with which the key can be used when encrypting/decrypting. + * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code PKCS1Padding}, + * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use + * the key with any other padding scheme will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() { return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); } /** - * Gets the set of padding modes with which the key can be used when signing/verifying. + * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key + * can be used when signing/verifying. Attempts to use the key with any other padding scheme + * will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() { return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings); } /** - * Gets the set of digest algorithms with which the key can be used. + * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key + * can be used. + * + * @see KeyStoreKeyProperties.Digest */ + @NonNull public @KeyStoreKeyProperties.DigestEnum String[] getDigests() { return ArrayUtils.cloneIfNotEmpty(mDigests); } diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java index 7332332..a7fab80 100644 --- a/keystore/java/android/security/KeyStoreParameter.java +++ b/keystore/java/android/security/KeyStoreParameter.java @@ -16,6 +16,9 @@ package android.security; +import android.annotation.IntRange; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; @@ -59,11 +62,11 @@ import javax.crypto.Cipher; * "key1", * new KeyStore.SecretKeyEntry(key), * new KeyStoreParameter.Builder(context) - * .setPurposes(KeyStoreKeyProperties.Purpose.ENCRYPT - * | KeyStoreKeyProperties.Purpose.DECRYPT) - * .setBlockMode(KeyStoreKeyProperties.BlockMode.CBC) + * .setPurposes(KeyStoreKeyProperties.PURPOSE_ENCRYPT + * | KeyStoreKeyProperties.PURPOSE_DECRYPT) + * .setBlockMode(KeyStoreKeyProperties.BLOCK_MODE_CBC) * .setEncryptionPaddings( - * KeyStoreKeyProperties.EncryptionPaddings.PKCS7) + * KeyStoreKeyProperties.ENCRYPTION_PADDING_PKCS7) * .build()); * // Key imported, obtain a reference to it. * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null); @@ -87,8 +90,8 @@ import javax.crypto.Cipher; * "key2", * new KeyStore.PrivateKeyEntry(privateKey, certChain), * new KeyStoreParameter.Builder(context) - * .setPurposes(KeyStoreKeyProperties.Purpose.SIGN) - * .setDigests(KeyStoreKeyProperties.Digest.SHA256) + * .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN) + * .setDigests(KeyStoreKeyProperties.DIGEST_SHA256) * // Only permit this key to be used if the user * // authenticated within the last ten minutes. * .setUserAuthenticationRequired(true) @@ -182,6 +185,7 @@ public final class KeyStoreParameter implements ProtectionParameter { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityStart() { return mKeyValidityStart; } @@ -191,6 +195,7 @@ public final class KeyStoreParameter implements ProtectionParameter { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForConsumptionEnd() { return mKeyValidityForConsumptionEnd; } @@ -200,39 +205,55 @@ public final class KeyStoreParameter implements ProtectionParameter { * * @return instant or {@code null} if not restricted. */ + @Nullable public Date getKeyValidityForOriginationEnd() { return mKeyValidityForOriginationEnd; } /** - * Gets the set of purposes for which the key can be used. + * Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { return mPurposes; } /** - * Gets the set of padding schemes with which the key can be used when encrypting/decrypting. + * Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code PKCS1Padding}, + * {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use + * the key with any other padding scheme will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() { return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); } /** - * Gets the set of padding schemes with which the key can be used when signing or verifying - * signatures. + * Gets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key + * can be used when signing/verifying. Attempts to use the key with any other padding scheme + * will be rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. */ + @NonNull public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() { return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings); } /** - * Gets the set of digest algorithms with which the key can be used. + * Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key + * can be used. * * @throws IllegalStateException if this set has not been specified. * * @see #isDigestsSpecified() + * @see KeyStoreKeyProperties.Digest */ + @NonNull public @KeyStoreKeyProperties.DigestEnum String[] getDigests() { if (mDigests == null) { throw new IllegalStateException("Digests not specified"); @@ -246,13 +267,19 @@ public final class KeyStoreParameter implements ProtectionParameter { * * @see #getDigests() */ + @NonNull public boolean isDigestsSpecified() { return mDigests != null; } /** - * Gets the set of block modes with which the key can be used. + * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * when encrypting/decrypting. Attempts to use the key with any other block modes will be + * rejected. + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() { return ArrayUtils.cloneIfNotEmpty(mBlockModes); } @@ -330,7 +357,7 @@ public final class KeyStoreParameter implements ProtectionParameter { * some UI to ask the user to unlock or initialize the Android KeyStore * facility. */ - public Builder(Context context) { + public Builder(@NonNull Context context) { if (context == null) { throw new NullPointerException("context == null"); } @@ -350,6 +377,7 @@ public final class KeyStoreParameter implements ProtectionParameter { * * @see KeyguardManager#isDeviceSecure() */ + @NonNull public Builder setEncryptionRequired(boolean required) { if (required) { mFlags |= KeyStore.FLAG_ENCRYPTED; @@ -364,10 +392,11 @@ public final class KeyStoreParameter implements ProtectionParameter { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> * * @see #setKeyValidityEnd(Date) */ + @NonNull public Builder setKeyValidityStart(Date startDate) { mKeyValidityStart = startDate; return this; @@ -378,12 +407,13 @@ public final class KeyStoreParameter implements ProtectionParameter { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> * * @see #setKeyValidityStart(Date) * @see #setKeyValidityForConsumptionEnd(Date) * @see #setKeyValidityForOriginationEnd(Date) */ + @NonNull public Builder setKeyValidityEnd(Date endDate) { setKeyValidityForOriginationEnd(endDate); setKeyValidityForConsumptionEnd(endDate); @@ -395,10 +425,11 @@ public final class KeyStoreParameter implements ProtectionParameter { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> * * @see #setKeyValidityForConsumptionEnd(Date) */ + @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { mKeyValidityForOriginationEnd = endDate; return this; @@ -410,36 +441,44 @@ public final class KeyStoreParameter implements ProtectionParameter { * * <p>By default, the key is valid at any instant. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> * * @see #setKeyValidityForOriginationEnd(Date) */ + @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { mKeyValidityForConsumptionEnd = endDate; return this; } /** - * Sets the set of purposes for which the key can be used. + * Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used. + * Attempts to use the key for any other purpose will be rejected. * * <p>This must be specified for all keys. There is no default. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. */ + @NonNull public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { mPurposes = purposes; return this; } /** - * 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. + * Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS7Padding}, + * {@code NoPadding}) 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 must be specified for keys which are used for encryption/decryption. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. */ + @NonNull public Builder setEncryptionPaddings( @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) { mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); @@ -447,14 +486,17 @@ public final class KeyStoreParameter implements ProtectionParameter { } /** - * 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. + * Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) 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 must be specified for RSA keys which are used for signing/verification. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. */ + @NonNull public Builder setSignaturePaddings( @KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) { mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings); @@ -463,27 +505,36 @@ public final class KeyStoreParameter implements ProtectionParameter { /** - * 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. + * Sets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the + * key can be used when signing/verifying or generating MACs. Attempts to use the key with + * any other digest algorithm 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. + * <p>For HMAC keys, the default is the digest algorithm specified in + * {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms + * must be specified. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> + * + * @see KeyStoreKeyProperties.Digest */ + @NonNull public Builder setDigests(@KeyStoreKeyProperties.DigestEnum String... digests) { mDigests = ArrayUtils.cloneIfNotEmpty(digests); 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. + * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}, {@code ECB}) 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. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> + * + * <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. */ + @NonNull public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) { mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); return this; @@ -523,8 +574,9 @@ public final class KeyStoreParameter implements ProtectionParameter { * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li> * </ul> * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> */ + @NonNull public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; @@ -543,10 +595,11 @@ public final class KeyStoreParameter implements ProtectionParameter { * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More * information</a>. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> * * @see #setUserAuthenticationValidityDurationSeconds(int) */ + @NonNull public Builder setUserAuthenticationRequired(boolean required) { mUserAuthenticationRequired = required; return this; @@ -558,14 +611,16 @@ public final class KeyStoreParameter implements ProtectionParameter { * * <p>By default, the user needs to authenticate for every use of the key. * - * <p><b>NOTE: This has currently no effect on asymmetric key pairs. + * <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b> * * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for * every use of the key. * * @see #setUserAuthenticationRequired(boolean) */ - public Builder setUserAuthenticationValidityDurationSeconds(int seconds) { + @NonNull + public Builder setUserAuthenticationValidityDurationSeconds( + @IntRange(from = -1) int seconds) { mUserAuthenticationValidityDurationSeconds = seconds; return this; } @@ -576,6 +631,7 @@ public final class KeyStoreParameter implements ProtectionParameter { * @throws IllegalArgumentException if a required field is missing * @return built instance of {@code KeyStoreParameter} */ + @NonNull public KeyStoreParameter build() { return new KeyStoreParameter( mContext, |
