From 3f8d4d840894468f2be8a5b56ff266cef2d71c50 Mon Sep 17 00:00:00 2001 From: Alex Klyubin Date: Wed, 13 May 2015 09:15:00 -0700 Subject: [PATCH] New AndroidKeyStore API in android.security.keystore. This CL addresses the comments from API Council about Android KeyStore KeyPairGeneratorSpec, KeyGeneratorSpec and KeyStoreParameter: 1. These abstractions should not take or hold references to Context. 2. The Builders of these abstractions should take all mandatory parameters in their constructors rather than expose them as setters -- only optional paratemers should be exposed via setters. These comments cannot be addressed without deprecation in the already launched KeyPairGeneratorSpec and KeyStoreParameter. Instead of deprecating just the getContext methods and Builder constructors, this CL goes for the nuclear option of deprecating KeyPairGeneratorSpec and KeyStoreParameter as a whole and exposing all of the AndroidKeyStore API in the new package android.security.keystore. This enables this CL to correct all of the accrued design issues with KeyPairGeneratorSpec (e.g., naming of certificate-related methods) and KeyStoreParameter. This also makes the transition to API Level M more clear for existing users of the AndroidKeyStore API. These users will only have to deal with the new always-mandatory parameters (e.g., purposes) and sometimes-mandatory (e.g., digests, block modes, paddings) if they switch to the new API. Prior to this CL they would've had to deal with this if they invoked any of the new methods of KeyPairGeneratorSpec or KeyStoreParameter introduced in API Level M. This CL rips out all the new API introduced into KeyPairGeneratorSpec and KeyStoreParameter classes for Android M, thus reverting these classes to the API launched in L MR1. This is because the new API is now in android.security.keystore.KeyGenParameterSpec and KeyProtection respectively. Bug: 21039983 Change-Id: I59672b3c6ef7bc25c40aa85f1c47d9d8a05d627c --- api/current.txt | 226 ++--- api/system-current.txt | 226 ++--- docs/html/training/articles/keystore.jd | 2 +- .../security/AndroidKeyPairGenerator.java | 143 ++- .../android/security/AndroidKeyStore.java | 123 ++- .../java/android/security/ArrayUtils.java | 2 +- keystore/java/android/security/KeyChain.java | 14 +- .../security/KeyPairGeneratorSpec.java | 630 ++----------- keystore/java/android/security/KeyStore.java | 15 +- .../android/security/KeyStoreCipherSpi.java | 3 +- .../KeyStoreCryptoOperationUtils.java | 1 + .../security/KeyStoreKeyGeneratorSpi.java | 100 +- .../android/security/KeyStoreParameter.java | 556 +----------- .../security/KeyStoreSecretKeyFactorySpi.java | 29 +- .../java/android/security/KeymasterUtils.java | 4 +- .../{ => keystore}/KeyExpiredException.java | 2 +- .../keystore/KeyGenParameterSpec.java | 857 ++++++++++++++++++ .../KeyInfo.java} | 73 +- .../KeyNotYetValidException.java | 2 +- .../KeyPermanentlyInvalidatedException.java | 2 +- .../KeyProperties.java} | 78 +- .../KeyProtection.java} | 425 +++++---- .../UserNotAuthenticatedException.java | 2 +- .../security/KeyPairGeneratorSpecTest.java | 56 +- .../src/android/security/KeyStoreTest.java | 1 - 25 files changed, 1854 insertions(+), 1718 deletions(-) rename keystore/java/android/security/{ => keystore}/KeyExpiredException.java (97%) create mode 100644 keystore/java/android/security/keystore/KeyGenParameterSpec.java rename keystore/java/android/security/{KeyStoreKeySpec.java => keystore/KeyInfo.java} (76%) rename keystore/java/android/security/{ => keystore}/KeyNotYetValidException.java (97%) rename keystore/java/android/security/{ => keystore}/KeyPermanentlyInvalidatedException.java (98%) rename keystore/java/android/security/{KeyStoreKeyProperties.java => keystore/KeyProperties.java} (90%) rename keystore/java/android/security/{KeyGeneratorSpec.java => keystore/KeyProtection.java} (52%) rename keystore/java/android/security/{ => keystore}/UserNotAuthenticatedException.java (97%) diff --git a/api/current.txt b/api/current.txt index d7b598239a97f..06bc66d23fa11 100644 --- a/api/current.txt +++ b/api/current.txt @@ -28354,15 +28354,67 @@ package android.security { ctor public KeyChainException(java.lang.Throwable); } + public final deprecated class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec { + method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); + method public android.content.Context getContext(); + method public java.util.Date getEndDate(); + method public int getKeySize(); + method public java.lang.String getKeyType(); + method public java.lang.String getKeystoreAlias(); + method public java.math.BigInteger getSerialNumber(); + method public java.util.Date getStartDate(); + method public javax.security.auth.x500.X500Principal getSubjectDN(); + method public boolean isEncryptionRequired(); + } + + public static final deprecated class KeyPairGeneratorSpec.Builder { + ctor public KeyPairGeneratorSpec.Builder(android.content.Context); + method public android.security.KeyPairGeneratorSpec build(); + method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec); + method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String); + method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired(); + method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date); + method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int); + method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException; + method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger); + method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date); + method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal); + } + + public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { + method public android.content.Context getContext(); + method public boolean isEncryptionRequired(); + } + + public static final deprecated class KeyStoreParameter.Builder { + ctor public KeyStoreParameter.Builder(android.content.Context); + method public android.security.KeyStoreParameter build(); + method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean); + } + + public class NetworkSecurityPolicy { + method public static android.security.NetworkSecurityPolicy getInstance(); + method public boolean isCleartextTrafficPermitted(); + } + +} + +package android.security.keystore { + public class KeyExpiredException extends java.security.InvalidKeyException { ctor public KeyExpiredException(); ctor public KeyExpiredException(java.lang.String); ctor public KeyExpiredException(java.lang.String, java.lang.Throwable); } - public class KeyGeneratorSpec implements java.security.spec.AlgorithmParameterSpec { + public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec { + method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); method public java.lang.String[] getBlockModes(); - method public android.content.Context getContext(); + method public java.util.Date getCertificateNotAfter(); + method public java.util.Date getCertificateNotBefore(); + method public java.math.BigInteger getCertificateSerialNumber(); + method public javax.security.auth.x500.X500Principal getCertificateSubject(); + method public java.lang.String[] getDigests(); method public java.lang.String[] getEncryptionPaddings(); method public int getKeySize(); method public java.util.Date getKeyValidityForConsumptionEnd(); @@ -28370,28 +28422,53 @@ package android.security { method public java.util.Date getKeyValidityStart(); method public java.lang.String getKeystoreAlias(); method public int getPurposes(); + method public java.lang.String[] getSignaturePaddings(); method public int getUserAuthenticationValidityDurationSeconds(); - method public boolean isEncryptionRequired(); + method public boolean isDigestsSpecified(); + method public boolean isEncryptionAtRestRequired(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); } - public static class KeyGeneratorSpec.Builder { - ctor public KeyGeneratorSpec.Builder(android.content.Context); - method public android.security.KeyGeneratorSpec build(); - method public android.security.KeyGeneratorSpec.Builder setAlias(java.lang.String); - method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...); - method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); - method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(); - method public android.security.KeyGeneratorSpec.Builder setKeySize(int); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setPurposes(int); - method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean); - method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean); - method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); + public static final class KeyGenParameterSpec.Builder { + ctor public KeyGenParameterSpec.Builder(java.lang.String, int); + method public android.security.keystore.KeyGenParameterSpec build(); + method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec); + method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(java.math.BigInteger); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal); + method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionAtRestRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int); + } + + public class KeyInfo implements java.security.spec.KeySpec { + method public java.lang.String[] getBlockModes(); + method public java.lang.String[] getDigests(); + method public java.lang.String[] getEncryptionPaddings(); + method public int getKeySize(); + method public java.util.Date getKeyValidityForConsumptionEnd(); + method public java.util.Date getKeyValidityForOriginationEnd(); + method public java.util.Date getKeyValidityStart(); + method public java.lang.String getKeystoreAlias(); + method public int getOrigin(); + method public int getPurposes(); + method public java.lang.String[] getSignaturePaddings(); + method public int getUserAuthenticationValidityDurationSeconds(); + method public boolean isInsideSecureHardware(); + method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -28400,63 +28477,13 @@ package android.security { ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable); } - public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec { - method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); - method public java.lang.String[] getBlockModes(); - method public android.content.Context getContext(); - method public java.lang.String[] getDigests(); - method public java.lang.String[] getEncryptionPaddings(); - method public java.util.Date getEndDate(); - method public int getKeySize(); - method public java.lang.String getKeyType(); - method public java.util.Date getKeyValidityForConsumptionEnd(); - method public java.util.Date getKeyValidityForOriginationEnd(); - method public java.util.Date getKeyValidityStart(); - method public java.lang.String getKeystoreAlias(); - method public int getPurposes(); - method public java.math.BigInteger getSerialNumber(); - method public java.lang.String[] getSignaturePaddings(); - method public java.util.Date getStartDate(); - method public javax.security.auth.x500.X500Principal getSubjectDN(); - method public int getUserAuthenticationValidityDurationSeconds(); - method public boolean isEncryptionRequired(); - method public boolean isRandomizedEncryptionRequired(); - method public boolean isUserAuthenticationRequired(); - } - - public static final class KeyPairGeneratorSpec.Builder { - ctor public KeyPairGeneratorSpec.Builder(android.content.Context); - method public android.security.KeyPairGeneratorSpec build(); - method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec); - method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String); - method public android.security.KeyPairGeneratorSpec.Builder setBlockModes(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setDigests(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired(); - method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int); - method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException; - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityStart(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setPurposes(int); - method public android.security.KeyPairGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean); - method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger); - method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal); - method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean); - method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); - } - public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException { ctor public KeyPermanentlyInvalidatedException(); ctor public KeyPermanentlyInvalidatedException(java.lang.String); ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable); } - public abstract class KeyStoreKeyProperties { + public abstract class KeyProperties { field public static final java.lang.String BLOCK_MODE_CBC = "CBC"; field public static final java.lang.String BLOCK_MODE_CTR = "CTR"; field public static final java.lang.String BLOCK_MODE_ECB = "ECB"; @@ -28491,29 +28518,10 @@ package android.security { field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS"; } - public class KeyStoreKeySpec implements java.security.spec.KeySpec { + public final class KeyProtection implements java.security.KeyStore.ProtectionParameter { method public java.lang.String[] getBlockModes(); method public java.lang.String[] getDigests(); method public java.lang.String[] getEncryptionPaddings(); - method public int getKeySize(); - method public java.util.Date getKeyValidityForConsumptionEnd(); - method public java.util.Date getKeyValidityForOriginationEnd(); - method public java.util.Date getKeyValidityStart(); - method public java.lang.String getKeystoreAlias(); - method public int getOrigin(); - method public int getPurposes(); - method public java.lang.String[] getSignaturePaddings(); - method public int getUserAuthenticationValidityDurationSeconds(); - method public boolean isInsideSecureHardware(); - method public boolean isUserAuthenticationRequired(); - method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); - } - - public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { - method public java.lang.String[] getBlockModes(); - method public android.content.Context getContext(); - method public java.lang.String[] getDigests(); - method public java.lang.String[] getEncryptionPaddings(); method public java.util.Date getKeyValidityForConsumptionEnd(); method public java.util.Date getKeyValidityForOriginationEnd(); method public java.util.Date getKeyValidityStart(); @@ -28521,32 +28529,26 @@ package android.security { method public java.lang.String[] getSignaturePaddings(); method public int getUserAuthenticationValidityDurationSeconds(); method public boolean isDigestsSpecified(); - method public boolean isEncryptionRequired(); + method public boolean isEncryptionAtRestRequired(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); } - public static final class KeyStoreParameter.Builder { - ctor public KeyStoreParameter.Builder(android.content.Context); - method public android.security.KeyStoreParameter build(); - method public android.security.KeyStoreParameter.Builder setBlockModes(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean); - method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date); - method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date); - method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date); - method public android.security.KeyStoreParameter.Builder setKeyValidityStart(java.util.Date); - method public android.security.KeyStoreParameter.Builder setPurposes(int); - method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean); - method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean); - method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int); - } - - public class NetworkSecurityPolicy { - method public static android.security.NetworkSecurityPolicy getInstance(); - method public boolean isCleartextTrafficPermitted(); + public static final class KeyProtection.Builder { + ctor public KeyProtection.Builder(int); + method public android.security.keystore.KeyProtection build(); + method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setEncryptionAtRestRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } public class UserNotAuthenticatedException extends java.security.InvalidKeyException { diff --git a/api/system-current.txt b/api/system-current.txt index 832895cc1c5b9..64793bc229943 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -30379,15 +30379,67 @@ package android.security { ctor public KeyChainException(java.lang.Throwable); } + public final deprecated class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec { + method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); + method public android.content.Context getContext(); + method public java.util.Date getEndDate(); + method public int getKeySize(); + method public java.lang.String getKeyType(); + method public java.lang.String getKeystoreAlias(); + method public java.math.BigInteger getSerialNumber(); + method public java.util.Date getStartDate(); + method public javax.security.auth.x500.X500Principal getSubjectDN(); + method public boolean isEncryptionRequired(); + } + + public static final deprecated class KeyPairGeneratorSpec.Builder { + ctor public KeyPairGeneratorSpec.Builder(android.content.Context); + method public android.security.KeyPairGeneratorSpec build(); + method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec); + method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String); + method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired(); + method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date); + method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int); + method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException; + method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger); + method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date); + method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal); + } + + public final deprecated class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { + method public android.content.Context getContext(); + method public boolean isEncryptionRequired(); + } + + public static final deprecated class KeyStoreParameter.Builder { + ctor public KeyStoreParameter.Builder(android.content.Context); + method public android.security.KeyStoreParameter build(); + method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean); + } + + public class NetworkSecurityPolicy { + method public static android.security.NetworkSecurityPolicy getInstance(); + method public boolean isCleartextTrafficPermitted(); + } + +} + +package android.security.keystore { + public class KeyExpiredException extends java.security.InvalidKeyException { ctor public KeyExpiredException(); ctor public KeyExpiredException(java.lang.String); ctor public KeyExpiredException(java.lang.String, java.lang.Throwable); } - public class KeyGeneratorSpec implements java.security.spec.AlgorithmParameterSpec { + public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec { + method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); method public java.lang.String[] getBlockModes(); - method public android.content.Context getContext(); + method public java.util.Date getCertificateNotAfter(); + method public java.util.Date getCertificateNotBefore(); + method public java.math.BigInteger getCertificateSerialNumber(); + method public javax.security.auth.x500.X500Principal getCertificateSubject(); + method public java.lang.String[] getDigests(); method public java.lang.String[] getEncryptionPaddings(); method public int getKeySize(); method public java.util.Date getKeyValidityForConsumptionEnd(); @@ -30395,28 +30447,53 @@ package android.security { method public java.util.Date getKeyValidityStart(); method public java.lang.String getKeystoreAlias(); method public int getPurposes(); + method public java.lang.String[] getSignaturePaddings(); method public int getUserAuthenticationValidityDurationSeconds(); - method public boolean isEncryptionRequired(); + method public boolean isDigestsSpecified(); + method public boolean isEncryptionAtRestRequired(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); } - public static class KeyGeneratorSpec.Builder { - ctor public KeyGeneratorSpec.Builder(android.content.Context); - method public android.security.KeyGeneratorSpec build(); - method public android.security.KeyGeneratorSpec.Builder setAlias(java.lang.String); - method public android.security.KeyGeneratorSpec.Builder setBlockModes(java.lang.String...); - method public android.security.KeyGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); - method public android.security.KeyGeneratorSpec.Builder setEncryptionRequired(); - method public android.security.KeyGeneratorSpec.Builder setKeySize(int); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setKeyValidityStart(java.util.Date); - method public android.security.KeyGeneratorSpec.Builder setPurposes(int); - method public android.security.KeyGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean); - method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationRequired(boolean); - method public android.security.KeyGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); + public static final class KeyGenParameterSpec.Builder { + ctor public KeyGenParameterSpec.Builder(java.lang.String, int); + method public android.security.keystore.KeyGenParameterSpec build(); + method public android.security.keystore.KeyGenParameterSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec); + method public android.security.keystore.KeyGenParameterSpec.Builder setBlockModes(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotAfter(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateNotBefore(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSerialNumber(java.math.BigInteger); + method public android.security.keystore.KeyGenParameterSpec.Builder setCertificateSubject(javax.security.auth.x500.X500Principal); + method public android.security.keystore.KeyGenParameterSpec.Builder setDigests(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionAtRestRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setEncryptionPaddings(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeySize(int); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityEnd(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setKeyValidityStart(java.util.Date); + method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int); + } + + public class KeyInfo implements java.security.spec.KeySpec { + method public java.lang.String[] getBlockModes(); + method public java.lang.String[] getDigests(); + method public java.lang.String[] getEncryptionPaddings(); + method public int getKeySize(); + method public java.util.Date getKeyValidityForConsumptionEnd(); + method public java.util.Date getKeyValidityForOriginationEnd(); + method public java.util.Date getKeyValidityStart(); + method public java.lang.String getKeystoreAlias(); + method public int getOrigin(); + method public int getPurposes(); + method public java.lang.String[] getSignaturePaddings(); + method public int getUserAuthenticationValidityDurationSeconds(); + method public boolean isInsideSecureHardware(); + method public boolean isUserAuthenticationRequired(); + method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); } public class KeyNotYetValidException extends java.security.InvalidKeyException { @@ -30425,63 +30502,13 @@ package android.security { ctor public KeyNotYetValidException(java.lang.String, java.lang.Throwable); } - public final class KeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec { - method public java.security.spec.AlgorithmParameterSpec getAlgorithmParameterSpec(); - method public java.lang.String[] getBlockModes(); - method public android.content.Context getContext(); - method public java.lang.String[] getDigests(); - method public java.lang.String[] getEncryptionPaddings(); - method public java.util.Date getEndDate(); - method public int getKeySize(); - method public java.lang.String getKeyType(); - method public java.util.Date getKeyValidityForConsumptionEnd(); - method public java.util.Date getKeyValidityForOriginationEnd(); - method public java.util.Date getKeyValidityStart(); - method public java.lang.String getKeystoreAlias(); - method public int getPurposes(); - method public java.math.BigInteger getSerialNumber(); - method public java.lang.String[] getSignaturePaddings(); - method public java.util.Date getStartDate(); - method public javax.security.auth.x500.X500Principal getSubjectDN(); - method public int getUserAuthenticationValidityDurationSeconds(); - method public boolean isEncryptionRequired(); - method public boolean isRandomizedEncryptionRequired(); - method public boolean isUserAuthenticationRequired(); - } - - public static final class KeyPairGeneratorSpec.Builder { - ctor public KeyPairGeneratorSpec.Builder(android.content.Context); - method public android.security.KeyPairGeneratorSpec build(); - method public android.security.KeyPairGeneratorSpec.Builder setAlgorithmParameterSpec(java.security.spec.AlgorithmParameterSpec); - method public android.security.KeyPairGeneratorSpec.Builder setAlias(java.lang.String); - method public android.security.KeyPairGeneratorSpec.Builder setBlockModes(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setDigests(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setEncryptionPaddings(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setEncryptionRequired(); - method public android.security.KeyPairGeneratorSpec.Builder setEndDate(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeySize(int); - method public android.security.KeyPairGeneratorSpec.Builder setKeyType(java.lang.String) throws java.security.NoSuchAlgorithmException; - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityEnd(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForConsumptionEnd(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityForOriginationEnd(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setKeyValidityStart(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setPurposes(int); - method public android.security.KeyPairGeneratorSpec.Builder setRandomizedEncryptionRequired(boolean); - method public android.security.KeyPairGeneratorSpec.Builder setSerialNumber(java.math.BigInteger); - method public android.security.KeyPairGeneratorSpec.Builder setSignaturePaddings(java.lang.String...); - method public android.security.KeyPairGeneratorSpec.Builder setStartDate(java.util.Date); - method public android.security.KeyPairGeneratorSpec.Builder setSubject(javax.security.auth.x500.X500Principal); - method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationRequired(boolean); - method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int); - } - public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException { ctor public KeyPermanentlyInvalidatedException(); ctor public KeyPermanentlyInvalidatedException(java.lang.String); ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable); } - public abstract class KeyStoreKeyProperties { + public abstract class KeyProperties { field public static final java.lang.String BLOCK_MODE_CBC = "CBC"; field public static final java.lang.String BLOCK_MODE_CTR = "CTR"; field public static final java.lang.String BLOCK_MODE_ECB = "ECB"; @@ -30516,29 +30543,10 @@ package android.security { field public static final java.lang.String SIGNATURE_PADDING_RSA_PSS = "PSS"; } - public class KeyStoreKeySpec implements java.security.spec.KeySpec { + public final class KeyProtection implements java.security.KeyStore.ProtectionParameter { method public java.lang.String[] getBlockModes(); method public java.lang.String[] getDigests(); method public java.lang.String[] getEncryptionPaddings(); - method public int getKeySize(); - method public java.util.Date getKeyValidityForConsumptionEnd(); - method public java.util.Date getKeyValidityForOriginationEnd(); - method public java.util.Date getKeyValidityStart(); - method public java.lang.String getKeystoreAlias(); - method public int getOrigin(); - method public int getPurposes(); - method public java.lang.String[] getSignaturePaddings(); - method public int getUserAuthenticationValidityDurationSeconds(); - method public boolean isInsideSecureHardware(); - method public boolean isUserAuthenticationRequired(); - method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware(); - } - - public final class KeyStoreParameter implements java.security.KeyStore.ProtectionParameter { - method public java.lang.String[] getBlockModes(); - method public android.content.Context getContext(); - method public java.lang.String[] getDigests(); - method public java.lang.String[] getEncryptionPaddings(); method public java.util.Date getKeyValidityForConsumptionEnd(); method public java.util.Date getKeyValidityForOriginationEnd(); method public java.util.Date getKeyValidityStart(); @@ -30546,32 +30554,26 @@ package android.security { method public java.lang.String[] getSignaturePaddings(); method public int getUserAuthenticationValidityDurationSeconds(); method public boolean isDigestsSpecified(); - method public boolean isEncryptionRequired(); + method public boolean isEncryptionAtRestRequired(); method public boolean isRandomizedEncryptionRequired(); method public boolean isUserAuthenticationRequired(); } - public static final class KeyStoreParameter.Builder { - ctor public KeyStoreParameter.Builder(android.content.Context); - method public android.security.KeyStoreParameter build(); - method public android.security.KeyStoreParameter.Builder setBlockModes(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setDigests(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setEncryptionPaddings(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setEncryptionRequired(boolean); - method public android.security.KeyStoreParameter.Builder setKeyValidityEnd(java.util.Date); - method public android.security.KeyStoreParameter.Builder setKeyValidityForConsumptionEnd(java.util.Date); - method public android.security.KeyStoreParameter.Builder setKeyValidityForOriginationEnd(java.util.Date); - method public android.security.KeyStoreParameter.Builder setKeyValidityStart(java.util.Date); - method public android.security.KeyStoreParameter.Builder setPurposes(int); - method public android.security.KeyStoreParameter.Builder setRandomizedEncryptionRequired(boolean); - method public android.security.KeyStoreParameter.Builder setSignaturePaddings(java.lang.String...); - method public android.security.KeyStoreParameter.Builder setUserAuthenticationRequired(boolean); - method public android.security.KeyStoreParameter.Builder setUserAuthenticationValidityDurationSeconds(int); - } - - public class NetworkSecurityPolicy { - method public static android.security.NetworkSecurityPolicy getInstance(); - method public boolean isCleartextTrafficPermitted(); + public static final class KeyProtection.Builder { + ctor public KeyProtection.Builder(int); + method public android.security.keystore.KeyProtection build(); + method public android.security.keystore.KeyProtection.Builder setBlockModes(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setDigests(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setEncryptionAtRestRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setEncryptionPaddings(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setKeyValidityEnd(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setKeyValidityForConsumptionEnd(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setKeyValidityForOriginationEnd(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date); + method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean); + method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int); } public class UserNotAuthenticatedException extends java.security.InvalidKeyException { diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd index fea3b2c8a7df1..4005a05efc2b3 100644 --- a/docs/html/training/articles/keystore.jd +++ b/docs/html/training/articles/keystore.jd @@ -88,7 +88,7 @@ and {@link java.security.KeyPairGenerator} or

Generating a New Secret Key

To generate the key, use a {@link javax.crypto.KeyGenerator} with - {@link android.security.KeyGeneratorSpec}. + {@link android.security.keystore.KeyGenParameterSpec}.

Working with Keystore Entries

diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java index ea90ca3998165..e9f83200b270d 100644 --- a/keystore/java/android/security/AndroidKeyPairGenerator.java +++ b/keystore/java/android/security/AndroidKeyPairGenerator.java @@ -16,6 +16,10 @@ package android.security; +import android.annotation.NonNull; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; + import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; import com.android.org.conscrypt.NativeConstants; import com.android.org.conscrypt.OpenSSLEngine; @@ -36,6 +40,7 @@ import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.RSAKeyGenParameterSpec; import java.security.spec.X509EncodedKeySpec; +import java.util.Locale; /** * Provides a way to create instances of a KeyPair which will be placed in the @@ -54,13 +59,13 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { public static class RSA extends AndroidKeyPairGenerator { public RSA() { - super(KeyStoreKeyProperties.KEY_ALGORITHM_RSA); + super(KeyProperties.KEY_ALGORITHM_RSA); } } public static class EC extends AndroidKeyPairGenerator { public EC() { - super(KeyStoreKeyProperties.KEY_ALGORITHM_EC); + super(KeyProperties.KEY_ALGORITHM_EC); } } @@ -80,18 +85,18 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { private final String mAlgorithm; - private android.security.KeyStore mKeyStore; + private KeyStore mKeyStore; - private KeyPairGeneratorSpec mSpec; - private @KeyStoreKeyProperties.KeyAlgorithmEnum String mKeyAlgorithm; + private KeyGenParameterSpec mSpec; + private @KeyProperties.KeyAlgorithmEnum String mKeyAlgorithm; private int mKeyType; private int mKeySize; - protected AndroidKeyPairGenerator(@KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { + protected AndroidKeyPairGenerator(@KeyProperties.KeyAlgorithmEnum String algorithm) { mAlgorithm = algorithm; } - @KeyStoreKeyProperties.KeyAlgorithmEnum String getAlgorithm() { + @KeyProperties.KeyAlgorithmEnum String getAlgorithm() { return mAlgorithm; } @@ -113,15 +118,16 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { @Override public KeyPair generateKeyPair() { if (mKeyStore == null || mSpec == null) { - throw new IllegalStateException( - "Must call initialize with an android.security.KeyPairGeneratorSpec first"); + throw new IllegalStateException("Not initialized"); + } - if (((mSpec.getFlags() & KeyStore.FLAG_ENCRYPTED) != 0) + final int flags = mSpec.getFlags(); + if (((flags & KeyStore.FLAG_ENCRYPTED) != 0) && (mKeyStore.state() != KeyStore.State.UNLOCKED)) { throw new IllegalStateException( - "Android keystore must be in initialized and unlocked state " - + "if encryption is required"); + "Encryption at rest using secure lock screen credential requested for key pair" + + ", but the user has not yet entered the credential"); } final String alias = mSpec.getKeystoreAlias(); @@ -131,8 +137,9 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { byte[][] args = getArgsForKeyType(mKeyType, mSpec.getAlgorithmParameterSpec()); final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; + if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, mKeyType, mKeySize, - mSpec.getFlags(), args)) { + flags, args)) { throw new IllegalStateException("could not generate key in keystore"); } @@ -175,7 +182,7 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { } if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes, KeyStore.UID_SELF, - mSpec.getFlags())) { + flags)) { Credentials.deleteAllTypesForAlias(mKeyStore, alias); throw new IllegalStateException("Can't store certificate in AndroidKeyStore"); } @@ -188,17 +195,17 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { throws Exception { final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); certGen.setPublicKey(publicKey); - certGen.setSerialNumber(mSpec.getSerialNumber()); - certGen.setSubjectDN(mSpec.getSubjectDN()); - certGen.setIssuerDN(mSpec.getSubjectDN()); - certGen.setNotBefore(mSpec.getStartDate()); - certGen.setNotAfter(mSpec.getEndDate()); + certGen.setSerialNumber(mSpec.getCertificateSerialNumber()); + certGen.setSubjectDN(mSpec.getCertificateSubject()); + certGen.setIssuerDN(mSpec.getCertificateSubject()); + certGen.setNotBefore(mSpec.getCertificateNotBefore()); + certGen.setNotAfter(mSpec.getCertificateNotAfter()); certGen.setSignatureAlgorithm(getDefaultSignatureAlgorithmForKeyAlgorithm(mKeyAlgorithm)); return certGen.generate(privateKey); } - private @KeyStoreKeyProperties.KeyAlgorithmEnum String getKeyAlgorithm( - KeyPairGeneratorSpec spec) { + @NonNull + private @KeyProperties.KeyAlgorithmEnum String getKeyAlgorithm(KeyPairGeneratorSpec spec) { String result = spec.getKeyType(); if (result != null) { return result; @@ -250,10 +257,10 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { } private static String getDefaultSignatureAlgorithmForKeyAlgorithm( - @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { - if (KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { + @KeyProperties.KeyAlgorithmEnum String algorithm) { + if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) { return "sha256WithRSA"; - } else if (KeyStoreKeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) { + } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) { return "sha256WithECDSA"; } else { throw new IllegalArgumentException("Unsupported key type " + algorithm); @@ -282,14 +289,86 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { throws InvalidAlgorithmParameterException { if (params == null) { throw new InvalidAlgorithmParameterException( - "must supply params of type android.security.KeyPairGeneratorSpec"); - } else if (!(params instanceof KeyPairGeneratorSpec)) { - throw new InvalidAlgorithmParameterException( - "params must be of type android.security.KeyPairGeneratorSpec"); + "Must supply params of type " + KeyGenParameterSpec.class.getName() + + " or " + KeyPairGeneratorSpec.class.getName()); + } + + String keyAlgorithm; + KeyGenParameterSpec spec; + if (params instanceof KeyPairGeneratorSpec) { + KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params; + try { + KeyGenParameterSpec.Builder specBuilder; + keyAlgorithm = getKeyAlgorithm(legacySpec).toUpperCase(Locale.US); + if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) { + specBuilder = new KeyGenParameterSpec.Builder( + legacySpec.getKeystoreAlias(), + KeyProperties.PURPOSE_SIGN + | KeyProperties.PURPOSE_VERIFY); + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_MD5, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); + } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { + specBuilder = new KeyGenParameterSpec.Builder( + legacySpec.getKeystoreAlias(), + KeyProperties.PURPOSE_ENCRYPT + | KeyProperties.PURPOSE_DECRYPT + | KeyProperties.PURPOSE_SIGN + | KeyProperties.PURPOSE_VERIFY); + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_MD5, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); + specBuilder.setSignaturePaddings( + KeyProperties.SIGNATURE_PADDING_RSA_PKCS1); + specBuilder.setBlockModes(KeyProperties.BLOCK_MODE_ECB); + specBuilder.setEncryptionPaddings( + KeyProperties.ENCRYPTION_PADDING_NONE, + KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1); + // Disable randomized encryption requirement to support encryption padding NONE + // above. + specBuilder.setRandomizedEncryptionRequired(false); + } else { + throw new InvalidAlgorithmParameterException( + "Unsupported key algorithm: " + keyAlgorithm); + } + + if (legacySpec.getKeySize() != -1) { + specBuilder.setKeySize(legacySpec.getKeySize()); + } + if (legacySpec.getAlgorithmParameterSpec() != null) { + specBuilder.setAlgorithmParameterSpec(legacySpec.getAlgorithmParameterSpec()); + } + specBuilder.setCertificateSubject(legacySpec.getSubjectDN()); + specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber()); + specBuilder.setCertificateNotBefore(legacySpec.getStartDate()); + specBuilder.setCertificateNotAfter(legacySpec.getEndDate()); + specBuilder.setEncryptionAtRestRequired(legacySpec.isEncryptionRequired()); + specBuilder.setUserAuthenticationRequired(false); + + spec = specBuilder.build(); + } catch (NullPointerException | IllegalArgumentException e) { + throw new InvalidAlgorithmParameterException(e); + } + } else if (params instanceof KeyGenParameterSpec) { + spec = (KeyGenParameterSpec) params; + keyAlgorithm = getAlgorithm(); + } else { + throw new InvalidAlgorithmParameterException( + "Unsupported params class: " + params.getClass().getName() + + ". Supported: " + KeyGenParameterSpec.class.getName() + + ", " + KeyPairGeneratorSpec.class); } - KeyPairGeneratorSpec spec = (KeyPairGeneratorSpec) params; - @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithm = getKeyAlgorithm(spec); int keyType = KeyStore.getKeyTypeForAlgorithm(keyAlgorithm); if (keyType == -1) { throw new InvalidAlgorithmParameterException( @@ -300,7 +379,7 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { keySize = getDefaultKeySize(keyType); if (keySize == -1) { throw new InvalidAlgorithmParameterException( - "Unsupported key algorithm: " + keyAlgorithm); + "Unsupported key algorithm: " + keyAlgorithm); } } checkCorrectParametersSpec(keyType, keySize, spec.getAlgorithmParameterSpec()); @@ -310,6 +389,6 @@ public abstract class AndroidKeyPairGenerator extends KeyPairGeneratorSpi { mKeyType = keyType; mKeySize = keySize; mSpec = spec; - mKeyStore = android.security.KeyStore.getInstance(); + mKeyStore = KeyStore.getInstance(); } } diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java index b8346410ae239..69bf877c3f947 100644 --- a/keystore/java/android/security/AndroidKeyStore.java +++ b/keystore/java/android/security/AndroidKeyStore.java @@ -24,6 +24,8 @@ import libcore.util.EmptyArray; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; +import android.security.keystore.KeyProperties; +import android.security.keystore.KeyProtection; import android.util.Log; import java.io.ByteArrayInputStream; @@ -129,11 +131,10 @@ public class AndroidKeyStore extends KeyStoreSpi { keymasterDigest = keymasterDigests.get(0); } - @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithmString; + @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString; try { - keyAlgorithmString = - KeyStoreKeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( - keymasterAlgorithm, keymasterDigest); + keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( + keymasterAlgorithm, keymasterDigest); } catch (IllegalArgumentException e) { throw (UnrecoverableKeyException) new UnrecoverableKeyException("Unsupported secret key type").initCause(e); @@ -270,7 +271,70 @@ public class AndroidKeyStore extends KeyStoreSpi { } private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain, - KeyStoreParameter params) throws KeyStoreException { + java.security.KeyStore.ProtectionParameter param) throws KeyStoreException { + KeyProtection spec; + if (param instanceof KeyStoreParameter) { + KeyStoreParameter legacySpec = (KeyStoreParameter) param; + try { + String keyAlgorithm = key.getAlgorithm(); + KeyProtection.Builder specBuilder; + if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) { + specBuilder = + new KeyProtection.Builder( + KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY); + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_MD5, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); + } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { + specBuilder = + new KeyProtection.Builder( + KeyProperties.PURPOSE_ENCRYPT + | KeyProperties.PURPOSE_DECRYPT + | KeyProperties.PURPOSE_SIGN + | KeyProperties.PURPOSE_VERIFY); + specBuilder.setDigests( + KeyProperties.DIGEST_NONE, + KeyProperties.DIGEST_MD5, + KeyProperties.DIGEST_SHA1, + KeyProperties.DIGEST_SHA224, + KeyProperties.DIGEST_SHA256, + KeyProperties.DIGEST_SHA384, + KeyProperties.DIGEST_SHA512); + specBuilder.setSignaturePaddings( + KeyProperties.SIGNATURE_PADDING_RSA_PKCS1); + specBuilder.setBlockModes(KeyProperties.BLOCK_MODE_ECB); + specBuilder.setEncryptionPaddings( + KeyProperties.ENCRYPTION_PADDING_NONE, + KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1); + // Disable randomized encryption requirement to support encryption padding NONE + // above. + specBuilder.setRandomizedEncryptionRequired(false); + } else { + throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm); + } + specBuilder.setEncryptionAtRestRequired(legacySpec.isEncryptionRequired()); + specBuilder.setUserAuthenticationRequired(false); + + spec = specBuilder.build(); + } catch (NullPointerException | IllegalArgumentException e) { + throw new KeyStoreException("Unsupported protection parameter", e); + } + } else if (param instanceof KeyProtection) { + spec = (KeyProtection) param; + } else if (param != null) { + throw new KeyStoreException( + "Unsupported protection parameter class:" + param.getClass().getName() + + ". Supported: " + KeyStoreParameter.class.getName() + ", " + + KeyProtection.class.getName()); + } else { + spec = null; + } + byte[] keyBytes = null; final String pkeyAlias; @@ -383,7 +447,7 @@ public class AndroidKeyStore extends KeyStoreSpi { Credentials.deleteSecretKeyTypeForAlias(mKeyStore, alias); } - final int flags = (params == null) ? 0 : params.getFlags(); + final int flags = (spec == null) ? 0 : spec.getFlags(); if (shouldReplacePrivateKey && !mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes, @@ -402,8 +466,16 @@ public class AndroidKeyStore extends KeyStoreSpi { } } - private void setSecretKeyEntry(String entryAlias, SecretKey key, KeyStoreParameter params) + private void setSecretKeyEntry(String entryAlias, SecretKey key, + java.security.KeyStore.ProtectionParameter param) throws KeyStoreException { + if ((param != null) && (!(param instanceof KeyProtection))) { + throw new KeyStoreException( + "Unsupported protection parameter class: " + param.getClass().getName() + + ". Supported: " + KeyProtection.class.getName()); + } + KeyProtection params = (KeyProtection) param; + if (key instanceof KeyStoreSecretKey) { // KeyStore-backed secret key. It cannot be duplicated into another entry and cannot // overwrite its own entry. @@ -453,10 +525,9 @@ public class AndroidKeyStore extends KeyStoreSpi { int keymasterAlgorithm; int keymasterDigest; try { - keymasterAlgorithm = KeyStoreKeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm( - keyAlgorithmString); - keymasterDigest = - KeyStoreKeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString); + keymasterAlgorithm = + KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(keyAlgorithmString); + keymasterDigest = KeyProperties.KeyAlgorithm.toKeymasterDigest(keyAlgorithmString); } catch (IllegalArgumentException e) { throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString); } @@ -467,7 +538,7 @@ public class AndroidKeyStore extends KeyStoreSpi { int[] keymasterDigests; if (params.isDigestsSpecified()) { // Digest(s) specified in parameters - keymasterDigests = KeyStoreKeyProperties.Digest.allToKeymaster(params.getDigests()); + keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests()); if (keymasterDigest != -1) { // Digest also specified in the JCA key algorithm name. if (!com.android.internal.util.ArrayUtils.contains( @@ -509,33 +580,32 @@ public class AndroidKeyStore extends KeyStoreSpi { } } - @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes(); + @KeyProperties.PurposeEnum int purposes = params.getPurposes(); int[] keymasterBlockModes = - KeyStoreKeyProperties.BlockMode.allToKeymaster(params.getBlockModes()); - if (((purposes & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0) + KeyProperties.BlockMode.allToKeymaster(params.getBlockModes()); + if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) { for (int keymasterBlockMode : keymasterBlockModes) { if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) { throw new KeyStoreException( "Randomized encryption (IND-CPA) required but may be violated by block" + " mode: " - + KeyStoreKeyProperties.BlockMode.fromKeymaster(keymasterBlockMode) - + ". See KeyStoreParameter documentation."); + + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode) + + ". See KeyProtection documentation."); } } } - for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) { + for (int keymasterPurpose : KeyProperties.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes); if (params.getSignaturePaddings().length > 0) { throw new KeyStoreException("Signature paddings not supported for symmetric keys"); } - int[] keymasterPaddings = KeyStoreKeyProperties.EncryptionPadding.allToKeymaster( + int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster( params.getEncryptionPaddings()); args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings); KeymasterUtils.addUserAuthArgs(args, - params.getContext(), params.isUserAuthenticationRequired(), params.getUserAuthenticationValidityDurationSeconds()); args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, @@ -551,7 +621,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 & KeyProperties.PURPOSE_ENCRYPT) != 0) && (!params.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); @@ -789,19 +859,12 @@ public class AndroidKeyStore extends KeyStoreSpi { return; } - if (param != null && !(param instanceof KeyStoreParameter)) { - throw new KeyStoreException( - "protParam should be android.security.KeyStoreParameter; was: " - + param.getClass().getName()); - } - if (entry instanceof PrivateKeyEntry) { PrivateKeyEntry prE = (PrivateKeyEntry) entry; - setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), - (KeyStoreParameter) param); + setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), param); } else if (entry instanceof SecretKeyEntry) { SecretKeyEntry secE = (SecretKeyEntry) entry; - setSecretKeyEntry(alias, secE.getSecretKey(), (KeyStoreParameter) param); + setSecretKeyEntry(alias, secE.getSecretKey(), param); } else { throw new KeyStoreException( "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry" diff --git a/keystore/java/android/security/ArrayUtils.java b/keystore/java/android/security/ArrayUtils.java index 2047d3fc0be50..71b99d035dd11 100644 --- a/keystore/java/android/security/ArrayUtils.java +++ b/keystore/java/android/security/ArrayUtils.java @@ -5,7 +5,7 @@ import libcore.util.EmptyArray; /** * @hide */ -abstract class ArrayUtils { +public abstract class ArrayUtils { private ArrayUtils() {} public static String[] nullToEmpty(String[] array) { diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 3853ecad12e1d..19b62a653e5ba 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -28,6 +28,8 @@ import android.os.Looper; import android.os.Process; import android.os.RemoteException; import android.os.UserHandle; +import android.security.keystore.KeyProperties; + import java.io.ByteArrayInputStream; import java.io.Closeable; import java.security.InvalidKeyException; @@ -266,7 +268,7 @@ public final class KeyChain { */ public static void choosePrivateKeyAlias(@NonNull Activity activity, @NonNull KeyChainAliasCallback response, - @KeyStoreKeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, + @KeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, @Nullable String host, int port, @Nullable String alias) { choosePrivateKeyAlias(activity, response, keyTypes, issuers, host, port, null, alias); } @@ -312,7 +314,7 @@ public final class KeyChain { */ public static void choosePrivateKeyAlias(@NonNull Activity activity, @NonNull KeyChainAliasCallback response, - @KeyStoreKeyProperties.KeyAlgorithmEnum String[] keyTypes, Principal[] issuers, + @KeyProperties.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 @@ -439,10 +441,10 @@ public final class KeyChain { * "RSA"). */ public static boolean isKeyAlgorithmSupported( - @NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { + @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { final String algUpper = algorithm.toUpperCase(Locale.US); - return KeyStoreKeyProperties.KEY_ALGORITHM_EC.equals(algUpper) - || KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equals(algUpper); + return KeyProperties.KEY_ALGORITHM_EC.equals(algUpper) + || KeyProperties.KEY_ALGORITHM_RSA.equals(algUpper); } /** @@ -453,7 +455,7 @@ public final class KeyChain { * that makes it non-exportable. */ public static boolean isBoundKeyAlgorithm( - @NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String algorithm) { + @NonNull @KeyProperties.KeyAlgorithmEnum String algorithm) { if (!isKeyAlgorithmSupported(algorithm)) { return false; } diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java index b07c05238ded1..efbce41f9dc70 100644 --- a/keystore/java/android/security/KeyPairGeneratorSpec.java +++ b/keystore/java/android/security/KeyPairGeneratorSpec.java @@ -17,14 +17,14 @@ 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.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; import android.text.TextUtils; import java.math.BigInteger; -import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; @@ -34,72 +34,32 @@ import java.util.Date; import javax.security.auth.x500.X500Principal; /** - * {@link AlgorithmParameterSpec} for initializing a {@link KeyPairGenerator} of the - * Android KeyStore facility. This class - * specifies whether user authentication is required for using the private key, what uses the - * private key is authorized for (e.g., only for signing -- decryption not permitted), whether the - * private key should be encrypted at rest, the private key's and validity start and end dates. + * This provides the required parameters needed for initializing the + * {@code KeyPairGenerator} that works with + * Android KeyStore + * facility. The Android KeyStore facility is accessed through a + * {@link java.security.KeyPairGenerator} API using the {@code AndroidKeyStore} + * provider. The {@code context} passed in may be used to pop up some UI to ask + * the user to unlock or initialize the Android KeyStore facility. + *

+ * After generation, the {@code keyStoreAlias} is used with the + * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)} + * interface to retrieve the {@link PrivateKey} and its associated + * {@link Certificate} chain. + *

+ * The KeyPair generator will create a self-signed certificate with the subject + * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer + * Distinguished Name along with the other parameters specified with the + * {@link Builder}. + *

+ * The self-signed X.509 certificate may be replaced at a later time by a + * certificate signed by a real Certificate Authority. * - *

To generate a key pair, create an instance of this class using the {@link Builder}, initialize - * a {@code KeyPairGenerator} of the desired key type (e.g., {@code EC} or {@code RSA}) from the - * {@code AndroidKeyStore} provider with the {@code KeyPairGeneratorSpec} instance, and then - * generate a key pair using {@link KeyPairGenerator#generateKeyPair()}. - * - *

The generated key pair will be returned by the {@code KeyPairGenerator} and also stored in the - * Android KeyStore under the alias specified in this {@code KeyPairGeneratorSpec}. To obtain the - * private key from the Android KeyStore use - * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or - * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}. - * To obtain the public key from the Android KeyStore use - * {@link java.security.KeyStore#getCertificate(String)} and then - * {@link Certificate#getPublicKey()}. - * - *

A self-signed X.509 certificate will be also generated and stored in the Android KeyStore. - * This is because the {@link java.security.KeyStore} abstraction does not support storing key pairs - * without a certificate. The subject, serial number, and validity dates of the certificate can be - * specified in this {@code KeyPairGeneratorSpec}. The self-signed certificate may be replaced at a - * later time by a certificate signed by a Certificate Authority (CA). - * - *

NOTE: The key material of the private keys generating using the {@code KeyPairGeneratorSpec} - * is not accessible. The key material of the public keys is accessible. - * - *

Example

- * The following example illustrates how to generate an EC key pair in the Android KeyStore under - * alias {@code key2} authorized to be used only for signing using SHA-256, SHA-384, or SHA-512 - * digest and only if the user has been authenticated within the last five minutes. - *
 {@code
- * KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
- *         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)
- *                 // Only permit this key to be used if the user authenticated
- *                 // within the last five minutes.
- *                 .setUserAuthenticationRequired(true)
- *                 .setUserAuthenticationValidityDurationSeconds(5 * 60)
- *                 .build());
- * KeyPair keyPair = keyPairGenerator.generateKey();
- *
- * // The key pair can also be obtained from the Android KeyStore any time as follows:
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * PrivateKey privateKey = (PrivateKey) keyStore.getKey("key2", null);
- * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey();
- * }
+ * @deprecated Use {@link KeyGenParameterSpec} instead. */ +@Deprecated public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { - private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake"); - private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1"); - private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970 - private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048 - private final Context mContext; private final String mKeystoreAlias; @@ -120,28 +80,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private final int mFlags; - private final Date mKeyValidityStart; - - private final Date mKeyValidityForOriginationEnd; - - private final Date mKeyValidityForConsumptionEnd; - - private final @KeyStoreKeyProperties.PurposeEnum int mPurposes; - - private final @KeyStoreKeyProperties.DigestEnum String[] mDigests; - - private final @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings; - - private final @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings; - - private final @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes; - - private final boolean mRandomizedEncryptionRequired; - - private final boolean mUserAuthenticationRequired; - - private final int mUserAuthenticationValidityDurationSeconds; - /** * Parameter specification for the "{@code AndroidKeyPairGenerator}" * instance of the {@link java.security.KeyPairGenerator} API. The @@ -162,7 +100,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * @param context Android context for the activity * @param keyStoreAlias name to use for the generated key in the Android * keystore - * @param keyType key algorithm to use (EC, RSA) + * @param keyType key algorithm to use (RSA, DSA, EC) * @param keySize size of key to generate * @param spec the underlying key type parameters * @param subjectDN X.509 v3 Subject Distinguished Name @@ -176,39 +114,21 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { */ public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize, AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber, - Date startDate, Date endDate, int flags, - Date keyValidityStart, - Date keyValidityForOriginationEnd, - Date keyValidityForConsumptionEnd, - @KeyStoreKeyProperties.PurposeEnum int purposes, - @KeyStoreKeyProperties.DigestEnum String[] digests, - @KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings, - @KeyStoreKeyProperties.SignaturePaddingEnum String[] signaturePaddings, - @KeyStoreKeyProperties.BlockModeEnum String[] blockModes, - boolean randomizedEncryptionRequired, - boolean userAuthenticationRequired, - int userAuthenticationValidityDurationSeconds) { + Date startDate, Date endDate, int flags) { if (context == null) { throw new IllegalArgumentException("context == null"); } else if (TextUtils.isEmpty(keyStoreAlias)) { throw new IllegalArgumentException("keyStoreAlias must not be empty"); - } else if ((userAuthenticationValidityDurationSeconds < 0) - && (userAuthenticationValidityDurationSeconds != -1)) { - throw new IllegalArgumentException( - "userAuthenticationValidityDurationSeconds must not be negative"); - } - - if (subjectDN == null) { - subjectDN = DEFAULT_CERT_SUBJECT; - } - if (startDate == null) { - startDate = DEFAULT_CERT_NOT_BEFORE; - } - if (endDate == null) { - endDate = DEFAULT_CERT_NOT_AFTER; - } - if (serialNumber == null) { - serialNumber = DEFAULT_CERT_SERIAL_NUMBER; + } else if (subjectDN == null) { + throw new IllegalArgumentException("subjectDN == null"); + } else if (serialNumber == null) { + throw new IllegalArgumentException("serialNumber == null"); + } else if (startDate == null) { + throw new IllegalArgumentException("startDate == null"); + } else if (endDate == null) { + throw new IllegalArgumentException("endDate == null"); + } else if (endDate.before(startDate)) { + throw new IllegalArgumentException("endDate < startDate"); } if (endDate.before(startDate)) { @@ -225,50 +145,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mStartDate = startDate; mEndDate = endDate; mFlags = flags; - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; - mPurposes = purposes; - mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests)); - mEncryptionPaddings = - ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); - mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings)); - mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); - mRandomizedEncryptionRequired = randomizedEncryptionRequired; - mUserAuthenticationRequired = userAuthenticationRequired; - mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; - } - - /** - * TODO: Remove this constructor once tests are switched over to the new one above. - * @hide - */ - public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize, - AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber, - Date startDate, Date endDate, int flags) { - - this(context, - keyStoreAlias, - keyType, - keySize, - spec, - subjectDN, - serialNumber, - startDate, - endDate, - flags, - startDate, - endDate, - endDate, - 0, // purposes - null, // digests - null, // encryption paddings - null, // signature paddings - null, // block modes - false, // randomized encryption required - false, // user authentication required - -1 // user authentication validity duration (seconds) - ); } /** @@ -288,10 +164,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * Returns the type of key pair (e.g., {@code EC}, {@code RSA}) to be generated. See - * {@link KeyStoreKeyProperties}.{@code KEY_ALGORITHM} constants. + * {@link KeyProperties}.{@code KEY_ALGORITHM} constants. */ @Nullable - public @KeyStoreKeyProperties.KeyAlgorithmEnum String getKeyType() { + public @KeyProperties.KeyAlgorithmEnum String getKeyType() { return mKeyType; } @@ -352,147 +228,26 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * @hide */ - int getFlags() { + public int getFlags() { return mFlags; } /** * Returns {@code true} if the key must be encrypted at rest. This will protect the key pair * with the secure lock screen credential (e.g., password, PIN, or pattern). + * + *

Note that encrypting the key at rest requires that the secure lock screen (e.g., password, + * PIN, pattern) is set up, otherwise key generation will fail. Moreover, this key will be + * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device + * Administrator). Finally, this key cannot be used until the user unlocks the secure lock + * screen after boot. + * + * @see KeyguardManager#isDeviceSecure() */ public boolean isEncryptionRequired() { return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; } - /** - * Gets the time instant before which the key pair is not yet valid. - * - * @return instant or {@code null} if not restricted. - */ - @Nullable - public Date getKeyValidityStart() { - return mKeyValidityStart; - } - - /** - * Gets the time instant after which the key pair is no longer valid for decryption and - * verification. - * - * @return instant or {@code null} if not restricted. - */ - @Nullable - public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; - } - - /** - * Gets the time instant after which the key pair is no longer valid for encryption and signing. - * - * @return instant or {@code null} if not restricted. - */ - @Nullable - public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. - */ - public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { - return mPurposes; - } - - /** - * 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 (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. - * - *

See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. - */ - @NonNull - public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() { - return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. - */ - @NonNull - public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() { - return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings); - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. - */ - @NonNull - public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() { - return ArrayUtils.cloneIfNotEmpty(mBlockModes); - } - - /** - * Returns {@code true} if encryption using this key must be sufficiently randomized to produce - * different ciphertexts for the same plaintext every time. The formal cryptographic property - * being required is indistinguishability under chosen-plaintext attack ({@code - * IND-CPA}). This property is important because it mitigates several classes of - * weaknesses due to which ciphertext may leak information about plaintext. For example, if a - * given plaintext always produces the same ciphertext, an attacker may see the repeated - * ciphertexts and be able to deduce something about the plaintext. - */ - public boolean isRandomizedEncryptionRequired() { - return mRandomizedEncryptionRequired; - } - - /** - * Returns {@code true} if user authentication is required for this key to be used. - * - *

This restriction applies only to private key operations. Public key operations are not - * restricted. - * - * @see #getUserAuthenticationValidityDurationSeconds() - */ - public boolean isUserAuthenticationRequired() { - return mUserAuthenticationRequired; - } - - /** - * Gets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. - * - *

This restriction applies only to private key operations. Public key operations are not - * restricted. - * - * @return duration in seconds or {@code -1} if authentication is required for every use of the - * key. - * - * @see #isUserAuthenticationRequired() - */ - public int getUserAuthenticationValidityDurationSeconds() { - return mUserAuthenticationValidityDurationSeconds; - } - /** * Builder class for {@link KeyPairGeneratorSpec} objects. *

@@ -513,7 +268,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { * .setSubject(new X500Principal("CN=myKey")).setSerial(BigInteger.valueOf(1337)) * .setStartDate(start.getTime()).setEndDate(end.getTime()).build(); * + * + * @deprecated Use {@link KeyGenParameterSpec.Builder} instead. */ + @Deprecated public final static class Builder { private final Context mContext; @@ -535,28 +293,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private int mFlags; - private Date mKeyValidityStart; - - private Date mKeyValidityForOriginationEnd; - - private Date mKeyValidityForConsumptionEnd; - - private @KeyStoreKeyProperties.PurposeEnum int mPurposes; - - private @KeyStoreKeyProperties.DigestEnum String[] mDigests; - - private @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings; - - private @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings; - - private @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes; - - private boolean mRandomizedEncryptionRequired = true; - - private boolean mUserAuthenticationRequired; - - private int mUserAuthenticationValidityDurationSeconds = -1; - /** * Creates a new instance of the {@code Builder} with the given * {@code context}. The {@code context} passed in may be used to pop up @@ -586,11 +322,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * 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. + * generated. See {@link KeyProperties}.{@code KEY_ALGORITHM} constants. * */ @NonNull - public Builder setKeyType(@NonNull @KeyStoreKeyProperties.KeyAlgorithmEnum String keyType) + public Builder setKeyType(@NonNull @KeyProperties.KeyAlgorithmEnum String keyType) throws NoSuchAlgorithmException { if (keyType == null) { throw new NullPointerException("keyType == null"); @@ -632,10 +368,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * Sets the subject used for the self-signed certificate of the * generated key pair. - * - *

The subject must be specified on API Level - * {@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. */ @NonNull public Builder setSubject(@NonNull X500Principal subject) { @@ -649,10 +381,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * Sets the serial number used for the self-signed certificate of the * generated key pair. - * - *

The serial number must be specified on API Level - * {@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. */ @NonNull public Builder setSerialNumber(@NonNull BigInteger serialNumber) { @@ -666,10 +394,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * Sets the start of the validity period for the self-signed certificate * of the generated key pair. - * - *

The date must be specified on API Level - * {@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. */ @NonNull public Builder setStartDate(@NonNull Date startDate) { @@ -683,10 +407,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { /** * Sets the end of the validity period for the self-signed certificate * of the generated key pair. - * - *

The date must be specified on API Level - * {@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. */ @NonNull public Builder setEndDate(@NonNull Date endDate) { @@ -715,239 +435,6 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { return this; } - /** - * Sets the time instant before which the key is not yet valid. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect. - * - * @see #setKeyValidityEnd(Date) - */ - @NonNull - public Builder setKeyValidityStart(Date startDate) { - mKeyValidityStart = startDate; - return this; - } - - /** - * Sets the time instant after which the key is no longer valid. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect. - * - * @see #setKeyValidityStart(Date) - * @see #setKeyValidityForConsumptionEnd(Date) - * @see #setKeyValidityForOriginationEnd(Date) - */ - @NonNull - public Builder setKeyValidityEnd(Date endDate) { - setKeyValidityForOriginationEnd(endDate); - setKeyValidityForConsumptionEnd(endDate); - return this; - } - - /** - * Sets the time instant after which the key is no longer valid for encryption and signing. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect. - * - * @see #setKeyValidityForConsumptionEnd(Date) - */ - @NonNull - public Builder setKeyValidityForOriginationEnd(Date endDate) { - mKeyValidityForOriginationEnd = endDate; - return this; - } - - /** - * Sets the time instant after which the key is no longer valid for decryption and - * verification. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect. - * - * @see #setKeyValidityForOriginationEnd(Date) - */ - @NonNull - public Builder setKeyValidityForConsumptionEnd(Date endDate) { - mKeyValidityForConsumptionEnd = endDate; - return this; - } - - /** - * 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. - * - *

This must be specified for all keys. There is no default. - * - *

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 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. - * - *

NOTE: This has currently no effect. - * - *

See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. - */ - @NonNull - public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { - mPurposes = purposes; - return this; - } - - /** - * 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. - * - *

This must be specified for keys which are used for signing/verification. - * - *

NOTE: This has currently no effect. - * - * @see KeyStoreKeyProperties.Digest - */ - @NonNull - public Builder setDigests(@KeyStoreKeyProperties.DigestEnum String... digests) { - mDigests = ArrayUtils.cloneIfNotEmpty(digests); - return this; - } - - /** - * 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. - * - *

This must be specified for keys which are used for encryption/decryption. - * - *

NOTE: This has currently no effect. - * - *

See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. - */ - @NonNull - public Builder setEncryptionPaddings( - @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) { - mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); - return this; - } - - /** - * 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. - * - *

This must be specified for RSA keys which are used for signing/verification. - * - *

NOTE: This has currently no effect. - * - *

See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. - */ - @NonNull - public Builder setSignaturePaddings( - @KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) { - mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings); - return this; - } - - /** - * 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. - * - *

This must be specified for encryption/decryption keys. - * - *

NOTE: This has currently no effect. - * - *

See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. - */ - @NonNull - public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) { - mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); - return this; - } - - /** - * Sets whether encryption using this key must be sufficiently randomized to produce - * different ciphertexts for the same plaintext every time. The formal cryptographic - * property being required is indistinguishability under chosen-plaintext attack - * ({@code IND-CPA}). This property is important because it mitigates several classes - * of weaknesses due to which ciphertext may leak information about plaintext. For example, - * if a given plaintext always produces the same ciphertext, an attacker may see the - * repeated ciphertexts and be able to deduce something about the plaintext. - * - *

By default, {@code IND-CPA} is required. - * - *

When {@code IND-CPA} is required, encryption/decryption transformations which do not - * offer {@code IND-CPA}, such as RSA without padding, are prohibited. - * - *

Before disabling this requirement, consider the following approaches instead: - *

- * - *

NOTE: This has currently no effect. - */ - @NonNull - public Builder setRandomizedEncryptionRequired(boolean required) { - mRandomizedEncryptionRequired = required; - return this; - } - - /** - * Sets whether user authentication is required to use this key. - * - *

By default, the key can be used without user authentication. - * - *

When user authentication is required, the user authorizes the use of the key by - * authenticating to this Android device using a subset of their secure lock screen - * credentials. Different authentication methods are used depending on whether the every - * use of the key must be authenticated (as specified by - * {@link #setUserAuthenticationValidityDurationSeconds(int)}). - * More - * information. - * - *

This restriction applies only to private key operations. Public key operations are not - * restricted. - * - *

NOTE: This has currently no effect. - * - * @see #setUserAuthenticationValidityDurationSeconds(int) - */ - @NonNull - public Builder setUserAuthenticationRequired(boolean required) { - mUserAuthenticationRequired = required; - return this; - } - - /** - * Sets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. - * - *

By default, the user needs to authenticate for every use of the key. - * - *

This restriction applies only to private key operations. Public key operations are not - * restricted. - * - *

NOTE: This has currently no effect. - * - * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for - * every use of the key. - * - * @see #setUserAuthenticationRequired(boolean) - */ - @NonNull - public Builder setUserAuthenticationValidityDurationSeconds( - @IntRange(from = -1) int seconds) { - mUserAuthenticationValidityDurationSeconds = seconds; - return this; - } - /** * Builds the instance of the {@code KeyPairGeneratorSpec}. * @@ -965,18 +452,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mSerialNumber, mStartDate, mEndDate, - mFlags, - mKeyValidityStart, - mKeyValidityForOriginationEnd, - mKeyValidityForConsumptionEnd, - mPurposes, - mDigests, - mEncryptionPaddings, - mSignaturePaddings, - mBlockModes, - mRandomizedEncryptionRequired, - mUserAuthenticationRequired, - mUserAuthenticationValidityDurationSeconds); + mFlags); } } } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index caa4fec4548eb..72c74dffc448d 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -35,6 +35,11 @@ import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterBlob; import android.security.keymaster.KeymasterDefs; import android.security.keymaster.OperationResult; +import android.security.keystore.KeyExpiredException; +import android.security.keystore.KeyNotYetValidException; +import android.security.keystore.KeyPermanentlyInvalidatedException; +import android.security.keystore.KeyProperties; +import android.security.keystore.UserNotAuthenticatedException; import android.util.Log; import java.security.InvalidKeyException; @@ -101,10 +106,10 @@ public class KeyStore { private KeyStore(IKeystoreService binder) { mBinder = binder; - mContext = getContext(); + mContext = getApplicationContext(); } - private static Context getContext() { + static Context getApplicationContext() { ActivityThread activityThread = ActivityThread.currentActivityThread(); if (activityThread == null) { throw new IllegalStateException( @@ -131,10 +136,10 @@ public class KeyStore { return mToken; } - static int getKeyTypeForAlgorithm(@KeyStoreKeyProperties.KeyAlgorithmEnum String keyType) { - if (KeyStoreKeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) { + static int getKeyTypeForAlgorithm(@KeyProperties.KeyAlgorithmEnum String keyType) { + if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) { return NativeConstants.EVP_PKEY_RSA; - } else if (KeyStoreKeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) { + } else if (KeyProperties.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 4eeca47a6b5c1..b0f1695188c2a 100644 --- a/keystore/java/android/security/KeyStoreCipherSpi.java +++ b/keystore/java/android/security/KeyStoreCipherSpi.java @@ -20,6 +20,7 @@ import android.os.IBinder; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; import android.security.keymaster.OperationResult; +import android.security.keystore.KeyProperties; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; @@ -496,7 +497,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry if ((mIv != null) && (mIv.length > 0)) { try { AlgorithmParameters params = - AlgorithmParameters.getInstance(KeyStoreKeyProperties.KEY_ALGORITHM_AES); + AlgorithmParameters.getInstance(KeyProperties.KEY_ALGORITHM_AES); params.init(new IvParameterSpec(mIv)); return params; } catch (NoSuchAlgorithmException e) { diff --git a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java index 311278bab16b8..c9bdd41676dde 100644 --- a/keystore/java/android/security/KeyStoreCryptoOperationUtils.java +++ b/keystore/java/android/security/KeyStoreCryptoOperationUtils.java @@ -17,6 +17,7 @@ package android.security; import android.security.keymaster.KeymasterDefs; +import android.security.keystore.UserNotAuthenticatedException; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java index d734d66d95fde..feec00f7b77b5 100644 --- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java @@ -19,11 +19,16 @@ package android.security; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; + +import libcore.util.EmptyArray; import java.security.InvalidAlgorithmParameterException; import java.security.ProviderException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; import java.util.Date; import javax.crypto.KeyGeneratorSpi; @@ -96,13 +101,14 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { private final int mKeymasterDigest; private final int mDefaultKeySizeBits; - private KeyGeneratorSpec mSpec; + private KeyGenParameterSpec mSpec; private SecureRandom mRng; protected int mKeySizeBits; private int[] mKeymasterPurposes; private int[] mKeymasterBlockModes; private int[] mKeymasterPaddings; + private int[] mKeymasterDigests; protected KeyStoreKeyGeneratorSpi( int keymasterAlgorithm, @@ -129,14 +135,14 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { @Override protected void engineInit(SecureRandom random) { - throw new UnsupportedOperationException("Cannot initialize without an " - + KeyGeneratorSpec.class.getName() + " parameter"); + throw new UnsupportedOperationException("Cannot initialize without a " + + KeyGenParameterSpec.class.getName() + " parameter"); } @Override protected void engineInit(int keySize, SecureRandom random) { throw new UnsupportedOperationException("Cannot initialize without a " - + KeyGeneratorSpec.class.getName() + " parameter"); + + KeyGenParameterSpec.class.getName() + " parameter"); } @Override @@ -146,11 +152,11 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { boolean success = false; try { - if ((params == null) || (!(params instanceof KeyGeneratorSpec))) { - throw new InvalidAlgorithmParameterException("Cannot initialize without an " - + KeyGeneratorSpec.class.getName() + " parameter"); + if ((params == null) || (!(params instanceof KeyGenParameterSpec))) { + throw new InvalidAlgorithmParameterException("Cannot initialize without a " + + KeyGenParameterSpec.class.getName() + " parameter"); } - KeyGeneratorSpec spec = (KeyGeneratorSpec) params; + KeyGenParameterSpec spec = (KeyGenParameterSpec) params; if (spec.getKeystoreAlias() == null) { throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided"); } @@ -168,13 +174,11 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } try { - mKeymasterPurposes = - KeyStoreKeyProperties.Purpose.allToKeymaster(spec.getPurposes()); - mKeymasterPaddings = KeyStoreKeyProperties.EncryptionPadding.allToKeymaster( + mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes()); + mKeymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster( spec.getEncryptionPaddings()); - mKeymasterBlockModes = - KeyStoreKeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()); - if (((spec.getPurposes() & KeyStoreKeyProperties.PURPOSE_ENCRYPT) != 0) + mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()); + if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0) && (spec.isRandomizedEncryptionRequired())) { for (int keymasterBlockMode : mKeymasterBlockModes) { if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible( @@ -182,14 +186,55 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { throw new InvalidAlgorithmParameterException( "Randomized encryption (IND-CPA) required but may be violated" + " by block mode: " - + KeyStoreKeyProperties.BlockMode.fromKeymaster( - keymasterBlockMode) - + ". See " + KeyGeneratorSpec.class.getName() + + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode) + + ". See " + KeyGenParameterSpec.class.getName() + " documentation."); } } } - } catch (IllegalArgumentException e) { + if (spec.isDigestsSpecified()) { + // Digest(s) explicitly specified in the spec + mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests()); + if (mKeymasterDigest != -1) { + // Key algorithm implies a digest -- ensure it's specified in the spec as + // first digest. + if (!com.android.internal.util.ArrayUtils.contains( + mKeymasterDigests, mKeymasterDigest)) { + throw new InvalidAlgorithmParameterException( + "Digests specified in algorithm parameters (" + + Arrays.asList(spec.getDigests()) + ") must include " + + " the digest " + + KeyProperties.Digest.fromKeymaster(mKeymasterDigest) + + " implied by key algorithm"); + } + if (mKeymasterDigests[0] != mKeymasterDigest) { + // The first digest is not the one implied by the key algorithm. + // Swap the implied digest with the first one. + for (int i = 0; i < mKeymasterDigests.length; i++) { + if (mKeymasterDigests[i] == mKeymasterDigest) { + mKeymasterDigests[i] = mKeymasterDigests[0]; + mKeymasterDigests[0] = mKeymasterDigest; + break; + } + } + } + } + } else { + // No digest specified in the spec + if (mKeymasterDigest != -1) { + // Key algorithm implies a digest -- use that digest + mKeymasterDigests = new int[] {mKeymasterDigest}; + } else { + mKeymasterDigests = EmptyArray.INT; + } + } + if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) { + if (mKeymasterDigests.length == 0) { + throw new InvalidAlgorithmParameterException( + "At least one digest algorithm must be specified"); + } + } + } catch (IllegalStateException | IllegalArgumentException e) { throw new InvalidAlgorithmParameterException(e); } @@ -212,29 +257,26 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { @Override protected SecretKey engineGenerateKey() { - KeyGeneratorSpec spec = mSpec; + KeyGenParameterSpec spec = mSpec; if (spec == null) { throw new IllegalStateException("Not initialized"); } - if ((spec.isEncryptionRequired()) + if ((spec.isEncryptionAtRestRequired()) && (mKeyStore.state() != KeyStore.State.UNLOCKED)) { throw new IllegalStateException( - "Android KeyStore must be in initialized and unlocked state if encryption is" - + " required"); + "Requested to import a key which must be encrypted at rest using secure lock" + + " screen credential, but the credential hasn't yet been entered by the user"); } KeymasterArguments args = new KeymasterArguments(); args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits); args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm); - if (mKeymasterDigest != -1) { - args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest); - } args.addInts(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes); args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes); args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings); + args.addInts(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests); KeymasterUtils.addUserAuthArgs(args, - spec.getContext(), spec.isUserAuthenticationRequired(), spec.getUserAuthenticationValidityDurationSeconds()); args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, @@ -247,7 +289,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() & KeyProperties.PURPOSE_ENCRYPT) != 0) && (!spec.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); @@ -265,9 +307,9 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { throw new ProviderException( "Keystore operation failed", KeyStore.getKeyStoreException(errorCode)); } - @KeyStoreKeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA; + @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA; try { - keyAlgorithmJCA = KeyStoreKeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm( + keyAlgorithmJCA = KeyProperties.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/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java index a7fab80d29d19..174e03f842dab 100644 --- a/keystore/java/android/security/KeyStoreParameter.java +++ b/keystore/java/android/security/KeyStoreParameter.java @@ -16,145 +16,51 @@ 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.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProtection; -import java.security.Key; +import java.security.KeyPairGenerator; import java.security.KeyStore.ProtectionParameter; -import java.security.cert.Certificate; -import java.util.Date; - -import javax.crypto.Cipher; /** - * Parameters specifying how to secure and restrict the use of a key or key pair being imported into - * the Android KeyStore facility. This class - * specifies whether user authentication is required for using the key, what uses the key is - * authorized for (e.g., only in {@code CTR} mode, or only for signing -- decryption not permitted), - * whether the key should be encrypted at rest, the key's and validity start and end dates. + * This provides the optional parameters that can be specified for + * {@code KeyStore} entries that work with + * Android KeyStore + * facility. The Android KeyStore facility is accessed through a + * {@link java.security.KeyStore} API using the {@code AndroidKeyStore} + * provider. The {@code context} passed in may be used to pop up some UI to ask + * the user to unlock or initialize the Android KeyStore facility. + *

+ * Any entries placed in the {@code KeyStore} may be retrieved later. Note that + * there is only one logical instance of the {@code KeyStore} per application + * UID so apps using the {@code sharedUid} facility will also share a + * {@code KeyStore}. + *

+ * Keys may be generated using the {@link KeyPairGenerator} facility with a + * {@link KeyPairGeneratorSpec} to specify the entry's {@code alias}. A + * self-signed X.509 certificate will be attached to generated entries, but that + * may be replaced at a later time by a certificate signed by a real Certificate + * Authority. * - *

To import a key or key pair into the Android KeyStore, create an instance of this class using - * the {@link Builder} and pass the instance into {@link java.security.KeyStore#setEntry(String, java.security.KeyStore.Entry, ProtectionParameter) KeyStore.setEntry} - * with the key or key pair being imported. - * - *

To obtain the secret/symmetric or private key from the Android KeyStore use - * {@link java.security.KeyStore#getKey(String, char[]) KeyStore.getKey(String, null)} or - * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter) KeyStore.getEntry(String, null)}. - * To obtain the public key from the Android KeyStore use - * {@link java.security.KeyStore#getCertificate(String)} and then - * {@link Certificate#getPublicKey()}. - * - *

NOTE: The key material of keys stored in the Android KeyStore is not accessible. - * - *

Example: Symmetric Key

- * The following example illustrates how to import an AES key into the Android KeyStore under alias - * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 - * padding. The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format. - *
 {@code
- * SecretKey key = ...; // AES key
- *
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * keyStore.setEntry(
- *         "key1",
- *         new KeyStore.SecretKeyEntry(key),
- *         new KeyStoreParameter.Builder(context)
- *                 .setPurposes(KeyStoreKeyProperties.PURPOSE_ENCRYPT
- *                         | KeyStoreKeyProperties.PURPOSE_DECRYPT)
- *                 .setBlockMode(KeyStoreKeyProperties.BLOCK_MODE_CBC)
- *                 .setEncryptionPaddings(
- *                         KeyStoreKeyProperties.ENCRYPTION_PADDING_PKCS7)
- *                 .build());
- * // Key imported, obtain a reference to it.
- * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null);
- * // The original key can now be thrown away.
- * }
- * - *

Example: Asymmetric Key Pair

- * The following example illustrates how to import an EC key pair into the Android KeyStore under - * alias {@code key2} authorized to be used only for signing with SHA-256 digest and only if - * the user has been authenticated within the last ten minutes. Both the private and the public key - * must export their key material via {@link Key#getEncoded()} in {@code PKCS#8} and {@code X.509} - * format respectively. - *
 {@code
- * PrivateKey privateKey = ...;   // EC private key
- * Certificate[] certChain = ...; // Certificate chain with the first certificate
- *                                // containing the corresponding EC public key.
- *
- * KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
- * keyStore.load(null);
- * keyStore.setEntry(
- *         "key2",
- *         new KeyStore.PrivateKeyEntry(privateKey, certChain),
- *         new KeyStoreParameter.Builder(context)
- *                 .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)
- *                 .setUserAuthenticationValidityDurationSeconds(10 * 60)
- *                 .build());
- * // Key pair imported, obtain a reference to it.
- * PrivateKey keyStorePrivateKey = (PrivateKey) keyStore.getKey("key2", null);
- * PublicKey publicKey = keyStore.getCertificate("key2").getPublicKey();
- * // The original private key can now be thrown away.
- * }
+ * @deprecated Use {@link KeyProtection} instead. */ +@Deprecated public final class KeyStoreParameter implements ProtectionParameter { private final Context mContext; private final int mFlags; - private final Date mKeyValidityStart; - private final Date mKeyValidityForOriginationEnd; - private final Date mKeyValidityForConsumptionEnd; - private final @KeyStoreKeyProperties.PurposeEnum int mPurposes; - private final @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings; - private final @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings; - private final @KeyStoreKeyProperties.DigestEnum String[] mDigests; - private final @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes; - private final boolean mRandomizedEncryptionRequired; - private final boolean mUserAuthenticationRequired; - private final int mUserAuthenticationValidityDurationSeconds; private KeyStoreParameter( Context context, - int flags, - Date keyValidityStart, - Date keyValidityForOriginationEnd, - Date keyValidityForConsumptionEnd, - @KeyStoreKeyProperties.PurposeEnum int purposes, - @KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings, - @KeyStoreKeyProperties.SignaturePaddingEnum String[] signaturePaddings, - @KeyStoreKeyProperties.DigestEnum String[] digests, - @KeyStoreKeyProperties.BlockModeEnum String[] blockModes, - boolean randomizedEncryptionRequired, - boolean userAuthenticationRequired, - int userAuthenticationValidityDurationSeconds) { + int flags) { if (context == null) { throw new IllegalArgumentException("context == null"); - } else if ((userAuthenticationValidityDurationSeconds < 0) - && (userAuthenticationValidityDurationSeconds != -1)) { - throw new IllegalArgumentException( - "userAuthenticationValidityDurationSeconds must not be negative"); } mContext = context; mFlags = flags; - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; - mPurposes = purposes; - mEncryptionPaddings = - ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); - mSignaturePaddings = - ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings)); - mDigests = ArrayUtils.cloneIfNotEmpty(digests); - mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes)); - mRandomizedEncryptionRequired = randomizedEncryptionRequired; - mUserAuthenticationRequired = userAuthenticationRequired; - mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; } /** @@ -175,150 +81,19 @@ public final class KeyStoreParameter implements ProtectionParameter { * Returns {@code true} if the {@link java.security.KeyStore} entry must be encrypted at rest. * This will protect the entry with the secure lock screen credential (e.g., password, PIN, or * pattern). + * + *

Note that encrypting the key at rest requires that the secure lock screen (e.g., password, + * PIN, pattern) is set up, otherwise key generation will fail. Moreover, this key will be + * deleted when the secure lock screen is disabled or reset (e.g., by the user or a Device + * Administrator). Finally, this key cannot be used until the user unlocks the secure lock + * screen after boot. + * + * @see KeyguardManager#isDeviceSecure() */ public boolean isEncryptionRequired() { return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0; } - /** - * Gets the time instant before which the key is not yet valid. - * - * @return instant or {@code null} if not restricted. - */ - @Nullable - public Date getKeyValidityStart() { - return mKeyValidityStart; - } - - /** - * Gets the time instant after which the key is no long valid for decryption and verification. - * - * @return instant or {@code null} if not restricted. - */ - @Nullable - public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; - } - - /** - * Gets the time instant after which the key is no long valid for encryption and signing. - * - * @return instant or {@code null} if not restricted. - */ - @Nullable - public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. - */ - public @KeyStoreKeyProperties.PurposeEnum int getPurposes() { - return mPurposes; - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. - */ - @NonNull - public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() { - return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings); - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. - */ - @NonNull - public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() { - return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings); - } - - /** - * 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"); - } - return ArrayUtils.cloneIfNotEmpty(mDigests); - } - - /** - * Returns {@code true} if the set of digest algorithms with which the key can be used has been - * specified. - * - * @see #getDigests() - */ - @NonNull - public boolean isDigestsSpecified() { - return mDigests != null; - } - - /** - * 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. - * - *

See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. - */ - @NonNull - public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() { - return ArrayUtils.cloneIfNotEmpty(mBlockModes); - } - - /** - * Returns {@code true} if encryption using this key must be sufficiently randomized to produce - * different ciphertexts for the same plaintext every time. The formal cryptographic property - * being required is indistinguishability under chosen-plaintext attack ({@code - * IND-CPA}). This property is important because it mitigates several classes of - * weaknesses due to which ciphertext may leak information about plaintext. For example, if a - * given plaintext always produces the same ciphertext, an attacker may see the repeated - * ciphertexts and be able to deduce something about the plaintext. - */ - public boolean isRandomizedEncryptionRequired() { - return mRandomizedEncryptionRequired; - } - - /** - * Returns {@code true} if user authentication is required for this key to be used. - * - * @see #getUserAuthenticationValidityDurationSeconds() - */ - public boolean isUserAuthenticationRequired() { - return mUserAuthenticationRequired; - } - - /** - * Gets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. - * - * @return duration in seconds or {@code -1} if authentication is required for every use of the - * key. - * - * @see #isUserAuthenticationRequired() - */ - public int getUserAuthenticationValidityDurationSeconds() { - return mUserAuthenticationValidityDurationSeconds; - } - /** * Builder class for {@link KeyStoreParameter} objects. *

@@ -332,24 +107,16 @@ public final class KeyStoreParameter implements ProtectionParameter { * *

      * KeyStoreParameter params = new KeyStoreParameter.Builder(mContext)
-     *         .setEncryptionRequired(true)
+     *         .setEncryptionRequired()
      *         .build();
      * 
+ * + * @deprecated Use {@link KeyProtection.Builder} instead. */ + @Deprecated public final static class Builder { private final Context mContext; private int mFlags; - private Date mKeyValidityStart; - private Date mKeyValidityForOriginationEnd; - private Date mKeyValidityForConsumptionEnd; - private @KeyStoreKeyProperties.PurposeEnum int mPurposes; - private @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings; - private @KeyStoreKeyProperties.SignaturePaddingEnum String[] mSignaturePaddings; - private @KeyStoreKeyProperties.DigestEnum String[] mDigests; - private @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes; - private boolean mRandomizedEncryptionRequired = true; - private boolean mUserAuthenticationRequired; - private int mUserAuthenticationValidityDurationSeconds = -1; /** * Creates a new instance of the {@code Builder} with the given @@ -387,244 +154,6 @@ public final class KeyStoreParameter implements ProtectionParameter { return this; } - /** - * Sets the time instant before which the key is not yet valid. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - * @see #setKeyValidityEnd(Date) - */ - @NonNull - public Builder setKeyValidityStart(Date startDate) { - mKeyValidityStart = startDate; - return this; - } - - /** - * Sets the time instant after which the key is no longer valid. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - * @see #setKeyValidityStart(Date) - * @see #setKeyValidityForConsumptionEnd(Date) - * @see #setKeyValidityForOriginationEnd(Date) - */ - @NonNull - public Builder setKeyValidityEnd(Date endDate) { - setKeyValidityForOriginationEnd(endDate); - setKeyValidityForConsumptionEnd(endDate); - return this; - } - - /** - * Sets the time instant after which the key is no longer valid for encryption and signing. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - * @see #setKeyValidityForConsumptionEnd(Date) - */ - @NonNull - public Builder setKeyValidityForOriginationEnd(Date endDate) { - mKeyValidityForOriginationEnd = endDate; - return this; - } - - /** - * Sets the time instant after which the key is no longer valid for decryption and - * verification. - * - *

By default, the key is valid at any instant. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - * @see #setKeyValidityForOriginationEnd(Date) - */ - @NonNull - public Builder setKeyValidityForConsumptionEnd(Date endDate) { - mKeyValidityForConsumptionEnd = endDate; - return this; - } - - /** - * 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. - * - *

This must be specified for all keys. There is no default. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - *

See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags. - */ - @NonNull - public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) { - mPurposes = purposes; - return this; - } - - /** - * 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. - * - *

This must be specified for keys which are used for encryption/decryption. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - *

See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants. - */ - @NonNull - public Builder setEncryptionPaddings( - @KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) { - mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings); - return this; - } - - /** - * 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. - * - *

This must be specified for RSA keys which are used for signing/verification. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - *

See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants. - */ - @NonNull - public Builder setSignaturePaddings( - @KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) { - mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings); - return this; - } - - - /** - * 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. - * - *

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. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - * @see KeyStoreKeyProperties.Digest - */ - @NonNull - public Builder setDigests(@KeyStoreKeyProperties.DigestEnum String... digests) { - mDigests = ArrayUtils.cloneIfNotEmpty(digests); - return this; - } - - /** - * 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. - * - *

This must be specified for encryption/decryption keys. - * - *

NOTE: This has currently no effect on asymmetric key pairs. - * - *

See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants. - */ - @NonNull - public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) { - mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes); - return this; - } - - /** - * Sets whether encryption using this key must be sufficiently randomized to produce - * different ciphertexts for the same plaintext every time. The formal cryptographic - * property being required is indistinguishability under chosen-plaintext attack - * ({@code IND-CPA}). This property is important because it mitigates several classes - * of weaknesses due to which ciphertext may leak information about plaintext. For example, - * if a given plaintext always produces the same ciphertext, an attacker may see the - * repeated ciphertexts and be able to deduce something about the plaintext. - * - *

By default, {@code IND-CPA} is required. - * - *

When {@code IND-CPA} is required: - *