sha512-kdf.c revision 341618
11556Srgrimes/*
21556Srgrimes * HMAC-SHA512 KDF (RFC 5295) and HKDF-Expand(SHA512) (RFC 5869)
31556Srgrimes * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
41556Srgrimes *
51556Srgrimes * This software may be distributed under the terms of the BSD license.
61556Srgrimes * See README for more details.
71556Srgrimes */
81556Srgrimes
91556Srgrimes#include "includes.h"
101556Srgrimes
111556Srgrimes#include "common.h"
121556Srgrimes#include "sha512.h"
131556Srgrimes
141556Srgrimes
151556Srgrimes/**
161556Srgrimes * hmac_sha512_kdf - HMAC-SHA512 based KDF (RFC 5295)
171556Srgrimes * @secret: Key for KDF
181556Srgrimes * @secret_len: Length of the key in bytes
191556Srgrimes * @label: A unique label for each purpose of the KDF or %NULL to select
201556Srgrimes *	RFC 5869 HKDF-Expand() with arbitrary seed (= info)
211556Srgrimes * @seed: Seed value to bind into the key
221556Srgrimes * @seed_len: Length of the seed
231556Srgrimes * @out: Buffer for the generated pseudo-random key
241556Srgrimes * @outlen: Number of bytes of key to generate
251556Srgrimes * Returns: 0 on success, -1 on failure.
261556Srgrimes *
271556Srgrimes * This function is used to derive new, cryptographically separate keys from a
281556Srgrimes * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
291556Srgrimes * with label = NULL and seed = info, this matches HKDF-Expand() defined in
301556Srgrimes * RFC 5869, Chapter 2.3.
311556Srgrimes */
321556Srgrimesint hmac_sha512_kdf(const u8 *secret, size_t secret_len,
331556Srgrimes		    const char *label, const u8 *seed, size_t seed_len,
341556Srgrimes		    u8 *out, size_t outlen)
351556Srgrimes{
361556Srgrimes	u8 T[SHA512_MAC_LEN];
371556Srgrimes	u8 iter = 1;
3836150Scharnier	const unsigned char *addr[4];
3936150Scharnier	size_t len[4];
4036150Scharnier	size_t pos, clen;
4136150Scharnier
4245916Scracauer	addr[0] = T;
431556Srgrimes	len[0] = SHA512_MAC_LEN;
441556Srgrimes	if (label) {
4517987Speter		addr[1] = (const unsigned char *) label;
4617987Speter		len[1] = os_strlen(label) + 1;
4717987Speter	} else {
4817987Speter		addr[1] = (const u8 *) "";
4917987Speter		len[1] = 0;
5017987Speter	}
5117987Speter	addr[2] = seed;
5217987Speter	len[2] = seed_len;
5319281Sache	addr[3] = &iter;
5438887Stegge	len[3] = 1;
5517987Speter
561556Srgrimes	if (hmac_sha512_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
571556Srgrimes		return -1;
581556Srgrimes
591556Srgrimes	pos = 0;
601556Srgrimes	for (;;) {
611556Srgrimes		clen = outlen - pos;
621556Srgrimes		if (clen > SHA512_MAC_LEN)
631556Srgrimes			clen = SHA512_MAC_LEN;
641556Srgrimes		os_memcpy(out + pos, T, clen);
651556Srgrimes		pos += clen;
661556Srgrimes
671556Srgrimes		if (pos == outlen)
681556Srgrimes			break;
691556Srgrimes
701556Srgrimes		if (iter == 255) {
711556Srgrimes			os_memset(out, 0, outlen);
721556Srgrimes			os_memset(T, 0, SHA512_MAC_LEN);
731556Srgrimes			return -1;
741556Srgrimes		}
751556Srgrimes		iter++;
7617987Speter
7717987Speter		if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0)
781556Srgrimes		{
791556Srgrimes			os_memset(out, 0, outlen);
801556Srgrimes			os_memset(T, 0, SHA512_MAC_LEN);
811556Srgrimes			return -1;
821556Srgrimes		}
831556Srgrimes	}
841556Srgrimes
851556Srgrimes	os_memset(T, 0, SHA512_MAC_LEN);
861556Srgrimes	return 0;
871556Srgrimes}
881556Srgrimes