1f05cddf9SRui Paulo /* 2f05cddf9SRui Paulo * SHA256-based PRF (IEEE 802.11r) 3*780fb4a2SCy Schubert * Copyright (c) 2003-2016, Jouni Malinen <j@w1.fi> 4f05cddf9SRui Paulo * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 7f05cddf9SRui Paulo */ 8f05cddf9SRui Paulo 9f05cddf9SRui Paulo #include "includes.h" 10f05cddf9SRui Paulo 11f05cddf9SRui Paulo #include "common.h" 12f05cddf9SRui Paulo #include "sha256.h" 13f05cddf9SRui Paulo #include "crypto.h" 14f05cddf9SRui Paulo 15f05cddf9SRui Paulo 16f05cddf9SRui Paulo /** 17f05cddf9SRui Paulo * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2) 18f05cddf9SRui Paulo * @key: Key for PRF 19f05cddf9SRui Paulo * @key_len: Length of the key in bytes 20f05cddf9SRui Paulo * @label: A unique label for each purpose of the PRF 21f05cddf9SRui Paulo * @data: Extra data to bind into the key 22f05cddf9SRui Paulo * @data_len: Length of the data 23f05cddf9SRui Paulo * @buf: Buffer for the generated pseudo-random key 24f05cddf9SRui Paulo * @buf_len: Number of bytes of key to generate 25*780fb4a2SCy Schubert * Returns: 0 on success, -1 on failure 26f05cddf9SRui Paulo * 27f05cddf9SRui Paulo * This function is used to derive new, cryptographically separate keys from a 28f05cddf9SRui Paulo * given key. 29f05cddf9SRui Paulo */ 30*780fb4a2SCy Schubert int sha256_prf(const u8 *key, size_t key_len, const char *label, 31f05cddf9SRui Paulo const u8 *data, size_t data_len, u8 *buf, size_t buf_len) 32f05cddf9SRui Paulo { 33*780fb4a2SCy Schubert return sha256_prf_bits(key, key_len, label, data, data_len, buf, 34*780fb4a2SCy Schubert buf_len * 8); 355b9c547cSRui Paulo } 365b9c547cSRui Paulo 375b9c547cSRui Paulo 385b9c547cSRui Paulo /** 395b9c547cSRui Paulo * sha256_prf_bits - IEEE Std 802.11-2012, 11.6.1.7.2 Key derivation function 405b9c547cSRui Paulo * @key: Key for KDF 415b9c547cSRui Paulo * @key_len: Length of the key in bytes 425b9c547cSRui Paulo * @label: A unique label for each purpose of the PRF 435b9c547cSRui Paulo * @data: Extra data to bind into the key 445b9c547cSRui Paulo * @data_len: Length of the data 455b9c547cSRui Paulo * @buf: Buffer for the generated pseudo-random key 465b9c547cSRui Paulo * @buf_len: Number of bits of key to generate 47*780fb4a2SCy Schubert * Returns: 0 on success, -1 on failure 485b9c547cSRui Paulo * 495b9c547cSRui Paulo * This function is used to derive new, cryptographically separate keys from a 505b9c547cSRui Paulo * given key. If the requested buf_len is not divisible by eight, the least 515b9c547cSRui Paulo * significant 1-7 bits of the last octet in the output are not part of the 525b9c547cSRui Paulo * requested output. 535b9c547cSRui Paulo */ 54*780fb4a2SCy Schubert int sha256_prf_bits(const u8 *key, size_t key_len, const char *label, 555b9c547cSRui Paulo const u8 *data, size_t data_len, u8 *buf, 565b9c547cSRui Paulo size_t buf_len_bits) 575b9c547cSRui Paulo { 58f05cddf9SRui Paulo u16 counter = 1; 59f05cddf9SRui Paulo size_t pos, plen; 60f05cddf9SRui Paulo u8 hash[SHA256_MAC_LEN]; 61f05cddf9SRui Paulo const u8 *addr[4]; 62f05cddf9SRui Paulo size_t len[4]; 63f05cddf9SRui Paulo u8 counter_le[2], length_le[2]; 645b9c547cSRui Paulo size_t buf_len = (buf_len_bits + 7) / 8; 65f05cddf9SRui Paulo 66f05cddf9SRui Paulo addr[0] = counter_le; 67f05cddf9SRui Paulo len[0] = 2; 68f05cddf9SRui Paulo addr[1] = (u8 *) label; 69f05cddf9SRui Paulo len[1] = os_strlen(label); 70f05cddf9SRui Paulo addr[2] = data; 71f05cddf9SRui Paulo len[2] = data_len; 72f05cddf9SRui Paulo addr[3] = length_le; 73f05cddf9SRui Paulo len[3] = sizeof(length_le); 74f05cddf9SRui Paulo 755b9c547cSRui Paulo WPA_PUT_LE16(length_le, buf_len_bits); 76f05cddf9SRui Paulo pos = 0; 77f05cddf9SRui Paulo while (pos < buf_len) { 78f05cddf9SRui Paulo plen = buf_len - pos; 79f05cddf9SRui Paulo WPA_PUT_LE16(counter_le, counter); 80f05cddf9SRui Paulo if (plen >= SHA256_MAC_LEN) { 81*780fb4a2SCy Schubert if (hmac_sha256_vector(key, key_len, 4, addr, len, 82*780fb4a2SCy Schubert &buf[pos]) < 0) 83*780fb4a2SCy Schubert return -1; 84f05cddf9SRui Paulo pos += SHA256_MAC_LEN; 85f05cddf9SRui Paulo } else { 86*780fb4a2SCy Schubert if (hmac_sha256_vector(key, key_len, 4, addr, len, 87*780fb4a2SCy Schubert hash) < 0) 88*780fb4a2SCy Schubert return -1; 89f05cddf9SRui Paulo os_memcpy(&buf[pos], hash, plen); 905b9c547cSRui Paulo pos += plen; 91f05cddf9SRui Paulo break; 92f05cddf9SRui Paulo } 93f05cddf9SRui Paulo counter++; 94f05cddf9SRui Paulo } 955b9c547cSRui Paulo 965b9c547cSRui Paulo /* 975b9c547cSRui Paulo * Mask out unused bits in the last octet if it does not use all the 985b9c547cSRui Paulo * bits. 995b9c547cSRui Paulo */ 1005b9c547cSRui Paulo if (buf_len_bits % 8) { 1015b9c547cSRui Paulo u8 mask = 0xff << (8 - buf_len_bits % 8); 1025b9c547cSRui Paulo buf[pos - 1] &= mask; 1035b9c547cSRui Paulo } 1045b9c547cSRui Paulo 1055b9c547cSRui Paulo os_memset(hash, 0, sizeof(hash)); 106*780fb4a2SCy Schubert 107*780fb4a2SCy Schubert return 0; 108f05cddf9SRui Paulo } 109