10a73ee0aSchristos /*
20a73ee0aSchristos * HMAC-SHA384 KDF (RFC 5295) and HKDF-Expand(SHA384) (RFC 5869)
30a73ee0aSchristos * Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
40a73ee0aSchristos *
50a73ee0aSchristos * This software may be distributed under the terms of the BSD license.
60a73ee0aSchristos * See README for more details.
70a73ee0aSchristos */
80a73ee0aSchristos
90a73ee0aSchristos #include "includes.h"
100a73ee0aSchristos
110a73ee0aSchristos #include "common.h"
120a73ee0aSchristos #include "sha384.h"
130a73ee0aSchristos
140a73ee0aSchristos
150a73ee0aSchristos /**
160a73ee0aSchristos * hmac_sha384_kdf - HMAC-SHA384 based KDF (RFC 5295)
170a73ee0aSchristos * @secret: Key for KDF
180a73ee0aSchristos * @secret_len: Length of the key in bytes
190a73ee0aSchristos * @label: A unique label for each purpose of the KDF or %NULL to select
200a73ee0aSchristos * RFC 5869 HKDF-Expand() with arbitrary seed (= info)
210a73ee0aSchristos * @seed: Seed value to bind into the key
220a73ee0aSchristos * @seed_len: Length of the seed
230a73ee0aSchristos * @out: Buffer for the generated pseudo-random key
240a73ee0aSchristos * @outlen: Number of bytes of key to generate
250a73ee0aSchristos * Returns: 0 on success, -1 on failure.
260a73ee0aSchristos *
270a73ee0aSchristos * This function is used to derive new, cryptographically separate keys from a
280a73ee0aSchristos * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
290a73ee0aSchristos * with label = NULL and seed = info, this matches HKDF-Expand() defined in
300a73ee0aSchristos * RFC 5869, Chapter 2.3.
310a73ee0aSchristos */
hmac_sha384_kdf(const u8 * secret,size_t secret_len,const char * label,const u8 * seed,size_t seed_len,u8 * out,size_t outlen)320a73ee0aSchristos int hmac_sha384_kdf(const u8 *secret, size_t secret_len,
330a73ee0aSchristos const char *label, const u8 *seed, size_t seed_len,
340a73ee0aSchristos u8 *out, size_t outlen)
350a73ee0aSchristos {
360a73ee0aSchristos u8 T[SHA384_MAC_LEN];
370a73ee0aSchristos u8 iter = 1;
380a73ee0aSchristos const unsigned char *addr[4];
390a73ee0aSchristos size_t len[4];
400a73ee0aSchristos size_t pos, clen;
410a73ee0aSchristos
420a73ee0aSchristos addr[0] = T;
430a73ee0aSchristos len[0] = SHA384_MAC_LEN;
440a73ee0aSchristos if (label) {
450a73ee0aSchristos addr[1] = (const unsigned char *) label;
460a73ee0aSchristos len[1] = os_strlen(label) + 1;
470a73ee0aSchristos } else {
480a73ee0aSchristos addr[1] = (const u8 *) "";
490a73ee0aSchristos len[1] = 0;
500a73ee0aSchristos }
510a73ee0aSchristos addr[2] = seed;
520a73ee0aSchristos len[2] = seed_len;
530a73ee0aSchristos addr[3] = &iter;
540a73ee0aSchristos len[3] = 1;
550a73ee0aSchristos
560a73ee0aSchristos if (hmac_sha384_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
570a73ee0aSchristos return -1;
580a73ee0aSchristos
590a73ee0aSchristos pos = 0;
600a73ee0aSchristos for (;;) {
610a73ee0aSchristos clen = outlen - pos;
620a73ee0aSchristos if (clen > SHA384_MAC_LEN)
630a73ee0aSchristos clen = SHA384_MAC_LEN;
640a73ee0aSchristos os_memcpy(out + pos, T, clen);
650a73ee0aSchristos pos += clen;
660a73ee0aSchristos
670a73ee0aSchristos if (pos == outlen)
680a73ee0aSchristos break;
690a73ee0aSchristos
700a73ee0aSchristos if (iter == 255) {
710a73ee0aSchristos os_memset(out, 0, outlen);
72*3d6c0713Schristos forced_memzero(T, SHA384_MAC_LEN);
730a73ee0aSchristos return -1;
740a73ee0aSchristos }
750a73ee0aSchristos iter++;
760a73ee0aSchristos
770a73ee0aSchristos if (hmac_sha384_vector(secret, secret_len, 4, addr, len, T) < 0)
780a73ee0aSchristos {
790a73ee0aSchristos os_memset(out, 0, outlen);
80*3d6c0713Schristos forced_memzero(T, SHA384_MAC_LEN);
810a73ee0aSchristos return -1;
820a73ee0aSchristos }
830a73ee0aSchristos }
840a73ee0aSchristos
85*3d6c0713Schristos forced_memzero(T, SHA384_MAC_LEN);
860a73ee0aSchristos return 0;
870a73ee0aSchristos }
88