Commit 195edb37 authored by Niels Möller's avatar Niels Möller
Browse files

Merge branch 'hkdf-support'

parents 2351995b 94f8644f
2017-09-06 Niels Möller <nisse@lysator.liu.se>
* hkdf.c (hkdf_expand): Eliminate a (signed) ssize_t variable, use
break rather than return at loop termination.
2017-09-06 Niels Möller <nisse@lysator.liu.se>
HKDF implementation, contributed by Nikos Mavrogiannopoulos.
* hkdf.c (hkdf_extract, hkdf_expand): New file, new functions.
* hkdf.h: New file.
* Makefile.in (nettle_SOURCES): Add hkdf.c.
(HEADERS): Add hkdf.h.
* testsuite/hkdf-test.c: Tests for hkdf-sha256 and hkdf-sha1.
* testsuite/Makefile.in (TS_NETTLE_SOURCES): Added hkdf-test.c.
* nettle.texinfo (Key derivation functions): Document HKDF.
2017-09-04 Andreas Schneider <asn@samba.org>
* fat-arm.c: Add missing define for _GNU_SOURCE.
......
......@@ -106,7 +106,7 @@ nettle_SOURCES = aes-decrypt-internal.c aes-decrypt.c \
gosthash94.c gosthash94-meta.c \
hmac.c hmac-md5.c hmac-ripemd160.c hmac-sha1.c \
hmac-sha224.c hmac-sha256.c hmac-sha384.c hmac-sha512.c \
knuth-lfib.c \
knuth-lfib.c hkdf.c \
md2.c md2-meta.c md4.c md4-meta.c \
md5.c md5-compress.c md5-compat.c md5-meta.c \
memeql-sec.c memxor.c memxor3.c \
......@@ -192,7 +192,7 @@ HEADERS = aes.h arcfour.h arctwo.h asn1.h blowfish.h \
curve25519.h des.h des-compat.h dsa.h dsa-compat.h eax.h \
ecc-curve.h ecc.h ecdsa.h eddsa.h \
gcm.h gosthash94.h hmac.h \
knuth-lfib.h \
knuth-lfib.h hkdf.h \
macros.h \
md2.h md4.h \
md5.h md5-compat.h \
......
/*
* Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GnuTLS.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
/* Functions for the HKDF handling.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <assert.h>
/* Needed for alloca on freebsd */
#include <stdlib.h>
#include <string.h>
#include "hmac.h"
#include "memxor.h"
#include "nettle-internal.h"
#include "hkdf.h"
/* hkdf_extract: Outputs a PRK of digest_size
*/
void
hkdf_extract(void *mac_ctx,
nettle_hash_update_func *update,
nettle_hash_digest_func *digest,
size_t digest_size,
size_t secret_size, const uint8_t *secret,
uint8_t *dst)
{
update(mac_ctx, secret_size, secret);
digest(mac_ctx, digest_size, dst);
}
/* hkdf_expand: Outputs an arbitrary key of size specified by length
*/
void
hkdf_expand(void *mac_ctx,
nettle_hash_update_func *update,
nettle_hash_digest_func *digest,
size_t digest_size,
size_t info_size, const uint8_t *info,
size_t length, uint8_t *dst)
{
uint8_t i = 1;
if (!length)
return;
for (;; dst += digest_size, length -= digest_size, i++)
{
update(mac_ctx, info_size, info);
update(mac_ctx, 1, &i);
if (length <= digest_size)
break;
digest(mac_ctx, digest_size, dst);
update(mac_ctx, digest_size, dst);
}
digest(mac_ctx, length, dst);
}
/* hkdf.h
TLS PRF code (RFC-5246, RFC-2246).
Copyright (C) 2017 Red Hat, Inc.
This file is part of GNU Nettle.
GNU Nettle is free software: you can redistribute it and/or
modify it under the terms of either:
* the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your
option) any later version.
or
* 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.
or both in parallel, as here.
GNU Nettle 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 copies of the GNU General Public License and
the GNU Lesser General Public License along with this program. If
not, see http://www.gnu.org/licenses/.
*/
#ifndef NETTLE_HKDF_H_INCLUDED
#define NETTLE_HKDF_H_INCLUDED
#include "nettle-meta.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Namespace mangling */
#define hkdf_extract nettle_hkdf_extract
#define hkdf_expand nettle_hkdf_expand
void
hkdf_extract(void *mac_ctx,
nettle_hash_update_func *update,
nettle_hash_digest_func *digest,
size_t digest_size,
size_t secret_size, const uint8_t *secret,
uint8_t *dst);
void
hkdf_expand(void *mac_ctx,
nettle_hash_update_func *update,
nettle_hash_digest_func *digest,
size_t digest_size,
size_t info_size, const uint8_t *info,
size_t length, uint8_t *dst);
#ifdef __cplusplus
}
#endif
#endif /* NETTLE_HKDF_H_INCLUDED */
......@@ -3366,12 +3366,7 @@ processing a new message.
@node Key derivation functions, Public-key algorithms, Keyed hash functions, Reference
@comment node-name, next, previous, up
@section Key derivation Functions
@cindex Key Derivation Function
@cindex Password Based Key Derivation Function
@cindex PKCS #5
@cindex KDF
@cindex PBKDF
A @dfn{key derivation function} (@acronym{KDF}) is a function that from
a given symmetric key derives other symmetric keys. A sub-class of KDFs
......@@ -3380,7 +3375,51 @@ which take as input a password or passphrase, and its purpose is
typically to strengthen it and protect against certain pre-computation
attacks by using salting and expensive computation.
@subsection HKDF: HMAC-based Extract-and-Expand
@cindex HKDF
HKDF is a key derivation function used as a building block of
higher-level protocols like TLS 1.3. It is a derivation function
based on HMAC described in @cite{RFC 5869},
and is split into two logical modules, called 'extract' and 'expand'.
The extract module takes an initial secret and a random
salt to "extract" a fixed-length pseudorandom key (PRK). The second stage
takes as input the previous PRK and some informational data (e.g.,
text) and expands them into multiple keys.
Nettle's @acronym{HKDF} functions are defined in
@file{<nettle/hkdf.h>}. There are two abstract functions for the extract
and expand operations that operate on any HMAC implemented via the @code{nettle_hash_update_func},
and @code{nettle_hash_digest_func} interfaces.
@deftypefun void hkdf_extract (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size,size_t secret_size, const uint8_t *secret, uint8_t *dst)
Extract a Pseudorandom Key (PRK) from a secret and a salt according
to HKDF. The HMAC must have been initialized, with its key being the
salt for the Extract operation. This function will call the
@var{update} and @var{digest} functions passing the @var{mac_ctx}
context parameter as an argument in order to compute digest of size
@var{digest_size}. Inputs are the secret @var{secret} of length
@var{secret_length}. The output length is fixed to @var{digest_size} octets,
thus the output buffer @var{dst} must have room for at least @var{digest_size} octets.
@end deftypefun
@deftypefun void hkdf_expand (void *mac_ctx, nettle_hash_update_func *update, nettle_hash_digest_func *digest, size_t digest_size, size_t info_size, const uint8_t *info, size_t length, uint8_t *dst)
Expand a Pseudorandom Key (PRK) to an arbitrary size according to HKDF.
The HMAC must have been initialized, with its key being the
PRK from the Extract operation. This function will call the
@var{update} and @var{digest} functions passing the @var{mac_ctx}
context parameter as an argument in order to compute digest of size
@var{digest_size}. Inputs are the info @var{info} of length
@var{info_length}, and the desired derived output length @var{length}.
The output buffer is @var{dst} which must have room for at least @var{length} octets.
@end deftypefun
@subsection @acronym{PBKDF2}
@cindex Password Based Key Derivation Function
@cindex PKCS #5
@cindex KDF
@cindex PBKDF
The most well known PBKDF is the @code{PKCS #5 PBKDF2} described in
@cite{RFC 2898} which uses a pseudo-random function such as
@acronym{HMAC-SHA1}.
......
......@@ -58,6 +58,9 @@ gosthash94-test$(EXEEXT): gosthash94-test.$(OBJEXT)
ripemd160-test$(EXEEXT): ripemd160-test.$(OBJEXT)
$(LINK) ripemd160-test.$(OBJEXT) $(TEST_OBJS) -o ripemd160-test$(EXEEXT)
hkdf-test$(EXEEXT): hkdf-test.$(OBJEXT)
$(LINK) hkdf-test.$(OBJEXT) $(TEST_OBJS) -o hkdf-test$(EXEEXT)
salsa20-test$(EXEEXT): salsa20-test.$(OBJEXT)
$(LINK) salsa20-test.$(OBJEXT) $(TEST_OBJS) -o salsa20-test$(EXEEXT)
......
......@@ -17,7 +17,7 @@ TS_NETTLE_SOURCES = aes-test.c arcfour-test.c arctwo-test.c \
des-test.c des3-test.c des-compat-test.c \
md2-test.c md4-test.c md5-test.c md5-compat-test.c \
memeql-test.c memxor-test.c gosthash94-test.c \
ripemd160-test.c \
ripemd160-test.c hkdf-test.c \
salsa20-test.c \
sha1-test.c sha224-test.c sha256-test.c \
sha384-test.c sha512-test.c sha512-224-test.c sha512-256-test.c \
......
#include "testutils.h"
#include "hkdf.h"
#include "hmac.h"
static void
test_hkdf_sha256(const struct tstring *ikm,
const struct tstring *salt,
const struct tstring *info,
const struct tstring *extract_output,
const struct tstring *expand_output)
{
struct hmac_sha256_ctx ctx;
uint8_t prk[SHA256_DIGEST_SIZE];
uint8_t *buffer = xalloc(expand_output->length);
hmac_sha256_set_key(&ctx, salt->length, salt->data);
hkdf_extract(&ctx,
(nettle_hash_update_func*) hmac_sha256_update,
(nettle_hash_digest_func*) hmac_sha256_digest,
SHA256_DIGEST_SIZE,
ikm->length, ikm->data, prk);
if (MEMEQ(SHA256_DIGEST_SIZE, prk, extract_output->data) == 0)
{
fprintf(stdout, "\nGot:\n");
print_hex(SHA256_DIGEST_SIZE, prk);
fprintf(stdout, "\nExpected:\n");
print_hex(extract_output->length, extract_output->data);
abort();
}
hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, prk);
hkdf_expand(&ctx,
(nettle_hash_update_func*) hmac_sha256_update,
(nettle_hash_digest_func*) hmac_sha256_digest,
SHA256_DIGEST_SIZE,
info->length, info->data,
expand_output->length, buffer);
if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0)
{
fprintf(stdout, "\nGot:\n");
print_hex(expand_output->length, buffer);
fprintf(stdout, "\nExpected:\n");
print_hex(expand_output->length, expand_output->data);
abort();
}
free(buffer);
}
static void
test_hkdf_sha1(const struct tstring *ikm,
const struct tstring *salt,
const struct tstring *info,
const struct tstring *extract_output,
const struct tstring *expand_output)
{
struct hmac_sha1_ctx ctx;
uint8_t prk[SHA1_DIGEST_SIZE];
uint8_t *buffer = xalloc(expand_output->length);
hmac_sha1_set_key(&ctx, salt->length, salt->data);
hkdf_extract(&ctx,
(nettle_hash_update_func*) hmac_sha1_update,
(nettle_hash_digest_func*) hmac_sha1_digest,
SHA1_DIGEST_SIZE,
ikm->length, ikm->data,
prk);
if (MEMEQ(SHA1_DIGEST_SIZE, prk, extract_output->data) == 0)
{
fprintf(stdout, "\nGot:\n");
print_hex(SHA1_DIGEST_SIZE, prk);
fprintf(stdout, "\nExpected:\n");
print_hex(extract_output->length, extract_output->data);
abort();
}
hmac_sha1_set_key(&ctx, SHA1_DIGEST_SIZE, prk);
hkdf_expand(&ctx,
(nettle_hash_update_func*) hmac_sha1_update,
(nettle_hash_digest_func*) hmac_sha1_digest,
SHA1_DIGEST_SIZE,
info->length, info->data,
expand_output->length, buffer);
if (MEMEQ(expand_output->length, expand_output->data, buffer) == 0)
{
fprintf(stdout, "\nGot:\n");
print_hex(expand_output->length, buffer);
fprintf(stdout, "\nExpected:\n");
print_hex(expand_output->length, expand_output->data);
abort();
}
free(buffer);
}
void
test_main(void)
{
/* HKDF test vectors from RFC5869 */
test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
SHEX("000102030405060708090a0b0c"),
SHEX("f0f1f2f3f4f5f6f7f8f9"),
SHEX("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"),
SHEX("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865"));
test_hkdf_sha256(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"),
SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"),
SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
SHEX("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"),
SHEX("b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87"));
test_hkdf_sha256(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
SDATA(""),
SDATA(""),
SHEX("19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04"),
SHEX("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8"));
test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b"),
SHEX("000102030405060708090a0b0c"),
SHEX("f0f1f2f3f4f5f6f7f8f9"),
SHEX("9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243"),
SHEX("085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896"));
test_hkdf_sha1(SHEX("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"),
SHEX("606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf"),
SHEX("b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
SHEX("8adae09a2a307059478d309b26c4115a224cfaf6"),
SHEX("0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4"));
test_hkdf_sha1(SHEX("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"),
SDATA(""),
SDATA(""),
SHEX("da8c8a73c7fa77288ec6f5e7c297786aa0d32d01"),
SHEX("0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918"));
test_hkdf_sha1(SHEX("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"),
SHEX(""),
SHEX(""),
SHEX("2adccada18779e7c2077ad2eb19d3f3e731385dd"),
SHEX("2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48"));
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment