[PATCH 1/2] crypto: Add portable PBKDF2-SHA256/SHA384 implementations

Chaitanya Tata chaitanya.mgit at gmail.com
Thu Sep 10 12:43:06 PDT 2026


pbkdf2_sha256() and pbkdf2_sha384() are declared in sha256.h/sha384.h
and used unconditionally by the new NAN pairing PMK derivation code
(src/nan/nan_crypto.c), but they were only ever implemented in
crypto_openssl.c. Every other crypto backend (internal, linux,
gnutls, nettle, wolfssl) is left with a declaration but no
definition, so any build with CONFIG_NAN and CONFIG_TLS != openssl
fails to link.

Add crypto-backend-agnostic implementations mirroring the existing
sha1-pbkdf2.c, built on top of the already-portable hmac_sha256()/
hmac_sha384() primitives, and wire them into the NEED_NAN section of
wpa_supplicant/Makefile and Android.mk for the same non-OpenSSL
backends that need sha1-pbkdf2.o.

Signed-off-by: Chaitanya Tata <Chaitanya.Tata at nordicsemi.no>
---
 src/crypto/sha256-pbkdf2.c | 94 ++++++++++++++++++++++++++++++++++++++
 src/crypto/sha384-pbkdf2.c | 94 ++++++++++++++++++++++++++++++++++++++
 wpa_supplicant/Android.mk  |  4 ++
 wpa_supplicant/Makefile    |  4 ++
 4 files changed, 196 insertions(+)
 create mode 100644 src/crypto/sha256-pbkdf2.c
 create mode 100644 src/crypto/sha384-pbkdf2.c

diff --git a/src/crypto/sha256-pbkdf2.c b/src/crypto/sha256-pbkdf2.c
new file mode 100644
index 000000000..2c3ab76f3
--- /dev/null
+++ b/src/crypto/sha256-pbkdf2.c
@@ -0,0 +1,94 @@
+/*
+ * SHA256-based key derivation function (PBKDF2)
+ * Copyright (c) 2003-2025, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+static int pbkdf2_sha256_f(const char *passphrase, const u8 *salt,
+			   size_t salt_len, int iterations, unsigned int count,
+			   u8 *digest)
+{
+	unsigned char tmp[SHA256_MAC_LEN], tmp2[SHA256_MAC_LEN];
+	int i, j;
+	unsigned char count_buf[4];
+	const u8 *addr[2];
+	size_t len[2];
+	size_t passphrase_len = os_strlen(passphrase);
+
+	addr[0] = salt;
+	len[0] = salt_len;
+	addr[1] = count_buf;
+	len[1] = 4;
+
+	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
+	 * U1 = PRF(P, S || i)
+	 * U2 = PRF(P, U1)
+	 * Uc = PRF(P, Uc-1)
+	 */
+
+	count_buf[0] = (count >> 24) & 0xff;
+	count_buf[1] = (count >> 16) & 0xff;
+	count_buf[2] = (count >> 8) & 0xff;
+	count_buf[3] = count & 0xff;
+	if (hmac_sha256_vector((u8 *) passphrase, passphrase_len, 2, addr, len,
+			       tmp))
+		return -1;
+	os_memcpy(digest, tmp, SHA256_MAC_LEN);
+
+	for (i = 1; i < iterations; i++) {
+		if (hmac_sha256((u8 *) passphrase, passphrase_len, tmp,
+				SHA256_MAC_LEN, tmp2))
+			return -1;
+		os_memcpy(tmp, tmp2, SHA256_MAC_LEN);
+		for (j = 0; j < SHA256_MAC_LEN; j++)
+			digest[j] ^= tmp2[j];
+	}
+	forced_memzero(tmp, SHA256_MAC_LEN);
+	forced_memzero(tmp2, SHA256_MAC_LEN);
+
+	return 0;
+}
+
+
+/**
+ * pbkdf2_sha256 - SHA256-based key derivation function (PBKDF2)
+ * @passphrase: ASCII passphrase
+ * @salt: Salt
+ * @salt_len: Salt length in bytes
+ * @iterations: Number of iterations to run
+ * @buf: Buffer for the generated key
+ * @buflen: Length of the buffer in bytes
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is described in RFC 2898. The main construction is from
+ * PKCS#5 v2.0.
+ */
+int pbkdf2_sha256(const char *passphrase, const u8 *salt, size_t salt_len,
+		  int iterations, u8 *buf, size_t buflen)
+{
+	unsigned int count = 0;
+	unsigned char *pos = buf;
+	size_t left = buflen, plen;
+	unsigned char digest[SHA256_MAC_LEN];
+
+	while (left > 0) {
+		count++;
+		if (pbkdf2_sha256_f(passphrase, salt, salt_len, iterations,
+				    count, digest))
+			return -1;
+		plen = left > SHA256_MAC_LEN ? SHA256_MAC_LEN : left;
+		os_memcpy(pos, digest, plen);
+		pos += plen;
+		left -= plen;
+	}
+	forced_memzero(digest, SHA256_MAC_LEN);
+
+	return 0;
+}
diff --git a/src/crypto/sha384-pbkdf2.c b/src/crypto/sha384-pbkdf2.c
new file mode 100644
index 000000000..b99fcada3
--- /dev/null
+++ b/src/crypto/sha384-pbkdf2.c
@@ -0,0 +1,94 @@
+/*
+ * SHA384-based key derivation function (PBKDF2)
+ * Copyright (c) 2003-2025, Jouni Malinen <j at w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha384.h"
+
+static int pbkdf2_sha384_f(const char *passphrase, const u8 *salt,
+			   size_t salt_len, int iterations, unsigned int count,
+			   u8 *digest)
+{
+	unsigned char tmp[SHA384_MAC_LEN], tmp2[SHA384_MAC_LEN];
+	int i, j;
+	unsigned char count_buf[4];
+	const u8 *addr[2];
+	size_t len[2];
+	size_t passphrase_len = os_strlen(passphrase);
+
+	addr[0] = salt;
+	len[0] = salt_len;
+	addr[1] = count_buf;
+	len[1] = 4;
+
+	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
+	 * U1 = PRF(P, S || i)
+	 * U2 = PRF(P, U1)
+	 * Uc = PRF(P, Uc-1)
+	 */
+
+	count_buf[0] = (count >> 24) & 0xff;
+	count_buf[1] = (count >> 16) & 0xff;
+	count_buf[2] = (count >> 8) & 0xff;
+	count_buf[3] = count & 0xff;
+	if (hmac_sha384_vector((u8 *) passphrase, passphrase_len, 2, addr, len,
+			       tmp))
+		return -1;
+	os_memcpy(digest, tmp, SHA384_MAC_LEN);
+
+	for (i = 1; i < iterations; i++) {
+		if (hmac_sha384((u8 *) passphrase, passphrase_len, tmp,
+				SHA384_MAC_LEN, tmp2))
+			return -1;
+		os_memcpy(tmp, tmp2, SHA384_MAC_LEN);
+		for (j = 0; j < SHA384_MAC_LEN; j++)
+			digest[j] ^= tmp2[j];
+	}
+	forced_memzero(tmp, SHA384_MAC_LEN);
+	forced_memzero(tmp2, SHA384_MAC_LEN);
+
+	return 0;
+}
+
+
+/**
+ * pbkdf2_sha384 - SHA384-based key derivation function (PBKDF2)
+ * @passphrase: ASCII passphrase
+ * @salt: Salt
+ * @salt_len: Salt length in bytes
+ * @iterations: Number of iterations to run
+ * @buf: Buffer for the generated key
+ * @buflen: Length of the buffer in bytes
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is described in RFC 2898. The main construction is from
+ * PKCS#5 v2.0.
+ */
+int pbkdf2_sha384(const char *passphrase, const u8 *salt, size_t salt_len,
+		  int iterations, u8 *buf, size_t buflen)
+{
+	unsigned int count = 0;
+	unsigned char *pos = buf;
+	size_t left = buflen, plen;
+	unsigned char digest[SHA384_MAC_LEN];
+
+	while (left > 0) {
+		count++;
+		if (pbkdf2_sha384_f(passphrase, salt, salt_len, iterations,
+				    count, digest))
+			return -1;
+		plen = left > SHA384_MAC_LEN ? SHA384_MAC_LEN : left;
+		os_memcpy(pos, digest, plen);
+		pos += plen;
+		left -= plen;
+	}
+	forced_memzero(digest, SHA384_MAC_LEN);
+
+	return 0;
+}
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index b530d1053..48cf5dbbb 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -313,6 +313,10 @@ OBJS += src/nan/nan_bootstrap.c
 ifdef CONFIG_PASN
 OBJS += src/nan/nan_pairing.c
 endif
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/sha256-pbkdf2.c
+OBJS += src/crypto/sha384-pbkdf2.c
+endif
 endif
 
 ifdef CONFIG_OWE
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8c8626a98..8c07c3133 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -351,6 +351,10 @@ OBJS += ../src/nan/nan_bootstrap.o
 ifdef CONFIG_PASN
 OBJS += ../src/nan/nan_pairing.o
 endif
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/sha256-pbkdf2.o
+OBJS += ../src/crypto/sha384-pbkdf2.o
+endif
 endif
 
 ifdef CONFIG_PR
-- 
2.43.0




More information about the Hostap mailing list