161145dc2SMartin Matuska // SPDX-License-Identifier: CDDL-1.0
2eda14cbcSMatt Macy /*
3eda14cbcSMatt Macy * CDDL HEADER START
4eda14cbcSMatt Macy *
5eda14cbcSMatt Macy * The contents of this file are subject to the terms of the
6eda14cbcSMatt Macy * Common Development and Distribution License (the "License").
7eda14cbcSMatt Macy * You may not use this file except in compliance with the License.
8eda14cbcSMatt Macy *
9eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
11eda14cbcSMatt Macy * See the License for the specific language governing permissions
12eda14cbcSMatt Macy * and limitations under the License.
13eda14cbcSMatt Macy *
14eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each
15eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the
17eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying
18eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner]
19eda14cbcSMatt Macy *
20eda14cbcSMatt Macy * CDDL HEADER END
21eda14cbcSMatt Macy */
22eda14cbcSMatt Macy /*
23eda14cbcSMatt Macy * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24eda14cbcSMatt Macy * Use is subject to license terms.
25eda14cbcSMatt Macy */
26eda14cbcSMatt Macy
27eda14cbcSMatt Macy #include <sys/zfs_context.h>
28eda14cbcSMatt Macy #include <modes/modes.h>
29eda14cbcSMatt Macy #include <sys/crypto/common.h>
30eda14cbcSMatt Macy #include <sys/crypto/impl.h>
31eda14cbcSMatt Macy
32eda14cbcSMatt Macy /*
33eda14cbcSMatt Macy * Initialize by setting iov_or_mp to point to the current iovec or mp,
34eda14cbcSMatt Macy * and by setting current_offset to an offset within the current iovec or mp.
35eda14cbcSMatt Macy */
36eda14cbcSMatt Macy void
crypto_init_ptrs(crypto_data_t * out,void ** iov_or_mp,offset_t * current_offset)37eda14cbcSMatt Macy crypto_init_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset)
38eda14cbcSMatt Macy {
39eda14cbcSMatt Macy offset_t offset;
40eda14cbcSMatt Macy
41eda14cbcSMatt Macy switch (out->cd_format) {
42eda14cbcSMatt Macy case CRYPTO_DATA_RAW:
43eda14cbcSMatt Macy *current_offset = out->cd_offset;
44eda14cbcSMatt Macy break;
45eda14cbcSMatt Macy
46eda14cbcSMatt Macy case CRYPTO_DATA_UIO: {
47184c1b94SMartin Matuska zfs_uio_t *uiop = out->cd_uio;
48eda14cbcSMatt Macy uint_t vec_idx;
49eda14cbcSMatt Macy
50eda14cbcSMatt Macy offset = out->cd_offset;
51184c1b94SMartin Matuska offset = zfs_uio_index_at_offset(uiop, offset, &vec_idx);
52eda14cbcSMatt Macy
53eda14cbcSMatt Macy *current_offset = offset;
54eda14cbcSMatt Macy *iov_or_mp = (void *)(uintptr_t)vec_idx;
55eda14cbcSMatt Macy break;
56eda14cbcSMatt Macy }
57eda14cbcSMatt Macy } /* end switch */
58eda14cbcSMatt Macy }
59eda14cbcSMatt Macy
60eda14cbcSMatt Macy /*
61eda14cbcSMatt Macy * Get pointers for where in the output to copy a block of encrypted or
62eda14cbcSMatt Macy * decrypted data. The iov_or_mp argument stores a pointer to the current
63eda14cbcSMatt Macy * iovec or mp, and offset stores an offset into the current iovec or mp.
64eda14cbcSMatt Macy */
65eda14cbcSMatt Macy void
crypto_get_ptrs(crypto_data_t * out,void ** iov_or_mp,offset_t * current_offset,uint8_t ** out_data_1,size_t * out_data_1_len,uint8_t ** out_data_2,size_t amt)66eda14cbcSMatt Macy crypto_get_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset,
67eda14cbcSMatt Macy uint8_t **out_data_1, size_t *out_data_1_len, uint8_t **out_data_2,
68eda14cbcSMatt Macy size_t amt)
69eda14cbcSMatt Macy {
70eda14cbcSMatt Macy offset_t offset;
71eda14cbcSMatt Macy
72eda14cbcSMatt Macy switch (out->cd_format) {
73eda14cbcSMatt Macy case CRYPTO_DATA_RAW: {
74eda14cbcSMatt Macy iovec_t *iov;
75eda14cbcSMatt Macy
76eda14cbcSMatt Macy offset = *current_offset;
77eda14cbcSMatt Macy iov = &out->cd_raw;
78eda14cbcSMatt Macy if ((offset + amt) <= iov->iov_len) {
79eda14cbcSMatt Macy /* one block fits */
80eda14cbcSMatt Macy *out_data_1 = (uint8_t *)iov->iov_base + offset;
81eda14cbcSMatt Macy *out_data_1_len = amt;
82eda14cbcSMatt Macy *out_data_2 = NULL;
83eda14cbcSMatt Macy *current_offset = offset + amt;
84eda14cbcSMatt Macy }
85eda14cbcSMatt Macy break;
86eda14cbcSMatt Macy }
87eda14cbcSMatt Macy
88eda14cbcSMatt Macy case CRYPTO_DATA_UIO: {
89184c1b94SMartin Matuska zfs_uio_t *uio = out->cd_uio;
90eda14cbcSMatt Macy offset_t offset;
91eda14cbcSMatt Macy uint_t vec_idx;
92eda14cbcSMatt Macy uint8_t *p;
93eda14cbcSMatt Macy uint64_t iov_len;
94eda14cbcSMatt Macy void *iov_base;
95eda14cbcSMatt Macy
96eda14cbcSMatt Macy offset = *current_offset;
97eda14cbcSMatt Macy vec_idx = (uintptr_t)(*iov_or_mp);
98184c1b94SMartin Matuska zfs_uio_iov_at_index(uio, vec_idx, &iov_base, &iov_len);
99eda14cbcSMatt Macy p = (uint8_t *)iov_base + offset;
100eda14cbcSMatt Macy *out_data_1 = p;
101eda14cbcSMatt Macy
102eda14cbcSMatt Macy if (offset + amt <= iov_len) {
103eda14cbcSMatt Macy /* can fit one block into this iov */
104eda14cbcSMatt Macy *out_data_1_len = amt;
105eda14cbcSMatt Macy *out_data_2 = NULL;
106eda14cbcSMatt Macy *current_offset = offset + amt;
107eda14cbcSMatt Macy } else {
108eda14cbcSMatt Macy /* one block spans two iovecs */
109eda14cbcSMatt Macy *out_data_1_len = iov_len - offset;
110dbd5678dSMartin Matuska if (vec_idx == zfs_uio_iovcnt(uio)) {
111dbd5678dSMartin Matuska *out_data_2 = NULL;
112eda14cbcSMatt Macy return;
113dbd5678dSMartin Matuska }
114eda14cbcSMatt Macy vec_idx++;
115184c1b94SMartin Matuska zfs_uio_iov_at_index(uio, vec_idx, &iov_base, &iov_len);
116eda14cbcSMatt Macy *out_data_2 = (uint8_t *)iov_base;
117eda14cbcSMatt Macy *current_offset = amt - *out_data_1_len;
118eda14cbcSMatt Macy }
119eda14cbcSMatt Macy *iov_or_mp = (void *)(uintptr_t)vec_idx;
120eda14cbcSMatt Macy break;
121eda14cbcSMatt Macy }
122eda14cbcSMatt Macy } /* end switch */
123eda14cbcSMatt Macy }
124eda14cbcSMatt Macy
125eda14cbcSMatt Macy void
crypto_free_mode_ctx(void * ctx)126eda14cbcSMatt Macy crypto_free_mode_ctx(void *ctx)
127eda14cbcSMatt Macy {
128eda14cbcSMatt Macy common_ctx_t *common_ctx = (common_ctx_t *)ctx;
129eda14cbcSMatt Macy
13075e1fea6SMartin Matuska switch (common_ctx->cc_flags & (CCM_MODE|GCM_MODE)) {
131eda14cbcSMatt Macy case CCM_MODE:
132eda14cbcSMatt Macy if (((ccm_ctx_t *)ctx)->ccm_pt_buf != NULL)
133eda14cbcSMatt Macy vmem_free(((ccm_ctx_t *)ctx)->ccm_pt_buf,
134eda14cbcSMatt Macy ((ccm_ctx_t *)ctx)->ccm_data_len);
135eda14cbcSMatt Macy
136eda14cbcSMatt Macy kmem_free(ctx, sizeof (ccm_ctx_t));
137eda14cbcSMatt Macy break;
138eda14cbcSMatt Macy
139eda14cbcSMatt Macy case GCM_MODE:
1402a58b312SMartin Matuska gcm_clear_ctx((gcm_ctx_t *)ctx);
141eda14cbcSMatt Macy kmem_free(ctx, sizeof (gcm_ctx_t));
14275e1fea6SMartin Matuska break;
14375e1fea6SMartin Matuska
14475e1fea6SMartin Matuska default:
14575e1fea6SMartin Matuska __builtin_unreachable();
146eda14cbcSMatt Macy }
147eda14cbcSMatt Macy }
1482a58b312SMartin Matuska
1492a58b312SMartin Matuska static void *
explicit_memset(void * s,int c,size_t n)1502a58b312SMartin Matuska explicit_memset(void *s, int c, size_t n)
1512a58b312SMartin Matuska {
1522a58b312SMartin Matuska memset(s, c, n);
1532a58b312SMartin Matuska __asm__ __volatile__("" :: "r"(s) : "memory");
1542a58b312SMartin Matuska return (s);
1552a58b312SMartin Matuska }
1562a58b312SMartin Matuska
1572a58b312SMartin Matuska /*
1582a58b312SMartin Matuska * Clear sensitive data in the context and free allocated memory.
1592a58b312SMartin Matuska *
1602a58b312SMartin Matuska * ctx->gcm_remainder may contain a plaintext remainder. ctx->gcm_H and
1612a58b312SMartin Matuska * ctx->gcm_Htable contain the hash sub key which protects authentication.
1622a58b312SMartin Matuska * ctx->gcm_pt_buf contains the plaintext result of decryption.
1632a58b312SMartin Matuska *
1642a58b312SMartin Matuska * Although extremely unlikely, ctx->gcm_J0 and ctx->gcm_tmp could be used for
1652a58b312SMartin Matuska * a known plaintext attack, they consist of the IV and the first and last
1662a58b312SMartin Matuska * counter respectively. If they should be cleared is debatable.
1672a58b312SMartin Matuska */
1682a58b312SMartin Matuska void
gcm_clear_ctx(gcm_ctx_t * ctx)1692a58b312SMartin Matuska gcm_clear_ctx(gcm_ctx_t *ctx)
1702a58b312SMartin Matuska {
1712a58b312SMartin Matuska explicit_memset(ctx->gcm_remainder, 0, sizeof (ctx->gcm_remainder));
1722a58b312SMartin Matuska explicit_memset(ctx->gcm_H, 0, sizeof (ctx->gcm_H));
1732a58b312SMartin Matuska #if defined(CAN_USE_GCM_ASM)
1742a58b312SMartin Matuska if (ctx->gcm_use_avx == B_TRUE) {
1752a58b312SMartin Matuska ASSERT3P(ctx->gcm_Htable, !=, NULL);
176*b1c1ee44SMartin Matuska explicit_memset(ctx->gcm_Htable, 0, ctx->gcm_htab_len);
1772a58b312SMartin Matuska kmem_free(ctx->gcm_Htable, ctx->gcm_htab_len);
1782a58b312SMartin Matuska }
1792a58b312SMartin Matuska #endif
1802a58b312SMartin Matuska if (ctx->gcm_pt_buf != NULL) {
181*b1c1ee44SMartin Matuska explicit_memset(ctx->gcm_pt_buf, 0, ctx->gcm_pt_buf_len);
1822a58b312SMartin Matuska vmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
1832a58b312SMartin Matuska }
1842a58b312SMartin Matuska /* Optional */
1852a58b312SMartin Matuska explicit_memset(ctx->gcm_J0, 0, sizeof (ctx->gcm_J0));
1862a58b312SMartin Matuska explicit_memset(ctx->gcm_tmp, 0, sizeof (ctx->gcm_tmp));
1872a58b312SMartin Matuska }
188