Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f7e7f744 authored by Alex Klyubin's avatar Alex Klyubin Committed by Android Git Automerger
Browse files

am a482b046: Merge "Require IND-CPA by default for new AndroidKeyStore keys."

* commit 'a482b046':
  Require IND-CPA by default for new AndroidKeyStore keys.
parents 7f757130 a482b046
Loading
Loading
Loading
Loading
+16 −5
Original line number Diff line number Diff line
@@ -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 :
@@ -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);
        }

+56 −0
Original line number Diff line number Diff line
@@ -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;

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

@@ -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) {
@@ -87,6 +90,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
        mPurposes = purposes;
        mPaddings = paddings;
        mBlockModes = blockModes;
        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
        mUserAuthenticators = userAuthenticators;
        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
    }
@@ -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.
@@ -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;

@@ -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.
@@ -394,6 +449,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
                    mPurposes,
                    mPaddings,
                    mBlockModes,
                    mRandomizedEncryptionRequired,
                    mUserAuthenticators,
                    mUserAuthenticationValidityDurationSeconds);
        }
+69 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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) {
@@ -171,6 +174,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
        mDigests = digests;
        mPaddings = paddings;
        mBlockModes = blockModes;
        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
        mUserAuthenticators = userAuthenticators;
        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
    }
@@ -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);
    }

    /**
@@ -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.
@@ -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;
@@ -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.
@@ -736,6 +802,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
                    mDigests,
                    mPaddings,
                    mBlockModes,
                    mRandomizedEncryptionRequired,
                    mUserAuthenticators,
                    mUserAuthenticationValidityDurationSeconds);
        }
+26 −0
Original line number Diff line number Diff line
@@ -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
         */
@@ -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
         */
+18 −5
Original line number Diff line number Diff line
@@ -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 :
@@ -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