[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