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