Merge "New AndroidKeyStore API in android.security.keystore." into mnc-dev
This commit is contained in:
226
api/current.txt
226
api/current.txt
@@ -28353,15 +28353,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();
|
||||
@@ -28369,28 +28421,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 {
|
||||
@@ -28399,63 +28476,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";
|
||||
@@ -28490,29 +28517,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();
|
||||
@@ -28520,32 +28528,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 {
|
||||
|
||||
@@ -30378,15 +30378,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();
|
||||
@@ -30394,28 +30446,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 {
|
||||
@@ -30424,63 +30501,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";
|
||||
@@ -30515,29 +30542,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();
|
||||
@@ -30545,32 +30553,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 {
|
||||
|
||||
@@ -88,7 +88,7 @@ and {@link java.security.KeyPairGenerator} or
|
||||
<h3 id="GeneratingANewSecretKey">Generating a New Secret Key</h3>
|
||||
|
||||
<p>To generate the key, use a {@link javax.crypto.KeyGenerator} with
|
||||
{@link android.security.KeyGeneratorSpec}.
|
||||
{@link android.security.keystore.KeyGenParameterSpec}.
|
||||
|
||||
<h3 id="WorkingWithKeyStoreEntries">Working with Keystore Entries</h3>
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -5,7 +5,7 @@ import libcore.util.EmptyArray;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
abstract class ArrayUtils {
|
||||
public abstract class ArrayUtils {
|
||||
private ArrayUtils() {}
|
||||
|
||||
public static String[] nullToEmpty(String[] array) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
* <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. 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
|
||||
* <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
|
||||
* facility</a>. 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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}.
|
||||
* <p>
|
||||
* The self-signed X.509 certificate may be replaced at a later time by a
|
||||
* certificate signed by a real Certificate Authority.
|
||||
*
|
||||
* <p>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()}.
|
||||
*
|
||||
* <p>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()}.
|
||||
*
|
||||
* <p>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).
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p><h3>Example</h3>
|
||||
* 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.
|
||||
* <pre> {@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();
|
||||
* }</pre>
|
||||
* @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).
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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 <em>indistinguishability under chosen-plaintext attack ({@code
|
||||
* IND-CPA})</em>. 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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
* <p>
|
||||
@@ -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();
|
||||
* </pre>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @see #setKeyValidityStart(Date)
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityEnd(Date endDate) {
|
||||
setKeyValidityForOriginationEnd(endDate);
|
||||
setKeyValidityForConsumptionEnd(endDate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid for encryption and signing.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityForConsumptionEnd(Date endDate) {
|
||||
mKeyValidityForConsumptionEnd = endDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
|
||||
* Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>This must be specified for all keys. There is no default.
|
||||
*
|
||||
* <p>If the set of purposes for which the key can be used does not contain
|
||||
* {@link KeyStoreKeyProperties#PURPOSE_SIGN}, the self-signed certificate generated by
|
||||
* {@link KeyPairGenerator} of {@code AndroidKeyStore} provider will contain an invalid
|
||||
* signature. This is OK if the certificate is only used for obtaining the public key from
|
||||
* Android KeyStore.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of digests algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which
|
||||
* the key can be used when signing/verifying. Attempts to use the key with any other digest
|
||||
* algorithm will be rejected.
|
||||
*
|
||||
* <p>This must be specified for keys which are used for signing/verification.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setEncryptionPaddings(
|
||||
@KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) {
|
||||
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
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.
|
||||
*
|
||||
* <p>This must be specified for RSA keys which are used for signing/verification.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSignaturePaddings(
|
||||
@KeyStoreKeyProperties.SignaturePaddingEnum String... paddings) {
|
||||
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
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.
|
||||
*
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) {
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <em>indistinguishability under chosen-plaintext attack
|
||||
* ({@code IND-CPA})</em>. 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.
|
||||
*
|
||||
* <p>By default, {@code IND-CPA} is required.
|
||||
*
|
||||
* <p>When {@code IND-CPA} is required, encryption/decryption transformations which do not
|
||||
* offer {@code IND-CPA}, such as RSA without padding, are prohibited.
|
||||
*
|
||||
* <p>Before disabling this requirement, consider the following approaches instead:
|
||||
* <ul>
|
||||
* <li>If you are using RSA encryption without padding, consider switching to padding
|
||||
* schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setRandomizedEncryptionRequired(boolean required) {
|
||||
mRandomizedEncryptionRequired = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether user authentication is required to use this key.
|
||||
*
|
||||
* <p>By default, the key can be used without user authentication.
|
||||
*
|
||||
* <p>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)}).
|
||||
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
|
||||
* information</a>.
|
||||
*
|
||||
* <p>This restriction applies only to private key operations. Public key operations are not
|
||||
* restricted.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>By default, the user needs to authenticate for every use of the key.
|
||||
*
|
||||
* <p>This restriction applies only to private key operations. Public key operations are not
|
||||
* restricted.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
|
||||
* every use of the key.
|
||||
*
|
||||
* @see #setUserAuthenticationRequired(boolean)
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. 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
|
||||
* <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
|
||||
* facility</a>. 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.
|
||||
* <p>
|
||||
* 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}.
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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()}.
|
||||
*
|
||||
* <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible.
|
||||
*
|
||||
* <p><h3>Example: Symmetric Key</h3>
|
||||
* 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.
|
||||
* <pre> {@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.
|
||||
* }</pre>
|
||||
*
|
||||
* <p><h3>Example: Asymmetric Key Pair</h3>
|
||||
* 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.
|
||||
* <pre> {@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.
|
||||
* }</pre>
|
||||
* @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).
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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 <em>indistinguishability under chosen-plaintext attack ({@code
|
||||
* IND-CPA})</em>. 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.
|
||||
* <p>
|
||||
@@ -332,24 +107,16 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* KeyStoreParameter params = new KeyStoreParameter.Builder(mContext)
|
||||
* .setEncryptionRequired(true)
|
||||
* .setEncryptionRequired()
|
||||
* .build();
|
||||
* </pre>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityStart(Date startDate) {
|
||||
mKeyValidityStart = startDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityStart(Date)
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityEnd(Date endDate) {
|
||||
setKeyValidityForOriginationEnd(endDate);
|
||||
setKeyValidityForConsumptionEnd(endDate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid for encryption and signing.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityForOriginationEnd(Date endDate) {
|
||||
mKeyValidityForOriginationEnd = endDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid for decryption and
|
||||
* verification.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityForConsumptionEnd(Date endDate) {
|
||||
mKeyValidityForConsumptionEnd = endDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
|
||||
* Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>This must be specified for all keys. There is no default.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS7Padding},
|
||||
* {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to
|
||||
* use the key with any other padding scheme will be rejected.
|
||||
*
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>This must be specified for RSA keys which are used for signing/verification.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>For HMAC keys, the default is the digest algorithm specified in
|
||||
* {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms
|
||||
* must be specified.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) {
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 <em>indistinguishability under chosen-plaintext attack
|
||||
* ({@code IND-CPA})</em>. 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.
|
||||
*
|
||||
* <p>By default, {@code IND-CPA} is required.
|
||||
*
|
||||
* <p>When {@code IND-CPA} is required:
|
||||
* <ul>
|
||||
* <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using
|
||||
* {@code ECB} mode or RSA encryption without padding, are prohibited;</li>
|
||||
* <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC},
|
||||
* {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when
|
||||
* encrypting, to ensure that only random IVs are used.</li>
|
||||
*
|
||||
* <p>Before disabling this requirement, consider the following approaches instead:
|
||||
* <ul>
|
||||
* <li>If you are generating a random IV for encryption and then initializing a {@code}
|
||||
* Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
|
||||
* instead. This will occur if the {@code Cipher} is initialized for encryption without an
|
||||
* IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
|
||||
* <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
|
||||
* random, such as the name of the file being encrypted, or transaction ID, or password,
|
||||
* or a device identifier), consider changing your design to use a random IV which will then
|
||||
* be provided in addition to the ciphertext to the entities which need to decrypt the
|
||||
* ciphertext.</li>
|
||||
* <li>If you are using RSA encryption without padding, consider switching to padding
|
||||
* schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setRandomizedEncryptionRequired(boolean required) {
|
||||
mRandomizedEncryptionRequired = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether user authentication is required to use this key.
|
||||
*
|
||||
* <p>By default, the key can be used without user authentication.
|
||||
*
|
||||
* <p>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)}).
|
||||
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
|
||||
* information</a>.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setUserAuthenticationValidityDurationSeconds(int)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUserAuthenticationRequired(boolean required) {
|
||||
mUserAuthenticationRequired = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>By default, the user needs to authenticate for every use of the key.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @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 KeyStoreParameter}.
|
||||
*
|
||||
@@ -635,18 +164,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
|
||||
public KeyStoreParameter build() {
|
||||
return new KeyStoreParameter(
|
||||
mContext,
|
||||
mFlags,
|
||||
mKeyValidityStart,
|
||||
mKeyValidityForOriginationEnd,
|
||||
mKeyValidityForConsumptionEnd,
|
||||
mPurposes,
|
||||
mEncryptionPaddings,
|
||||
mSignaturePaddings,
|
||||
mDigests,
|
||||
mBlockModes,
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticationRequired,
|
||||
mUserAuthenticationValidityDurationSeconds);
|
||||
mFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package android.security;
|
||||
|
||||
import android.security.keymaster.KeyCharacteristics;
|
||||
import android.security.keymaster.KeymasterDefs;
|
||||
import android.security.keystore.KeyInfo;
|
||||
import android.security.keystore.KeyProperties;
|
||||
|
||||
import libcore.util.EmptyArray;
|
||||
|
||||
@@ -55,7 +57,7 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
throw new InvalidKeySpecException(
|
||||
"Key material export of Android KeyStore keys is not supported");
|
||||
}
|
||||
if (!KeyStoreKeySpec.class.equals(keySpecClass)) {
|
||||
if (!KeyInfo.class.equals(keySpecClass)) {
|
||||
throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
|
||||
}
|
||||
String keyAliasInKeystore = ((KeyStoreSecretKey) key).getAlias();
|
||||
@@ -75,22 +77,22 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
}
|
||||
|
||||
boolean insideSecureHardware;
|
||||
@KeyStoreKeyProperties.OriginEnum int origin;
|
||||
@KeyProperties.OriginEnum int origin;
|
||||
int keySize;
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes;
|
||||
@KeyProperties.PurposeEnum int purposes;
|
||||
String[] encryptionPaddings;
|
||||
@KeyStoreKeyProperties.DigestEnum String[] digests;
|
||||
@KeyStoreKeyProperties.BlockModeEnum String[] blockModes;
|
||||
@KeyProperties.DigestEnum String[] digests;
|
||||
@KeyProperties.BlockModeEnum String[] blockModes;
|
||||
int keymasterSwEnforcedUserAuthenticators;
|
||||
int keymasterHwEnforcedUserAuthenticators;
|
||||
try {
|
||||
if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
|
||||
insideSecureHardware = true;
|
||||
origin = KeyStoreKeyProperties.Origin.fromKeymaster(
|
||||
origin = KeyProperties.Origin.fromKeymaster(
|
||||
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
|
||||
} else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
|
||||
insideSecureHardware = false;
|
||||
origin = KeyStoreKeyProperties.Origin.fromKeymaster(
|
||||
origin = KeyProperties.Origin.fromKeymaster(
|
||||
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
|
||||
} else {
|
||||
throw new InvalidKeySpecException("Key origin not available");
|
||||
@@ -100,15 +102,14 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
throw new InvalidKeySpecException("Key size not available");
|
||||
}
|
||||
keySize = keySizeInteger;
|
||||
purposes = KeyStoreKeyProperties.Purpose.allFromKeymaster(
|
||||
purposes = KeyProperties.Purpose.allFromKeymaster(
|
||||
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
|
||||
|
||||
List<String> encryptionPaddingsList = new ArrayList<String>();
|
||||
for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
|
||||
@KeyStoreKeyProperties.EncryptionPaddingEnum String jcaPadding;
|
||||
@KeyProperties.EncryptionPaddingEnum String jcaPadding;
|
||||
try {
|
||||
jcaPadding =
|
||||
KeyStoreKeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
|
||||
jcaPadding = KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidKeySpecException(
|
||||
"Unsupported encryption padding: " + keymasterPadding);
|
||||
@@ -118,9 +119,9 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
encryptionPaddings =
|
||||
encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
|
||||
|
||||
digests = KeyStoreKeyProperties.Digest.allFromKeymaster(
|
||||
digests = KeyProperties.Digest.allFromKeymaster(
|
||||
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
|
||||
blockModes = KeyStoreKeyProperties.BlockMode.allFromKeymaster(
|
||||
blockModes = KeyProperties.BlockMode.allFromKeymaster(
|
||||
keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
|
||||
keymasterSwEnforcedUserAuthenticators =
|
||||
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
|
||||
@@ -154,7 +155,7 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
|
||||
&& (keymasterHwEnforcedUserAuthenticators != 0)
|
||||
&& (keymasterSwEnforcedUserAuthenticators == 0);
|
||||
|
||||
return new KeyStoreKeySpec(entryAlias,
|
||||
return new KeyInfo(entryAlias,
|
||||
insideSecureHardware,
|
||||
origin,
|
||||
keySize,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package android.security;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.security.keymaster.KeymasterArguments;
|
||||
import android.security.keymaster.KeymasterDefs;
|
||||
@@ -73,7 +72,6 @@ public abstract class KeymasterUtils {
|
||||
* use of the key needs authorization.
|
||||
*/
|
||||
public static void addUserAuthArgs(KeymasterArguments args,
|
||||
Context context,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
if (!userAuthenticationRequired) {
|
||||
@@ -85,7 +83,7 @@ public abstract class KeymasterUtils {
|
||||
// Every use of this key needs to be authorized by the user. This currently means
|
||||
// fingerprint-only auth.
|
||||
FingerprintManager fingerprintManager =
|
||||
context.getSystemService(FingerprintManager.class);
|
||||
KeyStore.getApplicationContext().getSystemService(FingerprintManager.class);
|
||||
if ((fingerprintManager == null) || (!fingerprintManager.isHardwareDetected())) {
|
||||
throw new IllegalStateException(
|
||||
"This device does not support keys which require authentication for every"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
857
keystore/java/android/security/keystore/KeyGenParameterSpec.java
Normal file
857
keystore/java/android/security/keystore/KeyGenParameterSpec.java
Normal file
@@ -0,0 +1,857 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security.keystore;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.security.ArrayUtils;
|
||||
import android.security.KeyStore;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
/**
|
||||
* {@link AlgorithmParameterSpec} for initializing a {@link KeyPairGenerator} or a
|
||||
* {@link KeyGenerator} of the <a href="{@docRoot}training/articles/keystore.html">Android Keystore
|
||||
* system</a>. The spec determines whether user authentication is required for using the key, what
|
||||
* uses the key is authorized for (e.g., only for signing -- decryption not permitted), whether the
|
||||
* key should be encrypted at rest, the key's and validity start and end dates.
|
||||
*
|
||||
* <p>To generate an asymmetric key pair or a symmetric key, create an instance of this class using
|
||||
* the {@link Builder}, initialize a {@code KeyPairGenerator} or a {@code KeyGenerator} of the
|
||||
* desired key type (e.g., {@code EC} or {@code AES} -- see
|
||||
* {@link KeyProperties}.{@code KEY_ALGORITHM} constants) from the {@code AndroidKeyStore} provider
|
||||
* with the {@code KeyPairGeneratorSpec} instance, and then generate a key or key pair using
|
||||
* {@link KeyPairGenerator#generateKeyPair()}.
|
||||
*
|
||||
* <p>The generated key pair or key will be returned by the generator and also stored in the Android
|
||||
* Keystore system under the alias specified in this spec. To obtain the secret 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 system use
|
||||
* {@link java.security.KeyStore#getCertificate(String)} and then
|
||||
* {@link Certificate#getPublicKey()}.
|
||||
*
|
||||
* <p>For asymmetric key pairs, 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 customized in this spec. The self-signed certificate may be replaced at
|
||||
* a later time by a certificate signed by a Certificate Authority (CA).
|
||||
*
|
||||
* <p>NOTE: The key material of the generated symmetric and private keys is not accessible. The key
|
||||
* material of the public keys is accessible.
|
||||
*
|
||||
* <p><h3>Example: Asymmetric key pair</h3>
|
||||
* The following example illustrates how to generate an EC key pair in the Android KeyStore system
|
||||
* under alias {@code key1} 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.
|
||||
* <pre> {@code
|
||||
* KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
|
||||
* KeyProperties.KEY_ALGORITHM_EC,
|
||||
* "AndroidKeyStore");
|
||||
* keyPairGenerator.initialize(
|
||||
* new KeyGenParameterSpec.Builder("key1",
|
||||
* KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
|
||||
* .setDigests(KeyProperties.DIGEST_SHA256
|
||||
* | KeyProperties.DIGEST_SHA384
|
||||
* | KeyProperties.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.generateKeyPair();
|
||||
*
|
||||
* // 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("key1", null);
|
||||
* PublicKey publicKey = keyStore.getCertificate("key1").getPublicKey();
|
||||
* }</pre>
|
||||
*
|
||||
* <p><h3>Example: Symmetric key</h3>
|
||||
* The following example illustrates how to generate an AES key in the Android KeyStore system under
|
||||
* alias {@code key2} authorized to be used only for encryption/decryption in CTR mode.
|
||||
* <pre> {@code
|
||||
* KeyGenerator keyGenerator = KeyGenerator.getInstance(
|
||||
* KeyProperties.KEY_ALGORITHM_HMAC_SHA256,
|
||||
* "AndroidKeyStore");
|
||||
* keyGenerator.initialize(
|
||||
* new KeyGenParameterSpec.Builder("key2",
|
||||
* KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
* .setBlockModes(KeyProperties.BLOCK_MODE_CTR)
|
||||
* .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||
* .build());
|
||||
* SecretKey key = keyGenerator.generateKey();
|
||||
*
|
||||
* // The key can also be obtained from the Android Keystore any time as follows:
|
||||
* KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||
* keyStore.load(null);
|
||||
* key = (SecretKey) keyStore.getKey("key2", null);
|
||||
* }</pre>
|
||||
*/
|
||||
public final class KeyGenParameterSpec 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 String mKeystoreAlias;
|
||||
private final int mKeySize;
|
||||
private final AlgorithmParameterSpec mSpec;
|
||||
private final X500Principal mCertificateSubject;
|
||||
private final BigInteger mCertificateSerialNumber;
|
||||
private final Date mCertificateNotBefore;
|
||||
private final Date mCertificateNotAfter;
|
||||
private final int mFlags;
|
||||
private final Date mKeyValidityStart;
|
||||
private final Date mKeyValidityForOriginationEnd;
|
||||
private final Date mKeyValidityForConsumptionEnd;
|
||||
private final @KeyProperties.PurposeEnum int mPurposes;
|
||||
private final @KeyProperties.DigestEnum String[] mDigests;
|
||||
private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
|
||||
private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
|
||||
private final @KeyProperties.BlockModeEnum String[] mBlockModes;
|
||||
private final boolean mRandomizedEncryptionRequired;
|
||||
private final boolean mUserAuthenticationRequired;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
|
||||
/**
|
||||
* @hide should be built with Builder
|
||||
*/
|
||||
public KeyGenParameterSpec(
|
||||
String keyStoreAlias,
|
||||
int keySize,
|
||||
AlgorithmParameterSpec spec,
|
||||
X500Principal certificateSubject,
|
||||
BigInteger certificateSerialNumber,
|
||||
Date certificateNotBefore,
|
||||
Date certificateNotAfter,
|
||||
int flags,
|
||||
Date keyValidityStart,
|
||||
Date keyValidityForOriginationEnd,
|
||||
Date keyValidityForConsumptionEnd,
|
||||
@KeyProperties.PurposeEnum int purposes,
|
||||
@KeyProperties.DigestEnum String[] digests,
|
||||
@KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
|
||||
@KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
|
||||
@KeyProperties.BlockModeEnum String[] blockModes,
|
||||
boolean randomizedEncryptionRequired,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
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 (certificateSubject == null) {
|
||||
certificateSubject = DEFAULT_CERT_SUBJECT;
|
||||
}
|
||||
if (certificateNotBefore == null) {
|
||||
certificateNotBefore = DEFAULT_CERT_NOT_BEFORE;
|
||||
}
|
||||
if (certificateNotAfter == null) {
|
||||
certificateNotAfter = DEFAULT_CERT_NOT_AFTER;
|
||||
}
|
||||
if (certificateSerialNumber == null) {
|
||||
certificateSerialNumber = DEFAULT_CERT_SERIAL_NUMBER;
|
||||
}
|
||||
|
||||
if (certificateNotAfter.before(certificateNotBefore)) {
|
||||
throw new IllegalArgumentException("certificateNotAfter < certificateNotBefore");
|
||||
}
|
||||
|
||||
mKeystoreAlias = keyStoreAlias;
|
||||
mKeySize = keySize;
|
||||
mSpec = spec;
|
||||
mCertificateSubject = certificateSubject;
|
||||
mCertificateSerialNumber = certificateSerialNumber;
|
||||
mCertificateNotBefore = certificateNotBefore;
|
||||
mCertificateNotAfter = certificateNotAfter;
|
||||
mFlags = flags;
|
||||
mKeyValidityStart = keyValidityStart;
|
||||
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
|
||||
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
|
||||
mPurposes = purposes;
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alias that will be used in the {@code java.security.KeyStore}
|
||||
* in conjunction with the {@code AndroidKeyStore}.
|
||||
*/
|
||||
public String getKeystoreAlias() {
|
||||
return mKeystoreAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested key size or {@code -1} if default size should be used.
|
||||
*/
|
||||
public int getKeySize() {
|
||||
return mKeySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link AlgorithmParameterSpec} that will be used for creation
|
||||
* of the key pair.
|
||||
*/
|
||||
@NonNull
|
||||
public AlgorithmParameterSpec getAlgorithmParameterSpec() {
|
||||
return mSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subject distinguished name to be used on the X.509 certificate that will be put
|
||||
* in the {@link java.security.KeyStore}.
|
||||
*/
|
||||
@NonNull
|
||||
public X500Principal getCertificateSubject() {
|
||||
return mCertificateSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number to be used on the X.509 certificate that will be put in the
|
||||
* {@link java.security.KeyStore}.
|
||||
*/
|
||||
@NonNull
|
||||
public BigInteger getCertificateSerialNumber() {
|
||||
return mCertificateSerialNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start date to be used on the X.509 certificate that will be put in the
|
||||
* {@link java.security.KeyStore}.
|
||||
*/
|
||||
@NonNull
|
||||
public Date getCertificateNotBefore() {
|
||||
return mCertificateNotBefore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end date to be used on the X.509 certificate that will be put in the
|
||||
* {@link java.security.KeyStore}.
|
||||
*/
|
||||
@NonNull
|
||||
public Date getCertificateNotAfter() {
|
||||
return mCertificateNotAfter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int getFlags() {
|
||||
return mFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key must be encrypted at rest. This will protect the key with the
|
||||
* secure lock screen credential (e.g., password, PIN, or pattern).
|
||||
*
|
||||
* <p>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 isEncryptionAtRestRequired() {
|
||||
return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time instant before which the key is not yet valid or {@code null} if not
|
||||
* restricted.
|
||||
*/
|
||||
@Nullable
|
||||
public Date getKeyValidityStart() {
|
||||
return mKeyValidityStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time instant after which the key is no longer valid for decryption and
|
||||
* verification or {@code null} if not restricted.
|
||||
*/
|
||||
@Nullable
|
||||
public Date getKeyValidityForConsumptionEnd() {
|
||||
return mKeyValidityForConsumptionEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time instant after which the key is no longer valid for encryption and signing
|
||||
* or {@code null} if not restricted.
|
||||
*/
|
||||
@Nullable
|
||||
public Date getKeyValidityForOriginationEnd() {
|
||||
return mKeyValidityForOriginationEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
|
||||
* Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
public @KeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384} with which the
|
||||
* key can be used or {@code null} if not specified.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
|
||||
*
|
||||
* @throws IllegalStateException if this set has not been specified.
|
||||
*
|
||||
* @see #isDigestsSpecified()
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyProperties.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of padding schemes (e.g., {@code PKCS7Padding}, {@code OEAPPadding},
|
||||
* {@code PKCS1Padding}, {@code NoPadding}) with which the key can be used when
|
||||
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyProperties.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.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyProperties.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.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyProperties.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 <em>indistinguishability under chosen-plaintext attack ({@code
|
||||
* IND-CPA})</em>. 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.
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <p>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 of {@link KeyGenParameterSpec} instances.
|
||||
*/
|
||||
public final static class Builder {
|
||||
private final String mKeystoreAlias;
|
||||
private @KeyProperties.PurposeEnum int mPurposes;
|
||||
|
||||
private int mKeySize = -1;
|
||||
private AlgorithmParameterSpec mSpec;
|
||||
private X500Principal mCertificateSubject;
|
||||
private BigInteger mCertificateSerialNumber;
|
||||
private Date mCertificateNotBefore;
|
||||
private Date mCertificateNotAfter;
|
||||
private int mFlags;
|
||||
private Date mKeyValidityStart;
|
||||
private Date mKeyValidityForOriginationEnd;
|
||||
private Date mKeyValidityForConsumptionEnd;
|
||||
private @KeyProperties.DigestEnum String[] mDigests;
|
||||
private @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
|
||||
private @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
|
||||
private @KeyProperties.BlockModeEnum String[] mBlockModes;
|
||||
private boolean mRandomizedEncryptionRequired = true;
|
||||
private boolean mUserAuthenticationRequired;
|
||||
private int mUserAuthenticationValidityDurationSeconds = -1;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the {@code Builder}.
|
||||
*
|
||||
* @param keystoreAlias alias of the entry in which the generated key will appear in
|
||||
* Android KeyStore.
|
||||
* @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be
|
||||
* used. Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>If the set of purposes for which the key can be used does not contain
|
||||
* {@link KeyProperties#PURPOSE_SIGN}, the self-signed certificate generated by
|
||||
* {@link KeyPairGenerator} of {@code AndroidKeyStore} provider will contain an
|
||||
* invalid signature. This is OK if the certificate is only used for obtaining the
|
||||
* public key from Android KeyStore.
|
||||
*
|
||||
* <p><b>NOTE: The {@code purposes} parameter has currently no effect on asymmetric
|
||||
* key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
public Builder(@NonNull String keystoreAlias, @KeyProperties.PurposeEnum int purposes) {
|
||||
if (keystoreAlias == null) {
|
||||
throw new NullPointerException("keystoreAlias == null");
|
||||
}
|
||||
mKeystoreAlias = keystoreAlias;
|
||||
mPurposes = purposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size (in bits) of the key to be generated. For instance, for RSA keys this sets
|
||||
* the modulus size, for EC keys this selects a curve with a matching field size, and for
|
||||
* symmetric keys this sets the size of the bitstring which is their key material.
|
||||
*
|
||||
* <p>The default key size is specific to each key algorithm.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeySize(int keySize) {
|
||||
if (keySize < 0) {
|
||||
throw new IllegalArgumentException("keySize < 0");
|
||||
}
|
||||
mKeySize = keySize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the algorithm-specific key generation parameters. For example, for RSA keys this may
|
||||
* be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}.
|
||||
*/
|
||||
public Builder setAlgorithmParameterSpec(@NonNull AlgorithmParameterSpec spec) {
|
||||
if (spec == null) {
|
||||
throw new NullPointerException("spec == null");
|
||||
}
|
||||
mSpec = spec;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the subject used for the self-signed certificate of the generated key pair.
|
||||
*
|
||||
* <p>By default, the subject is {@code CN=fake}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCertificateSubject(@NonNull X500Principal subject) {
|
||||
if (subject == null) {
|
||||
throw new NullPointerException("subject == null");
|
||||
}
|
||||
mCertificateSubject = subject;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serial number used for the self-signed certificate of the generated key pair.
|
||||
*
|
||||
* <p>By default, the serial number is {@code 1}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCertificateSerialNumber(@NonNull BigInteger serialNumber) {
|
||||
if (serialNumber == null) {
|
||||
throw new NullPointerException("serialNumber == null");
|
||||
}
|
||||
mCertificateSerialNumber = serialNumber;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start of the validity period for the self-signed certificate of the generated
|
||||
* key pair.
|
||||
*
|
||||
* <p>By default, this date is {@code Jan 1 1970}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCertificateNotBefore(@NonNull Date date) {
|
||||
if (date == null) {
|
||||
throw new NullPointerException("date == null");
|
||||
}
|
||||
mCertificateNotBefore = date;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end of the validity period for the self-signed certificate of the generated key
|
||||
* pair.
|
||||
*
|
||||
* <p>By default, this date is {@code Jan 1 2048}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setCertificateNotAfter(@NonNull Date date) {
|
||||
if (date == null) {
|
||||
throw new NullPointerException("date == null");
|
||||
}
|
||||
mCertificateNotAfter = date;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether this key pair or key must be encrypted at rest. This will protect the key
|
||||
* pair or key with the secure lock screen credential (e.g., password, PIN, or pattern).
|
||||
*
|
||||
* <p>Note that enabling this feature 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()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setEncryptionAtRestRequired(boolean required) {
|
||||
if (required) {
|
||||
mFlags |= KeyStore.FLAG_ENCRYPTED;
|
||||
} else {
|
||||
mFlags &= ~KeyStore.FLAG_ENCRYPTED;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant before which the key is not yet valid.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityStart(Date startDate) {
|
||||
mKeyValidityStart = startDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityStart(Date)
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityEnd(Date endDate) {
|
||||
setKeyValidityForOriginationEnd(endDate);
|
||||
setKeyValidityForConsumptionEnd(endDate);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid for encryption and signing.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityForOriginationEnd(Date endDate) {
|
||||
mKeyValidityForOriginationEnd = endDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time instant after which the key is no longer valid for decryption and
|
||||
* verification.
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeyValidityForConsumptionEnd(Date endDate) {
|
||||
mKeyValidityForConsumptionEnd = endDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of digests algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which
|
||||
* the key can be used when signing/verifying. Attempts to use the key with any other digest
|
||||
* algorithm will be rejected.
|
||||
*
|
||||
* <p>This must be specified for keys which are used for signing/verification. For HMAC
|
||||
* keys, the set of digests defaults to the digest associated with the key algorithm (e.g.,
|
||||
* {@code SHA-256} for key algorithm {@code HmacSHA256}
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see KeyProperties.Digest
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDigests(@KeyProperties.DigestEnum String... digests) {
|
||||
mDigests = ArrayUtils.cloneIfNotEmpty(digests);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code OAEPPadding},
|
||||
* {@code PKCS1Padding}, {@code NoPadding}) with which the key can be used when
|
||||
* encrypting/decrypting. Attempts to use the key with any other padding scheme will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setEncryptionPaddings(
|
||||
@KeyProperties.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.
|
||||
*
|
||||
* <p>This must be specified for RSA keys which are used for signing/verification.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSignaturePaddings(
|
||||
@KeyProperties.SignaturePaddingEnum String... paddings) {
|
||||
mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
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.
|
||||
*
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBlockModes(@KeyProperties.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 <em>indistinguishability under chosen-plaintext attack
|
||||
* ({@code IND-CPA})</em>. 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.
|
||||
*
|
||||
* <p>By default, {@code IND-CPA} is required.
|
||||
*
|
||||
* <p>When {@code IND-CPA} is required:
|
||||
* <ul>
|
||||
* <li>encryption/decryption transformation which do not offer {@code IND-CPA}, such as
|
||||
* {@code ECB} with a symmetric encryption algorithm, or RSA encryption/decryption without
|
||||
* padding, are prohibited;</li>
|
||||
* <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM},
|
||||
* caller-provided IVs are rejected when encrypting, to ensure that only random IVs are
|
||||
* used.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Before disabling this requirement, consider the following approaches instead:
|
||||
* <ul>
|
||||
* <li>If you are generating a random IV for encryption and then initializing a {@code}
|
||||
* Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
|
||||
* instead. This will occur if the {@code Cipher} is initialized for encryption without an
|
||||
* IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
|
||||
* <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
|
||||
* random, such as the name of the file being encrypted, or transaction ID, or password,
|
||||
* or a device identifier), consider changing your design to use a random IV which will then
|
||||
* be provided in addition to the ciphertext to the entities which need to decrypt the
|
||||
* ciphertext.</li>
|
||||
* <li>If you are using RSA encryption without padding, consider switching to encryption
|
||||
* padding schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setRandomizedEncryptionRequired(boolean required) {
|
||||
mRandomizedEncryptionRequired = required;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether user authentication is required to use this key.
|
||||
*
|
||||
* <p>By default, the key can be used without user authentication.
|
||||
*
|
||||
* <p>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)}).
|
||||
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
|
||||
* information</a>.
|
||||
*
|
||||
* <p>This restriction applies only to private key operations. Public key operations are not
|
||||
* restricted.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>By default, the user needs to authenticate for every use of the key.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect.</b>
|
||||
*
|
||||
* @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
|
||||
* every use of the key.
|
||||
*
|
||||
* @see #setUserAuthenticationRequired(boolean)
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setUserAuthenticationValidityDurationSeconds(
|
||||
@IntRange(from = -1) int seconds) {
|
||||
mUserAuthenticationValidityDurationSeconds = seconds;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an instance of {@code KeyGenParameterSpec}.
|
||||
*
|
||||
* @throws IllegalArgumentException if a required field is missing
|
||||
*/
|
||||
@NonNull
|
||||
public KeyGenParameterSpec build() {
|
||||
return new KeyGenParameterSpec(
|
||||
mKeystoreAlias,
|
||||
mKeySize,
|
||||
mSpec,
|
||||
mCertificateSubject,
|
||||
mCertificateSerialNumber,
|
||||
mCertificateNotBefore,
|
||||
mCertificateNotAfter,
|
||||
mFlags,
|
||||
mKeyValidityStart,
|
||||
mKeyValidityForOriginationEnd,
|
||||
mKeyValidityForConsumptionEnd,
|
||||
mPurposes,
|
||||
mDigests,
|
||||
mEncryptionPaddings,
|
||||
mSignaturePaddings,
|
||||
mBlockModes,
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticationRequired,
|
||||
mUserAuthenticationValidityDurationSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.security.ArrayUtils;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.security.spec.KeySpec;
|
||||
@@ -27,55 +28,55 @@ import javax.crypto.SecretKey;
|
||||
|
||||
/**
|
||||
* Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
|
||||
* KeyStore</a>. This class describes whether the key material is available in
|
||||
* Keystore system</a>. This class describes whether the key material is available in
|
||||
* plaintext outside of secure hardware, whether user authentication is required for using the key
|
||||
* and whether this requirement is enforced by secure hardware, the key's origin, what uses the key
|
||||
* is authorized for (e.g., only in {@code CBC} mode, or signing only), whether the key should be
|
||||
* encrypted at rest, the key's and validity start and end dates.
|
||||
*
|
||||
* <p><h3>Example: Symmetric Key</h3>
|
||||
* The following example illustrates how to obtain a {@link KeyStoreKeySpec} describing the provided
|
||||
* Android KeyStore {@link SecretKey}.
|
||||
* The following example illustrates how to obtain a {@code KeyInfo} describing the provided Android
|
||||
* Keystore {@link SecretKey}.
|
||||
* <pre> {@code
|
||||
* SecretKey key = ...; // Android KeyStore key
|
||||
* SecretKey key = ...; // Android Keystore key
|
||||
*
|
||||
* SecretKeyFactory factory = SecretKeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
|
||||
* KeyStoreKeySpec spec;
|
||||
* KeyInfo keyInfo;
|
||||
* try {
|
||||
* spec = (KeyStoreKeySpec) factory.getKeySpec(key, KeyStoreKeySpec.class);
|
||||
* keyInfo = (KeyInfo) factory.getKeySpec(key, KeyInfo.class);
|
||||
* } catch (InvalidKeySpecException e) {
|
||||
* // Not an Android KeyStore key.
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* <p><h3>Example: Private Key</h3>
|
||||
* The following example illustrates how to obtain a {@link KeyStoreKeySpec} describing the provided
|
||||
* The following example illustrates how to obtain a {@code KeyInfo} describing the provided
|
||||
* Android KeyStore {@link PrivateKey}.
|
||||
* <pre> {@code
|
||||
* PrivateKey key = ...; // Android KeyStore key
|
||||
*
|
||||
* KeyFactory factory = KeyFactory.getInstance(key.getAlgorithm(), "AndroidKeyStore");
|
||||
* KeyStoreKeySpec spec;
|
||||
* KeyInfo keyInfo;
|
||||
* try {
|
||||
* spec = factory.getKeySpec(key, KeyStoreKeySpec.class);
|
||||
* keyInfo = factory.getKeySpec(key, KeyInfo.class);
|
||||
* } catch (InvalidKeySpecException e) {
|
||||
* // Not an Android KeyStore key.
|
||||
* }
|
||||
* }</pre>
|
||||
*/
|
||||
public class KeyStoreKeySpec implements KeySpec {
|
||||
public class KeyInfo implements KeySpec {
|
||||
private final String mKeystoreAlias;
|
||||
private final int mKeySize;
|
||||
private final boolean mInsideSecureHardware;
|
||||
private final @KeyStoreKeyProperties.OriginEnum int mOrigin;
|
||||
private final @KeyProperties.OriginEnum int mOrigin;
|
||||
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 @KeyProperties.PurposeEnum int mPurposes;
|
||||
private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
|
||||
private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
|
||||
private final @KeyProperties.DigestEnum String[] mDigests;
|
||||
private final @KeyProperties.BlockModeEnum String[] mBlockModes;
|
||||
private final boolean mUserAuthenticationRequired;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
|
||||
@@ -83,18 +84,18 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
KeyStoreKeySpec(String keystoreKeyAlias,
|
||||
public KeyInfo(String keystoreKeyAlias,
|
||||
boolean insideSecureHardware,
|
||||
@KeyStoreKeyProperties.OriginEnum int origin,
|
||||
@KeyProperties.OriginEnum int origin,
|
||||
int keySize,
|
||||
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,
|
||||
@KeyProperties.PurposeEnum int purposes,
|
||||
@KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
|
||||
@KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
|
||||
@KeyProperties.DigestEnum String[] digests,
|
||||
@KeyProperties.BlockModeEnum String[] blockModes,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds,
|
||||
boolean userAuthenticationRequirementEnforcedBySecureHardware) {
|
||||
@@ -135,9 +136,9 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the origin of the key. See {@link KeyStoreKeyProperties}.{@code ORIGIN} constants.
|
||||
* Gets the origin of the key. See {@link KeyProperties}.{@code ORIGIN} constants.
|
||||
*/
|
||||
public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
|
||||
public @KeyProperties.OriginEnum int getOrigin() {
|
||||
return mOrigin;
|
||||
}
|
||||
|
||||
@@ -182,9 +183,9 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
* Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
|
||||
* Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
|
||||
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
|
||||
public @KeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
@@ -193,10 +194,10 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
* when encrypting/decrypting. Attempts to use the key with any other block modes will be
|
||||
* rejected.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
|
||||
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() {
|
||||
public @KeyProperties.BlockModeEnum String[] getBlockModes() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
|
||||
}
|
||||
|
||||
@@ -205,10 +206,10 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
* {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
|
||||
* the key with any other padding scheme will be rejected.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
|
||||
public @KeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
|
||||
}
|
||||
|
||||
@@ -217,10 +218,10 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
* can be used when signing/verifying. Attempts to use the key with any other padding scheme
|
||||
* will be rejected.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyStoreKeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
|
||||
public @KeyProperties.SignaturePaddingEnum String[] getSignaturePaddings() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
|
||||
}
|
||||
|
||||
@@ -228,10 +229,10 @@ public class KeyStoreKeySpec implements KeySpec {
|
||||
* Gets the set of digest algorithms (e.g., {@code SHA-256}, {@code SHA-384}) with which the key
|
||||
* can be used.
|
||||
*
|
||||
* @see KeyStoreKeyProperties.Digest
|
||||
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyStoreKeyProperties.DigestEnum String[] getDigests() {
|
||||
public @KeyProperties.DigestEnum String[] getDigests() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mDigests);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
@@ -30,10 +30,10 @@ import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Properties of {@code AndroidKeyStore} keys.
|
||||
* Properties of <a href="{@docRoot}training/articles/keystore.html">Android Keystore</a> keys.
|
||||
*/
|
||||
public abstract class KeyStoreKeyProperties {
|
||||
private KeyStoreKeyProperties() {}
|
||||
public abstract class KeyProperties {
|
||||
private KeyProperties() {}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -68,10 +68,13 @@ public abstract class KeyStoreKeyProperties {
|
||||
*/
|
||||
public static final int PURPOSE_VERIFY = 1 << 3;
|
||||
|
||||
static abstract class Purpose {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static abstract class Purpose {
|
||||
private Purpose() {}
|
||||
|
||||
static int toKeymaster(@PurposeEnum int purpose) {
|
||||
public static int toKeymaster(@PurposeEnum int purpose) {
|
||||
switch (purpose) {
|
||||
case PURPOSE_ENCRYPT:
|
||||
return KeymasterDefs.KM_PURPOSE_ENCRYPT;
|
||||
@@ -86,7 +89,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
}
|
||||
|
||||
static @PurposeEnum int fromKeymaster(int purpose) {
|
||||
public static @PurposeEnum int fromKeymaster(int purpose) {
|
||||
switch (purpose) {
|
||||
case KeymasterDefs.KM_PURPOSE_ENCRYPT:
|
||||
return PURPOSE_ENCRYPT;
|
||||
@@ -102,7 +105,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static int[] allToKeymaster(@PurposeEnum int purposes) {
|
||||
public static int[] allToKeymaster(@PurposeEnum int purposes) {
|
||||
int[] result = getSetFlags(purposes);
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = toKeymaster(result[i]);
|
||||
@@ -110,7 +113,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
return result;
|
||||
}
|
||||
|
||||
static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) {
|
||||
public static @PurposeEnum int allFromKeymaster(@NonNull Collection<Integer> purposes) {
|
||||
@PurposeEnum int result = 0;
|
||||
for (int keymasterPurpose : purposes) {
|
||||
result |= fromKeymaster(keymasterPurpose);
|
||||
@@ -159,10 +162,14 @@ public abstract class KeyStoreKeyProperties {
|
||||
/** Keyed-Hash Message Authentication Code (HMAC) key using SHA-512 as the hash. */
|
||||
public static final String KEY_ALGORITHM_HMAC_SHA512 = "HmacSHA512";
|
||||
|
||||
static abstract class KeyAlgorithm {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static abstract class KeyAlgorithm {
|
||||
private KeyAlgorithm() {}
|
||||
|
||||
static int toKeymasterSecretKeyAlgorithm(@NonNull @KeyAlgorithmEnum String algorithm) {
|
||||
public static int toKeymasterSecretKeyAlgorithm(
|
||||
@NonNull @KeyAlgorithmEnum String algorithm) {
|
||||
if (KEY_ALGORITHM_AES.equalsIgnoreCase(algorithm)) {
|
||||
return KeymasterDefs.KM_ALGORITHM_AES;
|
||||
} else if (algorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
|
||||
@@ -174,7 +181,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm(
|
||||
public static @KeyAlgorithmEnum String fromKeymasterSecretKeyAlgorithm(
|
||||
int keymasterAlgorithm, int keymasterDigest) {
|
||||
switch (keymasterAlgorithm) {
|
||||
case KeymasterDefs.KM_ALGORITHM_AES:
|
||||
@@ -210,7 +217,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
*
|
||||
* @return keymaster digest or {@code -1} if the algorithm does not involve a digest.
|
||||
*/
|
||||
static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) {
|
||||
public static int toKeymasterDigest(@NonNull @KeyAlgorithmEnum String algorithm) {
|
||||
String algorithmUpper = algorithm.toUpperCase(Locale.US);
|
||||
if (algorithmUpper.startsWith("HMAC")) {
|
||||
String digestUpper = algorithmUpper.substring("HMAC".length());
|
||||
@@ -259,10 +266,13 @@ public abstract class KeyStoreKeyProperties {
|
||||
/** Galois/Counter Mode (GCM) block mode. */
|
||||
public static final String BLOCK_MODE_GCM = "GCM";
|
||||
|
||||
static abstract class BlockMode {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static abstract class BlockMode {
|
||||
private BlockMode() {}
|
||||
|
||||
static int toKeymaster(@NonNull @BlockModeEnum String blockMode) {
|
||||
public static int toKeymaster(@NonNull @BlockModeEnum String blockMode) {
|
||||
if (BLOCK_MODE_ECB.equalsIgnoreCase(blockMode)) {
|
||||
return KeymasterDefs.KM_MODE_ECB;
|
||||
} else if (BLOCK_MODE_CBC.equalsIgnoreCase(blockMode)) {
|
||||
@@ -277,7 +287,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static @BlockModeEnum String fromKeymaster(int blockMode) {
|
||||
public static @BlockModeEnum String fromKeymaster(int blockMode) {
|
||||
switch (blockMode) {
|
||||
case KeymasterDefs.KM_MODE_ECB:
|
||||
return BLOCK_MODE_ECB;
|
||||
@@ -293,7 +303,8 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static @BlockModeEnum String[] allFromKeymaster(@NonNull Collection<Integer> blockModes) {
|
||||
public static @BlockModeEnum String[] allFromKeymaster(
|
||||
@NonNull Collection<Integer> blockModes) {
|
||||
if ((blockModes == null) || (blockModes.isEmpty())) {
|
||||
return EmptyArray.STRING;
|
||||
}
|
||||
@@ -306,7 +317,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
return result;
|
||||
}
|
||||
|
||||
static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) {
|
||||
public static int[] allToKeymaster(@Nullable @BlockModeEnum String[] blockModes) {
|
||||
if ((blockModes == null) || (blockModes.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
@@ -350,10 +361,13 @@ public abstract class KeyStoreKeyProperties {
|
||||
*/
|
||||
public static final String ENCRYPTION_PADDING_RSA_OAEP = "OAEPPadding";
|
||||
|
||||
static abstract class EncryptionPadding {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static abstract class EncryptionPadding {
|
||||
private EncryptionPadding() {}
|
||||
|
||||
static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) {
|
||||
public static int toKeymaster(@NonNull @EncryptionPaddingEnum String padding) {
|
||||
if (ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
|
||||
return KeymasterDefs.KM_PAD_NONE;
|
||||
} else if (ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
|
||||
@@ -369,7 +383,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static @EncryptionPaddingEnum String fromKeymaster(int padding) {
|
||||
public static @EncryptionPaddingEnum String fromKeymaster(int padding) {
|
||||
switch (padding) {
|
||||
case KeymasterDefs.KM_PAD_NONE:
|
||||
return ENCRYPTION_PADDING_NONE;
|
||||
@@ -386,7 +400,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) {
|
||||
public static int[] allToKeymaster(@Nullable @EncryptionPaddingEnum String[] paddings) {
|
||||
if ((paddings == null) || (paddings.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
@@ -508,10 +522,13 @@ public abstract class KeyStoreKeyProperties {
|
||||
*/
|
||||
public static final String DIGEST_SHA512 = "SHA-512";
|
||||
|
||||
static abstract class Digest {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static abstract class Digest {
|
||||
private Digest() {}
|
||||
|
||||
static int toKeymaster(@NonNull @DigestEnum String digest) {
|
||||
public static int toKeymaster(@NonNull @DigestEnum String digest) {
|
||||
switch (digest.toUpperCase(Locale.US)) {
|
||||
case DIGEST_SHA1:
|
||||
return KeymasterDefs.KM_DIGEST_SHA1;
|
||||
@@ -533,7 +550,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static @DigestEnum String fromKeymaster(int digest) {
|
||||
public static @DigestEnum String fromKeymaster(int digest) {
|
||||
switch (digest) {
|
||||
case KeymasterDefs.KM_DIGEST_NONE:
|
||||
return DIGEST_NONE;
|
||||
@@ -555,7 +572,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) {
|
||||
public static @DigestEnum String[] allFromKeymaster(@NonNull Collection<Integer> digests) {
|
||||
if (digests.isEmpty()) {
|
||||
return EmptyArray.STRING;
|
||||
}
|
||||
@@ -569,7 +586,7 @@ public abstract class KeyStoreKeyProperties {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) {
|
||||
public static int[] allToKeymaster(@Nullable @DigestEnum String[] digests) {
|
||||
if ((digests == null) || (digests.length == 0)) {
|
||||
return EmptyArray.INT;
|
||||
}
|
||||
@@ -606,10 +623,13 @@ public abstract class KeyStoreKeyProperties {
|
||||
*/
|
||||
public static final int ORIGIN_UNKNOWN = 1 << 2;
|
||||
|
||||
static abstract class Origin {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static abstract class Origin {
|
||||
private Origin() {}
|
||||
|
||||
static @OriginEnum int fromKeymaster(int origin) {
|
||||
public static @OriginEnum int fromKeymaster(int origin) {
|
||||
switch (origin) {
|
||||
case KeymasterDefs.KM_ORIGIN_GENERATED:
|
||||
return ORIGIN_GENERATED;
|
||||
@@ -14,139 +14,143 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.security.ArrayUtils;
|
||||
import android.security.KeyStore;
|
||||
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
import java.security.Key;
|
||||
import java.security.KeyStore.ProtectionParameter;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
|
||||
/**
|
||||
* {@link AlgorithmParameterSpec} for initializing a {@link KeyGenerator} of the
|
||||
* Specification of how a key or key pair is secured when imported into the
|
||||
* <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class
|
||||
* specifies whether user authentication is required for using the key, what uses the key is
|
||||
* authorized for (e.g., only in {@code CBC} mode), whether the key should be encrypted at rest, the
|
||||
* key's and validity start and end dates.
|
||||
* specifies parameters such as 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.
|
||||
*
|
||||
* <p>To generate a key, create an instance of this class using the {@link Builder}, initialize a
|
||||
* {@code KeyGenerator} of the desired key type (e.g., {@code AES} or {@code HmacSHA256}) from the
|
||||
* {@code AndroidKeyStore} provider with the {@code KeyGeneratorSpec} instance, and then generate a
|
||||
* key using {@link KeyGenerator#generateKey()}.
|
||||
* <p>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.
|
||||
*
|
||||
* <p>The generated key will be returned by the {@code KeyGenerator} and also stored in the Android
|
||||
* KeyStore under the alias specified in this {@code KeyGeneratorSpec}. To obtain the key from the
|
||||
* Android KeyStore use
|
||||
* <p>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()}.
|
||||
*
|
||||
* <p>NOTE: The key material of the keys generating using the {@code KeyGeneratorSpec} is not
|
||||
* accessible.
|
||||
* <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible.
|
||||
*
|
||||
* <p><h3>Example</h3>
|
||||
* The following example illustrates how to generate an HMAC key in the Android KeyStore under alias
|
||||
* {@code key1} authorized to be used only for HMAC with SHA-256 digest and only if the user has
|
||||
* been authenticated within the last five minutes.
|
||||
* <p><h3>Example: Symmetric Key</h3>
|
||||
* 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.
|
||||
* <pre> {@code
|
||||
* KeyGenerator keyGenerator = KeyGenerator.getInstance(
|
||||
* KeyStoreKeyProperties.KEY_ALGORITHM_HMAC_SHA256,
|
||||
* "AndroidKeyStore");
|
||||
* keyGenerator.initialize(
|
||||
* new KeyGeneratorSpec.Builder(context)
|
||||
* .setAlias("key1")
|
||||
* .setPurposes(KeyStoreKeyProperties.PURPOSE_SIGN
|
||||
* | KeyStoreKeyProperties.PURPOSE_VERIFY)
|
||||
* // Only permit this key to be used if the user authenticated
|
||||
* // within the last five minutes.
|
||||
* .setUserAuthenticationRequired(true)
|
||||
* .setUserAuthenticationValidityDurationSeconds(5 * 60)
|
||||
* .build());
|
||||
* SecretKey key = keyGenerator.generateKey();
|
||||
* SecretKey key = ...; // AES key
|
||||
*
|
||||
* // The key can also be obtained from the Android KeyStore any time as follows:
|
||||
* KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||
* keyStore.load(null);
|
||||
* SecretKey key = (SecretKey) keyStore.getKey("key1", null);
|
||||
* keyStore.setEntry(
|
||||
* "key1",
|
||||
* new KeyStore.SecretKeyEntry(key),
|
||||
* new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
* .setBlockMode(KeyProperties.BLOCK_MODE_CBC)
|
||||
* .setEncryptionPaddings(KeyProperties.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.
|
||||
* }</pre>
|
||||
*
|
||||
* <p><h3>Example: Asymmetric Key Pair</h3>
|
||||
* 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.
|
||||
* <pre> {@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 KeyProtection.Builder(KeyProperties.PURPOSE_SIGN)
|
||||
* .setDigests(KeyProperties.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.
|
||||
* }</pre>
|
||||
*/
|
||||
public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
|
||||
private final Context mContext;
|
||||
private final String mKeystoreAlias;
|
||||
public final class KeyProtection implements ProtectionParameter {
|
||||
private final int mFlags;
|
||||
private final int mKeySize;
|
||||
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.BlockModeEnum String[] mBlockModes;
|
||||
private final @KeyProperties.PurposeEnum int mPurposes;
|
||||
private final @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
|
||||
private final @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
|
||||
private final @KeyProperties.DigestEnum String[] mDigests;
|
||||
private final @KeyProperties.BlockModeEnum String[] mBlockModes;
|
||||
private final boolean mRandomizedEncryptionRequired;
|
||||
private final boolean mUserAuthenticationRequired;
|
||||
private final int mUserAuthenticationValidityDurationSeconds;
|
||||
|
||||
private KeyGeneratorSpec(
|
||||
Context context,
|
||||
String keyStoreAlias,
|
||||
private KeyProtection(
|
||||
int flags,
|
||||
int keySize,
|
||||
Date keyValidityStart,
|
||||
Date keyValidityForOriginationEnd,
|
||||
Date keyValidityForConsumptionEnd,
|
||||
@KeyStoreKeyProperties.PurposeEnum int purposes,
|
||||
@KeyStoreKeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
|
||||
@KeyStoreKeyProperties.BlockModeEnum String[] blockModes,
|
||||
@KeyProperties.PurposeEnum int purposes,
|
||||
@KeyProperties.EncryptionPaddingEnum String[] encryptionPaddings,
|
||||
@KeyProperties.SignaturePaddingEnum String[] signaturePaddings,
|
||||
@KeyProperties.DigestEnum String[] digests,
|
||||
@KeyProperties.BlockModeEnum String[] blockModes,
|
||||
boolean randomizedEncryptionRequired,
|
||||
boolean userAuthenticationRequired,
|
||||
int userAuthenticationValidityDurationSeconds) {
|
||||
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)
|
||||
if ((userAuthenticationValidityDurationSeconds < 0)
|
||||
&& (userAuthenticationValidityDurationSeconds != -1)) {
|
||||
throw new IllegalArgumentException(
|
||||
"userAuthenticationValidityDurationSeconds must not be negative");
|
||||
}
|
||||
|
||||
mContext = context;
|
||||
mKeystoreAlias = keyStoreAlias;
|
||||
mFlags = flags;
|
||||
mKeySize = keySize;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Android context used for operations with this instance.
|
||||
*/
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alias that will be used in the {@code java.security.KeyStore} in conjunction with
|
||||
* the {@code AndroidKeyStore}.
|
||||
*/
|
||||
public String getKeystoreAlias() {
|
||||
return mKeystoreAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -155,10 +159,12 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested key size or {@code -1} if default size should be used.
|
||||
* 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).
|
||||
*/
|
||||
public int getKeySize() {
|
||||
return mKeySize;
|
||||
public boolean isEncryptionAtRestRequired() {
|
||||
return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,7 +178,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time instant after which the key is no longer valid for decryption and verification.
|
||||
* Gets the time instant after which the key is no long valid for decryption and verification.
|
||||
*
|
||||
* @return instant or {@code null} if not restricted.
|
||||
*/
|
||||
@@ -182,7 +188,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the time instant after which the key is no longer valid for encryption and signing.
|
||||
* Gets the time instant after which the key is no long valid for encryption and signing.
|
||||
*
|
||||
* @return instant or {@code null} if not restricted.
|
||||
*/
|
||||
@@ -195,33 +201,73 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
* Gets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
|
||||
* Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
|
||||
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
|
||||
public @KeyProperties.PurposeEnum int getPurposes() {
|
||||
return mPurposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code NoPadding}) with
|
||||
* which the key can be used when encrypting/decrypting. Attempts to use the key with any
|
||||
* other padding scheme will be rejected.
|
||||
* Gets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code PKCS1Padding},
|
||||
* {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to use
|
||||
* the key with any other padding scheme will be rejected.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyStoreKeyProperties.EncryptionPaddingEnum String[] getEncryptionPaddings() {
|
||||
public @KeyProperties.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.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyProperties.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.
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
|
||||
*
|
||||
* @throws IllegalStateException if this set has not been specified.
|
||||
*
|
||||
* @see #isDigestsSpecified()
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyProperties.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()
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
|
||||
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public @KeyStoreKeyProperties.BlockModeEnum String[] getBlockModes() {
|
||||
public @KeyProperties.BlockModeEnum String[] getBlockModes() {
|
||||
return ArrayUtils.cloneIfNotEmpty(mBlockModes);
|
||||
}
|
||||
|
||||
@@ -261,82 +307,58 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the key must be encrypted at rest. This will protect the key with the
|
||||
* secure lock screen credential (e.g., password, PIN, or pattern).
|
||||
* Builder of {@link KeyProtection} instances.
|
||||
*/
|
||||
public boolean isEncryptionRequired() {
|
||||
return (mFlags & KeyStore.FLAG_ENCRYPTED) != 0;
|
||||
}
|
||||
public final static class Builder {
|
||||
private @KeyProperties.PurposeEnum int mPurposes;
|
||||
|
||||
public static class Builder {
|
||||
private final Context mContext;
|
||||
private String mKeystoreAlias;
|
||||
private int mFlags;
|
||||
private int mKeySize = -1;
|
||||
private Date mKeyValidityStart;
|
||||
private Date mKeyValidityForOriginationEnd;
|
||||
private Date mKeyValidityForConsumptionEnd;
|
||||
private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
|
||||
private @KeyStoreKeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
|
||||
private @KeyStoreKeyProperties.BlockModeEnum String[] mBlockModes;
|
||||
private @KeyProperties.EncryptionPaddingEnum String[] mEncryptionPaddings;
|
||||
private @KeyProperties.SignaturePaddingEnum String[] mSignaturePaddings;
|
||||
private @KeyProperties.DigestEnum String[] mDigests;
|
||||
private @KeyProperties.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 some UI to ask the user to unlock or
|
||||
* initialize the Android KeyStore facility.
|
||||
* Creates a new instance of the {@code Builder}.
|
||||
*
|
||||
* @param purposes set of purposes (e.g., encrypt, decrypt, sign) for which the key can be
|
||||
* used. Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p><b>NOTE: The {@code purposes} parameter has currently no effect on asymmetric
|
||||
* key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
public Builder(@NonNull Context context) {
|
||||
if (context == null) {
|
||||
throw new NullPointerException("context == null");
|
||||
}
|
||||
mContext = context;
|
||||
public Builder(@KeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alias to be used to retrieve the key later from a {@link java.security.KeyStore}
|
||||
* instance using the {@code AndroidKeyStore} provider.
|
||||
* Sets whether this {@link java.security.KeyStore} entry must be encrypted at rest.
|
||||
* Encryption at rest will protect the entry with the secure lock screen credential (e.g.,
|
||||
* password, PIN, or pattern).
|
||||
*
|
||||
* <p>The alias must be provided. There is no default.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAlias(@NonNull String alias) {
|
||||
if (alias == null) {
|
||||
throw new NullPointerException("alias == null");
|
||||
}
|
||||
mKeystoreAlias = alias;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the size (in bits) of the key to be generated.
|
||||
*
|
||||
* <p>By default, the key size will be determines based on the key algorithm. For example,
|
||||
* for {@code HmacSHA256}, the key size will default to {@code 256}.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setKeySize(int keySize) {
|
||||
mKeySize = keySize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this key must be encrypted at rest. This will protect the key with the
|
||||
* secure lock screen credential (e.g., password, PIN, or pattern).
|
||||
*
|
||||
* <p>Note that this feature 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.
|
||||
* <p>Note that enabling this feature requires that the secure lock screen (e.g., password,
|
||||
* PIN, pattern) is set up, otherwise setting the {@code KeyStore} entry will fail.
|
||||
* Moreover, this entry will be deleted when the secure lock screen is disabled or reset
|
||||
* (e.g., by the user or a Device Administrator). Finally, this entry cannot be used until
|
||||
* the user unlocks the secure lock screen after boot.
|
||||
*
|
||||
* @see KeyguardManager#isDeviceSecure()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setEncryptionRequired() {
|
||||
mFlags |= KeyStore.FLAG_ENCRYPTED;
|
||||
public Builder setEncryptionAtRestRequired(boolean required) {
|
||||
if (required) {
|
||||
mFlags |= KeyStore.FLAG_ENCRYPTED;
|
||||
} else {
|
||||
mFlags &= ~KeyStore.FLAG_ENCRYPTED;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -345,6 +367,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
@@ -358,6 +382,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityStart(Date)
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
@@ -374,6 +400,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityForConsumptionEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
@@ -388,6 +416,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* <p>By default, the key is valid at any instant.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setKeyValidityForOriginationEnd(Date)
|
||||
*/
|
||||
@NonNull
|
||||
@@ -397,46 +427,73 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of purposes (e.g., encrypt, decrypt, sign) for which the key can be used.
|
||||
* Attempts to use the key for any other purpose will be rejected.
|
||||
*
|
||||
* <p>This must be specified for all keys. There is no default.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code PURPOSE} flags.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
|
||||
mPurposes = purposes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of padding schemes (e.g., {@code PKCS7Padding}, {@code NoPadding}) with
|
||||
* which the key can be used when encrypting/decrypting. Attempts to use the key with any
|
||||
* other padding scheme will be rejected.
|
||||
* Sets the set of padding schemes (e.g., {@code OAEPPadding}, {@code PKCS7Padding},
|
||||
* {@code NoPadding}) with which the key can be used when encrypting/decrypting. Attempts to
|
||||
* use the key with any other padding scheme will be rejected.
|
||||
*
|
||||
* <p>This must be specified for keys which are used for encryption/decryption.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code ENCRYPTION_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setEncryptionPaddings(
|
||||
@KeyStoreKeyProperties.EncryptionPaddingEnum String... paddings) {
|
||||
@KeyProperties.EncryptionPaddingEnum String... paddings) {
|
||||
mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be
|
||||
* used when encrypting/decrypting. Attempts to use the key with any other block modes will
|
||||
* be rejected.
|
||||
* Sets the set of padding schemes (e.g., {@code PSS}, {@code PKCS#1}) with which the key
|
||||
* can be used when signing/verifying. Attempts to use the key with any other padding scheme
|
||||
* will be rejected.
|
||||
*
|
||||
* <p>This must be specified for RSA keys which are used for signing/verification.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code SIGNATURE_PADDING} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setSignaturePaddings(
|
||||
@KeyProperties.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.
|
||||
*
|
||||
* <p>For HMAC keys, the default is the digest algorithm specified in
|
||||
* {@link Key#getAlgorithm()}. For asymmetric signing keys the set of digest algorithms
|
||||
* must be specified.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code DIGEST} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDigests(@KeyProperties.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.
|
||||
*
|
||||
* <p>This must be specified for encryption/decryption keys.
|
||||
*
|
||||
* <p>See {@link KeyStoreKeyProperties}.{@code BLOCK_MODE} constants.
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setBlockModes(@KeyStoreKeyProperties.BlockModeEnum String... blockModes) {
|
||||
public Builder setBlockModes(@KeyProperties.BlockModeEnum String... blockModes) {
|
||||
mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
|
||||
return this;
|
||||
}
|
||||
@@ -454,11 +511,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* <p>When {@code IND-CPA} is required:
|
||||
* <ul>
|
||||
* <li>block modes which do not offer {@code IND-CPA}, such as {@code ECB}, are prohibited;
|
||||
* </li>
|
||||
* <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM},
|
||||
* caller-provided IVs are rejected when encrypting, to ensure that only random IVs are
|
||||
* used.</li>
|
||||
* <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using
|
||||
* {@code ECB} mode or RSA encryption without padding, are prohibited;</li>
|
||||
* <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC},
|
||||
* {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when
|
||||
* encrypting, to ensure that only random IVs are used.</li>
|
||||
*
|
||||
* <p>Before disabling this requirement, consider the following approaches instead:
|
||||
* <ul>
|
||||
@@ -471,7 +528,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
* or a device identifier), consider changing your design to use a random IV which will then
|
||||
* be provided in addition to the ciphertext to the entities which need to decrypt the
|
||||
* ciphertext.</li>
|
||||
* <li>If you are using RSA encryption without padding, consider switching to padding
|
||||
* schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setRandomizedEncryptionRequired(boolean required) {
|
||||
@@ -492,6 +553,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
* <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More
|
||||
* information</a>.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @see #setUserAuthenticationValidityDurationSeconds(int)
|
||||
*/
|
||||
@NonNull
|
||||
@@ -506,6 +569,8 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
*
|
||||
* <p>By default, the user needs to authenticate for every use of the key.
|
||||
*
|
||||
* <p><b>NOTE: This has currently no effect on asymmetric key pairs.</b>
|
||||
*
|
||||
* @param seconds duration in seconds or {@code -1} if the user needs to authenticate for
|
||||
* every use of the key.
|
||||
*
|
||||
@@ -519,21 +584,21 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new instance instance of {@code KeyGeneratorSpec}.
|
||||
* Builds an instance of {@link KeyProtection}.
|
||||
*
|
||||
* @throws IllegalArgumentException if a required field is missing or violates a constraint.
|
||||
* @throws IllegalArgumentException if a required field is missing
|
||||
*/
|
||||
@NonNull
|
||||
public KeyGeneratorSpec build() {
|
||||
return new KeyGeneratorSpec(mContext,
|
||||
mKeystoreAlias,
|
||||
public KeyProtection build() {
|
||||
return new KeyProtection(
|
||||
mFlags,
|
||||
mKeySize,
|
||||
mKeyValidityStart,
|
||||
mKeyValidityForOriginationEnd,
|
||||
mKeyValidityForConsumptionEnd,
|
||||
mPurposes,
|
||||
mEncryptionPaddings,
|
||||
mSignaturePaddings,
|
||||
mDigests,
|
||||
mBlockModes,
|
||||
mRandomizedEncryptionRequired,
|
||||
mUserAuthenticationRequired,
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.security;
|
||||
package android.security.keystore;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
|
||||
@@ -24,11 +24,6 @@ import java.util.Date;
|
||||
import javax.security.auth.x500.X500Principal;
|
||||
|
||||
public class KeyPairGeneratorSpecTest extends AndroidTestCase {
|
||||
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 1980
|
||||
private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
|
||||
|
||||
private static final String TEST_ALIAS_1 = "test1";
|
||||
|
||||
private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
|
||||
@@ -110,37 +105,46 @@ public class KeyPairGeneratorSpecTest extends AndroidTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructor_NullSubjectDN_Success() throws Exception {
|
||||
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
|
||||
getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
|
||||
NOW_PLUS_10_YEARS, 0);
|
||||
assertEquals(DEFAULT_CERT_SUBJECT, spec.getSubjectDN());
|
||||
public void testConstructor_NullSubjectDN_Failure() throws Exception {
|
||||
try {
|
||||
new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
|
||||
NOW_PLUS_10_YEARS, 0);
|
||||
fail("Should throw IllegalArgumentException when subjectDN is null");
|
||||
} catch (IllegalArgumentException success) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructor_NullSerial_Success() throws Exception {
|
||||
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
|
||||
getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
|
||||
NOW_PLUS_10_YEARS, 0);
|
||||
assertEquals(DEFAULT_CERT_SERIAL_NUMBER, spec.getSerialNumber());
|
||||
public void testConstructor_NullSerial_Failure() throws Exception {
|
||||
try {
|
||||
new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
|
||||
NOW_PLUS_10_YEARS, 0);
|
||||
fail("Should throw IllegalArgumentException when startDate is null");
|
||||
} catch (IllegalArgumentException success) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructor_NullStartDate_Success() throws Exception {
|
||||
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
|
||||
getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, null,
|
||||
NOW_PLUS_10_YEARS, 0);
|
||||
assertEquals(DEFAULT_CERT_NOT_BEFORE, spec.getStartDate());
|
||||
public void testConstructor_NullStartDate_Failure() throws Exception {
|
||||
try {
|
||||
new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
|
||||
null, NOW_PLUS_10_YEARS, 0);
|
||||
fail("Should throw IllegalArgumentException when startDate is null");
|
||||
} catch (IllegalArgumentException success) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructor_NullEndDate_Success() throws Exception {
|
||||
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
|
||||
getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, null, 0);
|
||||
assertEquals(DEFAULT_CERT_NOT_AFTER, spec.getEndDate());
|
||||
public void testConstructor_NullEndDate_Failure() throws Exception {
|
||||
try {
|
||||
new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
|
||||
NOW, null, 0);
|
||||
fail("Should throw IllegalArgumentException when keystoreAlias is null");
|
||||
} catch (IllegalArgumentException success) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testConstructor_EndBeforeStart_Failure() throws Exception {
|
||||
try {
|
||||
new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1,
|
||||
SERIAL_1, NOW_PLUS_10_YEARS, NOW, 0);
|
||||
new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
|
||||
NOW_PLUS_10_YEARS, NOW, 0);
|
||||
fail("Should throw IllegalArgumentException when end is before start");
|
||||
} catch (IllegalArgumentException success) {
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.Process;
|
||||
import android.os.ServiceManager;
|
||||
import android.security.KeyStore;
|
||||
import android.security.keymaster.ExportResult;
|
||||
import android.security.keymaster.KeyCharacteristics;
|
||||
import android.security.keymaster.KeymasterArguments;
|
||||
|
||||
Reference in New Issue
Block a user