From 277437f3d6242706fd3a1b3d5ba89a9843f77264 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Wed, 7 Jul 2021 12:36:10 -0500 Subject: [PATCH] crypto: Add crypto_derive_sae_pt_ecc --- src/crypto.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/crypto.h | 7 ++++++ 2 files changed, 75 insertions(+) diff --git a/src/crypto.c b/src/crypto.c index b811aecf..6d12b5ac 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -33,6 +33,7 @@ #include +#include "ell/useful.h" #include "src/missing.h" #include "src/crypto.h" @@ -1144,3 +1145,70 @@ bool crypto_derive_pmkid(const uint8_t *pmk, else return hmac_sha1(pmk, 32, data, 20, out_pmkid, 16); } + +/* 802.11-2020, Table 12-1 Hash algorithm based on length of prime */ +static enum l_checksum_type ecc_hash_from_prime_len(size_t prime_len) +{ + if (prime_len <= 256 / 8) + return L_CHECKSUM_SHA256; + + if (prime_len <= 384 / 8) + return L_CHECKSUM_SHA384; + + return L_CHECKSUM_SHA512; +} + +struct l_ecc_point *crypto_derive_sae_pt_ecc(unsigned int group, + const char *ssid, + const char *password, + const char *identifier) +{ + const struct l_ecc_curve *curve = l_ecc_curve_from_ike_group(group); + enum l_checksum_type hash; + size_t hash_len; + uint8_t pwd_seed[64]; /* SHA512 is the biggest possible right now */ + uint8_t pwd_value[128]; + size_t pwd_value_len; + _auto_(l_ecc_scalar_free) struct l_ecc_scalar *u1 = NULL; + _auto_(l_ecc_scalar_free) struct l_ecc_scalar *u2 = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *p1 = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *p2 = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *pt = NULL; + + if (!curve) + return NULL; + + hash = ecc_hash_from_prime_len(l_ecc_curve_get_scalar_bytes(curve)); + hash_len = l_checksum_digest_length(hash); + + /* pwd-seed = HKDF-Extract(ssid, password [|| identifier]) */ + hkdf_extract(hash, ssid, strlen(ssid), 2, pwd_seed, + password, strlen(password), + identifier, identifier ? strlen(identifier) : 0); + + /* len = olen(p) + floor(olen(p)/2) */ + pwd_value_len = l_ecc_curve_get_scalar_bytes(curve); + pwd_value_len += pwd_value_len / 2; + + /* + * pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len) + */ + hkdf_expand(hash, pwd_seed, hash_len, "SAE Hash to Element u1 P1", + pwd_value, pwd_value_len); + u1 = l_ecc_scalar_new_modp(curve, pwd_value, pwd_value_len); + + /* + * pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len) + */ + hkdf_expand(hash, pwd_seed, hash_len, "SAE Hash to Element u2 P2", + pwd_value, pwd_value_len); + u2 = l_ecc_scalar_new_modp(curve, pwd_value, pwd_value_len); + + p1 = l_ecc_point_from_sswu(u1); + p2 = l_ecc_point_from_sswu(u2); + + pt = l_ecc_point_new(curve); + l_ecc_point_add(pt, p1, p2); + + return l_steal_ptr(pt); +} diff --git a/src/crypto.h b/src/crypto.h index a6f1ff09..50e07ff1 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -23,6 +23,8 @@ #include #include +struct l_ecc_point; + enum crypto_cipher { CRYPTO_CIPHER_WEP40 = 0x000fac01, CRYPTO_CIPHER_WEP104 = 0x000fac05, @@ -146,3 +148,8 @@ bool crypto_derive_ft_ptk(const uint8_t *pmk_r1, const uint8_t *pmk_r1_name, bool crypto_derive_pmkid(const uint8_t *pmk, const uint8_t *addr1, const uint8_t *addr2, uint8_t *out_pmkid, bool use_sha256); + +struct l_ecc_point *crypto_derive_sae_pt_ecc(unsigned int group, + const char *ssid, + const char *password, + const char *identifier);