1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3 * This file and its contents are supplied under the terms of the
4 * Common Development and Distribution License ("CDDL"), version 1.0.
5 * You may only use this file in accordance with the terms of version
6 * 1.0 of the CDDL.
7 *
8 * A full copy of the text of the CDDL should have accompanied this
9 * source. A copy of the CDDL is also available via the Internet at
10 * https://opensource.org/license/CDDL-1.0.
11 */
12
13 /*
14 * Copyright (c) 2017, Datto, Inc. All rights reserved.
15 * Copyright (c) 2026, TrueNAS.
16 */
17
18 #include <sys/zio_crypt.h>
19
20 void
zio_crypt_key_close_os(zio_crypt_key_t * key)21 zio_crypt_key_close_os(zio_crypt_key_t *key)
22 {
23 /* free crypto templates */
24 crypto_destroy_ctx_template(key->zk_current_sess.zs_tmpl);
25 crypto_destroy_ctx_template(key->zk_hmac_sess.zs_tmpl);
26 }
27
28 int
zio_crypt_key_open_os(zio_crypt_key_t * key,const zio_crypt_info_t * ci)29 zio_crypt_key_open_os(zio_crypt_key_t *key, const zio_crypt_info_t *ci)
30 {
31 crypto_mechanism_t mech = {0};
32 int ret;
33
34 /*
35 * Initialize the crypto templates. It's ok if this fails because
36 * this is just an optimization.
37 */
38 mech.cm_type = crypto_mech2id(ci->ci_mechname);
39 ret = crypto_create_ctx_template(&mech, &key->zk_current_key,
40 &key->zk_current_sess.zs_tmpl);
41 if (ret != CRYPTO_SUCCESS)
42 key->zk_current_sess.zs_tmpl = NULL;
43
44 mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
45 ret = crypto_create_ctx_template(&mech, &key->zk_hmac_key,
46 &key->zk_hmac_sess.zs_tmpl);
47 if (ret != CRYPTO_SUCCESS)
48 key->zk_hmac_sess.zs_tmpl = NULL;
49
50 return (0);
51 }
52
53 int
zio_crypt_key_reopen_os(zio_crypt_key_t * key,const zio_crypt_info_t * ci)54 zio_crypt_key_reopen_os(zio_crypt_key_t *key, const zio_crypt_info_t *ci)
55 {
56 int ret;
57 crypto_mechanism_t mech = {0};
58
59 crypto_destroy_ctx_template(key->zk_current_sess.zs_tmpl);
60
61 mech.cm_type = crypto_mech2id(ci->ci_mechname);
62 ret = crypto_create_ctx_template(&mech, &key->zk_current_key,
63 &key->zk_current_sess.zs_tmpl);
64 if (ret != CRYPTO_SUCCESS)
65 key->zk_current_sess.zs_tmpl = NULL;
66 return (0);
67 }
68
69 /*
70 * Initialise a pair of uios with the requested number of data iovecs. An
71 * additional iovec will be allocated for at the end for the ICP to use for the
72 * MAC buffer.
73 */
74 int
zio_crypt_uios_init_os(zfs_uio_t * u1,zfs_uio_t * u2,int iovcnt,int * idx)75 zio_crypt_uios_init_os(zfs_uio_t *u1, zfs_uio_t *u2, int iovcnt, int *idx)
76 {
77 memset(u1, 0, sizeof (zfs_uio_t));
78 memset(u2, 0, sizeof (zfs_uio_t));
79
80 /* One extra for the MAC. */
81 iovcnt++;
82
83 zfs_uio_iov(u1) = kmem_zalloc(iovcnt * sizeof (iovec_t), KM_SLEEP);
84 zfs_uio_iov(u2) = kmem_zalloc(iovcnt * sizeof (iovec_t), KM_SLEEP);
85
86 zfs_uio_iovcnt(u1) = zfs_uio_iovcnt(u2) = iovcnt;
87 zfs_uio_segflg(u1) = zfs_uio_segflg(u2) = UIO_SYSSPACE;
88
89 *idx = 0;
90
91 return (0);
92 }
93
94 void
zio_crypt_uios_fini_os(zfs_uio_t * u1,zfs_uio_t * u2)95 zio_crypt_uios_fini_os(zfs_uio_t *u1, zfs_uio_t *u2) {
96 ASSERT3U(zfs_uio_iovcnt(u1), ==, zfs_uio_iovcnt(u2));
97
98 kmem_free(zfs_uio_iov(u1), zfs_uio_iovcnt(u1) * sizeof (iovec_t));
99 kmem_free(zfs_uio_iov(u2), zfs_uio_iovcnt(u2) * sizeof (iovec_t));
100 }
101
102 static int
zio_encrypt_decrypt_os_common(boolean_t do_encrypt,const zio_crypt_info_t * ci,crypto_key_t * key,zio_crypt_session_t * sess,zfs_uio_t * src,zfs_uio_t * dst,size_t datalen,const uint8_t iv[ZIO_DATA_IV_LEN],const uint8_t * ad,size_t adlen,uint8_t mac[ZIO_DATA_MAC_LEN])103 zio_encrypt_decrypt_os_common(boolean_t do_encrypt, const zio_crypt_info_t *ci,
104 crypto_key_t *key, zio_crypt_session_t *sess,
105 zfs_uio_t *src, zfs_uio_t *dst, size_t datalen,
106 const uint8_t iv[ZIO_DATA_IV_LEN], const uint8_t *ad, size_t adlen,
107 uint8_t mac[ZIO_DATA_MAC_LEN])
108 {
109 ASSERT3U(zfs_uio_iovcnt(src), ==, zfs_uio_iovcnt(dst));
110
111 /* populate the source and dest structs */
112 crypto_data_t src_cd = {
113 .cd_format = CRYPTO_DATA_UIO,
114 .cd_uio = src,
115 .cd_offset = 0,
116 };
117 crypto_data_t dst_cd = {
118 .cd_format = CRYPTO_DATA_UIO,
119 .cd_uio = dst,
120 .cd_offset = 0,
121 };
122
123 if (do_encrypt) {
124 /*
125 * When encrypting, the MAC will be stored at the end of the
126 * encrypted data, so add the MAC buffer to the end of the dest
127 * UIO and extend the data length to accomodate it.
128 */
129 zfs_uio_iovbase(dst, zfs_uio_iovcnt(dst)-1) = mac;
130 zfs_uio_iovlen(dst, zfs_uio_iovcnt(dst)-1) = ZIO_DATA_MAC_LEN;
131 src_cd.cd_length = datalen;
132 dst_cd.cd_length = datalen + ZIO_DATA_MAC_LEN;
133 } else {
134 /*
135 * When decrypting, the MAC is presented at the end of the
136 * plaintext data, so add the MAC buffer to the end of the
137 * source UIO.
138 *
139 * Strangely, the ICP requires that the destination/plaintext
140 * must include the MAC length when decrypting, even though it
141 * will never write anything and does not need to have the
142 * extra space allocated. So we extend both source and data
143 * length to cover it.
144 */
145 zfs_uio_iovbase(src, zfs_uio_iovcnt(src)-1) = mac;
146 zfs_uio_iovlen(src, zfs_uio_iovcnt(src)-1) = ZIO_DATA_MAC_LEN;
147 src_cd.cd_length = dst_cd.cd_length =
148 datalen + ZIO_DATA_MAC_LEN;
149 }
150
151 /* setup encryption mechanism */
152 crypto_mechanism_t mech = {0};
153 mech.cm_type = crypto_mech2id(ci->ci_mechname);
154
155 /* setup encryption params */
156 union {
157 CK_AES_CCM_PARAMS ccm;
158 CK_AES_GCM_PARAMS gcm;
159 } params;
160
161 if (ci->ci_crypt_type == ZC_TYPE_CCM) {
162 CK_AES_CCM_PARAMS *ccm = ¶ms.ccm;
163 ccm->nonce = (uchar_t *)iv;
164 ccm->ulNonceSize = ZIO_DATA_IV_LEN;
165 ccm->authData = (uchar_t *)ad;
166 ccm->ulAuthDataSize = adlen;
167 ccm->ulDataSize = src_cd.cd_length;
168 ccm->ulMACSize = ZIO_DATA_MAC_LEN;
169 mech.cm_param = (caddr_t)ccm;
170 mech.cm_param_len = sizeof (*ccm);
171 } else {
172 CK_AES_GCM_PARAMS *gcm = ¶ms.gcm;
173 gcm->pIv = (uchar_t *)iv;
174 gcm->ulIvLen = ZIO_DATA_IV_LEN;
175 gcm->ulIvBits = CRYPTO_BYTES2BITS(ZIO_DATA_IV_LEN);
176 gcm->pAAD = (uchar_t *)ad;
177 gcm->ulAADLen = adlen;
178 gcm->ulTagBits = CRYPTO_BYTES2BITS(ZIO_DATA_MAC_LEN);
179 mech.cm_param = (caddr_t)gcm;
180 mech.cm_param_len = sizeof (*gcm);
181 }
182
183 /* perform the actual encryption */
184 crypto_ctx_template_t *tmpl = sess != NULL ? sess->zs_tmpl : NULL;
185 int err = 0;
186 if (do_encrypt) {
187 err = crypto_encrypt(&mech, &src_cd, key, tmpl, &dst_cd);
188 if (err != CRYPTO_SUCCESS)
189 err = SET_ERROR(EIO);
190 } else {
191 err = crypto_decrypt(&mech, &src_cd, key, tmpl, &dst_cd);
192 if (err != CRYPTO_SUCCESS) {
193 ASSERT3U(err, ==, CRYPTO_INVALID_MAC);
194 err = SET_ERROR(ECKSUM);
195 }
196 }
197
198 return (err);
199 }
200
201 int
zio_encrypt_os(const zio_crypt_info_t * ci,crypto_key_t * key,zio_crypt_session_t * sess,zfs_uio_t * plaintext,zfs_uio_t * ciphertext,size_t datalen,const uint8_t iv[ZIO_DATA_IV_LEN],const uint8_t * ad,size_t adlen,uint8_t mac[ZIO_DATA_MAC_LEN])202 zio_encrypt_os(const zio_crypt_info_t *ci,
203 crypto_key_t *key, zio_crypt_session_t *sess,
204 zfs_uio_t *plaintext, zfs_uio_t *ciphertext, size_t datalen,
205 const uint8_t iv[ZIO_DATA_IV_LEN], const uint8_t *ad, size_t adlen,
206 uint8_t mac[ZIO_DATA_MAC_LEN])
207 {
208 return (zio_encrypt_decrypt_os_common(B_TRUE, ci, key, sess,
209 plaintext, ciphertext, datalen, iv, ad, adlen, mac));
210 }
211
212 int
zio_decrypt_os(const zio_crypt_info_t * ci,crypto_key_t * key,zio_crypt_session_t * sess,zfs_uio_t * ciphertext,zfs_uio_t * plaintext,size_t datalen,const uint8_t iv[ZIO_DATA_IV_LEN],const uint8_t * ad,size_t adlen,uint8_t mac[ZIO_DATA_MAC_LEN])213 zio_decrypt_os(const zio_crypt_info_t *ci,
214 crypto_key_t *key, zio_crypt_session_t *sess,
215 zfs_uio_t *ciphertext, zfs_uio_t *plaintext, size_t datalen,
216 const uint8_t iv[ZIO_DATA_IV_LEN], const uint8_t *ad, size_t adlen,
217 uint8_t mac[ZIO_DATA_MAC_LEN])
218 {
219 return (zio_encrypt_decrypt_os_common(B_FALSE, ci, key, sess,
220 ciphertext, plaintext, datalen, iv, ad, adlen, mac));
221 }
222
223 int
zio_crypt_hmac_os(zio_crypt_key_t * key,const uint8_t * data,size_t datalen,uint8_t digest[SHA512_HMAC_LEN])224 zio_crypt_hmac_os(zio_crypt_key_t *key, const uint8_t *data, size_t datalen,
225 uint8_t digest[SHA512_HMAC_LEN])
226 {
227 /* initialize sha512-hmac mechanism */
228 crypto_mechanism_t mech = {0};
229 mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
230
231 /* initialize the crypto data */
232 crypto_data_t in = {
233 .cd_format = CRYPTO_DATA_RAW,
234 .cd_offset = 0,
235 .cd_length = datalen,
236 .cd_raw.iov_base = (void *)data,
237 .cd_raw.iov_len = datalen,
238 };
239 crypto_data_t out = {
240 .cd_format = CRYPTO_DATA_RAW,
241 .cd_offset = 0,
242 .cd_length = SHA512_HMAC_LEN,
243 .cd_raw.iov_base = (void *)digest,
244 .cd_raw.iov_len = SHA512_HMAC_LEN,
245 };
246
247 /* generate the hmac */
248 if (crypto_mac(&mech, &in, &key->zk_hmac_key,
249 key->zk_hmac_sess.zs_tmpl, &out) != CRYPTO_SUCCESS)
250 return (SET_ERROR(EIO));
251
252 return (0);
253 }
254
255 int
zio_crypt_hmac_init_os(zio_crypt_hmac_t * hmac,zio_crypt_key_t * key)256 zio_crypt_hmac_init_os(zio_crypt_hmac_t *hmac, zio_crypt_key_t *key)
257 {
258 /* initialize HMAC mechanism */
259 crypto_mechanism_t mech = {0};
260 mech.cm_type = crypto_mech2id(SUN_CKM_SHA512_HMAC);
261
262 if (crypto_mac_init(&mech, &key->zk_hmac_key, NULL,
263 &hmac->zh_ctx) != CRYPTO_SUCCESS)
264 return (SET_ERROR(EIO));
265
266 return (0);
267 }
268
269 int
zio_crypt_hmac_update_os(zio_crypt_hmac_t * hmac,const uint8_t * data,size_t datalen)270 zio_crypt_hmac_update_os(zio_crypt_hmac_t *hmac, const uint8_t *data,
271 size_t datalen)
272 {
273 crypto_data_t cd = {
274 .cd_format = CRYPTO_DATA_RAW,
275 .cd_offset = 0,
276 .cd_length = datalen,
277 .cd_raw.iov_base = (char *)data,
278 .cd_raw.iov_len = datalen,
279 };
280
281 if (crypto_mac_update(hmac->zh_ctx, &cd) != CRYPTO_SUCCESS)
282 return (SET_ERROR(EIO));
283
284 return (0);
285 }
286
287 int
zio_crypt_hmac_final_os(zio_crypt_hmac_t * hmac,uint8_t digest[SHA512_HMAC_LEN])288 zio_crypt_hmac_final_os(zio_crypt_hmac_t *hmac, uint8_t digest[SHA512_HMAC_LEN])
289 {
290 crypto_data_t cd = {
291 .cd_format = CRYPTO_DATA_RAW,
292 .cd_offset = 0,
293 .cd_length = SHA512_HMAC_LEN,
294 .cd_raw.iov_base = (char *)digest,
295 .cd_raw.iov_len = SHA512_HMAC_LEN,
296 };
297
298 if (crypto_mac_final(hmac->zh_ctx, &cd) != CRYPTO_SUCCESS)
299 return (SET_ERROR(EIO));
300
301 return (0);
302 }
303