xref: /freebsd/sys/contrib/openzfs/module/icp/algs/modes/modes.c (revision b1c1ee4429fcca8f69873a8be66184e68e1b19d7)
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