1f05cddf9SRui Paulo /*
2f05cddf9SRui Paulo * SHA256-based PRF (IEEE 802.11r)
3780fb4a2SCy 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
25780fb4a2SCy 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 */
sha256_prf(const u8 * key,size_t key_len,const char * label,const u8 * data,size_t data_len,u8 * buf,size_t buf_len)30780fb4a2SCy 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 {
33780fb4a2SCy Schubert return sha256_prf_bits(key, key_len, label, data, data_len, buf,
34780fb4a2SCy 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
47780fb4a2SCy 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 */
sha256_prf_bits(const u8 * key,size_t key_len,const char * label,const u8 * data,size_t data_len,u8 * buf,size_t buf_len_bits)54780fb4a2SCy 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) {
81780fb4a2SCy Schubert if (hmac_sha256_vector(key, key_len, 4, addr, len,
82780fb4a2SCy Schubert &buf[pos]) < 0)
83780fb4a2SCy Schubert return -1;
84f05cddf9SRui Paulo pos += SHA256_MAC_LEN;
85f05cddf9SRui Paulo } else {
86780fb4a2SCy Schubert if (hmac_sha256_vector(key, key_len, 4, addr, len,
87780fb4a2SCy Schubert hash) < 0)
88780fb4a2SCy 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
105*206b73d0SCy Schubert forced_memzero(hash, sizeof(hash));
106780fb4a2SCy Schubert
107780fb4a2SCy Schubert return 0;
108f05cddf9SRui Paulo }
109