Add KDF examples

HKDF (RFC 5869), PBKDF2 (RFC 2898) and scrypt (RFC 7914), each
verified against its RFC known-answer test vector.
pull/610/head
Anthony 2026-07-24 15:18:39 -04:00 committed by Anthony Hu
parent 9f751293e3
commit f09fb7378f
5 changed files with 396 additions and 0 deletions

View File

@ -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"

View File

@ -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
crypto/kdf/hkdf.c 100644
View File

@ -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 */

117
crypto/kdf/pbkdf2.c 100644
View File

@ -0,0 +1,117 @@
/* pbkdf2.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 PBKDF2 (RFC 2898) password-based key derivation, run against the
* PBKDF2-HMAC-SHA256 test vector from RFC 7914 Section 11, then with
* realistic parameters. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
#include <wolfssl/wolfcrypt/random.h>
#ifndef NO_PWDBASED
/* RFC 7914 Section 11: PBKDF2-HMAC-SHA256, P="passwd", S="salt", c=1,
* dkLen=64. */
static const byte expected_dk[64] = {
0x55, 0xac, 0x04, 0x6e, 0x56, 0xe3, 0x08, 0x9f,
0xec, 0x16, 0x91, 0xc2, 0x25, 0x44, 0xb6, 0x05,
0xf9, 0x41, 0x85, 0x21, 0x6d, 0xde, 0x04, 0x65,
0xe6, 0x8b, 0x9d, 0x57, 0xc2, 0x0d, 0xac, 0xbc,
0x49, 0xca, 0x9c, 0xcc, 0xf1, 0x79, 0xb6, 0x45,
0x99, 0x16, 0x64, 0xb3, 0x9d, 0x77, 0xef, 0x31,
0x7c, 0x71, 0xb8, 0x45, 0xb1, 0xe3, 0x0b, 0xd5,
0x09, 0x11, 0x20, 0x41, 0xd3, 0xa1, 0x97, 0x83
};
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 dk[64];
WC_RNG rng;
byte salt[16];
const char* password = "correct horse battery staple";
/* Known-answer check. */
ret = wc_PBKDF2(dk, (const byte*)"passwd", 6, (const byte*)"salt", 4, 1,
(int)sizeof(dk), WC_SHA256);
if (ret != 0) {
printf("wc_PBKDF2 failed %d\n", ret);
return 1;
}
if (memcmp(dk, expected_dk, sizeof(dk)) != 0) {
printf("Derived key does not match RFC 7914 test vector!\n");
return 1;
}
printf("Derived key matches RFC 7914 test vector\n");
/* Realistic use: random per-user salt and a high iteration count. The
* iteration count is the work factor; NIST SP 800-132 requires at least
* 1000, modern guidance is 600000+ for SHA-256. */
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("wc_InitRng failed %d\n", ret);
return 1;
}
ret = wc_RNG_GenerateBlock(&rng, salt, sizeof(salt));
wc_FreeRng(&rng);
if (ret != 0) {
printf("wc_RNG_GenerateBlock failed %d\n", ret);
return 1;
}
ret = wc_PBKDF2(dk, (const byte*)password, (int)strlen(password), salt,
(int)sizeof(salt), 600000, 32, WC_SHA256);
if (ret != 0) {
printf("wc_PBKDF2 failed %d\n", ret);
return 1;
}
print_hex("salt", salt, sizeof(salt));
print_hex("key ", dk, 32);
printf("Derived 32-byte key with 600000 iterations\n");
return 0;
}
#else
int main(void)
{
printf("Please build wolfSSL without NO_PWDBASED (PBKDF2 is on by "
"default)\n");
return 0;
}
#endif /* !NO_PWDBASED */

View File

@ -0,0 +1,89 @@
/* scrypt-kdf.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 scrypt (RFC 7914) memory-hard password-based key derivation,
* run against the test vector from RFC 7914 Section 12. */
#include <stdio.h>
#include <string.h>
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
#ifdef HAVE_SCRYPT
/* RFC 7914 Section 12, vector 2: P="password", S="NaCl", N=1024, r=8, p=16,
* dkLen=64. */
static const byte expected_dk[64] = {
0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00,
0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe,
0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30,
0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62,
0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88,
0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda,
0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d,
0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40
};
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 dk[64];
/* cost is log2(N): 10 -> N=1024. r (block size) scales memory use,
* p (parallelization) scales CPU cost. */
ret = wc_scrypt(dk, (const byte*)"password", 8, (const byte*)"NaCl", 4,
10, 8, 16, (int)sizeof(dk));
if (ret != 0) {
printf("wc_scrypt failed %d\n", ret);
return 1;
}
print_hex("key", dk, sizeof(dk));
if (memcmp(dk, expected_dk, sizeof(dk)) != 0) {
printf("Derived key does not match RFC 7914 test vector!\n");
return 1;
}
printf("Derived key matches RFC 7914 test vector\n");
return 0;
}
#else
int main(void)
{
printf("Please build wolfSSL with ./configure --enable-scrypt\n");
return 0;
}
#endif /* HAVE_SCRYPT */