1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#ifndef _KERNEL
27#include <stdlib.h>
28#endif
29
30#include <sys/strsun.h>
31#include <sys/types.h>
32#include <modes/modes.h>
33#include <sys/crypto/common.h>
34#include <sys/crypto/impl.h>
35
36/*
37 * Initialize by setting iov_or_mp to point to the current iovec or mp,
38 * and by setting current_offset to an offset within the current iovec or mp.
39 */
40void
41crypto_init_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset)
42{
43	offset_t offset;
44
45	switch (out->cd_format) {
46	case CRYPTO_DATA_RAW:
47		*current_offset = out->cd_offset;
48		break;
49
50	case CRYPTO_DATA_UIO: {
51		uio_t *uiop = out->cd_uio;
52		uintptr_t vec_idx;
53
54		offset = out->cd_offset;
55		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
56		    offset >= uiop->uio_iov[vec_idx].iov_len;
57		    offset -= uiop->uio_iov[vec_idx++].iov_len)
58			;
59
60		*current_offset = offset;
61		*iov_or_mp = (void *)vec_idx;
62		break;
63	}
64
65	case CRYPTO_DATA_MBLK: {
66		mblk_t *mp;
67
68		offset = out->cd_offset;
69		for (mp = out->cd_mp; mp != NULL && offset >= MBLKL(mp);
70		    offset -= MBLKL(mp), mp = mp->b_cont)
71			;
72
73		*current_offset = offset;
74		*iov_or_mp = mp;
75		break;
76
77	}
78	} /* end switch */
79}
80
81/*
82 * Get pointers for where in the output to copy a block of encrypted or
83 * decrypted data.  The iov_or_mp argument stores a pointer to the current
84 * iovec or mp, and offset stores an offset into the current iovec or mp.
85 */
86void
87crypto_get_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset,
88    uint8_t **out_data_1, size_t *out_data_1_len, uint8_t **out_data_2,
89    size_t amt)
90{
91	offset_t offset;
92
93	switch (out->cd_format) {
94	case CRYPTO_DATA_RAW: {
95		iovec_t *iov;
96
97		offset = *current_offset;
98		iov = &out->cd_raw;
99		if ((offset + amt) <= iov->iov_len) {
100			/* one block fits */
101			*out_data_1 = (uint8_t *)iov->iov_base + offset;
102			*out_data_1_len = amt;
103			*out_data_2 = NULL;
104			*current_offset = offset + amt;
105		}
106		break;
107	}
108
109	case CRYPTO_DATA_UIO: {
110		uio_t *uio = out->cd_uio;
111		iovec_t *iov;
112		offset_t offset;
113		uintptr_t vec_idx;
114		uint8_t *p;
115
116		offset = *current_offset;
117		vec_idx = (uintptr_t)(*iov_or_mp);
118		iov = &uio->uio_iov[vec_idx];
119		p = (uint8_t *)iov->iov_base + offset;
120		*out_data_1 = p;
121
122		if (offset + amt <= iov->iov_len) {
123			/* can fit one block into this iov */
124			*out_data_1_len = amt;
125			*out_data_2 = NULL;
126			*current_offset = offset + amt;
127		} else {
128			/* one block spans two iovecs */
129			*out_data_1_len = iov->iov_len - offset;
130			if (vec_idx == uio->uio_iovcnt)
131				return;
132			vec_idx++;
133			iov = &uio->uio_iov[vec_idx];
134			*out_data_2 = (uint8_t *)iov->iov_base;
135			*current_offset = amt - *out_data_1_len;
136		}
137		*iov_or_mp = (void *)vec_idx;
138		break;
139	}
140
141	case CRYPTO_DATA_MBLK: {
142		mblk_t *mp;
143		uint8_t *p;
144
145		offset = *current_offset;
146		mp = (mblk_t *)*iov_or_mp;
147		p = mp->b_rptr + offset;
148		*out_data_1 = p;
149		if ((p + amt) <= mp->b_wptr) {
150			/* can fit one block into this mblk */
151			*out_data_1_len = amt;
152			*out_data_2 = NULL;
153			*current_offset = offset + amt;
154		} else {
155			/* one block spans two mblks */
156			*out_data_1_len = _PTRDIFF(mp->b_wptr, p);
157			if ((mp = mp->b_cont) == NULL)
158				return;
159			*out_data_2 = mp->b_rptr;
160			*current_offset = (amt - *out_data_1_len);
161		}
162		*iov_or_mp = mp;
163		break;
164	}
165	} /* end switch */
166}
167
168void
169crypto_free_mode_ctx(void *ctx)
170{
171	common_ctx_t *common_ctx = (common_ctx_t *)ctx;
172
173	switch (common_ctx->cc_flags &
174	    (ECB_MODE|CBC_MODE|CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) {
175	case ECB_MODE:
176#ifdef _KERNEL
177		kmem_free(common_ctx, sizeof (ecb_ctx_t));
178#else
179		free(common_ctx);
180#endif
181		break;
182
183	case CBC_MODE:
184#ifdef _KERNEL
185		kmem_free(common_ctx, sizeof (cbc_ctx_t));
186#else
187		free(common_ctx);
188#endif
189		break;
190
191	case CTR_MODE:
192#ifdef _KERNEL
193		kmem_free(common_ctx, sizeof (ctr_ctx_t));
194#else
195		free(common_ctx);
196#endif
197		break;
198
199	case CCM_MODE:
200#ifdef _KERNEL
201		if (((ccm_ctx_t *)ctx)->ccm_pt_buf != NULL)
202			kmem_free(((ccm_ctx_t *)ctx)->ccm_pt_buf,
203			    ((ccm_ctx_t *)ctx)->ccm_data_len);
204
205		kmem_free(ctx, sizeof (ccm_ctx_t));
206#else
207		if (((ccm_ctx_t *)ctx)->ccm_pt_buf != NULL)
208			free(((ccm_ctx_t *)ctx)->ccm_pt_buf);
209		free(ctx);
210#endif
211		break;
212
213	case GCM_MODE:
214	case GMAC_MODE:
215#ifdef _KERNEL
216		if (((gcm_ctx_t *)ctx)->gcm_pt_buf != NULL)
217			kmem_free(((gcm_ctx_t *)ctx)->gcm_pt_buf,
218			    ((gcm_ctx_t *)ctx)->gcm_pt_buf_len);
219
220		kmem_free(ctx, sizeof (gcm_ctx_t));
221#else
222		if (((gcm_ctx_t *)ctx)->gcm_pt_buf != NULL)
223			free(((gcm_ctx_t *)ctx)->gcm_pt_buf);
224		free(ctx);
225#endif
226	}
227}
228