sha256-kdf.c revision 281681
1281681Srpaulo/* 2281681Srpaulo * HMAC-SHA256 KDF (RFC 5295) 3281681Srpaulo * Copyright (c) 2014, 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 19281681Srpaulo * @label: A unique label for each purpose of the KDF 20281681Srpaulo * @seed: Seed value to bind into the key 21281681Srpaulo * @seed_len: Length of the seed 22281681Srpaulo * @out: Buffer for the generated pseudo-random key 23281681Srpaulo * @outlen: Number of bytes of key to generate 24281681Srpaulo * Returns: 0 on success, -1 on failure. 25281681Srpaulo * 26281681Srpaulo * This function is used to derive new, cryptographically separate keys from a 27281681Srpaulo * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. 28281681Srpaulo */ 29281681Srpauloint hmac_sha256_kdf(const u8 *secret, size_t secret_len, 30281681Srpaulo const char *label, const u8 *seed, size_t seed_len, 31281681Srpaulo u8 *out, size_t outlen) 32281681Srpaulo{ 33281681Srpaulo u8 T[SHA256_MAC_LEN]; 34281681Srpaulo u8 iter = 1; 35281681Srpaulo const unsigned char *addr[4]; 36281681Srpaulo size_t len[4]; 37281681Srpaulo size_t pos, clen; 38281681Srpaulo 39281681Srpaulo addr[0] = T; 40281681Srpaulo len[0] = SHA256_MAC_LEN; 41281681Srpaulo addr[1] = (const unsigned char *) label; 42281681Srpaulo len[1] = os_strlen(label) + 1; 43281681Srpaulo addr[2] = seed; 44281681Srpaulo len[2] = seed_len; 45281681Srpaulo addr[3] = &iter; 46281681Srpaulo len[3] = 1; 47281681Srpaulo 48281681Srpaulo if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0) 49281681Srpaulo return -1; 50281681Srpaulo 51281681Srpaulo pos = 0; 52281681Srpaulo for (;;) { 53281681Srpaulo clen = outlen - pos; 54281681Srpaulo if (clen > SHA256_MAC_LEN) 55281681Srpaulo clen = SHA256_MAC_LEN; 56281681Srpaulo os_memcpy(out + pos, T, clen); 57281681Srpaulo pos += clen; 58281681Srpaulo 59281681Srpaulo if (pos == outlen) 60281681Srpaulo break; 61281681Srpaulo 62281681Srpaulo if (iter == 255) { 63281681Srpaulo os_memset(out, 0, outlen); 64281681Srpaulo return -1; 65281681Srpaulo } 66281681Srpaulo iter++; 67281681Srpaulo 68281681Srpaulo if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0) 69281681Srpaulo { 70281681Srpaulo os_memset(out, 0, outlen); 71281681Srpaulo return -1; 72281681Srpaulo } 73281681Srpaulo } 74281681Srpaulo 75281681Srpaulo return 0; 76281681Srpaulo} 77