1341618Scy/* 2341618Scy * HMAC-SHA512 KDF (RFC 5295) and HKDF-Expand(SHA512) (RFC 5869) 3341618Scy * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi> 4341618Scy * 5341618Scy * This software may be distributed under the terms of the BSD license. 6341618Scy * See README for more details. 7341618Scy */ 8341618Scy 9341618Scy#include "includes.h" 10341618Scy 11341618Scy#include "common.h" 12341618Scy#include "sha512.h" 13341618Scy 14341618Scy 15341618Scy/** 16341618Scy * hmac_sha512_kdf - HMAC-SHA512 based KDF (RFC 5295) 17341618Scy * @secret: Key for KDF 18341618Scy * @secret_len: Length of the key in bytes 19341618Scy * @label: A unique label for each purpose of the KDF or %NULL to select 20341618Scy * RFC 5869 HKDF-Expand() with arbitrary seed (= info) 21341618Scy * @seed: Seed value to bind into the key 22341618Scy * @seed_len: Length of the seed 23341618Scy * @out: Buffer for the generated pseudo-random key 24341618Scy * @outlen: Number of bytes of key to generate 25341618Scy * Returns: 0 on success, -1 on failure. 26341618Scy * 27341618Scy * This function is used to derive new, cryptographically separate keys from a 28341618Scy * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used 29341618Scy * with label = NULL and seed = info, this matches HKDF-Expand() defined in 30341618Scy * RFC 5869, Chapter 2.3. 31341618Scy */ 32341618Scyint hmac_sha512_kdf(const u8 *secret, size_t secret_len, 33341618Scy const char *label, const u8 *seed, size_t seed_len, 34341618Scy u8 *out, size_t outlen) 35341618Scy{ 36341618Scy u8 T[SHA512_MAC_LEN]; 37341618Scy u8 iter = 1; 38341618Scy const unsigned char *addr[4]; 39341618Scy size_t len[4]; 40341618Scy size_t pos, clen; 41341618Scy 42341618Scy addr[0] = T; 43341618Scy len[0] = SHA512_MAC_LEN; 44341618Scy if (label) { 45341618Scy addr[1] = (const unsigned char *) label; 46341618Scy len[1] = os_strlen(label) + 1; 47341618Scy } else { 48341618Scy addr[1] = (const u8 *) ""; 49341618Scy len[1] = 0; 50341618Scy } 51341618Scy addr[2] = seed; 52341618Scy len[2] = seed_len; 53341618Scy addr[3] = &iter; 54341618Scy len[3] = 1; 55341618Scy 56341618Scy if (hmac_sha512_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0) 57341618Scy return -1; 58341618Scy 59341618Scy pos = 0; 60341618Scy for (;;) { 61341618Scy clen = outlen - pos; 62341618Scy if (clen > SHA512_MAC_LEN) 63341618Scy clen = SHA512_MAC_LEN; 64341618Scy os_memcpy(out + pos, T, clen); 65341618Scy pos += clen; 66341618Scy 67341618Scy if (pos == outlen) 68341618Scy break; 69341618Scy 70341618Scy if (iter == 255) { 71341618Scy os_memset(out, 0, outlen); 72351611Scy forced_memzero(T, SHA512_MAC_LEN); 73341618Scy return -1; 74341618Scy } 75341618Scy iter++; 76341618Scy 77341618Scy if (hmac_sha512_vector(secret, secret_len, 4, addr, len, T) < 0) 78341618Scy { 79341618Scy os_memset(out, 0, outlen); 80351611Scy forced_memzero(T, SHA512_MAC_LEN); 81341618Scy return -1; 82341618Scy } 83341618Scy } 84341618Scy 85351611Scy forced_memzero(T, SHA512_MAC_LEN); 86341618Scy return 0; 87341618Scy} 88