diff mbox series

[12/21] dpp-util: add crypto for PKEX

Message ID 20231012200150.338401-13-prestwoj@gmail.com (mailing list archive)
State New
Headers show
Series DPP PKEX Changes | expand

Commit Message

James Prestwood Oct. 12, 2023, 8:01 p.m. UTC
---
 src/dpp-util.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/dpp-util.h |  32 ++++++++
 2 files changed, 240 insertions(+)

Comments

Denis Kenzior Oct. 19, 2023, 3:13 p.m. UTC | #1
Hi James,

On 10/12/23 15:01, James Prestwood wrote:
> ---
>   src/dpp-util.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++
>   src/dpp-util.h |  32 ++++++++
>   2 files changed, 240 insertions(+)
> 

You may want to add some references to the code?  i.e. which part corresponds to 
what section in the spec.

> diff --git a/src/dpp-util.c b/src/dpp-util.c
> index 0406a4dc..b0556917 100644
> --- a/src/dpp-util.c
> +++ b/src/dpp-util.c
> @@ -39,6 +39,32 @@
>   #include "ell/asn1-private.h"
>   #include "src/ie.h"
>   

<snip>

> +
> +struct l_ecc_point *dpp_derive_q(const struct l_ecc_curve *curve,
> +					bool responder,
> +					const char *key,
> +					const char *identifier,
> +					const uint8_t *mac)

Should this use the [static 6] syntax?  Or I guess not since mac can be NULL. 
Why can mac be NULL?

We have derive_l_responder and derive_l_initiator, but derive_q has a boolean 
parameter?  Lets be consistent.

> +{
> +	_auto_(l_ecc_scalar_free) struct l_ecc_scalar *scalar = NULL;
> +	_auto_(l_ecc_point_free) struct l_ecc_point *ret = NULL;
> +	uint8_t hash[L_ECC_SCALAR_MAX_BYTES];
> +	unsigned int bytes = l_ecc_curve_get_scalar_bytes(curve);
> +	enum l_checksum_type type = dpp_sha_from_key_len(bytes);
> +	_auto_(l_ecc_point_free) struct l_ecc_point *p = NULL;
> +	const uint8_t *p_data = responder ? dpp_pkex_responder_p256 :
> +					dpp_pkex_initiator_p256;
> +	struct l_checksum *sha = l_checksum_new(type);
> +
> +	if (mac)
> +		l_checksum_update(sha, mac, 6);
> +
> +	if (identifier)
> +		l_checksum_update(sha, identifier, strlen(identifier));
> +
> +	l_checksum_update(sha, key, strlen(key));
> +	l_checksum_get_digest(sha, hash, bytes);
> +	l_checksum_free(sha);
> +
> +	/* Unlikely but can happen */
> +	scalar = l_ecc_scalar_new(curve, hash, bytes);
> +	if (!scalar)
> +		return NULL;
> +
> +	p = l_ecc_point_from_data(curve, L_ECC_POINT_TYPE_FULL,
> +					p_data, bytes * 2);
> +	if (!p)
> +		return NULL;
> +
> +	ret = l_ecc_point_new(curve);
> +
> +	if (!l_ecc_point_multiply(ret, scalar, p))
> +		return NULL;
> +
> +	return l_steal_ptr(ret);
> +}
> +
> +bool dpp_derive_z(const uint8_t *mac_i, const uint8_t *mac_r,

[static 6]?

> +				const struct l_ecc_point *n,
> +				const struct l_ecc_point *m,
> +				const struct l_ecc_point *k,
> +				const char *key,
> +				const char *identifier,
> +				void *z_out, size_t *z_len)
> +{
> +	const struct l_ecc_curve *curve = l_ecc_point_get_curve(n);
> +	size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
> +	enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
> +	uint8_t k_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t m_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t n_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t prk[L_ECC_SCALAR_MAX_BYTES];
> +
> +	l_ecc_point_get_x(k, k_x, sizeof(k_x));
> +	l_ecc_point_get_x(m, m_x, sizeof(m_x));
> +	l_ecc_point_get_x(n, n_x, sizeof(n_x));
> +
> +	hkdf_extract(sha, NULL, 0, 1, prk, k_x, bytes);
> +
> +	/* HKDF-Extract (since it doesn't take non-string arguments)*/
> +	prf_plus(sha, prk, bytes, z_out, bytes, 5, mac_i, 6, mac_r, 6, m_x,
> +			bytes, n_x, bytes, key, strlen(key));
> +
> +	*z_len = bytes;
> +
> +	return true;
> +}
> +
> +bool dpp_derive_u(const struct l_ecc_point *j,
> +			const uint8_t *mac_i,

[static 6]?

> +			const struct l_ecc_point *a,
> +			const struct l_ecc_point *y,
> +			const struct l_ecc_point *x,
> +			void *u_out, size_t *u_len)
> +{
> +	const struct l_ecc_curve *curve = l_ecc_point_get_curve(y);
> +	uint8_t j_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t a_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t y_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t x_x[L_ECC_SCALAR_MAX_BYTES];
> +	size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
> +	enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
> +	struct l_checksum *hmac;
> +
> +	l_ecc_point_get_x(j, j_x, bytes);
> +	l_ecc_point_get_x(a, a_x, bytes);
> +	l_ecc_point_get_x(y, y_x, bytes);
> +	l_ecc_point_get_x(x, x_x, bytes);
> +
> +	/* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x)*/
> +	hmac = l_checksum_new_hmac(sha, j_x, bytes);
> +	l_checksum_update(hmac, mac_i, 6);
> +	l_checksum_update(hmac, a_x, bytes);
> +	l_checksum_update(hmac, y_x, bytes);
> +	l_checksum_update(hmac, x_x, bytes);
> +	l_checksum_get_digest(hmac, u_out, bytes);
> +	l_checksum_free(hmac);
> +
> +	*u_len = bytes;
> +
> +	return true;
> +}
> +
> +bool dpp_derive_v(const struct l_ecc_point *l, const uint8_t *mac,

And here?

> +			const struct l_ecc_point *b,
> +			const struct l_ecc_point *x,
> +			const struct l_ecc_point *y,
> +			uint8_t *v_out, size_t *v_len)
> +{
> +	const struct l_ecc_curve *curve = l_ecc_point_get_curve(l);
> +	uint8_t l_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t b_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t x_x[L_ECC_SCALAR_MAX_BYTES];
> +	uint8_t y_x[L_ECC_SCALAR_MAX_BYTES];
> +	size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
> +	enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
> +	struct l_checksum *hmac;
> +
> +	l_ecc_point_get_x(l, l_x, sizeof(l_x));
> +	l_ecc_point_get_x(b, b_x, sizeof(b_x));
> +	l_ecc_point_get_x(x, x_x, sizeof(x_x));
> +	l_ecc_point_get_x(y, y_x, sizeof(y_x));
> +
> +	hmac = l_checksum_new_hmac(sha, l_x, bytes);
> +
> +	if (mac)
> +		l_checksum_update(hmac, mac, 6);
> +
> +	l_checksum_update(hmac, b_x, bytes);
> +	l_checksum_update(hmac, x_x, bytes);
> +	l_checksum_update(hmac, y_x, bytes);
> +	l_checksum_get_digest(hmac, v_out, bytes);
> +	l_checksum_free(hmac);
> +
> +	*v_len = bytes;
> +
> +	return true;
> +}

<snip>

Unit tests?

Regards,
-Denis
James Prestwood Oct. 19, 2023, 3:27 p.m. UTC | #2
Hi Denis,

On 10/19/23 8:13 AM, Denis Kenzior wrote:
> Hi James,
> 
> On 10/12/23 15:01, James Prestwood wrote:
>> ---
>>   src/dpp-util.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++
>>   src/dpp-util.h |  32 ++++++++
>>   2 files changed, 240 insertions(+)
>>
> 
> You may want to add some references to the code?  i.e. which part 
> corresponds to what section in the spec.
> 
>> diff --git a/src/dpp-util.c b/src/dpp-util.c
>> index 0406a4dc..b0556917 100644
>> --- a/src/dpp-util.c
>> +++ b/src/dpp-util.c
>> @@ -39,6 +39,32 @@
>>   #include "ell/asn1-private.h"
>>   #include "src/ie.h"
> 
> <snip>
> 
>> +
>> +struct l_ecc_point *dpp_derive_q(const struct l_ecc_curve *curve,
>> +                    bool responder,
>> +                    const char *key,
>> +                    const char *identifier,
>> +                    const uint8_t *mac)
> 
> Should this use the [static 6] syntax?  Or I guess not since mac can be 
> NULL. Why can mac be NULL?

I'll leave some spec section comments, but PKEX versions use slightly 
different derivations. I only wanted to support PKEXv1 for now but was 
more less future proofing to avoid an API change later.

> 
> We have derive_l_responder and derive_l_initiator, but derive_q has a 
> boolean parameter?  Lets be consistent.

I'll make a common function and add dpp_derive_q_{responder,initiator}. 
The original reason for the to "derive_l" APIs was because the 
derivation is vastly different, where 'q' is basically the same just 
different ECC points. But I agree, its not consistent.

> 
>> +{
>> +    _auto_(l_ecc_scalar_free) struct l_ecc_scalar *scalar = NULL;
>> +    _auto_(l_ecc_point_free) struct l_ecc_point *ret = NULL;
>> +    uint8_t hash[L_ECC_SCALAR_MAX_BYTES];
>> +    unsigned int bytes = l_ecc_curve_get_scalar_bytes(curve);
>> +    enum l_checksum_type type = dpp_sha_from_key_len(bytes);
>> +    _auto_(l_ecc_point_free) struct l_ecc_point *p = NULL;
>> +    const uint8_t *p_data = responder ? dpp_pkex_responder_p256 :
>> +                    dpp_pkex_initiator_p256;
>> +    struct l_checksum *sha = l_checksum_new(type);
>> +
>> +    if (mac)
>> +        l_checksum_update(sha, mac, 6);
>> +
>> +    if (identifier)
>> +        l_checksum_update(sha, identifier, strlen(identifier));
>> +
>> +    l_checksum_update(sha, key, strlen(key));
>> +    l_checksum_get_digest(sha, hash, bytes);
>> +    l_checksum_free(sha);
>> +
>> +    /* Unlikely but can happen */
>> +    scalar = l_ecc_scalar_new(curve, hash, bytes);
>> +    if (!scalar)
>> +        return NULL;
>> +
>> +    p = l_ecc_point_from_data(curve, L_ECC_POINT_TYPE_FULL,
>> +                    p_data, bytes * 2);
>> +    if (!p)
>> +        return NULL;
>> +
>> +    ret = l_ecc_point_new(curve);
>> +
>> +    if (!l_ecc_point_multiply(ret, scalar, p))
>> +        return NULL;
>> +
>> +    return l_steal_ptr(ret);
>> +}
>> +
>> +bool dpp_derive_z(const uint8_t *mac_i, const uint8_t *mac_r,
> 
> [static 6]?
> 
>> +                const struct l_ecc_point *n,
>> +                const struct l_ecc_point *m,
>> +                const struct l_ecc_point *k,
>> +                const char *key,
>> +                const char *identifier,
>> +                void *z_out, size_t *z_len)
>> +{
>> +    const struct l_ecc_curve *curve = l_ecc_point_get_curve(n);
>> +    size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
>> +    enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
>> +    uint8_t k_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t m_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t n_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t prk[L_ECC_SCALAR_MAX_BYTES];
>> +
>> +    l_ecc_point_get_x(k, k_x, sizeof(k_x));
>> +    l_ecc_point_get_x(m, m_x, sizeof(m_x));
>> +    l_ecc_point_get_x(n, n_x, sizeof(n_x));
>> +
>> +    hkdf_extract(sha, NULL, 0, 1, prk, k_x, bytes);
>> +
>> +    /* HKDF-Extract (since it doesn't take non-string arguments)*/
>> +    prf_plus(sha, prk, bytes, z_out, bytes, 5, mac_i, 6, mac_r, 6, m_x,
>> +            bytes, n_x, bytes, key, strlen(key));
>> +
>> +    *z_len = bytes;
>> +
>> +    return true;
>> +}
>> +
>> +bool dpp_derive_u(const struct l_ecc_point *j,
>> +            const uint8_t *mac_i,
> 
> [static 6]?
> 
>> +            const struct l_ecc_point *a,
>> +            const struct l_ecc_point *y,
>> +            const struct l_ecc_point *x,
>> +            void *u_out, size_t *u_len)
>> +{
>> +    const struct l_ecc_curve *curve = l_ecc_point_get_curve(y);
>> +    uint8_t j_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t a_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t y_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t x_x[L_ECC_SCALAR_MAX_BYTES];
>> +    size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
>> +    enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
>> +    struct l_checksum *hmac;
>> +
>> +    l_ecc_point_get_x(j, j_x, bytes);
>> +    l_ecc_point_get_x(a, a_x, bytes);
>> +    l_ecc_point_get_x(y, y_x, bytes);
>> +    l_ecc_point_get_x(x, x_x, bytes);
>> +
>> +    /* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x)*/
>> +    hmac = l_checksum_new_hmac(sha, j_x, bytes);
>> +    l_checksum_update(hmac, mac_i, 6);
>> +    l_checksum_update(hmac, a_x, bytes);
>> +    l_checksum_update(hmac, y_x, bytes);
>> +    l_checksum_update(hmac, x_x, bytes);
>> +    l_checksum_get_digest(hmac, u_out, bytes);
>> +    l_checksum_free(hmac);
>> +
>> +    *u_len = bytes;
>> +
>> +    return true;
>> +}
>> +
>> +bool dpp_derive_v(const struct l_ecc_point *l, const uint8_t *mac,
> 
> And here?
> 
>> +            const struct l_ecc_point *b,
>> +            const struct l_ecc_point *x,
>> +            const struct l_ecc_point *y,
>> +            uint8_t *v_out, size_t *v_len)
>> +{
>> +    const struct l_ecc_curve *curve = l_ecc_point_get_curve(l);
>> +    uint8_t l_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t b_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t x_x[L_ECC_SCALAR_MAX_BYTES];
>> +    uint8_t y_x[L_ECC_SCALAR_MAX_BYTES];
>> +    size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
>> +    enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
>> +    struct l_checksum *hmac;
>> +
>> +    l_ecc_point_get_x(l, l_x, sizeof(l_x));
>> +    l_ecc_point_get_x(b, b_x, sizeof(b_x));
>> +    l_ecc_point_get_x(x, x_x, sizeof(x_x));
>> +    l_ecc_point_get_x(y, y_x, sizeof(y_x));
>> +
>> +    hmac = l_checksum_new_hmac(sha, l_x, bytes);
>> +
>> +    if (mac)
>> +        l_checksum_update(hmac, mac, 6);
>> +
>> +    l_checksum_update(hmac, b_x, bytes);
>> +    l_checksum_update(hmac, x_x, bytes);
>> +    l_checksum_update(hmac, y_x, bytes);
>> +    l_checksum_get_digest(hmac, v_out, bytes);
>> +    l_checksum_free(hmac);
>> +
>> +    *v_len = bytes;
>> +
>> +    return true;
>> +}
> 
> <snip>
> 
> Unit tests?
> 
> Regards,
> -Denis
>
diff mbox series

Patch

diff --git a/src/dpp-util.c b/src/dpp-util.c
index 0406a4dc..b0556917 100644
--- a/src/dpp-util.c
+++ b/src/dpp-util.c
@@ -39,6 +39,32 @@ 
 #include "ell/asn1-private.h"
 #include "src/ie.h"
 
+static const uint8_t dpp_pkex_initiator_p256[64] = {
+	/* X */
+	0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b,
+	0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54,
+	0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07,
+	0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25,
+	/* Y */
+	0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b,
+	0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc,
+	0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45,
+	0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4
+};
+
+static const uint8_t dpp_pkex_responder_p256[64] = {
+	/* X */
+	0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39,
+	0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f,
+	0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f,
+	0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76,
+	/* Y */
+	0xd9, 0xfb, 0xf6, 0xb9, 0xf5, 0xfa, 0xdf, 0x19,
+	0x58, 0xd8, 0x3e, 0xc9, 0x89, 0x7a, 0x35, 0xc1,
+	0xbd, 0xe9, 0x0b, 0x77, 0x7a, 0xcb, 0x91, 0x2a,
+	0xe8, 0x21, 0x3f, 0x47, 0x52, 0x02, 0x4d, 0x67
+};
+
 static void append_freqs(struct l_string *uri,
 					const uint32_t *freqs, size_t len)
 {
@@ -1134,3 +1160,185 @@  void dpp_free_uri_info(struct dpp_uri_info *info)
 
 	l_free(info);
 }
+
+struct l_ecc_point *dpp_derive_l_initiator(
+				const struct l_ecc_point *boot_public,
+				const struct l_ecc_point *proto_public,
+				const struct l_ecc_scalar *boot_private)
+{
+	const struct l_ecc_curve *curve = l_ecc_point_get_curve(boot_public);
+	struct l_ecc_point *ret = l_ecc_point_new(curve);
+
+	l_ecc_point_add(ret, boot_public, proto_public);
+	l_ecc_point_multiply(ret, boot_private, ret);
+
+	return ret;
+}
+
+struct l_ecc_point *dpp_derive_l_responder(
+				const struct l_ecc_scalar *boot_private,
+				const struct l_ecc_scalar *proto_private,
+				const struct l_ecc_point *peer_public)
+{
+	const struct l_ecc_curve *curve = l_ecc_point_get_curve(peer_public);
+	_auto_(l_ecc_scalar_free) struct l_ecc_scalar *order =
+					l_ecc_curve_get_order(curve);
+	_auto_(l_ecc_scalar_free) struct l_ecc_scalar *sum =
+					l_ecc_scalar_new(curve, NULL, 0);
+	_auto_(l_ecc_point_free) struct l_ecc_point *ret =
+					l_ecc_point_new(curve);
+
+	if (!l_ecc_scalar_add(sum, boot_private, proto_private, order))
+		return NULL;
+
+	if (!l_ecc_point_multiply(ret, sum, peer_public))
+		return NULL;
+
+	return l_steal_ptr(ret);
+}
+
+struct l_ecc_point *dpp_derive_q(const struct l_ecc_curve *curve,
+					bool responder,
+					const char *key,
+					const char *identifier,
+					const uint8_t *mac)
+{
+	_auto_(l_ecc_scalar_free) struct l_ecc_scalar *scalar = NULL;
+	_auto_(l_ecc_point_free) struct l_ecc_point *ret = NULL;
+	uint8_t hash[L_ECC_SCALAR_MAX_BYTES];
+	unsigned int bytes = l_ecc_curve_get_scalar_bytes(curve);
+	enum l_checksum_type type = dpp_sha_from_key_len(bytes);
+	_auto_(l_ecc_point_free) struct l_ecc_point *p = NULL;
+	const uint8_t *p_data = responder ? dpp_pkex_responder_p256 :
+					dpp_pkex_initiator_p256;
+	struct l_checksum *sha = l_checksum_new(type);
+
+	if (mac)
+		l_checksum_update(sha, mac, 6);
+
+	if (identifier)
+		l_checksum_update(sha, identifier, strlen(identifier));
+
+	l_checksum_update(sha, key, strlen(key));
+	l_checksum_get_digest(sha, hash, bytes);
+	l_checksum_free(sha);
+
+	/* Unlikely but can happen */
+	scalar = l_ecc_scalar_new(curve, hash, bytes);
+	if (!scalar)
+		return NULL;
+
+	p = l_ecc_point_from_data(curve, L_ECC_POINT_TYPE_FULL,
+					p_data, bytes * 2);
+	if (!p)
+		return NULL;
+
+	ret = l_ecc_point_new(curve);
+
+	if (!l_ecc_point_multiply(ret, scalar, p))
+		return NULL;
+
+	return l_steal_ptr(ret);
+}
+
+bool dpp_derive_z(const uint8_t *mac_i, const uint8_t *mac_r,
+				const struct l_ecc_point *n,
+				const struct l_ecc_point *m,
+				const struct l_ecc_point *k,
+				const char *key,
+				const char *identifier,
+				void *z_out, size_t *z_len)
+{
+	const struct l_ecc_curve *curve = l_ecc_point_get_curve(n);
+	size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
+	enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
+	uint8_t k_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t m_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t n_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t prk[L_ECC_SCALAR_MAX_BYTES];
+
+	l_ecc_point_get_x(k, k_x, sizeof(k_x));
+	l_ecc_point_get_x(m, m_x, sizeof(m_x));
+	l_ecc_point_get_x(n, n_x, sizeof(n_x));
+
+	hkdf_extract(sha, NULL, 0, 1, prk, k_x, bytes);
+
+	/* HKDF-Extract (since it doesn't take non-string arguments)*/
+	prf_plus(sha, prk, bytes, z_out, bytes, 5, mac_i, 6, mac_r, 6, m_x,
+			bytes, n_x, bytes, key, strlen(key));
+
+	*z_len = bytes;
+
+	return true;
+}
+
+bool dpp_derive_u(const struct l_ecc_point *j,
+			const uint8_t *mac_i,
+			const struct l_ecc_point *a,
+			const struct l_ecc_point *y,
+			const struct l_ecc_point *x,
+			void *u_out, size_t *u_len)
+{
+	const struct l_ecc_curve *curve = l_ecc_point_get_curve(y);
+	uint8_t j_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t a_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t y_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t x_x[L_ECC_SCALAR_MAX_BYTES];
+	size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
+	enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
+	struct l_checksum *hmac;
+
+	l_ecc_point_get_x(j, j_x, bytes);
+	l_ecc_point_get_x(a, a_x, bytes);
+	l_ecc_point_get_x(y, y_x, bytes);
+	l_ecc_point_get_x(x, x_x, bytes);
+
+	/* u = HMAC(J.x, MAC-Initiator | A.x | Y'.x | X.x)*/
+	hmac = l_checksum_new_hmac(sha, j_x, bytes);
+	l_checksum_update(hmac, mac_i, 6);
+	l_checksum_update(hmac, a_x, bytes);
+	l_checksum_update(hmac, y_x, bytes);
+	l_checksum_update(hmac, x_x, bytes);
+	l_checksum_get_digest(hmac, u_out, bytes);
+	l_checksum_free(hmac);
+
+	*u_len = bytes;
+
+	return true;
+}
+
+bool dpp_derive_v(const struct l_ecc_point *l, const uint8_t *mac,
+			const struct l_ecc_point *b,
+			const struct l_ecc_point *x,
+			const struct l_ecc_point *y,
+			uint8_t *v_out, size_t *v_len)
+{
+	const struct l_ecc_curve *curve = l_ecc_point_get_curve(l);
+	uint8_t l_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t b_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t x_x[L_ECC_SCALAR_MAX_BYTES];
+	uint8_t y_x[L_ECC_SCALAR_MAX_BYTES];
+	size_t bytes = l_ecc_curve_get_scalar_bytes(curve);
+	enum l_checksum_type sha = dpp_sha_from_key_len(bytes);
+	struct l_checksum *hmac;
+
+	l_ecc_point_get_x(l, l_x, sizeof(l_x));
+	l_ecc_point_get_x(b, b_x, sizeof(b_x));
+	l_ecc_point_get_x(x, x_x, sizeof(x_x));
+	l_ecc_point_get_x(y, y_x, sizeof(y_x));
+
+	hmac = l_checksum_new_hmac(sha, l_x, bytes);
+
+	if (mac)
+		l_checksum_update(hmac, mac, 6);
+
+	l_checksum_update(hmac, b_x, bytes);
+	l_checksum_update(hmac, x_x, bytes);
+	l_checksum_update(hmac, y_x, bytes);
+	l_checksum_get_digest(hmac, v_out, bytes);
+	l_checksum_free(hmac);
+
+	*v_len = bytes;
+
+	return true;
+}
diff --git a/src/dpp-util.h b/src/dpp-util.h
index 96711c35..6b00796e 100644
--- a/src/dpp-util.h
+++ b/src/dpp-util.h
@@ -183,3 +183,35 @@  struct l_ecc_point *dpp_point_from_asn1(const uint8_t *asn1, size_t len);
 
 struct dpp_uri_info *dpp_parse_uri(const char *uri);
 void dpp_free_uri_info(struct dpp_uri_info *info);
+
+struct l_ecc_point *dpp_derive_q(const struct l_ecc_curve *curve,
+					bool responder,
+					const char *key,
+					const char *identifier,
+					const uint8_t *mac);
+struct l_ecc_point *dpp_derive_l_initiator(
+				const struct l_ecc_point *boot_public,
+				const struct l_ecc_point *proto_public,
+				const struct l_ecc_scalar *boot_private);
+struct l_ecc_point *dpp_derive_l_responder(
+				const struct l_ecc_scalar *boot_private,
+				const struct l_ecc_scalar *proto_private,
+				const struct l_ecc_point *peer_public);
+bool dpp_derive_z(const uint8_t *mac_i, const uint8_t *mac_r,
+				const struct l_ecc_point *n,
+				const struct l_ecc_point *m,
+				const struct l_ecc_point *k,
+				const char *key,
+				const char *identifier,
+				void *z_out, size_t *z_len);
+bool dpp_derive_u(const struct l_ecc_point *j,
+			const uint8_t *mac_i,
+			const struct l_ecc_point *a,
+			const struct l_ecc_point *y,
+			const struct l_ecc_point *x,
+			void *u_out, size_t *u_len);
+bool dpp_derive_v(const struct l_ecc_point *l, const uint8_t *mac,
+			const struct l_ecc_point *b,
+			const struct l_ecc_point *x,
+			const struct l_ecc_point *y,
+			uint8_t *v_out, size_t *v_len);