1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * CDDL HEADER START
4 *
5 * This file and its contents are supplied under the terms of the
6 * Common Development and Distribution License ("CDDL"), version 1.0.
7 * You may only use this file in accordance with the terms of version
8 * 1.0 of the CDDL.
9 *
10 * A full copy of the text of the CDDL should have accompanied this
11 * source. A copy of the CDDL is also available via the Internet at
12 * http://www.illumos.org/license/CDDL.
13 *
14 * CDDL HEADER END
15 */
16
17 /*
18 * Copyright (c) 2017, Datto, Inc. All rights reserved.
19 */
20
21 #include <sys/dmu.h>
22 #include <sys/hkdf.h>
23 #include <sys/freebsd_crypto.h>
24 #include <sys/hkdf.h>
25
26 static int
hkdf_sha512_extract(uint8_t * salt,uint_t salt_len,uint8_t * key_material,uint_t km_len,uint8_t * out_buf)27 hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
28 uint_t km_len, uint8_t *out_buf)
29 {
30 crypto_key_t key;
31
32 /* initialize the salt as a crypto key */
33 key.ck_length = CRYPTO_BYTES2BITS(salt_len);
34 key.ck_data = salt;
35
36 crypto_mac(&key, key_material, km_len, out_buf, SHA512_DIGEST_LENGTH);
37
38 return (0);
39 }
40
41 static int
hkdf_sha512_expand(uint8_t * extract_key,uint8_t * info,uint_t info_len,uint8_t * out_buf,uint_t out_len)42 hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
43 uint8_t *out_buf, uint_t out_len)
44 {
45 struct hmac_ctx ctx;
46 crypto_key_t key;
47 uint_t i, T_len = 0, pos = 0;
48 uint8_t c;
49 uint_t N = (out_len + SHA512_DIGEST_LENGTH) / SHA512_DIGEST_LENGTH;
50 uint8_t T[SHA512_DIGEST_LENGTH];
51
52 if (N > 255)
53 return (SET_ERROR(EINVAL));
54
55 /* initialize the salt as a crypto key */
56 key.ck_length = CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH);
57 key.ck_data = extract_key;
58
59 for (i = 1; i <= N; i++) {
60 c = i;
61
62 crypto_mac_init(&ctx, &key);
63 crypto_mac_update(&ctx, T, T_len);
64 crypto_mac_update(&ctx, info, info_len);
65 crypto_mac_update(&ctx, &c, 1);
66 crypto_mac_final(&ctx, T, SHA512_DIGEST_LENGTH);
67 memcpy(out_buf + pos, T,
68 (i != N) ? SHA512_DIGEST_LENGTH : (out_len - pos));
69 pos += SHA512_DIGEST_LENGTH;
70 }
71
72 return (0);
73 }
74
75 /*
76 * HKDF is designed to be a relatively fast function for deriving keys from a
77 * master key + a salt. We use this function to generate new encryption keys
78 * so as to avoid hitting the cryptographic limits of the underlying
79 * encryption modes. Note that, for the sake of deriving encryption keys, the
80 * info parameter is called the "salt" everywhere else in the code.
81 */
82 int
hkdf_sha512(uint8_t * key_material,uint_t km_len,uint8_t * salt,uint_t salt_len,uint8_t * info,uint_t info_len,uint8_t * output_key,uint_t out_len)83 hkdf_sha512(uint8_t *key_material, uint_t km_len, uint8_t *salt,
84 uint_t salt_len, uint8_t *info, uint_t info_len, uint8_t *output_key,
85 uint_t out_len)
86 {
87 int ret;
88 uint8_t extract_key[SHA512_DIGEST_LENGTH];
89
90 ret = hkdf_sha512_extract(salt, salt_len, key_material, km_len,
91 extract_key);
92 if (ret != 0)
93 return (ret);
94
95 ret = hkdf_sha512_expand(extract_key, info, info_len, output_key,
96 out_len);
97 if (ret != 0)
98 return (ret);
99
100 return (0);
101 }
102