Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/module/zfs/hkdf.c
48383 views
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/crypto/api.h>
22
#include <sys/sha2.h>
23
#include <sys/hkdf.h>
24
25
static int
26
hkdf_sha512_extract(uint8_t *salt, uint_t salt_len, uint8_t *key_material,
27
uint_t km_len, uint8_t *out_buf)
28
{
29
int ret;
30
crypto_mechanism_t mech;
31
crypto_key_t key;
32
crypto_data_t input_cd, output_cd;
33
34
/* initialize HMAC mechanism */
35
mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
36
mech.cm_param = NULL;
37
mech.cm_param_len = 0;
38
39
/* initialize the salt as a crypto key */
40
key.ck_length = CRYPTO_BYTES2BITS(salt_len);
41
key.ck_data = salt;
42
43
/* initialize crypto data for the input and output data */
44
input_cd.cd_format = CRYPTO_DATA_RAW;
45
input_cd.cd_offset = 0;
46
input_cd.cd_length = km_len;
47
input_cd.cd_raw.iov_base = (char *)key_material;
48
input_cd.cd_raw.iov_len = input_cd.cd_length;
49
50
output_cd.cd_format = CRYPTO_DATA_RAW;
51
output_cd.cd_offset = 0;
52
output_cd.cd_length = SHA512_DIGEST_LENGTH;
53
output_cd.cd_raw.iov_base = (char *)out_buf;
54
output_cd.cd_raw.iov_len = output_cd.cd_length;
55
56
ret = crypto_mac(&mech, &input_cd, &key, NULL, &output_cd);
57
if (ret != CRYPTO_SUCCESS)
58
return (SET_ERROR(EIO));
59
60
return (0);
61
}
62
63
static int
64
hkdf_sha512_expand(uint8_t *extract_key, uint8_t *info, uint_t info_len,
65
uint8_t *out_buf, uint_t out_len)
66
{
67
int ret;
68
crypto_mechanism_t mech;
69
crypto_context_t ctx;
70
crypto_key_t key;
71
crypto_data_t T_cd, info_cd, c_cd;
72
uint_t i, T_len = 0, pos = 0;
73
uint8_t c;
74
uint_t N = (out_len + SHA512_DIGEST_LENGTH) / SHA512_DIGEST_LENGTH;
75
uint8_t T[SHA512_DIGEST_LENGTH];
76
77
if (N > 255)
78
return (SET_ERROR(EINVAL));
79
80
/* initialize HMAC mechanism */
81
mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
82
mech.cm_param = NULL;
83
mech.cm_param_len = 0;
84
85
/* initialize the salt as a crypto key */
86
key.ck_length = CRYPTO_BYTES2BITS(SHA512_DIGEST_LENGTH);
87
key.ck_data = extract_key;
88
89
/* initialize crypto data for the input and output data */
90
T_cd.cd_format = CRYPTO_DATA_RAW;
91
T_cd.cd_offset = 0;
92
T_cd.cd_raw.iov_base = (char *)T;
93
94
c_cd.cd_format = CRYPTO_DATA_RAW;
95
c_cd.cd_offset = 0;
96
c_cd.cd_length = 1;
97
c_cd.cd_raw.iov_base = (char *)&c;
98
c_cd.cd_raw.iov_len = c_cd.cd_length;
99
100
info_cd.cd_format = CRYPTO_DATA_RAW;
101
info_cd.cd_offset = 0;
102
info_cd.cd_length = info_len;
103
info_cd.cd_raw.iov_base = (char *)info;
104
info_cd.cd_raw.iov_len = info_cd.cd_length;
105
106
for (i = 1; i <= N; i++) {
107
c = i;
108
109
T_cd.cd_length = T_len;
110
T_cd.cd_raw.iov_len = T_cd.cd_length;
111
112
ret = crypto_mac_init(&mech, &key, NULL, &ctx);
113
if (ret != CRYPTO_SUCCESS)
114
return (SET_ERROR(EIO));
115
116
ret = crypto_mac_update(ctx, &T_cd);
117
if (ret != CRYPTO_SUCCESS)
118
return (SET_ERROR(EIO));
119
120
ret = crypto_mac_update(ctx, &info_cd);
121
if (ret != CRYPTO_SUCCESS)
122
return (SET_ERROR(EIO));
123
124
ret = crypto_mac_update(ctx, &c_cd);
125
if (ret != CRYPTO_SUCCESS)
126
return (SET_ERROR(EIO));
127
128
T_len = SHA512_DIGEST_LENGTH;
129
T_cd.cd_length = T_len;
130
T_cd.cd_raw.iov_len = T_cd.cd_length;
131
132
ret = crypto_mac_final(ctx, &T_cd);
133
if (ret != CRYPTO_SUCCESS)
134
return (SET_ERROR(EIO));
135
136
memcpy(out_buf + pos, T,
137
(i != N) ? SHA512_DIGEST_LENGTH : (out_len - pos));
138
pos += SHA512_DIGEST_LENGTH;
139
}
140
141
return (0);
142
}
143
144
/*
145
* HKDF is designed to be a relatively fast function for deriving keys from a
146
* master key + a salt. We use this function to generate new encryption keys
147
* so as to avoid hitting the cryptographic limits of the underlying
148
* encryption modes. Note that, for the sake of deriving encryption keys, the
149
* info parameter is called the "salt" everywhere else in the code.
150
*/
151
int
152
hkdf_sha512(uint8_t *key_material, uint_t km_len, uint8_t *salt,
153
uint_t salt_len, uint8_t *info, uint_t info_len, uint8_t *output_key,
154
uint_t out_len)
155
{
156
int ret;
157
uint8_t extract_key[SHA512_DIGEST_LENGTH];
158
159
ret = hkdf_sha512_extract(salt, salt_len, key_material, km_len,
160
extract_key);
161
if (ret != 0)
162
return (ret);
163
164
ret = hkdf_sha512_expand(extract_key, info, info_len, output_key,
165
out_len);
166
if (ret != 0)
167
return (ret);
168
169
return (0);
170
}
171
172