fix(wpa_supplicant): Add optimizations in fastpsk

This commit is contained in:
Kapil Gupta
2026-04-25 12:45:31 +05:30
parent fb42f5353a
commit db025d7015
3 changed files with 114 additions and 44 deletions
+12 -6
View File
@@ -118,8 +118,12 @@ if(CONFIG_ESP_WIFI_MBEDTLS_CRYPTO)
"esp_supplicant/src/crypto/crypto_mbedtls-bignum.c"
"esp_supplicant/src/crypto/crypto_mbedtls-rsa.c"
"esp_supplicant/src/crypto/crypto_mbedtls-ec.c")
if(NOT CONFIG_IDF_TARGET_ESP32)
list(APPEND crypto_src "esp_supplicant/src/crypto/fastpsk.c")
if(CONFIG_MBEDTLS_HARDWARE_SHA)
if(NOT CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG)
list(APPEND crypto_src "esp_supplicant/src/crypto/fastpsk.c")
else()
list(APPEND crypto_src "esp_supplicant/src/crypto/fastpbkdf2.c")
endif()
endif()
# Add internal RC4 as RC4 has been removed from mbedtls
set(crypto_src ${crypto_src} "src/crypto/rc4.c")
@@ -130,8 +134,6 @@ if(CONFIG_ESP_WIFI_MBEDTLS_CRYPTO)
set(crypto_src ${crypto_src} "src/crypto/sha1-pbkdf2.c"
${crypto_src} "src/crypto/sha1.c"
${crypto_src} "src/crypto/sha1-internal.c")
else()
set(crypto_src ${crypto_src} "esp_supplicant/src/crypto/fastpbkdf2.c")
endif()
if(NOT CONFIG_MBEDTLS_SHA1_C AND CONFIG_MBEDTLS_HARDWARE_SHA)
set(crypto_src ${crypto_src} "src/crypto/sha1.c")
@@ -272,8 +274,12 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
CONFIG_NO_RADIUS
)
if(CONFIG_MBEDTLS_SHA1_C OR CONFIG_MBEDTLS_HARDWARE_SHA)
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_FAST_PBKDF2)
if(CONFIG_MBEDTLS_HARDWARE_SHA)
if(NOT CONFIG_SOC_SHA_SUPPORT_PARALLEL_ENG)
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_FAST_PSK)
else()
target_compile_definitions(${COMPONENT_LIB} PRIVATE CONFIG_FAST_PBKDF2)
endif()
endif()
if(CONFIG_ESP_WIFI_ENABLE_WPA3_SAE)
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -36,9 +36,11 @@
#include "mbedtls/esp_config.h"
#include "mbedtls/sha1.h"
#ifdef CONFIG_FAST_PSK
#include "fastpsk.h"
#endif
#ifdef CONFIG_FAST_PBKDF2
#include "fastpbkdf2.h"
#include "fastpsk.h"
#endif
static int digest_vector(mbedtls_md_type_t md_type, size_t num_elem,
@@ -777,23 +779,19 @@ cleanup:
int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
#ifdef CONFIG_FAST_PBKDF2
/* For ESP32: Using pbkdf2_hmac_sha1() because esp_fast_psk() utilizes hardware,
* but for ESP32, the SHA1 hardware implementation is slower than the software implementation.
*/
#if defined(CONFIG_IDF_TARGET_ESP32) || !defined(CONFIG_SOC_SHA_SUPPORTED)
fastpbkdf2_hmac_sha1((const u8 *) passphrase, os_strlen(passphrase),
ssid, ssid_len, iterations, buf, buflen);
return 0;
#else
return esp_fast_psk(passphrase, os_strlen(passphrase), ssid, ssid_len, iterations, buf, buflen);
#endif
#else
int ret = mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, (const u8 *) passphrase,
os_strlen(passphrase), ssid,
ssid_len, iterations, buflen, buf);
return ret == 0 ? 0 : -1;
if (ssid_len <= 32 && os_strlen(passphrase) <= 63 &&
iterations == 4096 && buflen == 32) {
#if defined(CONFIG_FAST_PSK)
return esp_fast_psk(passphrase, os_strlen(passphrase), ssid, ssid_len, iterations, buf, buflen);
#elif defined(CONFIG_FAST_PBKDF2)
fastpbkdf2_hmac_sha1((const u8 *) passphrase, os_strlen(passphrase),
ssid, ssid_len, iterations, buf, buflen);
return 0;
#endif
}
return mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA1, (const u8 *) passphrase,
os_strlen(passphrase), ssid,
ssid_len, iterations, buflen, buf) == 0 ? 0 : -1;
}
#endif /* defined(CONFIG_MBEDTLS_SHA1_C) || defined(CONFIG_MBEDTLS_HARDWARE_SHA) */
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -46,8 +46,12 @@
* - Subsequent `U` values are derived using SHA1 on the previous `U` value.
* 4. All intermediate values are XORed together to produce the final segment of the key.
* 5. The `esp_fast_psk` function combines two invocations of `fast_psk_f` to produce the complete 32-byte key.
* - The first invocation computes the first 16 bytes.
* - The second invocation computes the second 16 bytes.
* - The first invocation computes the first 20 bytes (SHA1_OUTPUT_SZ).
* - The second invocation computes the remaining 12 bytes.
*
* On non-parallel-engine targets (all except ESP32), the ipad/opad SHA states are
* computed once and restored via esp_sha_write_digest_state() each iteration,
* halving the SHA block operations per iteration from 4 to 2.
*
* - The code uses the ESP SHA1 hardware accelerator for faster computation.
*/
@@ -140,6 +144,7 @@ static void pad_blocks(union hmac_block *ctx, size_t len)
PUT_UINT32_BE(bits, bytes, FAST_PSK_SHA1_BLOCKS_BUF_BYTES - 4);
}
#if SOC_SHA_SUPPORT_PARALLEL_ENG
/*
* Performs SHA1 hash operation on two consecutive blocks.
* Input: blocks array (two blocks of 64 bytes each), output (20-byte digest).
@@ -158,7 +163,7 @@ static inline void write32_be(uint32_t n, uint8_t out[4])
}
#endif /* CONFIG_IDF_TARGET_ESP32 */
void sha1_op(uint32_t blocks[FAST_PSK_SHA1_BLOCKS_BUF_WORDS], uint32_t output[SHA1_OUTPUT_SZ_WORDS])
static void sha1_op(uint32_t blocks[FAST_PSK_SHA1_BLOCKS_BUF_WORDS], uint32_t output[SHA1_OUTPUT_SZ_WORDS])
{
esp_sha_set_mode(SHA1);
/* First block */
@@ -174,6 +179,7 @@ void sha1_op(uint32_t blocks[FAST_PSK_SHA1_BLOCKS_BUF_WORDS], uint32_t output[SH
}
#endif /* CONFIG_IDF_TARGET_ESP32 */
}
#endif /* SOC_SHA_SUPPORT_PARALLEL_ENG */
/*
* Implements the PBKDF2-HMAC-SHA1 function for WPA key derivation.
@@ -184,11 +190,16 @@ void sha1_op(uint32_t blocks[FAST_PSK_SHA1_BLOCKS_BUF_WORDS], uint32_t output[SH
* - count: The iteration counter.
* - digest: Output buffer for the resulting digest (20 bytes).
*/
void fast_psk_f(const char *password, size_t password_len, const uint8_t *ssid, size_t ssid_len, uint32_t count, uint8_t digest[SHA1_OUTPUT_SZ])
static void fast_psk_f(const char *password, size_t password_len, const uint8_t *ssid, size_t ssid_len, uint32_t count, uint8_t digest[SHA1_OUTPUT_SZ])
{
struct fast_psk_context ctx_, *ctx = &ctx_;
size_t i;
#if !SOC_SHA_SUPPORT_PARALLEL_ENG
uint32_t ipad_state[SHA1_OUTPUT_SZ_WORDS];
uint32_t opad_state[SHA1_OUTPUT_SZ_WORDS];
#endif
/* Clear the context */
memset(ctx, 0, sizeof(*ctx));
@@ -212,19 +223,23 @@ void fast_psk_f(const char *password, size_t password_len, const uint8_t *ssid,
sha1_setup();
uint32_t *pi, *po;
pi = ctx->inner.whole_words;
po = ctx->outer.whole_words;
// T1 = SHA1(K ^ ipad, S || i)
sha1_op(pi, ctx->outer.block[1].words);
// U1 = SHA1(K ^ opad, T1)
pad_blocks(&ctx->outer, SHA1_BLOCK_SZ + SHA1_OUTPUT_SZ);
uint32_t *inner_blk1 = ctx->inner.block[1].words;
uint32_t *outer_blk1 = ctx->outer.block[1].words;
uint32_t *sum = ctx->sum;
#if SOC_SHA_SUPPORT_PARALLEL_ENG
/*
* Parallel engine (ESP32): no state save/restore available.
* Each sha1_op processes 2 blocks (ipad/opad + data) = 4 block ops per iteration.
*/
uint32_t *pi = ctx->inner.whole_words;
uint32_t *po = ctx->outer.whole_words;
// T1 = SHA1(K ^ ipad, S || i)
sha1_op(pi, outer_blk1);
// U1 = SHA1(K ^ opad, T1)
pad_blocks(&ctx->outer, SHA1_BLOCK_SZ + SHA1_OUTPUT_SZ);
sha1_op(po, inner_blk1);
/* Copy result to the sum */
memcpy(sum, inner_blk1, SHA1_OUTPUT_SZ);
@@ -244,13 +259,61 @@ void fast_psk_f(const char *password, size_t password_len, const uint8_t *ssid,
sum[j] ^= inner_blk1[j];
}
}
#else
/*
* Core engine: save ipad/opad SHA states once, restore each iteration.
* Each iteration processes only 1 data block per HMAC = 2 block ops total,
* half of the parallel engine path.
*/
esp_sha_set_mode(SHA1);
/* Process ipad/opad blocks once, save intermediate SHA1 states */
esp_sha_block(SHA1, ctx->inner.block[0].words, true);
esp_sha_read_digest_state(SHA1, ipad_state);
esp_sha_block(SHA1, ctx->outer.block[0].words, true);
esp_sha_read_digest_state(SHA1, opad_state);
// T1 = SHA1(ipad_state, S || i)
esp_sha_write_digest_state(SHA1, ipad_state);
esp_sha_block(SHA1, inner_blk1, false);
esp_sha_read_digest_state(SHA1, outer_blk1);
// U1 = SHA1(opad_state, T1)
pad_blocks(&ctx->outer, SHA1_BLOCK_SZ + SHA1_OUTPUT_SZ);
esp_sha_write_digest_state(SHA1, opad_state);
esp_sha_block(SHA1, outer_blk1, false);
esp_sha_read_digest_state(SHA1, inner_blk1);
memcpy(sum, inner_blk1, SHA1_OUTPUT_SZ);
pad_blocks(&ctx->inner, SHA1_BLOCK_SZ + SHA1_OUTPUT_SZ);
/*
* Iterations 2..4096.
* esp_sha_read_digest_state writes exactly 20 bytes (5 words) for SHA1,
* so the padding at bytes [20..63] in each block stays intact.
*/
for (i = 1; i < 4096; ++i) {
// Tn = SHA1(ipad_state, Un-1)
esp_sha_write_digest_state(SHA1, ipad_state);
esp_sha_block(SHA1, inner_blk1, false);
esp_sha_read_digest_state(SHA1, outer_blk1);
// Un = SHA1(opad_state, Tn)
esp_sha_write_digest_state(SHA1, opad_state);
esp_sha_block(SHA1, outer_blk1, false);
esp_sha_read_digest_state(SHA1, inner_blk1);
for (size_t j = 0; j < SHA1_OUTPUT_SZ_WORDS; ++j) {
sum[j] ^= inner_blk1[j];
}
}
#endif /* SOC_SHA_SUPPORT_PARALLEL_ENG */
sha1_teardown();
/* Copy the final result to the output digest */
memcpy(digest, sum, SHA1_OUTPUT_SZ);
/* Clear sensitive data */
/* Clear context */
memset(ctx, 0, sizeof(*ctx));
}
@@ -260,13 +323,16 @@ int esp_fast_psk(const char *password, size_t password_len, const uint8_t *ssid,
return -1; /* Invalid input parameters */
}
/* Compute the first 16 bytes of the PSK */
/*
* PBKDF2 with dkLen=32 needs two 20-byte F() blocks:
* output[0..19] = F(password, ssid, 4096, 1)
* output[20..31] = F(password, ssid, 4096, 2)[0..11]
*
* Compute block 2 first so its first 12 bytes can be placed at
* output[20..31], then block 1 overwrites output[0..19].
*/
fast_psk_f(password, password_len, ssid, ssid_len, 2, output);
/* Replicate the first 16 bytes to form the second half temporarily */
memcpy(output + SHA1_OUTPUT_SZ, output, 32 - SHA1_OUTPUT_SZ);
/* Compute the second 16 bytes of the PSK */
fast_psk_f(password, password_len, ssid, ssid_len, 1, output);
return 0; /* Success */