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
parent
9f751293e3
commit
f09fb7378f
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
```
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
Loading…
Reference in New Issue