1281681Srpaulo/* 2346981Scy * HMAC-SHA256 KDF (RFC 5295) and HKDF-Expand(SHA256) (RFC 5869) 3346981Scy * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi> 4281681Srpaulo * 5281681Srpaulo * This software may be distributed under the terms of the BSD license. 6281681Srpaulo * See README for more details. 7281681Srpaulo */ 8281681Srpaulo 9281681Srpaulo#include "includes.h" 10281681Srpaulo 11281681Srpaulo#include "common.h" 12281681Srpaulo#include "sha256.h" 13281681Srpaulo 14281681Srpaulo 15281681Srpaulo/** 16281681Srpaulo * hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295) 17281681Srpaulo * @secret: Key for KDF 18281681Srpaulo * @secret_len: Length of the key in bytes 19346981Scy * @label: A unique label for each purpose of the KDF or %NULL to select 20346981Scy * RFC 5869 HKDF-Expand() with arbitrary seed (= info) 21281681Srpaulo * @seed: Seed value to bind into the key 22281681Srpaulo * @seed_len: Length of the seed 23281681Srpaulo * @out: Buffer for the generated pseudo-random key 24281681Srpaulo * @outlen: Number of bytes of key to generate 25281681Srpaulo * Returns: 0 on success, -1 on failure. 26281681Srpaulo * 27281681Srpaulo * This function is used to derive new, cryptographically separate keys from a 28346981Scy * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used 29346981Scy * with label = NULL and seed = info, this matches HKDF-Expand() defined in 30346981Scy * RFC 5869, Chapter 2.3. 31281681Srpaulo */ 32281681Srpauloint hmac_sha256_kdf(const u8 *secret, size_t secret_len, 33281681Srpaulo const char *label, const u8 *seed, size_t seed_len, 34281681Srpaulo u8 *out, size_t outlen) 35281681Srpaulo{ 36281681Srpaulo u8 T[SHA256_MAC_LEN]; 37281681Srpaulo u8 iter = 1; 38281681Srpaulo const unsigned char *addr[4]; 39281681Srpaulo size_t len[4]; 40281681Srpaulo size_t pos, clen; 41281681Srpaulo 42281681Srpaulo addr[0] = T; 43281681Srpaulo len[0] = SHA256_MAC_LEN; 44346981Scy if (label) { 45346981Scy addr[1] = (const unsigned char *) label; 46346981Scy len[1] = os_strlen(label) + 1; 47346981Scy } else { 48346981Scy addr[1] = (const u8 *) ""; 49346981Scy len[1] = 0; 50346981Scy } 51281681Srpaulo addr[2] = seed; 52281681Srpaulo len[2] = seed_len; 53281681Srpaulo addr[3] = &iter; 54281681Srpaulo len[3] = 1; 55281681Srpaulo 56281681Srpaulo if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0) 57281681Srpaulo return -1; 58281681Srpaulo 59281681Srpaulo pos = 0; 60281681Srpaulo for (;;) { 61281681Srpaulo clen = outlen - pos; 62281681Srpaulo if (clen > SHA256_MAC_LEN) 63281681Srpaulo clen = SHA256_MAC_LEN; 64281681Srpaulo os_memcpy(out + pos, T, clen); 65281681Srpaulo pos += clen; 66281681Srpaulo 67281681Srpaulo if (pos == outlen) 68281681Srpaulo break; 69281681Srpaulo 70281681Srpaulo if (iter == 255) { 71281681Srpaulo os_memset(out, 0, outlen); 72351611Scy forced_memzero(T, SHA256_MAC_LEN); 73281681Srpaulo return -1; 74281681Srpaulo } 75281681Srpaulo iter++; 76281681Srpaulo 77281681Srpaulo if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0) 78281681Srpaulo { 79281681Srpaulo os_memset(out, 0, outlen); 80351611Scy forced_memzero(T, SHA256_MAC_LEN); 81281681Srpaulo return -1; 82281681Srpaulo } 83281681Srpaulo } 84281681Srpaulo 85351611Scy forced_memzero(T, SHA256_MAC_LEN); 86281681Srpaulo return 0; 87281681Srpaulo} 88