/*
 * Copyright (C) 2018 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 com.android.ike.ikev2.message;

import static com.android.ike.ikev2.SaProposal.DhGroup;
import static com.android.ike.ikev2.SaProposal.EncryptionAlgorithm;
import static com.android.ike.ikev2.SaProposal.IntegrityAlgorithm;
import static com.android.ike.ikev2.SaProposal.PseudorandomFunction;

import android.annotation.IntDef;
import android.util.ArraySet;
import android.util.Pair;

import com.android.ike.ikev2.SaProposal;
import com.android.ike.ikev2.exceptions.IkeException;
import com.android.ike.ikev2.exceptions.InvalidSyntaxException;
import com.android.ike.ikev2.exceptions.NoValidProposalChosenException;
import com.android.internal.annotations.VisibleForTesting;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * IkeSaPayload represents a Security Association payload. It contains one or more {@link Proposal}.
 *
 * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3">RFC 7296, Internet Key Exchange
 *     Protocol Version 2 (IKEv2)</a>
 */
public final class IkeSaPayload extends IkePayload {
    public final boolean isSaResponse;
    public final List<Proposal> proposalList;
    /**
     * Construct an instance of IkeSaPayload for decoding an inbound packet.
     *
     * @param critical indicates if this payload is critical. Ignored in supported payload as
     *     instructed by the RFC 7296.
     * @param isResp indicates if this payload is in a response message.
     * @param payloadBody the encoded payload body in byte array.
     */
    IkeSaPayload(boolean critical, boolean isResp, byte[] payloadBody) throws IkeException {
        super(IkePayload.PAYLOAD_TYPE_SA, critical);

        ByteBuffer inputBuffer = ByteBuffer.wrap(payloadBody);
        proposalList = new LinkedList<>();
        while (inputBuffer.hasRemaining()) {
            Proposal proposal = Proposal.readFrom(inputBuffer);
            proposalList.add(proposal);
        }

        // An SA response must have exactly one SA proposal.
        if (isResp && proposalList.size() != 1) {
            throw new InvalidSyntaxException(
                    "Expected only one negotiated proposal from SA response: "
                            + "Multiple negotiated proposals found.");
        }
        isSaResponse = isResp;
    }

    /**
     * Construct an instance of IkeSaPayload for building outbound packet.
     *
     * <p>The length of spis must be the same as saProposals.
     *
     * @param isResp indicates if this payload is in a response message.
     * @param isIkeSa indicates if this payload is for IKE SA or Child SA
     * @param spiSize the size of attached SPIs.
     * @param spis the array of all attached SPIs.
     * @param saProposals the array of all SA Proposals.
     */
    public IkeSaPayload(
            boolean isResp, boolean isIkeSa, byte spiSize, long[] spis, SaProposal[] saProposals) {
        super(IkePayload.PAYLOAD_TYPE_SA, false);

        if (saProposals.length < 1
                || isResp && (saProposals.length > 1)
                || saProposals.length != spis.length) {
            throw new IllegalArgumentException("Invalid SA payload.");
        }

        // TODO: Check that saProposals.length <= 255 in IkeSessionOptions and ChildSessionOptions
        isSaResponse = isResp;

        proposalList = new ArrayList<Proposal>(saProposals.length);
        int protocolId = isIkeSa ? PROTOCOL_ID_IKE : PROTOCOL_ID_ESP;
        for (int i = 0; i < saProposals.length; i++) {
            // Proposal number must start from 1.
            Proposal proposal =
                    new Proposal(
                            (byte) (i + 1) /*proposal number*/,
                            protocolId,
                            spiSize,
                            spis[i],
                            saProposals[i],
                            false /*does not have unrecognized Transform*/);
            proposalList.add(proposal);
        }
    }

    /**
     * Construct an instance of IkeSaPayload for building outbound IKE initial setup request.
     *
     * <p>According to RFC 7296, for an initial IKE SA negotiation, no SPI is included in SA
     * Proposal. IKE library, as a client, only supports requesting this initial negotiation.
     *
     * @param saProposals the array of all SA Proposals.
     */
    public IkeSaPayload(SaProposal[] saProposals) {
        this(
                false /*is request*/,
                true /*is IKE SA*/,
                (byte) 0,
                new long[saProposals.length],
                saProposals);
    }

    /**
     * Validate and return the negotiated SA proposal from the received SA payload.
     *
     * @param reqSaPayload SA payload from SA initiator to validate against.
     * @return the validated negotiated SA proposal.
     * @throws NoValidProposalChosenException if received SA proposal is invalid.
     */
    public SaProposal getVerifiedNegotiatedProposal(IkeSaPayload reqSaPayload)
            throws NoValidProposalChosenException {
        if (!isSaResponse) {
            throw new UnsupportedOperationException(
                    "Cannot get negotiated SA proposal from a request message.");
        }

        // If negotiated proposal has an unrecognized Transform, throw an exception.
        Proposal respProposal = proposalList.get(0);
        if (respProposal.hasUnrecognizedTransform) {
            throw new NoValidProposalChosenException(
                    "Negotiated proposal has unrecognized Transform.");
        }

        // In SA request payload, the first proposal MUST be 1, and subsequent proposals MUST be one
        // more than the previous proposal. In SA response payload, the negotiated proposal number
        // MUST match the selected proposal number in SA request Payload.
        int negotiatedProposalNum = respProposal.number;
        List<Proposal> reqProposalList = reqSaPayload.proposalList;
        if (negotiatedProposalNum < 1 || negotiatedProposalNum > reqProposalList.size()) {
            throw new NoValidProposalChosenException(
                    "Negotiated proposal has invalid proposal number.");
        }

        Proposal reqProposal = reqProposalList.get(negotiatedProposalNum - 1);
        if (!respProposal.isNegotiatedFrom(reqProposal)) {
            throw new NoValidProposalChosenException("Invalid negotiated proposal.");
        }
        return respProposal.saProposal;
    }

    @VisibleForTesting
    interface TransformDecoder {
        Transform[] decodeTransforms(int count, ByteBuffer inputBuffer) throws IkeException;
    }

    // TODO: Add another constructor for building outbound message.

    /**
     * Proposal represents a set contains cryptographic algorithms and key generating materials. It
     * contains multiple {@link Transform}.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.1">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     *     <p>Proposals with an unrecognized Protocol ID, containing an unrecognized Transform Type
     *     or lacking a necessary Transform Type shall be ignored when processing a received SA
     *     Payload.
     */
    public static final class Proposal {
        private static final byte LAST_PROPOSAL = 0;
        private static final byte NOT_LAST_PROPOSAL = 2;

        @VisibleForTesting
        static TransformDecoder sTransformDecoder =
                new TransformDecoder() {
                    @Override
                    public Transform[] decodeTransforms(int count, ByteBuffer inputBuffer)
                            throws IkeException {
                        Transform[] transformArray = new Transform[count];
                        for (int i = 0; i < count; i++) {
                            Transform transform = Transform.readFrom(inputBuffer);
                            if (transform.isSupported) {
                                transformArray[i] = transform;
                            }
                        }
                        return transformArray;
                    }
                };

        public final byte number;
        /** All supported protocol will fall into {@link ProtocolId} */
        public final int protocolId;

        public final byte spiSize;
        public final long spi;

        public final SaProposal saProposal;

        public final boolean hasUnrecognizedTransform;

        // TODO: Validate this proposal

        @VisibleForTesting
        Proposal(
                byte number,
                int protocolId,
                byte spiSize,
                long spi,
                SaProposal saProposal,
                boolean hasUnrecognizedTransform) {
            this.number = number;
            this.protocolId = protocolId;
            this.spiSize = spiSize;
            this.spi = spi;
            this.saProposal = saProposal;
            this.hasUnrecognizedTransform = hasUnrecognizedTransform;
        }

        @VisibleForTesting
        static Proposal readFrom(ByteBuffer inputBuffer) throws IkeException {
            byte isLast = inputBuffer.get();
            if (isLast != LAST_PROPOSAL && isLast != NOT_LAST_PROPOSAL) {
                throw new InvalidSyntaxException(
                        "Invalid value of Last Proposal Substructure: " + isLast);
            }
            // Skip RESERVED byte
            inputBuffer.get();

            int length = Short.toUnsignedInt(inputBuffer.getShort());
            byte number = inputBuffer.get();
            int protocolId = Byte.toUnsignedInt(inputBuffer.get());

            byte spiSize = inputBuffer.get();
            int transformCount = Byte.toUnsignedInt(inputBuffer.get());

            // TODO: Add check: spiSize must be 0 in initial IKE SA negotiation
            // spiSize should be either 8 for IKE or 4 for IPsec.
            long spi = SPI_NOT_INCLUDED;
            switch (spiSize) {
                case 0:
                    // No SPI field here.
                    break;
                case SPI_LEN_IPSEC:
                    spi = Integer.toUnsignedLong(inputBuffer.getInt());
                    break;
                case SPI_LEN_IKE:
                    spi = inputBuffer.getLong();
                    break;
                default:
                    throw new InvalidSyntaxException(
                            "Invalid value of spiSize in Proposal Substructure: " + spiSize);
            }

            Transform[] transformArray =
                    sTransformDecoder.decodeTransforms(transformCount, inputBuffer);
            // TODO: Validate that sum of all Transforms' lengths plus Proposal header length equals
            // to Proposal's length.

            List<EncryptionTransform> encryptAlgoList = new LinkedList<>();
            List<PrfTransform> prfList = new LinkedList<>();
            List<IntegrityTransform> integAlgoList = new LinkedList<>();
            List<DhGroupTransform> dhGroupList = new LinkedList<>();
            List<EsnTransform> esnList = new LinkedList<>();

            boolean hasUnrecognizedTransform = false;

            for (Transform transform : transformArray) {
                switch (transform.type) {
                    case Transform.TRANSFORM_TYPE_ENCR:
                        encryptAlgoList.add((EncryptionTransform) transform);
                        break;
                    case Transform.TRANSFORM_TYPE_PRF:
                        prfList.add((PrfTransform) transform);
                        break;
                    case Transform.TRANSFORM_TYPE_INTEG:
                        integAlgoList.add((IntegrityTransform) transform);
                        break;
                    case Transform.TRANSFORM_TYPE_DH:
                        dhGroupList.add((DhGroupTransform) transform);
                        break;
                    case Transform.TRANSFORM_TYPE_ESN:
                        esnList.add((EsnTransform) transform);
                        break;
                    default:
                        hasUnrecognizedTransform = true;
                }
            }

            SaProposal saProposal =
                    new SaProposal(
                            protocolId,
                            encryptAlgoList.toArray(
                                    new EncryptionTransform[encryptAlgoList.size()]),
                            prfList.toArray(new PrfTransform[prfList.size()]),
                            integAlgoList.toArray(new IntegrityTransform[integAlgoList.size()]),
                            dhGroupList.toArray(new DhGroupTransform[dhGroupList.size()]),
                            esnList.toArray(new EsnTransform[esnList.size()]));

            return new Proposal(
                    number, protocolId, spiSize, spi, saProposal, hasUnrecognizedTransform);
        }
        // TODO: Add another contructor for encoding.

        /** Package private */
        boolean isNegotiatedFrom(Proposal reqProposal) {
            if (protocolId != reqProposal.protocolId || number != reqProposal.number) {
                return false;
            }
            return saProposal.isNegotiatedFrom(reqProposal.saProposal);
        }
    }

    @VisibleForTesting
    interface AttributeDecoder {
        List<Attribute> decodeAttributes(int length, ByteBuffer inputBuffer) throws IkeException;
    }

    /**
     * Transform is an abstract base class that represents the common information for all Transform
     * types. It may contain one or more {@link Attribute}.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     *     <p>Transforms with unrecognized Transform ID or containing unrecognized Attribute Type
     *     shall be ignored when processing received SA payload.
     */
    public abstract static class Transform {

        @Retention(RetentionPolicy.SOURCE)
        @IntDef({
            TRANSFORM_TYPE_ENCR,
            TRANSFORM_TYPE_PRF,
            TRANSFORM_TYPE_INTEG,
            TRANSFORM_TYPE_DH,
            TRANSFORM_TYPE_ESN
        })
        public @interface TransformType {}

        public static final int TRANSFORM_TYPE_ENCR = 1;
        public static final int TRANSFORM_TYPE_PRF = 2;
        public static final int TRANSFORM_TYPE_INTEG = 3;
        public static final int TRANSFORM_TYPE_DH = 4;
        public static final int TRANSFORM_TYPE_ESN = 5;

        private static final byte LAST_TRANSFORM = 0;
        private static final byte NOT_LAST_TRANSFORM = 3;
        private static final int TRANSFORM_HEADER_LEN = 8;

        // TODO: Add constants for supported algorithms

        @VisibleForTesting
        static AttributeDecoder sAttributeDecoder =
                new AttributeDecoder() {
                    public List<Attribute> decodeAttributes(int length, ByteBuffer inputBuffer)
                            throws IkeException {
                        List<Attribute> list = new LinkedList<>();
                        int parsedLength = TRANSFORM_HEADER_LEN;
                        while (parsedLength < length) {
                            Pair<Attribute, Integer> pair = Attribute.readFrom(inputBuffer);
                            parsedLength += pair.second;
                            list.add(pair.first);
                        }
                        // TODO: Validate that parsedLength equals to length.
                        return list;
                    }
                };

        // Only supported type falls into {@link TransformType}
        public final int type;
        public final int id;
        public final boolean isSupported;

        /** Construct an instance of Transform for building an outbound packet. */
        protected Transform(int type, int id) {
            this.type = type;
            this.id = id;
            if (!isSupportedTransformId(id)) {
                throw new IllegalArgumentException(
                        "Unsupported " + getTransformTypeString() + " Algorithm ID: " + id);
            }
            this.isSupported = true;
        }

        /** Construct an instance of Transform for decoding an inbound packet. */
        protected Transform(int type, int id, List<Attribute> attributeList) {
            this.type = type;
            this.id = id;
            this.isSupported =
                    isSupportedTransformId(id) && !hasUnrecognizedAttribute(attributeList);
        }

        @VisibleForTesting
        static Transform readFrom(ByteBuffer inputBuffer) throws IkeException {
            byte isLast = inputBuffer.get();
            if (isLast != LAST_TRANSFORM && isLast != NOT_LAST_TRANSFORM) {
                throw new InvalidSyntaxException(
                        "Invalid value of Last Transform Substructure: " + isLast);
            }

            // Skip RESERVED byte
            inputBuffer.get();

            int length = Short.toUnsignedInt(inputBuffer.getShort());
            int type = Byte.toUnsignedInt(inputBuffer.get());

            // Skip RESERVED byte
            inputBuffer.get();

            int id = Short.toUnsignedInt(inputBuffer.getShort());

            // Decode attributes
            List<Attribute> attributeList = sAttributeDecoder.decodeAttributes(length, inputBuffer);

            validateAttributeUniqueness(attributeList);

            switch (type) {
                case TRANSFORM_TYPE_ENCR:
                    return new EncryptionTransform(id, attributeList);
                case TRANSFORM_TYPE_PRF:
                    return new PrfTransform(id, attributeList);
                case TRANSFORM_TYPE_INTEG:
                    return new IntegrityTransform(id, attributeList);
                case TRANSFORM_TYPE_DH:
                    return new DhGroupTransform(id, attributeList);
                case TRANSFORM_TYPE_ESN:
                    return new EsnTransform(id, attributeList);
                default:
                    return new UnrecognizedTransform(type, id, attributeList);
            }
        }

        // Throw InvalidSyntaxException if there are multiple Attributes of the same type
        private static void validateAttributeUniqueness(List<Attribute> attributeList)
                throws IkeException {
            Set<Integer> foundTypes = new ArraySet<>();
            for (Attribute attr : attributeList) {
                if (!foundTypes.add(attr.type)) {
                    throw new InvalidSyntaxException(
                            "There are multiple Attributes of the same type. ");
                }
            }
        }

        // Check if there is Attribute with unrecognized type.
        protected abstract boolean hasUnrecognizedAttribute(List<Attribute> attributeList);

        // Check if this Transform ID is supported.
        protected abstract boolean isSupportedTransformId(int id);

        /**
         * Get Tranform Type as a String.
         *
         * @return Tranform Type as a String.
         */
        public abstract String getTransformTypeString();

        // TODO: Add abstract getTransformIdString() to return specific algorithm/dhGroup name
    }

    /**
     * EncryptionTransform represents an encryption algorithm. It may contain an Atrribute
     * specifying the key length.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     */
    public static final class EncryptionTransform extends Transform {
        private static final int KEY_LEN_UNASSIGNED = 0;

        public final int keyLength;

        /**
         * Contruct an instance of EncryptionTransform with fixed key length for building an
         * outbound packet.
         *
         * @param id the IKE standard Transform ID.
         */
        public EncryptionTransform(@EncryptionAlgorithm int id) {
            this(id, KEY_LEN_UNASSIGNED);
        }

        /**
         * Contruct an instance of EncryptionTransform with variable key length for building an
         * outbound packet.
         *
         * @param id the IKE standard Transform ID.
         * @param keyLength the specified key length of this encryption algorithm.
         */
        public EncryptionTransform(@EncryptionAlgorithm int id, int keyLength) {
            super(Transform.TRANSFORM_TYPE_ENCR, id);

            this.keyLength = keyLength;
            try {
                validateKeyLength();
            } catch (InvalidSyntaxException e) {
                throw new IllegalArgumentException(e);
            }
        }

        /**
         * Contruct an instance of EncryptionTransform for decoding an inbound packet.
         *
         * @param id the IKE standard Transform ID.
         * @param attributeList the decoded list of Attribute.
         * @throws InvalidSyntaxException for syntax error.
         */
        protected EncryptionTransform(int id, List<Attribute> attributeList)
                throws InvalidSyntaxException {
            super(Transform.TRANSFORM_TYPE_ENCR, id, attributeList);
            if (!isSupported) {
                keyLength = KEY_LEN_UNASSIGNED;
            } else {
                if (attributeList.size() == 0) {
                    keyLength = KEY_LEN_UNASSIGNED;
                } else {
                    KeyLengthAttribute attr = getKeyLengthAttribute(attributeList);
                    keyLength = attr.keyLength;
                }
                validateKeyLength();
            }
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, id, keyLength);
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof EncryptionTransform)) return false;

            EncryptionTransform other = (EncryptionTransform) o;
            return (type == other.type && id == other.id && keyLength == other.keyLength);
        }

        @Override
        protected boolean isSupportedTransformId(int id) {
            return SaProposal.isSupportedEncryptionAlgorithm(id);
        }

        @Override
        protected boolean hasUnrecognizedAttribute(List<Attribute> attributeList) {
            for (Attribute attr : attributeList) {
                if (attr instanceof UnrecognizedAttribute) {
                    return true;
                }
            }
            return false;
        }

        private KeyLengthAttribute getKeyLengthAttribute(List<Attribute> attributeList) {
            for (Attribute attr : attributeList) {
                if (attr.type == Attribute.ATTRIBUTE_TYPE_KEY_LENGTH) {
                    return (KeyLengthAttribute) attr;
                }
            }
            throw new IllegalArgumentException("Cannot find Attribute with Key Length type");
        }

        private void validateKeyLength() throws InvalidSyntaxException {
            switch (id) {
                case SaProposal.ENCRYPTION_ALGORITHM_3DES:
                    if (keyLength != KEY_LEN_UNASSIGNED) {
                        throw new InvalidSyntaxException(
                                "Must not set Key Length value for this "
                                        + getTransformTypeString()
                                        + " Algorithm ID: "
                                        + id);
                    }
                    return;
                case SaProposal.ENCRYPTION_ALGORITHM_AES_CBC:
                    /* fall through */
                case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_8:
                    /* fall through */
                case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_12:
                    /* fall through */
                case SaProposal.ENCRYPTION_ALGORITHM_AES_GCM_16:
                    if (keyLength == KEY_LEN_UNASSIGNED) {
                        throw new InvalidSyntaxException(
                                "Must set Key Length value for this "
                                        + getTransformTypeString()
                                        + " Algorithm ID: "
                                        + id);
                    }
                    if (keyLength != SaProposal.KEY_LEN_AES_128
                            && keyLength != SaProposal.KEY_LEN_AES_192
                            && keyLength != SaProposal.KEY_LEN_AES_256) {
                        throw new InvalidSyntaxException(
                                "Invalid key length for this "
                                        + getTransformTypeString()
                                        + " Algorithm ID: "
                                        + id);
                    }
                    return;
                default:
                    // Won't hit here.
                    throw new IllegalArgumentException(
                            "Unrecognized Encryption Algorithm ID: " + id);
            }
        }

        @Override
        public String getTransformTypeString() {
            return "Encryption Algorithm";
        }
    }

    /**
     * PrfTransform represents an pseudorandom function.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     */
    public static final class PrfTransform extends Transform {
        /**
         * Contruct an instance of PrfTransform for building an outbound packet.
         *
         * @param id the IKE standard Transform ID.
         */
        public PrfTransform(@PseudorandomFunction int id) {
            super(Transform.TRANSFORM_TYPE_PRF, id);
        }

        /**
         * Contruct an instance of PrfTransform for decoding an inbound packet.
         *
         * @param id the IKE standard Transform ID.
         * @param attributeList the decoded list of Attribute.
         * @throws InvalidSyntaxException for syntax error.
         */
        protected PrfTransform(int id, List<Attribute> attributeList)
                throws InvalidSyntaxException {
            super(Transform.TRANSFORM_TYPE_PRF, id, attributeList);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, id);
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof PrfTransform)) return false;

            PrfTransform other = (PrfTransform) o;
            return (type == other.type && id == other.id);
        }

        @Override
        protected boolean isSupportedTransformId(int id) {
            return SaProposal.isSupportedPseudorandomFunction(id);
        }

        @Override
        protected boolean hasUnrecognizedAttribute(List<Attribute> attributeList) {
            return !attributeList.isEmpty();
        }

        @Override
        public String getTransformTypeString() {
            return "Pseudorandom Function";
        }
    }

    /**
     * IntegrityTransform represents an integrity algorithm.
     *
     * <p>Proposing integrity algorithm for ESP SA is optional. Omitting the IntegrityTransform is
     * equivalent to including it with a value of NONE. When multiple integrity algorithms are
     * provided, choosing any of them are acceptable.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     */
    public static final class IntegrityTransform extends Transform {
        /**
         * Contruct an instance of IntegrityTransform for building an outbound packet.
         *
         * @param id the IKE standard Transform ID.
         */
        public IntegrityTransform(@IntegrityAlgorithm int id) {
            super(Transform.TRANSFORM_TYPE_INTEG, id);
        }

        /**
         * Contruct an instance of IntegrityTransform for decoding an inbound packet.
         *
         * @param id the IKE standard Transform ID.
         * @param attributeList the decoded list of Attribute.
         * @throws InvalidSyntaxException for syntax error.
         */
        protected IntegrityTransform(int id, List<Attribute> attributeList)
                throws InvalidSyntaxException {
            super(Transform.TRANSFORM_TYPE_INTEG, id, attributeList);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, id);
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof IntegrityTransform)) return false;

            IntegrityTransform other = (IntegrityTransform) o;
            return (type == other.type && id == other.id);
        }

        @Override
        protected boolean isSupportedTransformId(int id) {
            return SaProposal.isSupportedIntegrityAlgorithm(id);
        }

        @Override
        protected boolean hasUnrecognizedAttribute(List<Attribute> attributeList) {
            return !attributeList.isEmpty();
        }

        @Override
        public String getTransformTypeString() {
            return "Integrity Algorithm";
        }
    }

    /**
     * DhGroupTransform represents a Diffie-Hellman Group
     *
     * <p>Proposing DH group for non-first Child SA is optional. Omitting the DhGroupTransform is
     * equivalent to including it with a value of NONE. When multiple DH groups are provided,
     * choosing any of them are acceptable.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     */
    public static final class DhGroupTransform extends Transform {
        /**
         * Contruct an instance of DhGroupTransform for building an outbound packet.
         *
         * @param id the IKE standard Transform ID.
         */
        public DhGroupTransform(@DhGroup int id) {
            super(Transform.TRANSFORM_TYPE_DH, id);
        }

        /**
         * Contruct an instance of DhGroupTransform for decoding an inbound packet.
         *
         * @param id the IKE standard Transform ID.
         * @param attributeList the decoded list of Attribute.
         * @throws InvalidSyntaxException for syntax error.
         */
        protected DhGroupTransform(int id, List<Attribute> attributeList)
                throws InvalidSyntaxException {
            super(Transform.TRANSFORM_TYPE_DH, id, attributeList);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, id);
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof DhGroupTransform)) return false;

            DhGroupTransform other = (DhGroupTransform) o;
            return (type == other.type && id == other.id);
        }

        @Override
        protected boolean isSupportedTransformId(int id) {
            return SaProposal.isSupportedDhGroup(id);
        }

        @Override
        protected boolean hasUnrecognizedAttribute(List<Attribute> attributeList) {
            return !attributeList.isEmpty();
        }

        @Override
        public String getTransformTypeString() {
            return "Diffie-Hellman Group";
        }
    }

    /**
     * EsnTransform represents ESN policy that indicates if IPsec SA uses tranditional 32-bit
     * sequence numbers or extended(64-bit) sequence numbers.
     *
     * <p>Currently IKE library only supports negotiating IPsec SA that do not use extended sequence
     * numbers. The Transform ID of EsnTransform in outbound packets is not user configurable.
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.2">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     */
    public static final class EsnTransform extends Transform {
        @Retention(RetentionPolicy.SOURCE)
        @IntDef({ESN_POLICY_NO_EXTENDED, ESN_POLICY_EXTENDED})
        public @interface EsnPolicy {}

        public static final int ESN_POLICY_NO_EXTENDED = 0;
        public static final int ESN_POLICY_EXTENDED = 1;

        /**
         * Construct an instance of EsnTransform indicates using no-extended sequence numbers for
         * building an outbound packet.
         */
        public EsnTransform() {
            super(Transform.TRANSFORM_TYPE_ESN, ESN_POLICY_NO_EXTENDED);
        }

        /**
         * Contruct an instance of EsnTransform for decoding an inbound packet.
         *
         * @param id the IKE standard Transform ID.
         * @param attributeList the decoded list of Attribute.
         * @throws InvalidSyntaxException for syntax error.
         */
        protected EsnTransform(int id, List<Attribute> attributeList)
                throws InvalidSyntaxException {
            super(Transform.TRANSFORM_TYPE_ESN, id, attributeList);
        }

        @Override
        public int hashCode() {
            return Objects.hash(type, id);
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof EsnTransform)) return false;

            EsnTransform other = (EsnTransform) o;
            return (type == other.type && id == other.id);
        }

        @Override
        protected boolean isSupportedTransformId(int id) {
            return (id == ESN_POLICY_NO_EXTENDED || id == ESN_POLICY_EXTENDED);
        }

        @Override
        protected boolean hasUnrecognizedAttribute(List<Attribute> attributeList) {
            return !attributeList.isEmpty();
        }

        @Override
        public String getTransformTypeString() {
            return "Extended Sequence Numbers";
        }
    }

    /**
     * UnrecognizedTransform represents a Transform with unrecognized Transform Type.
     *
     * <p>Proposals containing an UnrecognizedTransform should be ignored.
     */
    protected static final class UnrecognizedTransform extends Transform {
        protected UnrecognizedTransform(int type, int id, List<Attribute> attributeList) {
            super(type, id, attributeList);
        }

        @Override
        protected boolean isSupportedTransformId(int id) {
            return false;
        }

        @Override
        protected boolean hasUnrecognizedAttribute(List<Attribute> attributeList) {
            return !attributeList.isEmpty();
        }

        /**
         * Return Tranform Type of Unrecognized Transform as a String.
         *
         * @return Tranform Type of Unrecognized Transform as a String.
         */
        @Override
        public String getTransformTypeString() {
            return "Unrecognized Transform Type";
        }
    }

    /**
     * Attribute is an abtract base class for completing the specification of some {@link
     * Transform}.
     *
     * <p>Attribute is either in Type/Value format or Type/Length/Value format. For TV format,
     * Attribute length is always 4 bytes containing value for 2 bytes. While for TLV format,
     * Attribute length is determined by length field.
     *
     * <p>Currently only Key Length type is supported
     *
     * @see <a href="https://tools.ietf.org/html/rfc7296#section-3.3.5">RFC 7296, Internet Key
     *     Exchange Protocol Version 2 (IKEv2)</a>
     */
    public abstract static class Attribute {
        @Retention(RetentionPolicy.SOURCE)
        @IntDef({ATTRIBUTE_TYPE_KEY_LENGTH})
        public @interface AttributeType {}

        // Support only one Attribute type: Key Length. Should use Type/Value format.
        public static final int ATTRIBUTE_TYPE_KEY_LENGTH = 14;

        private static final int TV_ATTRIBUTE_VALUE_LEN = 2;
        private static final int TV_ATTRIBUTE_TOTAL_LEN = 4;
        private static final int TVL_ATTRIBUTE_HEADER_LEN = TV_ATTRIBUTE_TOTAL_LEN;

        // Only Key Length type belongs to AttributeType
        public final int type;

        /** Construct an instance of an Attribute when decoding message. */
        protected Attribute(int type) {
            this.type = type;
        }

        @VisibleForTesting
        static Pair<Attribute, Integer> readFrom(ByteBuffer inputBuffer) throws IkeException {
            short formatAndType = inputBuffer.getShort();
            int type = formatAndType & 0x7fff;

            int length = 0;
            byte[] value = new byte[0];
            if ((formatAndType & 0x8000) == 0x8000) {
                // Type/Value format
                length = TV_ATTRIBUTE_TOTAL_LEN;
                value = new byte[TV_ATTRIBUTE_VALUE_LEN];
            } else {
                // Type/Length/Value format
                if (type == ATTRIBUTE_TYPE_KEY_LENGTH) {
                    throw new InvalidSyntaxException("Wrong format in Transform Attribute");
                }

                length = Short.toUnsignedInt(inputBuffer.getShort());
                int valueLen = length - TVL_ATTRIBUTE_HEADER_LEN;
                // IkeMessage will catch exception if valueLen is negative.
                value = new byte[valueLen];
            }

            inputBuffer.get(value);

            switch (type) {
                case ATTRIBUTE_TYPE_KEY_LENGTH:
                    return new Pair(new KeyLengthAttribute(value), length);
                default:
                    return new Pair(new UnrecognizedAttribute(type, value), length);
            }
        }
    }

    /** KeyLengthAttribute represents a Key Length type Attribute */
    public static final class KeyLengthAttribute extends Attribute {
        public final int keyLength;

        protected KeyLengthAttribute(byte[] value) {
            this(Short.toUnsignedInt(ByteBuffer.wrap(value).getShort()));
        }

        protected KeyLengthAttribute(int keyLength) {
            super(ATTRIBUTE_TYPE_KEY_LENGTH);
            this.keyLength = keyLength;
        }
    }

    /**
     * UnrecognizedAttribute represents a Attribute with unrecoginzed Attribute Type.
     *
     * <p>Transforms containing UnrecognizedAttribute should be ignored.
     */
    protected static final class UnrecognizedAttribute extends Attribute {
        protected UnrecognizedAttribute(int type, byte[] value) {
            super(type);
        }
    }

    /**
     * Encode SA payload to ByteBUffer.
     *
     * @param nextPayload type of payload that follows this payload.
     * @param byteBuffer destination ByteBuffer that stores encoded payload.
     */
    @Override
    protected void encodeToByteBuffer(@PayloadType int nextPayload, ByteBuffer byteBuffer) {
        throw new UnsupportedOperationException(
                "It is not supported to encode a " + getTypeString());
        // TODO: Implement encoding SA payload.
    }

    /**
     * Get entire payload length.
     *
     * @return entire payload length.
     */
    @Override
    protected int getPayloadLength() {
        throw new UnsupportedOperationException(
                "It is not supported to get payload length of " + getTypeString());
        // TODO: Implement this method for SA payload.
    }

    /**
     * Return the payload type as a String.
     *
     * @return the payload type as a String.
     */
    @Override
    public String getTypeString() {
        return "SA Payload";
    }
}
