10.9. Key agreement

Three functions are provided for a Diffie-Hellman-style key agreement where each party combines its own private key with the peer’s public key, to produce a shared secret value:

Using psa_key_agreement() or psa_key_derivation_key_agreement() is recommended, as these do not expose the shared secret to the application.

Note

In general the shared secret is not directly suitable for use as a key because it is biased.

10.9.1. Key agreement algorithms

PSA_ALG_FFDH (macro)

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

#define PSA_ALG_FFDH ((psa_algorithm_t)0x09010000)

This standalone key agreement algorithm can be used directly in a call to psa_key_agreement() or psa_raw_key_agreement(), or combined with a key derivation operation using PSA_ALG_KEY_AGREEMENT() for use with psa_key_derivation_key_agreement().

When used as a key’s permitted-algorithm policy, the following uses are permitted:

When used as part of a multi-part key derivation operation, this implements a Diffie-Hellman key agreement scheme using a single Diffie-Hellman key-pair for each participant. This includes the dhEphem, dhOneFlow, and dhStatic schemes. The input step PSA_KEY_DERIVATION_INPUT_SECRET is used when providing the secret and peer keys to the operation.

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

This key agreement scheme is defined by NIST Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography [SP800-56A] §5.7.1.1 under the name FFC DH.

Compatible key types

PSA_ALG_ECDH (macro)

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

#define PSA_ALG_ECDH ((psa_algorithm_t)0x09020000)

This standalone key agreement algorithm can be used directly in a call to psa_key_agreement() or psa_raw_key_agreement(), or combined with a key derivation operation using PSA_ALG_KEY_AGREEMENT() for use with psa_key_derivation_key_agreement().

When used as a key’s permitted-algorithm policy, the following uses are permitted:

When used as part of a multi-part key derivation operation, this implements a Diffie-Hellman key agreement scheme using a single elliptic curve key-pair for each participant. This includes the Ephemeral unified model, the Static unified model, and the One-pass Diffie-Hellman schemes. The input step PSA_KEY_DERIVATION_INPUT_SECRET is used when providing the secret and peer keys to the operation.

The shared secret produced by key agreement is the x-coordinate of the shared secret point. It is always \(\lceil{(m / 8)}\rceil\) 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 \(Z = d_A Q_B = d_B Q_A\) in little-endian byte order.

    • For Curve25519, this is the X25519 function defined in Curve25519: new Diffie-Hellman speed records [Curve25519]. The bit size \(m\) is 255.

    • For Curve448, this is the X448 function defined in Ed448-Goldilocks, a new elliptic curve [Curve448]. The bit size \(m\) is 448.

  • For Weierstrass curves (curve families PSA_ECC_FAMILY_SECP_XX, PSA_ECC_FAMILY_SECT_XX, PSA_ECC_FAMILY_BRAINPOOL_P_R1 and PSA_ECC_FAMILY_FRP) the shared secret is the x-coordinate of \(Z = h d_A Q_B = h d_B Q_A\) in big-endian byte order. This is the Elliptic Curve Cryptography Cofactor Diffie-Hellman primitive defined by SEC 1: Elliptic Curve Cryptography [SEC1] §3.3.2 as, and also as ECC CDH by NIST Special Publication 800-56A: Recommendation for Pair-Wise Key-Establishment Schemes Using Discrete Logarithm Cryptography [SP800-56A] §5.7.1.2.

    • Over prime fields (curve families PSA_ECC_FAMILY_SECP_XX, PSA_ECC_FAMILY_BRAINPOOL_P_R1 and PSA_ECC_FAMILY_FRP), the bit size is \(m = \lceil{\log_2(p)}\rceil\) for the field \(\mathbb{F}_p\).

    • Over binary fields (curve families PSA_ECC_FAMILY_SECT_XX), the bit size is \(m\) for the field \(\mathbb{F}_{2^m}\).

    Note

    The cofactor Diffie-Hellman primitive is equivalent to the standard elliptic curve Diffie-Hellman calculation \(Z = d_A Q_B = d_B Q_A\) ([SEC1] §3.3.1) for curves where the cofactor \(h\) is 1. This is true for all curves in the PSA_ECC_FAMILY_SECP_XX, PSA_ECC_FAMILY_BRAINPOOL_P_R1, and PSA_ECC_FAMILY_FRP families.

Compatible key types

where family is a Weierstrass or Montgomery Elliptic curve family. That is, one of the following values:

PSA_ALG_KEY_AGREEMENT (macro)

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

#define PSA_ALG_KEY_AGREEMENT(ka_alg, kdf_alg) \
    /* specification-defined value */

Parameters

ka_alg

A key agreement algorithm: a value of type psa_algorithm_t such that PSA_ALG_IS_KEY_AGREEMENT(ka_alg) is true.

kdf_alg

A key derivation algorithm: a value of type psa_algorithm_t such that PSA_ALG_IS_KEY_DERIVATION(kdf_alg) is true.

Returns

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.

Description

A combined key agreement algorithm is used with a multi-part key derivation operation, using a call to psa_key_derivation_key_agreement().

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().

Compatible key types

The resulting combined key agreement algorithm is compatible with the same key types as the standalone key agreement algorithm used to construct it.

10.9.2. Standalone key agreement

psa_key_agreement (function)

Perform a key agreement and return the shared secret as a derivation key.

psa_status_t psa_key_agreement(psa_key_id_t private_key,
                               const uint8_t * peer_key,
                               size_t peer_key_length,
                               psa_algorithm_t alg,
                               const psa_key_attributes_t * attributes,
                               psa_key_id_t * key);

Parameters

private_key

Identifier of the private key to use. It must permit the usage PSA_KEY_USAGE_DERIVE.

peer_key

Public key of the peer. The peer key data is parsed with the type PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) where type is the type of private_key, and with the same bit-size as private_key. The peer key must be in the format that psa_import_key() accepts for this public key type. These formats are described in Key formats.

peer_key_length

Size of peer_key in bytes.

alg

The standalone key agreement algorithm to compute: a value of type psa_algorithm_t such that PSA_ALG_IS_STANDALONE_KEY_AGREEMENT(alg) is true.

attributes

The attributes for the new key. This function uses the attributes as follows:

Note

This is an input parameter: it is not updated with the final key attributes. The final attributes of the new key can be queried by calling psa_get_key_attributes() with the key’s identifier.

key

On success, an identifier for the newly created key. PSA_KEY_ID_NULL on failure.

Returns: psa_status_t

PSA_SUCCESS

Success. The new key contains the share secret. If the key is persistent, the key material and the key’s metadata have been saved to persistent storage.

PSA_ERROR_BAD_STATE

The library requires initializing by a call to psa_crypto_init().

PSA_ERROR_INVALID_HANDLE

private_key is not a valid key identifier.

PSA_ERROR_NOT_PERMITTED

The following conditions can result in this error:

  • private_key does not have the PSA_KEY_USAGE_DERIVE flag, or it does not permit the requested algorithm.

  • The implementation does not permit creating a key with the specified attributes due to some implementation-specific policy.

PSA_ERROR_ALREADY_EXISTS

This is an attempt to create a persistent key, and there is already a persistent key with the given identifier.

PSA_ERROR_INVALID_ARGUMENT

The following conditions can result in this error:

  • alg is not a key agreement algorithm.

  • private_key is not compatible with alg.

  • peer_key is not a valid public key corresponding to private_key.

  • The output key attributes in attributes are not valid :

    • The key type is not valid for key agreement output.

    • The key size is nonzero, and is not the size of the shared secret.

    • The key lifetime is invalid.

    • The key identifier is not valid for the key lifetime.

    • The key usage flags include invalid values.

    • The key’s permitted-usage algorithm is invalid.

    • The key attributes, as a whole, are invalid.

PSA_ERROR_NOT_SUPPORTED

The following conditions can result in this error:

  • alg is not supported or is not a key agreement algorithm.

  • private_key is not supported for use with alg.

  • The output key attributes, as a whole, are not supported, either by the implementation in general or in the specified storage location.

PSA_ERROR_INSUFFICIENT_MEMORY

PSA_ERROR_INSUFFICIENT_STORAGE

PSA_ERROR_COMMUNICATION_FAILURE

PSA_ERROR_CORRUPTION_DETECTED

PSA_ERROR_STORAGE_FAILURE

PSA_ERROR_DATA_CORRUPT

PSA_ERROR_DATA_INVALID

Description

A key agreement algorithm takes two inputs: a private key private_key, and a public key peer_key. The result of this function is a shared secret, returned as a derivation key. This key can be input to a key derivation operation using psa_key_derivation_input_key().

Warning

The shared secret resulting from a key agreement algorithm such as finite-field Diffie-Hellman or elliptic curve Diffie-Hellman has biases. This makes it unsuitable for use as key material, for example, as an AES key. Instead, it is recommended that a key derivation algorithm is applied to the result, to derive unbiased cryptographic keys.

psa_raw_key_agreement (function)

Perform a key agreement and return the shared secret.

psa_status_t psa_raw_key_agreement(psa_algorithm_t alg,
                                   psa_key_id_t private_key,
                                   const uint8_t * peer_key,
                                   size_t peer_key_length,
                                   uint8_t * output,
                                   size_t output_size,
                                   size_t * output_length);

Parameters

alg

The standalone key agreement algorithm to compute: a value of type psa_algorithm_t such that PSA_ALG_IS_STANDALONE_KEY_AGREEMENT(alg) is true.

private_key

Identifier of the private key to use. It must permit the usage PSA_KEY_USAGE_DERIVE.

peer_key

Public key of the peer. The peer key data is parsed with the type PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) where type is the type of private_key, and with the same bit-size as private_key. The peer key must be in the format that psa_import_key() accepts for this public key type. These formats are described in Key formats.

peer_key_length

Size of peer_key in bytes.

output

Buffer where the shared secret is to be written.

output_size

Size of the output buffer in bytes. This must be appropriate for the keys:

output_length

On success, the number of bytes that make up the returned output.

Returns: psa_status_t

PSA_SUCCESS

Success. The first (*output_length) bytes of output contain the shared secret.

PSA_ERROR_BAD_STATE

The library requires initializing by a call to psa_crypto_init().

PSA_ERROR_INVALID_HANDLE

private_key is not a valid key identifier.

PSA_ERROR_NOT_PERMITTED

private_key does not have the PSA_KEY_USAGE_DERIVE flag, or it does not permit the requested algorithm.

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 a sufficient buffer size.

PSA_ERROR_INVALID_ARGUMENT

The following conditions can result in this error:

  • alg is not a key agreement algorithm.

  • private_key is not compatible with alg.

  • peer_key is not a valid public key corresponding to private_key.

PSA_ERROR_NOT_SUPPORTED

The following conditions can result in this error:

  • alg is not supported or is not a key agreement algorithm.

  • private_key is not supported for use with alg.

PSA_ERROR_INSUFFICIENT_MEMORY

PSA_ERROR_COMMUNICATION_FAILURE

PSA_ERROR_CORRUPTION_DETECTED

PSA_ERROR_STORAGE_FAILURE

PSA_ERROR_DATA_CORRUPT

PSA_ERROR_DATA_INVALID

Description

A key agreement algorithm takes two inputs: a private key private_key, and a public key peer_key. The result of this function is a shared secret, returned in the output buffer.

Warning

The result of a key agreement algorithm such as finite-field Diffie-Hellman or elliptic curve Diffie-Hellman has biases, and is not suitable for direct use as key material, for example, as an AES key. 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, either use psa_key_agreement() to obtain the result of the key agreement as a derivation key, or use psa_key_derivation_key_agreement() and other functions from the key derivation interface.

10.9.3. Combining key agreement and key derivation

psa_key_derivation_key_agreement (function)

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

psa_status_t psa_key_derivation_key_agreement(psa_key_derivation_operation_t * operation,
                                              psa_key_derivation_step_t step,
                                              psa_key_id_t private_key,
                                              const uint8_t * peer_key,
                                              size_t peer_key_length);

Parameters

operation

The key derivation operation object to use. It must have been set up with psa_key_derivation_setup() with a combined key agreement and derivation algorithm alg: a value of type psa_algorithm_t such that PSA_ALG_IS_KEY_AGREEMENT(alg) is true and PSA_ALG_IS_STANDALONE_KEY_AGREEMENT(alg) is false.

The operation must be ready for an input of the type given by step.

step

Which step the input data is for.

private_key

Identifier of the private key to use. It must permit the usage PSA_KEY_USAGE_DERIVE.

peer_key

Public key of the peer. The peer key data is parsed with the type PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR(type) where type is the type of private_key, and with the same bit-size as private_key. The peer key must be in the format that psa_import_key() accepts for this public key type. These formats are described in Key formats.

peer_key_length

Size of peer_key in bytes.

Returns: psa_status_t

PSA_SUCCESS

Success.

PSA_ERROR_BAD_STATE

The following conditions can result in this error:

  • The operation state is not valid for this key agreement step.

  • The library requires initializing by a call to psa_crypto_init().

PSA_ERROR_INVALID_HANDLE

private_key is not a valid key identifier.

PSA_ERROR_NOT_PERMITTED

private_key does not have the PSA_KEY_USAGE_DERIVE flag, or it does not permit the operation’s algorithm.

PSA_ERROR_INVALID_ARGUMENT

The following conditions can result in this error:

  • The operation’s algorithm is not a key agreement algorithm.

  • step does not permit an input resulting from a key agreement.

  • private_key is not compatible with the operation’s algorithm.

  • peer_key is not a valid public key corresponding to private_key.

PSA_ERROR_NOT_SUPPORTED

private_key is not supported for use with the operation’s algorithm.

PSA_ERROR_INSUFFICIENT_MEMORY

PSA_ERROR_COMMUNICATION_FAILURE

PSA_ERROR_CORRUPTION_DETECTED

PSA_ERROR_STORAGE_FAILURE

PSA_ERROR_DATA_CORRUPT

PSA_ERROR_DATA_INVALID

Description

A key agreement algorithm takes two inputs: a private key private_key, and a public key peer_key. The result of this function is a shared secret, which is directly input to the key derivation operation. Output from the key derivation operation can then be used as 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().

Note

This function cannot be used when the resulting shared secret is required for multiple key derivations.

Instead, the application can call psa_key_agreement() to obtain the shared secret as a derivation key. This key can be used as input to as many key derivation operations as required.

10.9.4. Support macros

PSA_ALG_KEY_AGREEMENT_GET_BASE (macro)

Get the standalone key agreement algorithm from a combined key agreement and key derivation algorithm.

#define PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) /* specification-defined value */

Parameters

alg

A key agreement algorithm: a value of type psa_algorithm_t such that PSA_ALG_IS_KEY_AGREEMENT(alg) is true.

Returns

The underlying standalone 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.

Description

See also PSA_ALG_KEY_AGREEMENT() and PSA_ALG_KEY_AGREEMENT_GET_KDF().

PSA_ALG_KEY_AGREEMENT_GET_KDF (macro)

Get the key derivation algorithm used in a combined key agreement and key derivation algorithm.

#define PSA_ALG_KEY_AGREEMENT_GET_KDF(alg) /* specification-defined value */

Parameters

alg

A key agreement algorithm: a value of type psa_algorithm_t such that PSA_ALG_IS_KEY_AGREEMENT(alg) is true.

Returns

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.

Description

See also PSA_ALG_KEY_AGREEMENT() and PSA_ALG_KEY_AGREEMENT_GET_BASE().

PSA_ALG_IS_STANDALONE_KEY_AGREEMENT (macro)

Whether the specified algorithm is a standalone key agreement algorithm.

#define PSA_ALG_IS_STANDALONE_KEY_AGREEMENT(alg) \
    /* specification-defined value */

Parameters

alg

An algorithm identifier: a value of type psa_algorithm_t.

Returns

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

Description

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

The standalone key agreement algorithm can be extracted from a combined key agreement algorithm identifier using PSA_ALG_KEY_AGREEMENT_GET_BASE().

PSA_ALG_IS_RAW_KEY_AGREEMENT (macro)

Whether the specified algorithm is a standalone key agreement algorithm.

#define PSA_ALG_IS_RAW_KEY_AGREEMENT(alg) \
    PSA_ALG_IS_STANDALONE_KEY_AGREEMENT(alg)

Parameters

alg

An algorithm identifier: a value of type psa_algorithm_t.

Description

This is the original API name for PSA_ALG_IS_STANDALONE_KEY_AGREEMENT().

PSA_ALG_IS_FFDH (macro)

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

#define PSA_ALG_IS_FFDH(alg) /* specification-defined value */

Parameters

alg

An algorithm identifier: a value of type psa_algorithm_t.

Returns

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.

Description

This includes the standalone finite field Diffie-Hellman algorithm, as well as finite-field Diffie-Hellman combined with any supported key derivation algorithm.

PSA_ALG_IS_ECDH (macro)

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

#define PSA_ALG_IS_ECDH(alg) /* specification-defined value */

Parameters

alg

An algorithm identifier: a value of type psa_algorithm_t.

Returns

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.

Description

This includes the standalone elliptic curve Diffie-Hellman algorithm, as well as elliptic curve Diffie-Hellman combined with any supported key derivation algorithm.

PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE (macro)

Sufficient output buffer size for psa_raw_key_agreement().

#define PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE(key_type, key_bits) \
    /* implementation-defined value */

Parameters

key_type

A supported key type.

key_bits

The size of the key in bits.

Returns

A sufficient output buffer size for the specified key type and size. An implementation can return either 0 or a correct size for a key type and size that it recognizes, but does not support. If the parameters are not valid, the return value is unspecified.

Description

If the size of the output buffer is at least this large, it is guaranteed that psa_raw_key_agreement() will not fail due to an insufficient buffer size. The actual size of the output might be smaller in any given call.

See also PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE.

PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE (macro)

Sufficient output buffer size for psa_raw_key_agreement(), for any of the supported key types and key agreement algorithms.

#define PSA_RAW_KEY_AGREEMENT_OUTPUT_MAX_SIZE \
    /* implementation-defined value */

If the size of the output buffer is at least this large, it is guaranteed that psa_raw_key_agreement() will not fail due to an insufficient buffer size.

See also PSA_RAW_KEY_AGREEMENT_OUTPUT_SIZE().