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

Commit 0ee9376e authored by Alex Klyubin's avatar Alex Klyubin
Browse files

Add EcIesParameterSpec to enable ECIES crypto.

Bug: 18088752
Change-Id: I597b019106c500188e0fbbc9608722668c08b421
parent ba2836e6
Loading
Loading
Loading
Loading
+287 −0
Original line number Diff line number Diff line
package android.security;

import android.annotation.IntDef;

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>
 *
 * @hide
 */
public class EcIesParameterSpec implements AlgorithmParameterSpec {

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(value = {PointFormat.UNCOMPRESSED, PointFormat.COMPRESSED})
    public @interface PointFormatEnum {}

    /**
     * Wire format of the EC point.
     */
    public static abstract class PointFormat {

        private PointFormat() {}

        /** Unspecified point format. */
        public static final int UNSPECIFIED = -1;

        /**
         * Uncompressed 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 UNCOMPRESSED = 0;

        /**
         * Compressed 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 COMPRESSED = 1;
    }

    /**
     * Default parameter spec: NIST P-256 curve (aka secp256r1 aka prime256v1), compressed point
     * format, {@code HKDFwithSHA256}, DEM uses 128-bit AES GCM.
     */
    public static final EcIesParameterSpec DEFAULT = new EcIesParameterSpec(
            "P-256",
            PointFormat.COMPRESSED,
            "HKDFwithSHA256",
            "AES/GCM/NoPadding",
            128,
            null,
            0);

    private final String mKemCurveName;
    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(
            String kemCurveName,
            @PointFormatEnum int kemPointFormat,
            String kemKdfAlgorithm,
            String demCipherTransformation,
            int demCipherKeySize,
            String demMacAlgorithm,
            int demMacKeySize) {
        mKemCurveName = kemCurveName;
        mKemPointFormat = kemPointFormat;
        mKemKdfAlgorithm = kemKdfAlgorithm;
        mDemCipherTransformation = demCipherTransformation;
        mDemCipherKeySize = demCipherKeySize;
        mDemMacAlgorithm = demMacAlgorithm;
        mDemMacKeySize = demMacKeySize;
    }

    /**
     * Returns KEM EC curve name (e.g., {@code secp256r1}) or {@code null} if not specified.
     */
    public String getKemCurveName() {
        return mKemCurveName;
    }

    /**
     * Returns KEM EC point wire format or {@link PointFormat#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.
     */
    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()
     */
    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()
     */
    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 String mKemCurveName;
        private @PointFormatEnum int mKemPointFormat = PointFormat.UNSPECIFIED;
        private String mKemKdfAlgorithm;
        private String mDemCipherTransformation;
        private int mDemCipherKeySize = 128;
        private String mDemMacAlgorithm;
        private int mDemMacKeySize = -1;

        /**
         * Sets KEM EC curve name. For example, {@code P-256} or {@code secp256r1}.
         *
         * <p>NOTE: Only curves with cofactor of {@code 1} are supported.
         */
        public Builder setKemCurveName(String name) {
            mKemCurveName = name;
            return this;
        }

        /**
         * 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}.
         */
        public Builder setKemKdfAlgorithm(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)
         */
        public Builder setDemCipherTransformation(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)
         */
        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)
         */
        public Builder setDemMacAlgorithm(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)
         */
        public Builder setDemMacKeySize(int sizeBits) {
            mDemMacKeySize = sizeBits;
            return this;
        }

        /**
         * Returns a new {@link EcIesParameterSpec} based on the current state of this builder.
         */
        public EcIesParameterSpec build() {
            int demMacKeySize = (mDemMacKeySize != -1) ? mDemMacKeySize : mDemCipherKeySize;
            return new EcIesParameterSpec(
                    mKemCurveName,
                    mKemPointFormat,
                    mKemKdfAlgorithm,
                    mDemCipherTransformation,
                    mDemCipherKeySize,
                    mDemMacAlgorithm,
                    demMacKeySize
                    );
        }
    }
}