.. _key-agreement:

Key agreement
=============

.. _key-agreement-algorithms:

Key agreement algorithms
------------------------

.. macro:: PSA_ALG_KEY_AGREEMENT
    :definition: /* specification-defined value */

    .. summary::
        Macro to build a combined algorithm that chains a key agreement with a key derivation.

    .. param:: ka_alg
        A key agreement algorithm (``PSA_ALG_XXX`` value such that :code:`PSA_ALG_IS_KEY_AGREEMENT(ka_alg)` is true).
    .. param:: kdf_alg
        A key derivation algorithm (``PSA_ALG_XXX`` value such that :code:`PSA_ALG_IS_KEY_DERIVATION(kdf_alg)` is true).

    .. return::
        The corresponding key agreement and derivation algorithm.

        Unspecified if ``ka_alg`` is not a supported key agreement algorithm or ``kdf_alg`` is not a supported key derivation algorithm.

    The component parts of a key agreement algorithm can be extracted using `PSA_ALG_KEY_AGREEMENT_GET_BASE()` and `PSA_ALG_KEY_AGREEMENT_GET_KDF()`.

.. macro:: PSA_ALG_FFDH
    :definition: ((psa_algorithm_t)0x09010000)

    .. summary::
        The finite-field Diffie-Hellman (DH) key agreement algorithm.

    The shared secret produced by key agreement is ``g^{ab}`` in big-endian format. It is ``ceiling(m / 8)`` bytes long where ``m`` is the size of the prime ``p`` in bits.

.. macro:: PSA_ALG_ECDH
    :definition: ((psa_algorithm_t)0x09020000)

    .. summary::
        The elliptic curve Diffie-Hellman (ECDH) key agreement algorithm.

    The shared secret produced by key agreement is the x-coordinate of the shared secret point. It is always ``ceiling(m / 8)`` bytes long where ``m`` is the bit size associated with the curve, i.e. the bit size of the order of the curve's coordinate field. When ``m`` is not a multiple of 8, the byte containing the most significant bit of the shared secret is padded with zero bits. The byte order is either little-endian or big-endian depending on the curve type.

    * For Montgomery curves (curve family `PSA_ECC_FAMILY_MONTGOMERY`), the shared secret is the x-coordinate of ``d_A Q_B = d_B Q_A`` in little-endian byte order. The bit size is 448 for Curve448 and 255 for Curve25519.
    * For Weierstrass curves over prime fields (curve families ``PSA_ECC_FAMILY_SECP_XX``, `PSA_ECC_FAMILY_BRAINPOOL_P_R1` and `PSA_ECC_FAMILY_FRP`), the shared secret is the x-coordinate of ``d_A Q_B = d_B Q_A`` in big-endian byte order. The bit size is ``m = ceiling(log_2(p))`` for the field ``F_p``.
    * For Weierstrass curves over binary fields (curve families ``PSA_ECC_FAMILY_SECT_XX``), the shared secret is the x-coordinate of ``d_A Q_B = d_B Q_A`` in big-endian byte order. The bit size is ``m`` for the field ``F_{2^m}``.

Standalone key agreement
------------------------

.. function:: psa_raw_key_agreement

    .. summary::
        Perform a key agreement and return the raw shared secret.

    .. param:: psa_algorithm_t alg
        The key agreement algorithm to compute (``PSA_ALG_XXX`` value such that :code:`PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)` is true).
    .. param:: psa_key_id_t private_key
        Identifier of the private key to use.
        It must allow the usage `PSA_KEY_USAGE_DERIVE`.
    .. param:: const uint8_t * peer_key
        Public key of the peer. It must be in the same format that `psa_import_key()` accepts. The standard formats for public keys are documented in the documentation of `psa_export_public_key()`.
    .. param:: size_t peer_key_length
        Size of ``peer_key`` in bytes.
    .. param:: uint8_t * output
        Buffer where the decrypted message is to be written.
    .. param:: size_t output_size
        Size of the ``output`` buffer in bytes.
        This must be appropriate for the keys:

        * The required output size is :code:`PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(type, bits)` where ``type`` is the type of ``private_key`` and ``bits`` is the bit-size of either ``private_key`` or the ``peer_key``.
        * `PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE` evaluates to the maximum output size of any supported raw key agreement algorithm.

    .. param:: size_t * output_length
        On success, the number of bytes that make up the returned output.

    .. return:: psa_status_t
    .. retval:: PSA_SUCCESS
        Success.
    .. retval:: PSA_ERROR_INVALID_HANDLE
    .. retval:: PSA_ERROR_NOT_PERMITTED
        The key does not have the `PSA_KEY_USAGE_DERIVE` flag, or it does not permit the requested algorithm.
    .. retval:: PSA_ERROR_INVALID_ARGUMENT
        ``alg`` is not a key agreement algorithm
    .. retval:: PSA_ERROR_INVALID_ARGUMENT
        ``private_key`` is not compatible with ``alg``, or ``peer_key`` is not valid for ``alg`` or not compatible with ``private_key``.
    .. retval:: PSA_ERROR_BUFFER_TOO_SMALL
        The size of the ``output`` buffer is too small.
        `PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE()` or `PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE` can be used to determine the required buffer size.
    .. retval:: PSA_ERROR_NOT_SUPPORTED
        ``alg`` is not a supported key agreement algorithm.
    .. retval:: PSA_ERROR_INSUFFICIENT_MEMORY
    .. retval:: PSA_ERROR_COMMUNICATION_FAILURE
    .. retval:: PSA_ERROR_HARDWARE_FAILURE
    .. retval:: PSA_ERROR_CORRUPTION_DETECTED
    .. retval:: PSA_ERROR_STORAGE_FAILURE
    .. retval:: PSA_ERROR_DATA_CORRUPT
    .. retval:: PSA_ERROR_DATA_INVALID
    .. retval:: PSA_ERROR_BAD_STATE
        The library has not been previously initialized by `psa_crypto_init()`. It is implementation-dependent whether a failure to initialize results in this error code.

    .. warning::
        The raw result of a key agreement algorithm such as finite-field Diffie-Hellman or elliptic curve Diffie-Hellman has biases, and is not suitable for use as key material. Instead it is recommended that the result is used as input to a key derivation algorithm. To chain a key agreement with a key derivation, use `psa_key_derivation_key_agreement()` and other functions from the key derivation interface.

Combining key agreement and key derivation
------------------------------------------

.. function:: psa_key_derivation_key_agreement

    .. summary::
        Perform a key agreement and use the shared secret as input to a key derivation.

    .. param:: psa_key_derivation_operation_t * operation
        The key derivation operation object to use. It must have been set up with `psa_key_derivation_setup()` with a key agreement and derivation algorithm ``alg`` (``PSA_ALG_XXX`` value such that :code:`PSA_ALG_IS_KEY_AGREEMENT(alg)` is true and :code:`PSA_ALG_IS_RAW_KEY_AGREEMENT(alg)` is false). The operation must be ready for an input of the type given by ``step``.
    .. param:: psa_key_derivation_step_t step
        Which step the input data is for.
    .. param:: psa_key_id_t private_key
        Identifier of the private key to use.
        It must allow the usage `PSA_KEY_USAGE_DERIVE`.
    .. param:: const uint8_t * peer_key
        Public key of the peer. The peer key must be in the same format that `psa_import_key()` accepts for the public key type corresponding to the type of private_key. That is, this function performs the equivalent of :code:`psa_import_key(..., peer_key, peer_key_length)` where with key attributes indicating the public key type corresponding to the type of ``private_key``. For example, for EC keys, this means that peer_key is interpreted as a point on the curve that the private key is on. The standard formats for public keys are documented in the documentation of `psa_export_public_key()`.
    .. param:: size_t peer_key_length
        Size of ``peer_key`` in bytes.

    .. return:: psa_status_t
    .. retval:: PSA_SUCCESS
        Success.
    .. retval:: PSA_ERROR_BAD_STATE
        The operation state is not valid for this key agreement ``step``.
    .. retval:: PSA_ERROR_INVALID_HANDLE
    .. retval:: PSA_ERROR_NOT_PERMITTED
        The key does not have the `PSA_KEY_USAGE_DERIVE` flag, or it does not permit the requested algorithm.
    .. retval:: PSA_ERROR_INVALID_ARGUMENT
        ``private_key`` is not compatible with ``alg``, or ``peer_key`` is not valid for ``alg`` or not compatible with ``private_key``.
    .. retval:: PSA_ERROR_NOT_SUPPORTED
        ``alg`` is not supported or is not a key derivation algorithm.
    .. retval:: PSA_ERROR_INVALID_ARGUMENT
        ``step`` does not allow an input resulting from a key agreement.
    .. retval:: PSA_ERROR_INSUFFICIENT_MEMORY
    .. retval:: PSA_ERROR_COMMUNICATION_FAILURE
    .. retval:: PSA_ERROR_HARDWARE_FAILURE
    .. retval:: PSA_ERROR_CORRUPTION_DETECTED
    .. retval:: PSA_ERROR_STORAGE_FAILURE
    .. retval:: PSA_ERROR_DATA_CORRUPT
    .. retval:: PSA_ERROR_DATA_INVALID
    .. retval:: PSA_ERROR_BAD_STATE
        The library has not been previously initialized by `psa_crypto_init()`. It is implementation-dependent whether a failure to initialize results in this error code.

    A key agreement algorithm takes two inputs: a private key ``private_key`` a public key ``peer_key``. The result of this function is passed as input to a key derivation. The output of this key derivation can be extracted by reading from the resulting operation to produce keys and other cryptographic material.

    If this function returns an error status, the operation enters an error state and must be aborted by calling `psa_key_derivation_abort()`.

Support macros
--------------

.. macro:: PSA_ALG_KEY_AGREEMENT_GET_BASE
    :definition: /* specification-defined value */

    .. summary::
        Get the raw key agreement algorithm from a full key agreement algorithm.

    .. param:: alg
        A key agreement algorithm identifier (value of type `psa_algorithm_t` such that :code:`PSA_ALG_IS_KEY_AGREEMENT(alg)` is true).

    .. return::
        The underlying raw key agreement algorithm if ``alg`` is a key agreement algorithm.

        Unspecified if ``alg`` is not a key agreement algorithm or if it is not supported by the implementation.

    See also `PSA_ALG_KEY_AGREEMENT()` and `PSA_ALG_KEY_AGREEMENT_GET_KDF()`.

.. macro:: PSA_ALG_KEY_AGREEMENT_GET_KDF
    :definition: /* specification-defined value */

    .. summary::
        Get the key derivation algorithm used in a full key agreement algorithm.

    .. param:: alg
        A key agreement algorithm identifier (value of type `psa_algorithm_t` such that :code:`PSA_ALG_IS_KEY_AGREEMENT(alg)` is true).

    .. return::
        The underlying key derivation algorithm if ``alg`` is a key agreement algorithm.

        Unspecified if ``alg`` is not a key agreement algorithm or if it is not supported by the implementation.

    See also `PSA_ALG_KEY_AGREEMENT()` and `PSA_ALG_KEY_AGREEMENT_GET_BASE()`.

.. macro:: PSA_ALG_IS_RAW_KEY_AGREEMENT
    :definition: /* specification-defined value */

    .. summary::
        Whether the specified algorithm is a raw key agreement algorithm.

    .. param:: alg
        An algorithm identifier (value of type `psa_algorithm_t`).

    .. return::
        ``1`` if ``alg`` is a raw key agreement algorithm, ``0`` otherwise. This macro can return either ``0`` or ``1`` if ``alg`` is not a supported algorithm identifier.

    A raw key agreement algorithm is one that does not specify a key derivation function. Usually, raw key agreement algorithms are constructed directly with a ``PSA_ALG_xxx`` macro while non-raw key agreement algorithms are constructed with `PSA_ALG_KEY_AGREEMENT()`.

    The raw key agreement algorithm can be extracted from a full key agreement algorithm identifier using `PSA_ALG_KEY_AGREEMENT_GET_BASE()`.

.. macro:: PSA_ALG_IS_FFDH
    :definition: /* specification-defined value */

    .. summary::
        Whether the specified algorithm is a finite field Diffie-Hellman algorithm.

    .. param:: alg
        An algorithm identifier (value of type `psa_algorithm_t`).

    .. return::
        ``1`` if ``alg`` is a finite field Diffie-Hellman algorithm, ``0`` otherwise. This macro can return either ``0`` or ``1`` if ``alg`` is not a supported key agreement algorithm identifier.

    This includes the raw finite field Diffie-Hellman algorithm as well as finite-field Diffie-Hellman followed by any supporter key derivation algorithm.

.. macro:: PSA_ALG_IS_ECDH
    :definition: /* specification-defined value */

    .. summary::
        Whether the specified algorithm is an elliptic curve Diffie-Hellman algorithm.

    .. param:: alg
        An algorithm identifier (value of type `psa_algorithm_t`).

    .. return::
        ``1`` if ``alg`` is an elliptic curve Diffie-Hellman algorithm, ``0`` otherwise. This macro can return either ``0`` or ``1`` if ``alg`` is not a supported key agreement algorithm identifier.

    This includes the raw elliptic curve Diffie-Hellman algorithm as well as elliptic curve Diffie-Hellman followed by any supporter key derivation algorithm.

.. macro:: PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE
    :definition: /* implementation-defined value */

    .. summary::
        Sufficient output buffer size for `psa_raw_key_agreement()`.

    .. param:: key_type
        A supported key type.
    .. param:: key_bits
        The size of the key in bits.

    .. return::
        If the parameters are valid and supported, return a buffer size in bytes that guarantees that `psa_raw_key_agreement()` will not fail with `PSA_ERROR_BUFFER_TOO_SMALL`. If the parameters are a valid combination that is not supported by the implementation, this macro must return either a sensible size or ``0``. If the parameters are not valid, the return value is unspecified.

    This macro returns a compile-time constant if its arguments are compile-time constants.

    .. warning::
        This function might evaluate its arguments multiple times or zero times. Providing arguments that have side effects will result in implementation-specific behavior, and is non-portable.

    See also `PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE`.

.. macro:: PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE
    :definition: /* implementation-defined value */

    .. summary::
        Maximum size of the output from `psa_raw_key_agreement()`.

    This macro must expand to a compile-time constant integer.
    It is recommended that this value is the maximum size of the output any raw key agreement algorithm supported by the implementation, in bytes. The value must not be smaller than this maximum.

    See also `PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE()`.
