Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions .github/examples-manifest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,16 @@ profiles:
flags: "--enable-opensslall --enable-opensslextra --enable-static --enable-shared"

crypto:
# union of crypto/*: 3des, aes, aes-modes, camellia, ascon, keywrap, pkcs12
# union of crypto/* and hash/*: 3des, aes, aes-modes, camellia, ascon,
# keywrap, kdf, pkcs12, siphash, blake2
flags: >-
--enable-pwdbased --enable-des3 --enable-camellia --enable-ascon
--enable-experimental --enable-aesgcm-stream --enable-aesccm --enable-aesctr
--enable-aescfb --enable-aesofb --enable-aeseax --enable-aessiv
--enable-aesxts --enable-aeskeywrap --enable-keygen --enable-certgen
--enable-certext --enable-pkcs12 --enable-static --enable-shared
--enable-certext --enable-pkcs12 --enable-blake2 --enable-blake2s
--enable-siphash --enable-hkdf --enable-scrypt
--enable-static --enable-shared
# aes-cts and aes-ecb have no configure flag: without these defines both
# compile to a stub main() that prints "not compiled in" and returns 0.
# WC_RNG_SEED_CB likewise has no --enable of its own (only opensslextra and
Expand All @@ -87,7 +90,7 @@ profiles:
flags: >-
--enable-ecc --enable-ed25519 --enable-ed448 --enable-curve25519
--enable-curve448 --enable-keygen --enable-rsapss --enable-srp --enable-hpke
--enable-aesgcm --enable-static --enable-shared
--enable-aesgcm --enable-eccsi --enable-sakke --enable-static --enable-shared
# WOLFSSL_RSA_KEY_CHECK has no configure option: pk/rsa-kg calls
# wc_CheckRsaKey, which rsa.c only defines under that macro.
cflags: "-DWOLFSSL_PUBLIC_MP -DUSE_CERT_BUFFERS_2048 -DWOLFSSL_ECDSA_DETERMINISTIC_K -DWOLFSSL_RSA_KEY_CHECK"
Expand Down Expand Up @@ -146,7 +149,7 @@ profiles:
# so without it the client dies on "failed to set the requested group".
flags: >-
--enable-mlkem --enable-dilithium --enable-lms --enable-xmss
--enable-extra-pqc-hybrids
--enable-extra-pqc-hybrids --enable-slhdsa=yes,sha2
--enable-experimental --enable-tls13 --enable-static --enable-shared

acert:
Expand Down Expand Up @@ -345,6 +348,11 @@ examples:
# openssl dgst, so these assert the algorithm is right, not just that it ran.
# input.txt is tracked -- if it changes on purpose, recompute these.

- id: hash-blake2
path: hash/blake2
profile: crypto
mode: check

- id: embedded
path: embedded
profile: default
Expand Down Expand Up @@ -405,6 +413,11 @@ examples:
profile: crypto
mode: check

- id: crypto-kdf
path: crypto/kdf
profile: crypto
mode: check

- id: crypto-keywrap
path: crypto/keywrap
profile: crypto
Expand All @@ -415,6 +428,19 @@ examples:
profile: crypto
mode: check

- id: crypto-siphash
path: crypto/siphash
profile: crypto
mode: check

- id: crypto-sm
path: crypto/sm
mode: skip
reason: >-
SM2/SM3/SM4 live in the separate wolfSSL/wolfsm overlay, which must be
installed into the wolfSSL source tree before configure. No cached
profile can express that patch step yet.

- id: signature
path: signature
profile: default
Expand Down Expand Up @@ -590,6 +616,11 @@ examples:
profile: pq
mode: check

- id: pq-slh-dsa
path: pq/slh_dsa
profile: pq
mode: check

- id: pq-stateful-hash-sig
path: pq/stateful_hash_sig
profile: pq
Expand Down Expand Up @@ -742,6 +773,10 @@ examples:
path: pk/hpke
profile: pk
mode: check
- id: pk-mikey-sakke
path: pk/mikey-sakke
profile: pk
mode: check
- id: pk-rsa-kg
path: pk/rsa-kg
profile: pk
Expand Down
26 changes: 26 additions & 0 deletions crypto/kdf/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
CC=gcc
WOLFSSL_INSTALL_DIR=/usr/local
CFLAGS=-Wall -I$(WOLFSSL_INSTALL_DIR)/include
LIBS=-L$(WOLFSSL_INSTALL_DIR)/lib -lwolfssl -lm

all: hkdf pbkdf2 scrypt-kdf

hkdf: hkdf.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

pbkdf2: pbkdf2.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

scrypt-kdf: scrypt-kdf.o
$(CC) -o $@ $^ $(CFLAGS) $(LIBS)

.PHONY: clean all check

clean:
rm -f *.o hkdf pbkdf2 scrypt-kdf

check: all
out=$$(./hkdf) && printf '%s' "$$out" | grep -q 'matches RFC 5869 Test Case 1'
out=$$(./pbkdf2) && printf '%s' "$$out" | grep -q 'matches RFC 7914 test vector'
out=$$(./scrypt-kdf) && printf '%s' "$$out" | grep -q 'matches RFC 7914 test vector'
@echo "PASS: crypto-kdf checks"
34 changes: 34 additions & 0 deletions crypto/kdf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# wolfSSL KDF Examples

Demonstrates the main wolfCrypt key derivation functions, each verified
against its RFC known-answer test vector.

* `hkdf.c` - HKDF (RFC 5869): extract-then-expand derivation from existing
keying material, shown both as separate `wc_HKDF_Extract()` /
`wc_HKDF_Expand()` steps and as the one-shot `wc_HKDF()`.
* `pbkdf2.c` - PBKDF2 (RFC 2898) via `wc_PBKDF2()`: deriving keys from
passwords with a salt and an iteration work factor.
* `scrypt-kdf.c` - scrypt (RFC 7914) via `wc_scrypt()`: memory-hard
password-based derivation for stronger resistance to GPU/ASIC attacks.

Use HKDF when the input is already a high-entropy secret (e.g. a DH shared
secret); use PBKDF2 or scrypt when the input is a password.

## Building wolfSSL

```
./configure --enable-hkdf --enable-scrypt
make
sudo make install
```

PBKDF2 is enabled by default (disabled only by `NO_PWDBASED`).

## Building and running the examples

```
make
./hkdf
./pbkdf2
./scrypt-kdf
```
130 changes: 130 additions & 0 deletions crypto/kdf/hkdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/* hkdf.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL. (formerly known as CyaSSL)
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/

/* Example of HKDF (RFC 5869): extract-then-expand key derivation, run against
* RFC 5869 Test Case 1. */

#include <stdio.h>
#include <string.h>

#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/hmac.h>

#ifdef HAVE_HKDF

/* RFC 5869 Test Case 1 (SHA-256). */
static const byte ikm[22] = {
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
};
static const byte salt[13] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c
};
static const byte info[10] = {
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9
};
static const byte expected_prk[32] = {
0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5
};
static const byte expected_okm[42] = {
0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a,
0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a,
0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c,
0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf,
0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18,
0x58, 0x65
};

static void print_hex(const char* label, const byte* data, word32 len)
{
word32 i;

printf("%s: ", label);
for (i = 0; i < len; i++)
printf("%02x", data[i]);
printf("\n");
}

int main(void)
{
int ret;
byte prk[32];
byte okm[42];

/* Extract: concentrate the input keying material into a fixed-size PRK. */
ret = wc_HKDF_Extract(WC_SHA256, salt, sizeof(salt), ikm, sizeof(ikm),
prk);
if (ret != 0) {
printf("wc_HKDF_Extract failed %d\n", ret);
return 1;
}
print_hex("PRK", prk, sizeof(prk));
if (memcmp(prk, expected_prk, sizeof(prk)) != 0) {
printf("PRK does not match RFC 5869 test vector!\n");
return 1;
}

/* Expand: stretch the PRK into the output keying material. */
ret = wc_HKDF_Expand(WC_SHA256, prk, sizeof(prk), info, sizeof(info),
okm, sizeof(okm));
if (ret != 0) {
printf("wc_HKDF_Expand failed %d\n", ret);
return 1;
}
print_hex("OKM", okm, sizeof(okm));
if (memcmp(okm, expected_okm, sizeof(okm)) != 0) {
printf("OKM does not match RFC 5869 test vector!\n");
return 1;
}

/* wc_HKDF does both steps in one call. */
memset(okm, 0, sizeof(okm));
ret = wc_HKDF(WC_SHA256, ikm, sizeof(ikm), salt, sizeof(salt), info,
sizeof(info), okm, sizeof(okm));
if (ret != 0) {
printf("wc_HKDF failed %d\n", ret);
return 1;
}
if (memcmp(okm, expected_okm, sizeof(okm)) != 0) {
printf("One-shot OKM does not match!\n");
return 1;
}
printf("HKDF output matches RFC 5869 Test Case 1\n");

return 0;
}

#else

int main(void)
{
printf("Please build wolfSSL with ./configure --enable-hkdf\n");
return 0;
}

#endif /* HAVE_HKDF */
Loading
Loading