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