xref: /freebsd/contrib/wpa/src/crypto/sha256-prf.c (revision c5c3ba6b43cac20dc9432eac15758d41cb2b8b1f)
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