Loading keystore/java/android/security/AndroidKeyStore.java +16 −5 Original line number Diff line number Diff line Loading @@ -512,12 +512,23 @@ public class AndroidKeyStore extends KeyStoreSpi { } } int purposes = params.getPurposes(); @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes(); @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes(); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) { @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes = blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES; if (incompatibleBlockModes != 0) { throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be" + " violated by block mode(s): " + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes) + ". See KeyStoreParameter documentation."); } } for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(params.getBlockModes())) { for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) { args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode); } for (int keymasterPadding : Loading Loading @@ -549,8 +560,8 @@ public class AndroidKeyStore extends KeyStoreSpi { args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) { // Permit caller-specified IV. This is needed for the Cipher abstraction. && (!params.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); } Loading keystore/java/android/security/KeyGeneratorSpec.java +56 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.text.TextUtils; import java.security.spec.AlgorithmParameterSpec; import java.util.Date; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; Loading Loading @@ -51,6 +52,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; Loading @@ -65,6 +67,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { @KeyStoreKeyConstraints.PurposeEnum int purposes, @KeyStoreKeyConstraints.PaddingEnum int paddings, @KeyStoreKeyConstraints.BlockModeEnum int blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators, int userAuthenticationValidityDurationSeconds) { if (context == null) { Loading @@ -87,6 +90,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mPurposes = purposes; mPaddings = paddings; mBlockModes = blockModes; mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; } Loading Loading @@ -168,6 +172,19 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { return 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; } /** * Gets the set of user authenticators which protect access to this key. The key can only be * used iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -207,6 +224,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; Loading Loading @@ -345,6 +363,43 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { 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>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> * * <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> * </ul> */ public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; } /** * Sets the user authenticators which protect access to this key. The key can only be used * iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -394,6 +449,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mPurposes, mPaddings, mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, mUserAuthenticationValidityDurationSeconds); } Loading keystore/java/android/security/KeyPairGeneratorSpec.java +69 −2 Original line number Diff line number Diff line Loading @@ -86,6 +86,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; Loading Loading @@ -132,6 +134,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { @KeyStoreKeyConstraints.DigestEnum int digests, @KeyStoreKeyConstraints.PaddingEnum int paddings, @KeyStoreKeyConstraints.BlockModeEnum int blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators, int userAuthenticationValidityDurationSeconds) { if (context == null) { Loading Loading @@ -171,6 +174,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mDigests = digests; mPaddings = paddings; mBlockModes = blockModes; mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; } Loading @@ -182,8 +186,26 @@ 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) { this(context, keyStoreAlias, keyType, keySize, spec, subjectDN, serialNumber, startDate, endDate, flags, startDate, endDate, endDate, 0, 0, 0, 0, 0, -1); this(context, keyStoreAlias, keyType, keySize, spec, subjectDN, serialNumber, startDate, endDate, flags, startDate, endDate, endDate, 0, 0, 0, 0, true, 0, -1); } /** Loading Loading @@ -342,6 +364,21 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { return 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. * * @hide */ public boolean isRandomizedEncryptionRequired() { return mRandomizedEncryptionRequired; } /** * Gets the set of user authenticators which protect access to the private key. The key can only * be used iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -429,6 +466,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; Loading Loading @@ -669,6 +708,33 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { 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> * * @hide */ public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; } /** * Sets the user authenticators which protect access to this key. The key can only be used * iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -736,6 +802,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mDigests, mPaddings, mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, mUserAuthenticationValidityDurationSeconds); } Loading keystore/java/android/security/KeyStoreKeyConstraints.java +26 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,14 @@ public abstract class KeyStoreKeyConstraints { /** Galois/Counter Mode (GCM) block mode. */ public static final int GCM = 1 << 3; /** * Set of block modes compatible with IND-CPA if used correctly. * * @hide */ public static final @BlockModeEnum int IND_CPA_COMPATIBLE_MODES = CBC | CTR | GCM; /** * @hide */ Loading Loading @@ -667,6 +675,24 @@ public abstract class KeyStoreKeyConstraints { } } /** * @hide */ public static String allToString(@BlockModeEnum int modes) { StringBuilder result = new StringBuilder("["); boolean firstValue = true; for (@BlockModeEnum int mode : getSetFlags(modes)) { if (firstValue) { firstValue = false; } else { result.append(", "); } result.append(toString(mode)); } result.append(']'); return result.toString(); } /** * @hide */ Loading keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +18 −5 Original line number Diff line number Diff line Loading @@ -138,13 +138,26 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits; args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits); int purposes = spec.getPurposes(); @KeyStoreKeyConstraints.PurposeEnum int purposes = spec.getPurposes(); @KeyStoreKeyConstraints.BlockModeEnum int blockModes = spec.getBlockModes(); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) && (spec.isRandomizedEncryptionRequired())) { @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes = blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES; if (incompatibleBlockModes != 0) { throw new IllegalStateException( "Randomized encryption (IND-CPA) required but may be violated by block" + " mode(s): " + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes) + ". See KeyGeneratorSpec documentation."); } } for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(spec.getBlockModes())) { for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) { args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode); } for (int keymasterPadding : Loading Loading @@ -173,8 +186,8 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE)); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) { // Permit caller-specified IV. This is needed due to the Cipher abstraction. && (!spec.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); } Loading Loading
keystore/java/android/security/AndroidKeyStore.java +16 −5 Original line number Diff line number Diff line Loading @@ -512,12 +512,23 @@ public class AndroidKeyStore extends KeyStoreSpi { } } int purposes = params.getPurposes(); @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes(); @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes(); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) && (params.isRandomizedEncryptionRequired())) { @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes = blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES; if (incompatibleBlockModes != 0) { throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be" + " violated by block mode(s): " + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes) + ". See KeyStoreParameter documentation."); } } for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(params.getBlockModes())) { for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) { args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode); } for (int keymasterPadding : Loading Loading @@ -549,8 +560,8 @@ public class AndroidKeyStore extends KeyStoreSpi { args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) { // Permit caller-specified IV. This is needed for the Cipher abstraction. && (!params.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); } Loading
keystore/java/android/security/KeyGeneratorSpec.java +56 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.text.TextUtils; import java.security.spec.AlgorithmParameterSpec; import java.util.Date; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; Loading Loading @@ -51,6 +52,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; Loading @@ -65,6 +67,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { @KeyStoreKeyConstraints.PurposeEnum int purposes, @KeyStoreKeyConstraints.PaddingEnum int paddings, @KeyStoreKeyConstraints.BlockModeEnum int blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators, int userAuthenticationValidityDurationSeconds) { if (context == null) { Loading @@ -87,6 +90,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mPurposes = purposes; mPaddings = paddings; mBlockModes = blockModes; mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; } Loading Loading @@ -168,6 +172,19 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { return 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; } /** * Gets the set of user authenticators which protect access to this key. The key can only be * used iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -207,6 +224,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { private @KeyStoreKeyConstraints.PurposeEnum int mPurposes; private @KeyStoreKeyConstraints.PaddingEnum int mPaddings; private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; Loading Loading @@ -345,6 +363,43 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { 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>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> * * <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> * </ul> */ public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; } /** * Sets the user authenticators which protect access to this key. The key can only be used * iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -394,6 +449,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec { mPurposes, mPaddings, mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, mUserAuthenticationValidityDurationSeconds); } Loading
keystore/java/android/security/KeyPairGeneratorSpec.java +69 −2 Original line number Diff line number Diff line Loading @@ -86,6 +86,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private final boolean mRandomizedEncryptionRequired; private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private final int mUserAuthenticationValidityDurationSeconds; Loading Loading @@ -132,6 +134,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { @KeyStoreKeyConstraints.DigestEnum int digests, @KeyStoreKeyConstraints.PaddingEnum int paddings, @KeyStoreKeyConstraints.BlockModeEnum int blockModes, boolean randomizedEncryptionRequired, @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators, int userAuthenticationValidityDurationSeconds) { if (context == null) { Loading Loading @@ -171,6 +174,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mDigests = digests; mPaddings = paddings; mBlockModes = blockModes; mRandomizedEncryptionRequired = randomizedEncryptionRequired; mUserAuthenticators = userAuthenticators; mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds; } Loading @@ -182,8 +186,26 @@ 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) { this(context, keyStoreAlias, keyType, keySize, spec, subjectDN, serialNumber, startDate, endDate, flags, startDate, endDate, endDate, 0, 0, 0, 0, 0, -1); this(context, keyStoreAlias, keyType, keySize, spec, subjectDN, serialNumber, startDate, endDate, flags, startDate, endDate, endDate, 0, 0, 0, 0, true, 0, -1); } /** Loading Loading @@ -342,6 +364,21 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { return 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. * * @hide */ public boolean isRandomizedEncryptionRequired() { return mRandomizedEncryptionRequired; } /** * Gets the set of user authenticators which protect access to the private key. The key can only * be used iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -429,6 +466,8 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes; private boolean mRandomizedEncryptionRequired = true; private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators; private int mUserAuthenticationValidityDurationSeconds = -1; Loading Loading @@ -669,6 +708,33 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { 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> * * @hide */ public Builder setRandomizedEncryptionRequired(boolean required) { mRandomizedEncryptionRequired = required; return this; } /** * Sets the user authenticators which protect access to this key. The key can only be used * iff the user has authenticated to at least one of these user authenticators. Loading Loading @@ -736,6 +802,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec { mDigests, mPaddings, mBlockModes, mRandomizedEncryptionRequired, mUserAuthenticators, mUserAuthenticationValidityDurationSeconds); } Loading
keystore/java/android/security/KeyStoreKeyConstraints.java +26 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,14 @@ public abstract class KeyStoreKeyConstraints { /** Galois/Counter Mode (GCM) block mode. */ public static final int GCM = 1 << 3; /** * Set of block modes compatible with IND-CPA if used correctly. * * @hide */ public static final @BlockModeEnum int IND_CPA_COMPATIBLE_MODES = CBC | CTR | GCM; /** * @hide */ Loading Loading @@ -667,6 +675,24 @@ public abstract class KeyStoreKeyConstraints { } } /** * @hide */ public static String allToString(@BlockModeEnum int modes) { StringBuilder result = new StringBuilder("["); boolean firstValue = true; for (@BlockModeEnum int mode : getSetFlags(modes)) { if (firstValue) { firstValue = false; } else { result.append(", "); } result.append(toString(mode)); } result.append(']'); return result.toString(); } /** * @hide */ Loading
keystore/java/android/security/KeyStoreKeyGeneratorSpi.java +18 −5 Original line number Diff line number Diff line Loading @@ -138,13 +138,26 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { } int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits; args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits); int purposes = spec.getPurposes(); @KeyStoreKeyConstraints.PurposeEnum int purposes = spec.getPurposes(); @KeyStoreKeyConstraints.BlockModeEnum int blockModes = spec.getBlockModes(); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) && (spec.isRandomizedEncryptionRequired())) { @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes = blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES; if (incompatibleBlockModes != 0) { throw new IllegalStateException( "Randomized encryption (IND-CPA) required but may be violated by block" + " mode(s): " + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes) + ". See KeyGeneratorSpec documentation."); } } for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) { args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose); } for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(spec.getBlockModes())) { for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) { args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode); } for (int keymasterPadding : Loading Loading @@ -173,8 +186,8 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi { ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE)); if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0) || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) { // Permit caller-specified IV. This is needed due to the Cipher abstraction. && (!spec.isRandomizedEncryptionRequired())) { // Permit caller-provided IV when encrypting with this key args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE); } Loading