diff options
Diffstat (limited to 'keystore/java/android/security')
7 files changed, 111 insertions, 330 deletions
diff --git a/keystore/java/android/security/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java deleted file mode 100644 index 1cd8784..0000000 --- a/keystore/java/android/security/EcIesParameterSpec.java +++ /dev/null @@ -1,272 +0,0 @@ -package android.security; - -import android.annotation.IntDef; -import android.annotation.NonNull; -import android.annotation.Nullable; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.Cipher; -import javax.crypto.Mac; - -/** - * {@link AlgorithmParameterSpec} for ECIES (Integrated Encryption Scheme using Elliptic Curve - * cryptography) based on {@code ISO/IEC 18033-2}. - * - * <p>ECIES is a hybrid authenticated encryption scheme. Encryption is performed using an Elliptic - * Curve (EC) public key. The resulting ciphertext can be decrypted only using the corresponding EC - * private key. The scheme is called hybrid because the EC key is only used to securely encapsulate - * symmetric key material. Encryption of plaintext and authentication of the corresponding - * ciphertext is performed using symmetric cryptography. - * - * <p>Encryption using ECIES consists of two stages: - * <ol> - * <li>Key Encapsulation Mechanism (KEM) randomly generates symmetric key material and securely - * encapsulates it in the output so that it can be extracted by the KEM when decrypting. - * Encapsulated key material is represented in the output as an EC point.</li> - * <li>The above symmetric key material is used by Data Encapsulation Mechanism (DEM) to encrypt the - * provided plaintext and authenticate the ciphertext. The resulting authenticated ciphertext is - * then output. When decrypting, the DEM first authenticates the ciphertext and, only if it - * authenticates, decrypts the ciphertext and outputs the plaintext.</li> - * </ol> - * - * <p>Details of KEM: - * <ul> - * <li>Only curves with cofactor of {@code 1} are supported.</li> - * <li>{@code CheckMode}, {@code OldCofactorMode}, {@code CofactorMode}, and {@code SingleHashMode} - * are {@code 0}. - * <li>Point format is specified by {@link #getKemPointFormat()}.</li> - * <li>KDF algorithm is specified by {@link #getKemKdfAlgorithm()}.</li> - * </ul> - * - * <p>Details of DEM: - * <ul> - * <li>Only DEM1-like mechanism is supported, with its symmetric cipher (SC) specified by - * {@link #getDemCipherTransformation()} (e.g., {@code AES/CBC/NoPadding} for standard DEM1) and - * MAC algorithm specified by {@link #getDemMacAlgorithm()} (e.g., {@code HmacSHA1} for standard - * DEM1).</li> - * </ul> - */ -public class EcIesParameterSpec implements AlgorithmParameterSpec { - - /** - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef({ - POINT_FORMAT_UNSPECIFIED, - POINT_FORMAT_UNCOMPRESSED, - POINT_FORMAT_COMPRESSED, - }) - public @interface PointFormatEnum {} - - /** Unspecified EC point format. */ - public static final int POINT_FORMAT_UNSPECIFIED = -1; - - /** - * Uncompressed EC point format: both coordinates are stored separately. - * - * <p>The wire format is byte {@code 0x04} followed by binary representation of the {@code x} - * coordinate followed by binary representation of the {@code y} coordinate. See - * {@code ISO 18033-2} section {@code 5.4.3}. - */ - public static final int POINT_FORMAT_UNCOMPRESSED = 0; - - /** - * Compressed EC point format: only one coordinate is stored. - * - * <p>The wire format is byte {@code 0x02} or {@code 0x03} (depending on the value of the stored - * coordinate) followed by the binary representation of the {@code x} coordinate. See - * {@code ISO 18033-2} section {@code 5.4.3}. - */ - public static final int POINT_FORMAT_COMPRESSED = 1; - - /** - * Default parameter spec: compressed point format, {@code HKDFwithSHA256}, DEM uses 128-bit AES - * GCM. - */ - public static final EcIesParameterSpec DEFAULT = new EcIesParameterSpec( - POINT_FORMAT_COMPRESSED, - "HKDFwithSHA256", - "AES/GCM/NoPadding", - 128, - null, - 0); - - private final @PointFormatEnum int mKemPointFormat; - private final String mKemKdfAlgorithm; - private final String mDemCipherTransformation; - private final int mDemCipherKeySize; - private final String mDemMacAlgorithm; - private final int mDemMacKeySize; - - private EcIesParameterSpec( - @PointFormatEnum int kemPointFormat, - String kemKdfAlgorithm, - String demCipherTransformation, - int demCipherKeySize, - String demMacAlgorithm, - int demMacKeySize) { - mKemPointFormat = kemPointFormat; - mKemKdfAlgorithm = kemKdfAlgorithm; - mDemCipherTransformation = demCipherTransformation; - mDemCipherKeySize = demCipherKeySize; - mDemMacAlgorithm = demMacAlgorithm; - mDemMacKeySize = demMacKeySize; - } - - /** - * Returns KEM EC point wire format or {@link #POINT_FORMAT_UNSPECIFIED} if not specified. - */ - public @PointFormatEnum int getKemPointFormat() { - return mKemPointFormat; - } - - /** - * Returns KEM KDF algorithm (e.g., {@code HKDFwithSHA256} or {@code KDF1withSHA1}) or - * {@code null} if not specified. - */ - @Nullable - public String getKemKdfAlgorithm() { - return mKemKdfAlgorithm; - } - - /** - * Returns DEM {@link Cipher} transformation (e.g., {@code AES/GCM/NoPadding} or - * {@code AES/CBC/PKCS7Padding}) or {@code null} if not specified. - * - * @see Cipher#getInstance(String) - * @see #getDemCipherKeySize() - */ - @Nullable - public String getDemCipherTransformation() { - return mDemCipherTransformation; - } - - /** - * Returns DEM {@link Cipher} key size in bits. - * - * @see #getDemCipherTransformation() - */ - public int getDemCipherKeySize() { - return mDemCipherKeySize; - } - - /** - * Returns DEM {@link Mac} algorithm (e.g., {@code HmacSHA256} or {@code HmacSHA1}) or - * {@code null} if not specified. - * - * @see Mac#getInstance(String) - * @see #getDemMacKeySize() - */ - @Nullable - public String getDemMacAlgorithm() { - return mDemMacAlgorithm; - } - - /** - * Returns DEM {@link Mac} key size in bits. - * - * @see #getDemCipherTransformation() - */ - public int getDemMacKeySize() { - return mDemMacKeySize; - } - - /** - * Builder of {@link EcIesParameterSpec}. - */ - public static class Builder { - private @PointFormatEnum int mKemPointFormat = POINT_FORMAT_UNSPECIFIED; - private String mKemKdfAlgorithm; - private String mDemCipherTransformation; - private int mDemCipherKeySize = 128; - private String mDemMacAlgorithm; - private int mDemMacKeySize = -1; - - /** - * Sets KEM EC point wire format. - */ - public Builder setKemPointFormat(@PointFormatEnum int pointFormat) { - mKemPointFormat = pointFormat; - return this; - } - - /** - * Sets KEM KDF algorithm. For example, {@code HKDFwithSHA256}, {@code KDF2withSHA256}, or - * {@code KDF1withSHA1}. - */ - @NonNull - public Builder setKemKdfAlgorithm(@Nullable String algorithm) { - mKemKdfAlgorithm = algorithm; - return this; - } - - /** - * Sets DEM {@link Cipher} transformation. For example, {@code AES/GCM/NoPadding}, - * {@code AES/CBC/PKCS7Padding} or {@code AES/CTR/NoPadding}. - * - * @see Cipher#getInstance(String) - */ - @NonNull - public Builder setDemCipherTransformation(@Nullable String transformation) { - mDemCipherTransformation = transformation; - return this; - } - - /** - * Returns DEM {@link Cipher} key size in bits. - * - * <p>The default value is {@code 128} bits. - * - * @see #setDemCipherTransformation(String) - */ - @NonNull - public Builder setDemCipherKeySize(int sizeBits) { - mDemCipherKeySize = sizeBits; - return this; - } - - /** - * Sets DEM {@link Mac} algorithm. For example, {@code HmacSHA256} or {@code HmacSHA1}. - * - * @see Mac#getInstance(String) - */ - @NonNull - public Builder setDemMacAlgorithm(@Nullable String algorithm) { - mDemMacAlgorithm = algorithm; - return this; - } - - /** - * Sets DEM {@link Mac} key size in bits. - * - * <p>By default, {@code Mac} key size is the same as the {@code Cipher} key size. - * - * @see #setDemCipherKeySize(int) - */ - @NonNull - public Builder setDemMacKeySize(int sizeBits) { - mDemMacKeySize = sizeBits; - return this; - } - - /** - * Returns a new {@link EcIesParameterSpec} based on the current state of this builder. - */ - @NonNull - public EcIesParameterSpec build() { - int demMacKeySize = (mDemMacKeySize != -1) ? mDemMacKeySize : mDemCipherKeySize; - return new EcIesParameterSpec( - mKemPointFormat, - mKemKdfAlgorithm, - mDemCipherTransformation, - mDemCipherKeySize, - mDemMacAlgorithm, - demMacKeySize - ); - } - } -} diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java index b93424d..2de60fd 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -624,7 +624,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato int keySizeBits, KeyGenParameterSpec spec) { // Constraints: - // 1. Key must be authorized for signing. + // 1. Key must be authorized for signing without user authentication. // 2. Signature digest must be one of key's authorized digests. // 3. For RSA keys, the digest output size must not exceed modulus size minus space needed // for RSA PKCS#1 signature padding (about 29 bytes: minimum 10 bytes of padding + 15--19 @@ -636,6 +636,10 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato // Key not authorized for signing return null; } + if (spec.isUserAuthenticationRequired()) { + // Key not authorized for use without user authentication + return null; + } if (!spec.isDigestsSpecified()) { // Key not authorized for any digests -- can't sign return null; diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 47aab74..8d4bfcd 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -59,9 +59,19 @@ import javax.security.auth.x500.X500Principal; * 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: If a private key is not authorized to sign the self-signed certificate, then the + * certificate will be created with an invalid signature which will not verify. Such a certificate + * is still useful because it provides access to the public key. To generate a valid + * signature for the certificate the key needs to be authorized for + * {@link KeyProperties#PURPOSE_SIGN}, a suitable digest or {@link KeyProperties#DIGEST_NONE}, and + * {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or + * {@link KeyProperties#ENCRYPTION_PADDING_NONE}. + * * <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>Instances of this class are immutable. + * * <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, @@ -71,11 +81,12 @@ import javax.security.auth.x500.X500Principal; * KeyProperties.KEY_ALGORITHM_EC, * "AndroidKeyStore"); * keyPairGenerator.initialize( - * new KeyGenParameterSpec.Builder("key1", + * new KeyGenParameterSpec.Builder( + * "key1", * KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) - * .setDigests(KeyProperties.DIGEST_SHA256 - * | KeyProperties.DIGEST_SHA384 - * | KeyProperties.DIGEST_SHA512) + * .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) @@ -92,16 +103,17 @@ import javax.security.auth.x500.X500Principal; * * <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. + * alias {@code key2} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 + * padding. * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( - * KeyProperties.KEY_ALGORITHM_HMAC_SHA256, + * KeyProperties.KEY_ALGORITHM_AES, * "AndroidKeyStore"); * keyGenerator.initialize( * new KeyGenParameterSpec.Builder("key2", * KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - * .setBlockModes(KeyProperties.BLOCK_MODE_CTR) - * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + * .setBlockModes(KeyProperties.BLOCK_MODE_CBC) + * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) * .build()); * SecretKey key = keyGenerator.generateKey(); * @@ -161,10 +173,6 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { 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) { @@ -189,11 +197,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { mSpec = spec; mCertificateSubject = certificateSubject; mCertificateSerialNumber = certificateSerialNumber; - mCertificateNotBefore = certificateNotBefore; - mCertificateNotAfter = certificateNotAfter; - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; + mCertificateNotBefore = Utils.cloneIfNotNull(certificateNotBefore); + mCertificateNotAfter = Utils.cloneIfNotNull(certificateNotAfter); + mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); mPurposes = purposes; mDigests = ArrayUtils.cloneIfNotEmpty(digests); mEncryptionPaddings = @@ -209,6 +217,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * Returns the alias that will be used in the {@code java.security.KeyStore} * in conjunction with the {@code AndroidKeyStore}. */ + @NonNull public String getKeystoreAlias() { return mKeystoreAlias; } @@ -223,10 +232,10 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Returns the {@link AlgorithmParameterSpec} that will be used for creation - * of the key pair. + * Returns the key algorithm-specific {@link AlgorithmParameterSpec} that will be used for + * creation of the key or {@code null} if algorithm-specific defaults should be used. */ - @NonNull + @Nullable public AlgorithmParameterSpec getAlgorithmParameterSpec() { return mSpec; } @@ -255,7 +264,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Date getCertificateNotBefore() { - return mCertificateNotBefore; + return Utils.cloneIfNotNull(mCertificateNotBefore); } /** @@ -264,7 +273,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Date getCertificateNotAfter() { - return mCertificateNotAfter; + return Utils.cloneIfNotNull(mCertificateNotAfter); } /** @@ -273,7 +282,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @Nullable public Date getKeyValidityStart() { - return mKeyValidityStart; + return Utils.cloneIfNotNull(mKeyValidityStart); } /** @@ -282,7 +291,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @Nullable public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; + return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd); } /** @@ -291,7 +300,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @Nullable public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; + return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd); } /** @@ -403,7 +412,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the - * key. + * key. * * @see #isUserAuthenticationRequired() */ @@ -439,7 +448,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * Creates a new instance of the {@code Builder}. * * @param keystoreAlias alias of the entry in which the generated key will appear in - * Android KeyStore. + * Android KeyStore. Must not be empty. * @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. * @@ -454,6 +463,8 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { public Builder(@NonNull String keystoreAlias, @KeyProperties.PurposeEnum int purposes) { if (keystoreAlias == null) { throw new NullPointerException("keystoreAlias == null"); + } else if (keystoreAlias.isEmpty()) { + throw new IllegalArgumentException("keystoreAlias must not be empty"); } mKeystoreAlias = keystoreAlias; mPurposes = purposes; @@ -480,7 +491,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { /** * Sets the algorithm-specific key generation parameters. For example, for RSA keys this may - * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec}. + * be an instance of {@link java.security.spec.RSAKeyGenParameterSpec} whereas for EC keys + * this may be an instance of {@link java.security.spec.ECGenParameterSpec}. + * + * <p>These key generation parameters must match other explicitly set parameters (if any), + * such as key size. */ public Builder setAlgorithmParameterSpec(@NonNull AlgorithmParameterSpec spec) { if (spec == null) { @@ -529,7 +544,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { if (date == null) { throw new NullPointerException("date == null"); } - mCertificateNotBefore = date; + mCertificateNotBefore = Utils.cloneIfNotNull(date); return this; } @@ -544,7 +559,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { if (date == null) { throw new NullPointerException("date == null"); } - mCertificateNotAfter = date; + mCertificateNotAfter = Utils.cloneIfNotNull(date); return this; } @@ -557,7 +572,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Builder setKeyValidityStart(Date startDate) { - mKeyValidityStart = startDate; + mKeyValidityStart = Utils.cloneIfNotNull(startDate); return this; } @@ -586,7 +601,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { - mKeyValidityForOriginationEnd = endDate; + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -600,7 +615,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { */ @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { - mKeyValidityForConsumptionEnd = endDate; + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -760,14 +775,15 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { @NonNull public Builder setUserAuthenticationValidityDurationSeconds( @IntRange(from = -1) int seconds) { + if (seconds < -1) { + throw new IllegalArgumentException("seconds must be -1 or larger"); + } mUserAuthenticationValidityDurationSeconds = seconds; return this; } /** * Builds an instance of {@code KeyGenParameterSpec}. - * - * @throws IllegalArgumentException if a required field is missing */ @NonNull public KeyGenParameterSpec build() { diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java index e4f921e..03b4100 100644 --- a/keystore/java/android/security/keystore/KeyInfo.java +++ b/keystore/java/android/security/keystore/KeyInfo.java @@ -33,6 +33,8 @@ import javax.crypto.SecretKey; * 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>Instances of this class are immutable. + * * <p><h3>Example: Symmetric Key</h3> * The following example illustrates how to obtain a {@code KeyInfo} describing the provided Android * Keystore {@link SecretKey}. @@ -102,9 +104,9 @@ public class KeyInfo implements KeySpec { mInsideSecureHardware = insideSecureHardware; mOrigin = origin; mKeySize = keySize; - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; + mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); mPurposes = purposes; mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); @@ -155,7 +157,7 @@ public class KeyInfo implements KeySpec { */ @Nullable public Date getKeyValidityStart() { - return mKeyValidityStart; + return Utils.cloneIfNotNull(mKeyValidityStart); } /** @@ -165,7 +167,7 @@ public class KeyInfo implements KeySpec { */ @Nullable public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; + return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd); } /** @@ -175,7 +177,7 @@ public class KeyInfo implements KeySpec { */ @Nullable public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; + return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd); } /** diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java index 403e814..f9fe176 100644 --- a/keystore/java/android/security/keystore/KeyProperties.java +++ b/keystore/java/android/security/keystore/KeyProperties.java @@ -370,7 +370,7 @@ public abstract class KeyProperties { * No encryption padding. * * <p><b>NOTE</b>: If a key is authorized to be used with no padding, then it can be used with - * any padding scheme. + * any padding scheme, both for encryption and signing. */ public static final String ENCRYPTION_PADDING_NONE = "NoPadding"; diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 432fc12..1e0611c 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -47,6 +47,8 @@ import javax.crypto.Cipher; * * <p>NOTE: The key material of keys stored in the Android KeyStore is not accessible. * + * <p>Instances of this class are immutable. + * * <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 @@ -122,15 +124,9 @@ public final class KeyProtection implements ProtectionParameter { boolean randomizedEncryptionRequired, boolean userAuthenticationRequired, int userAuthenticationValidityDurationSeconds) { - if ((userAuthenticationValidityDurationSeconds < 0) - && (userAuthenticationValidityDurationSeconds != -1)) { - throw new IllegalArgumentException( - "userAuthenticationValidityDurationSeconds must not be negative"); - } - - mKeyValidityStart = keyValidityStart; - mKeyValidityForOriginationEnd = keyValidityForOriginationEnd; - mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd; + mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart); + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd); + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd); mPurposes = purposes; mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings)); @@ -150,7 +146,7 @@ public final class KeyProtection implements ProtectionParameter { */ @Nullable public Date getKeyValidityStart() { - return mKeyValidityStart; + return Utils.cloneIfNotNull(mKeyValidityStart); } /** @@ -160,7 +156,7 @@ public final class KeyProtection implements ProtectionParameter { */ @Nullable public Date getKeyValidityForConsumptionEnd() { - return mKeyValidityForConsumptionEnd; + return Utils.cloneIfNotNull(mKeyValidityForConsumptionEnd); } /** @@ -170,7 +166,7 @@ public final class KeyProtection implements ProtectionParameter { */ @Nullable public Date getKeyValidityForOriginationEnd() { - return mKeyValidityForOriginationEnd; + return Utils.cloneIfNotNull(mKeyValidityForOriginationEnd); } /** @@ -320,7 +316,7 @@ public final class KeyProtection implements ProtectionParameter { */ @NonNull public Builder setKeyValidityStart(Date startDate) { - mKeyValidityStart = startDate; + mKeyValidityStart = Utils.cloneIfNotNull(startDate); return this; } @@ -349,7 +345,7 @@ public final class KeyProtection implements ProtectionParameter { */ @NonNull public Builder setKeyValidityForOriginationEnd(Date endDate) { - mKeyValidityForOriginationEnd = endDate; + mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -363,7 +359,7 @@ public final class KeyProtection implements ProtectionParameter { */ @NonNull public Builder setKeyValidityForConsumptionEnd(Date endDate) { - mKeyValidityForConsumptionEnd = endDate; + mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(endDate); return this; } @@ -517,6 +513,9 @@ public final class KeyProtection implements ProtectionParameter { @NonNull public Builder setUserAuthenticationValidityDurationSeconds( @IntRange(from = -1) int seconds) { + if (seconds < -1) { + throw new IllegalArgumentException("seconds must be -1 or larger"); + } mUserAuthenticationValidityDurationSeconds = seconds; return this; } diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java new file mode 100644 index 0000000..9bec682 --- /dev/null +++ b/keystore/java/android/security/keystore/Utils.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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 java.util.Date; + +/** + * Assorted utility methods. + * + * @hide + */ +abstract class Utils { + private Utils() {} + + static Date cloneIfNotNull(Date value) { + return (value != null) ? (Date) value.clone() : null; + } +} |
