1289284Srpaulo/* 2289284Srpaulo * SHA384-based KDF (IEEE 802.11ac) 3346981Scy * Copyright (c) 2003-2017, Jouni Malinen <j@w1.fi> 4289284Srpaulo * 5289284Srpaulo * This software may be distributed under the terms of the BSD license. 6289284Srpaulo * See README for more details. 7289284Srpaulo */ 8289284Srpaulo 9289284Srpaulo#include "includes.h" 10289284Srpaulo 11289284Srpaulo#include "common.h" 12289284Srpaulo#include "sha384.h" 13289284Srpaulo#include "crypto.h" 14289284Srpaulo 15289284Srpaulo 16289284Srpaulo/** 17289284Srpaulo * sha384_prf - SHA384-based Key derivation function (IEEE 802.11ac, 11.6.1.7.2) 18289284Srpaulo * @key: Key for KDF 19289284Srpaulo * @key_len: Length of the key in bytes 20289284Srpaulo * @label: A unique label for each purpose of the PRF 21289284Srpaulo * @data: Extra data to bind into the key 22289284Srpaulo * @data_len: Length of the data 23289284Srpaulo * @buf: Buffer for the generated pseudo-random key 24289284Srpaulo * @buf_len: Number of bytes of key to generate 25346981Scy * Returns: 0 on success, -1 on failure 26289284Srpaulo * 27289284Srpaulo * This function is used to derive new, cryptographically separate keys from a 28289284Srpaulo * given key. 29289284Srpaulo */ 30346981Scyint sha384_prf(const u8 *key, size_t key_len, const char *label, 31346981Scy const u8 *data, size_t data_len, u8 *buf, size_t buf_len) 32289284Srpaulo{ 33346981Scy return sha384_prf_bits(key, key_len, label, data, data_len, buf, 34346981Scy buf_len * 8); 35289284Srpaulo} 36289284Srpaulo 37289284Srpaulo 38289284Srpaulo/** 39289284Srpaulo * sha384_prf_bits - IEEE Std 802.11ac-2013, 11.6.1.7.2 Key derivation function 40289284Srpaulo * @key: Key for KDF 41289284Srpaulo * @key_len: Length of the key in bytes 42289284Srpaulo * @label: A unique label for each purpose of the PRF 43289284Srpaulo * @data: Extra data to bind into the key 44289284Srpaulo * @data_len: Length of the data 45289284Srpaulo * @buf: Buffer for the generated pseudo-random key 46289284Srpaulo * @buf_len: Number of bits of key to generate 47346981Scy * Returns: 0 on success, -1 on failure 48289284Srpaulo * 49289284Srpaulo * This function is used to derive new, cryptographically separate keys from a 50289284Srpaulo * given key. If the requested buf_len is not divisible by eight, the least 51289284Srpaulo * significant 1-7 bits of the last octet in the output are not part of the 52289284Srpaulo * requested output. 53289284Srpaulo */ 54346981Scyint sha384_prf_bits(const u8 *key, size_t key_len, const char *label, 55346981Scy const u8 *data, size_t data_len, u8 *buf, 56346981Scy size_t buf_len_bits) 57289284Srpaulo{ 58289284Srpaulo u16 counter = 1; 59289284Srpaulo size_t pos, plen; 60289284Srpaulo u8 hash[SHA384_MAC_LEN]; 61289284Srpaulo const u8 *addr[4]; 62289284Srpaulo size_t len[4]; 63289284Srpaulo u8 counter_le[2], length_le[2]; 64289284Srpaulo size_t buf_len = (buf_len_bits + 7) / 8; 65289284Srpaulo 66289284Srpaulo addr[0] = counter_le; 67289284Srpaulo len[0] = 2; 68289284Srpaulo addr[1] = (u8 *) label; 69289284Srpaulo len[1] = os_strlen(label); 70289284Srpaulo addr[2] = data; 71289284Srpaulo len[2] = data_len; 72289284Srpaulo addr[3] = length_le; 73289284Srpaulo len[3] = sizeof(length_le); 74289284Srpaulo 75289284Srpaulo WPA_PUT_LE16(length_le, buf_len_bits); 76289284Srpaulo pos = 0; 77289284Srpaulo while (pos < buf_len) { 78289284Srpaulo plen = buf_len - pos; 79289284Srpaulo WPA_PUT_LE16(counter_le, counter); 80289284Srpaulo if (plen >= SHA384_MAC_LEN) { 81346981Scy if (hmac_sha384_vector(key, key_len, 4, addr, len, 82346981Scy &buf[pos]) < 0) 83346981Scy return -1; 84289284Srpaulo pos += SHA384_MAC_LEN; 85289284Srpaulo } else { 86346981Scy if (hmac_sha384_vector(key, key_len, 4, addr, len, 87346981Scy hash) < 0) 88346981Scy return -1; 89289284Srpaulo os_memcpy(&buf[pos], hash, plen); 90289284Srpaulo pos += plen; 91289284Srpaulo break; 92289284Srpaulo } 93289284Srpaulo counter++; 94289284Srpaulo } 95289284Srpaulo 96289284Srpaulo /* 97289284Srpaulo * Mask out unused bits in the last octet if it does not use all the 98289284Srpaulo * bits. 99289284Srpaulo */ 100289284Srpaulo if (buf_len_bits % 8) { 101289284Srpaulo u8 mask = 0xff << (8 - buf_len_bits % 8); 102289284Srpaulo buf[pos - 1] &= mask; 103289284Srpaulo } 104289284Srpaulo 105351611Scy forced_memzero(hash, sizeof(hash)); 106346981Scy 107346981Scy return 0; 108289284Srpaulo} 109