Merge "New AndroidKeyStore API in android.security.keystore." into mnc-dev

This commit is contained in:
Alex Klyubin
2015-05-13 21:33:36 +00:00
committed by Android (Google) Code Review
25 changed files with 1854 additions and 1718 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -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"

View File

@@ -5,7 +5,7 @@ import libcore.util.EmptyArray;
/**
* @hide
*/
abstract class ArrayUtils {
public abstract class ArrayUtils {
private ArrayUtils() {}
public static String[] nullToEmpty(String[] array) {

View File

@@ -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;
}

View File

@@ -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(&quot;CN=myKey&quot;)).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);
}
}
}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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,

View File

@@ -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"

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.security;
package android.security.keystore;
import java.security.InvalidKeyException;

View 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);
}
}
}

View File

@@ -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 &#123;
* spec = (KeyStoreKeySpec) factory.getKeySpec(key, KeyStoreKeySpec.class);
* keyInfo = (KeyInfo) factory.getKeySpec(key, KeyInfo.class);
* &#125; catch (InvalidKeySpecException e) &#123;
* // Not an Android KeyStore key.
* &#125;
* }</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 &#123;
* spec = factory.getKeySpec(key, KeyStoreKeySpec.class);
* keyInfo = factory.getKeySpec(key, KeyInfo.class);
* &#125; catch (InvalidKeySpecException e) &#123;
* // Not an Android KeyStore key.
* &#125;
* }</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);
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.security;
package android.security.keystore;
import java.security.InvalidKeyException;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.security;
package android.security.keystore;
import java.security.InvalidKeyException;

View File

@@ -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;

View File

@@ -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,

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package android.security;
package android.security.keystore;
import java.security.InvalidKeyException;

View File

@@ -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) {
}

View File

@@ -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;