xref: /onnv-gate/usr/src/uts/common/crypto/io/blowfish.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * Blowfish provider for the Kernel Cryptographic Framework (KCF)
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/systm.h>
35*0Sstevel@tonic-gate #include <sys/modctl.h>
36*0Sstevel@tonic-gate #include <sys/cmn_err.h>
37*0Sstevel@tonic-gate #include <sys/ddi.h>
38*0Sstevel@tonic-gate #include <sys/crypto/common.h>
39*0Sstevel@tonic-gate #include <sys/crypto/spi.h>
40*0Sstevel@tonic-gate #include <sys/sysmacros.h>
41*0Sstevel@tonic-gate #include <sys/strsun.h>
42*0Sstevel@tonic-gate #include <sys/note.h>
43*0Sstevel@tonic-gate #include <blowfish_impl.h>
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate extern struct mod_ops mod_cryptoops;
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate /*
48*0Sstevel@tonic-gate  * Module linkage information for the kernel.
49*0Sstevel@tonic-gate  */
50*0Sstevel@tonic-gate static struct modlcrypto modlcrypto = {
51*0Sstevel@tonic-gate 	&mod_cryptoops,
52*0Sstevel@tonic-gate 	"Blowfish Kernel SW Provider %I%"
53*0Sstevel@tonic-gate };
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
56*0Sstevel@tonic-gate 	MODREV_1,
57*0Sstevel@tonic-gate 	(void *)&modlcrypto,
58*0Sstevel@tonic-gate 	NULL
59*0Sstevel@tonic-gate };
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate /*
62*0Sstevel@tonic-gate  * CSPI information (entry points, provider info, etc.)
63*0Sstevel@tonic-gate  */
64*0Sstevel@tonic-gate typedef enum blowfish_mech_type {
65*0Sstevel@tonic-gate 	BF_ECB_MECH_INFO_TYPE,		/* SUN_CKM_BF_ECB */
66*0Sstevel@tonic-gate 	BF_CBC_MECH_INFO_TYPE		/* SUN_CKM_BF_CBC */
67*0Sstevel@tonic-gate } blowfish_mech_type_t;
68*0Sstevel@tonic-gate 
69*0Sstevel@tonic-gate /*
70*0Sstevel@tonic-gate  * bc_keysched:		Pointer to key schedule.
71*0Sstevel@tonic-gate  *
72*0Sstevel@tonic-gate  * bc_keysched_len:	Length of the key schedule.
73*0Sstevel@tonic-gate  *
74*0Sstevel@tonic-gate  * bc_remainder:	This is for residual data, i.e. data that can't
75*0Sstevel@tonic-gate  *			be processed because there are too few bytes.
76*0Sstevel@tonic-gate  *			Must wait until more data arrives.
77*0Sstevel@tonic-gate  *
78*0Sstevel@tonic-gate  * bc_remainder_len:	Number of bytes in bc_remainder.
79*0Sstevel@tonic-gate  *
80*0Sstevel@tonic-gate  * bc_iv:		Scratch buffer that sometimes contains the IV.
81*0Sstevel@tonic-gate  *
82*0Sstevel@tonic-gate  * bc_lastblock:	Scratch buffer.
83*0Sstevel@tonic-gate  *
84*0Sstevel@tonic-gate  * bc_lastp:		Pointer to previous block of ciphertext.
85*0Sstevel@tonic-gate  *
86*0Sstevel@tonic-gate  * bc_copy_to:		Pointer to where encrypted residual data needs
87*0Sstevel@tonic-gate  *			to be copied.
88*0Sstevel@tonic-gate  *
89*0Sstevel@tonic-gate  * bc_flags:		BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE
90*0Sstevel@tonic-gate  *			When a context is freed, it is necessary
91*0Sstevel@tonic-gate  *			to know whether the key schedule was allocated
92*0Sstevel@tonic-gate  *			by the caller, or by blowfish_common_init().
93*0Sstevel@tonic-gate  *			If allocated by the latter, then it needs to be freed.
94*0Sstevel@tonic-gate  *
95*0Sstevel@tonic-gate  *			BLOWFISH_CBC_MODE
96*0Sstevel@tonic-gate  *			If flag is not set, the mode is BLOWFISH_ECB_MODE.
97*0Sstevel@tonic-gate  *
98*0Sstevel@tonic-gate  */
99*0Sstevel@tonic-gate typedef struct blowfish_ctx {
100*0Sstevel@tonic-gate 	void *bc_keysched;
101*0Sstevel@tonic-gate 	size_t bc_keysched_len;
102*0Sstevel@tonic-gate 	uint64_t bc_iv;
103*0Sstevel@tonic-gate 	uint64_t bc_lastblock;
104*0Sstevel@tonic-gate 	uint64_t bc_remainder;
105*0Sstevel@tonic-gate 	size_t bc_remainder_len;
106*0Sstevel@tonic-gate 	uint8_t *bc_lastp;
107*0Sstevel@tonic-gate 	uint8_t *bc_copy_to;
108*0Sstevel@tonic-gate 	uint32_t bc_flags;
109*0Sstevel@tonic-gate } blowfish_ctx_t;
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate #define	BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE	0x00000001
112*0Sstevel@tonic-gate #define	BLOWFISH_CBC_MODE			0x00000002
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate #define	BLOWFISH_COPY_BLOCK(src, dst) \
115*0Sstevel@tonic-gate 	(dst)[0] = (src)[0]; \
116*0Sstevel@tonic-gate 	(dst)[1] = (src)[1]; \
117*0Sstevel@tonic-gate 	(dst)[2] = (src)[2]; \
118*0Sstevel@tonic-gate 	(dst)[3] = (src)[3]; \
119*0Sstevel@tonic-gate 	(dst)[4] = (src)[4]; \
120*0Sstevel@tonic-gate 	(dst)[5] = (src)[5]; \
121*0Sstevel@tonic-gate 	(dst)[6] = (src)[6]; \
122*0Sstevel@tonic-gate 	(dst)[7] = (src)[7]
123*0Sstevel@tonic-gate 
124*0Sstevel@tonic-gate #define	BLOWFISH_XOR_BLOCK(src, dst) \
125*0Sstevel@tonic-gate 	(dst)[0] ^= (src)[0]; \
126*0Sstevel@tonic-gate 	(dst)[1] ^= (src)[1]; \
127*0Sstevel@tonic-gate 	(dst)[2] ^= (src)[2]; \
128*0Sstevel@tonic-gate 	(dst)[3] ^= (src)[3]; \
129*0Sstevel@tonic-gate 	(dst)[4] ^= (src)[4]; \
130*0Sstevel@tonic-gate 	(dst)[5] ^= (src)[5]; \
131*0Sstevel@tonic-gate 	(dst)[6] ^= (src)[6]; \
132*0Sstevel@tonic-gate 	(dst)[7] ^= (src)[7]
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate /*
135*0Sstevel@tonic-gate  * Mechanism info structure passed to KCF during registration.
136*0Sstevel@tonic-gate  */
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate static crypto_mech_info_t blowfish_mech_info_tab[] = {
139*0Sstevel@tonic-gate 	/* BLOWFISH_ECB */
140*0Sstevel@tonic-gate 	{SUN_CKM_BF_ECB, BF_ECB_MECH_INFO_TYPE,
141*0Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
142*0Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
143*0Sstevel@tonic-gate 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS},
144*0Sstevel@tonic-gate 	/* BLOWFISH_CBC */
145*0Sstevel@tonic-gate 	{SUN_CKM_BF_CBC, BF_CBC_MECH_INFO_TYPE,
146*0Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
147*0Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
148*0Sstevel@tonic-gate 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS}
149*0Sstevel@tonic-gate };
150*0Sstevel@tonic-gate 
151*0Sstevel@tonic-gate #define	BLOWFISH_VALID_MECH(mech)				\
152*0Sstevel@tonic-gate 	(((mech)->cm_type == BF_ECB_MECH_INFO_TYPE ||		\
153*0Sstevel@tonic-gate 	(mech)->cm_type == BF_CBC_MECH_INFO_TYPE) ? 1 : 0)
154*0Sstevel@tonic-gate 
155*0Sstevel@tonic-gate /* operations are in-place if the output buffer is NULL */
156*0Sstevel@tonic-gate #define	BLOWFISH_ARG_INPLACE(input, output)			\
157*0Sstevel@tonic-gate 	if ((output) == NULL)					\
158*0Sstevel@tonic-gate 		(output) = (input);
159*0Sstevel@tonic-gate 
160*0Sstevel@tonic-gate static void blowfish_provider_status(crypto_provider_handle_t, uint_t *);
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate static crypto_control_ops_t blowfish_control_ops = {
163*0Sstevel@tonic-gate 	blowfish_provider_status
164*0Sstevel@tonic-gate };
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate static int blowfish_common_init(crypto_ctx_t *, crypto_mechanism_t *,
167*0Sstevel@tonic-gate     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
168*0Sstevel@tonic-gate static int blowfish_common_init_ctx(blowfish_ctx_t *,
169*0Sstevel@tonic-gate     crypto_spi_ctx_template_t *, crypto_mechanism_t *, crypto_key_t *, int);
170*0Sstevel@tonic-gate static int blowfish_encrypt_final(crypto_ctx_t *, crypto_data_t *,
171*0Sstevel@tonic-gate     crypto_req_handle_t);
172*0Sstevel@tonic-gate static int blowfish_decrypt_final(crypto_ctx_t *, crypto_data_t *,
173*0Sstevel@tonic-gate     crypto_req_handle_t);
174*0Sstevel@tonic-gate 
175*0Sstevel@tonic-gate static int blowfish_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
176*0Sstevel@tonic-gate     crypto_req_handle_t);
177*0Sstevel@tonic-gate static int blowfish_encrypt_update(crypto_ctx_t *, crypto_data_t *,
178*0Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
179*0Sstevel@tonic-gate static int blowfish_encrypt_atomic(crypto_provider_handle_t,
180*0Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
181*0Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate static int blowfish_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
184*0Sstevel@tonic-gate     crypto_req_handle_t);
185*0Sstevel@tonic-gate static int blowfish_decrypt_update(crypto_ctx_t *, crypto_data_t *,
186*0Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
187*0Sstevel@tonic-gate static int blowfish_decrypt_atomic(crypto_provider_handle_t,
188*0Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
189*0Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate static crypto_cipher_ops_t blowfish_cipher_ops = {
192*0Sstevel@tonic-gate 	blowfish_common_init,
193*0Sstevel@tonic-gate 	blowfish_encrypt,
194*0Sstevel@tonic-gate 	blowfish_encrypt_update,
195*0Sstevel@tonic-gate 	blowfish_encrypt_final,
196*0Sstevel@tonic-gate 	blowfish_encrypt_atomic,
197*0Sstevel@tonic-gate 	blowfish_common_init,
198*0Sstevel@tonic-gate 	blowfish_decrypt,
199*0Sstevel@tonic-gate 	blowfish_decrypt_update,
200*0Sstevel@tonic-gate 	blowfish_decrypt_final,
201*0Sstevel@tonic-gate 	blowfish_decrypt_atomic
202*0Sstevel@tonic-gate };
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate static int blowfish_create_ctx_template(crypto_provider_handle_t,
205*0Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
206*0Sstevel@tonic-gate     size_t *, crypto_req_handle_t);
207*0Sstevel@tonic-gate static int blowfish_free_context(crypto_ctx_t *);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate static crypto_ctx_ops_t blowfish_ctx_ops = {
210*0Sstevel@tonic-gate 	blowfish_create_ctx_template,
211*0Sstevel@tonic-gate 	blowfish_free_context
212*0Sstevel@tonic-gate };
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate static crypto_ops_t blowfish_crypto_ops = {
215*0Sstevel@tonic-gate 	&blowfish_control_ops,
216*0Sstevel@tonic-gate 	NULL,
217*0Sstevel@tonic-gate 	&blowfish_cipher_ops,
218*0Sstevel@tonic-gate 	NULL,
219*0Sstevel@tonic-gate 	NULL,
220*0Sstevel@tonic-gate 	NULL,
221*0Sstevel@tonic-gate 	NULL,
222*0Sstevel@tonic-gate 	NULL,
223*0Sstevel@tonic-gate 	NULL,
224*0Sstevel@tonic-gate 	NULL,
225*0Sstevel@tonic-gate 	NULL,
226*0Sstevel@tonic-gate 	NULL,
227*0Sstevel@tonic-gate 	NULL,
228*0Sstevel@tonic-gate 	&blowfish_ctx_ops
229*0Sstevel@tonic-gate };
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate static crypto_provider_info_t blowfish_prov_info = {
232*0Sstevel@tonic-gate 	CRYPTO_SPI_VERSION_1,
233*0Sstevel@tonic-gate 	"Blowfish Software Provider",
234*0Sstevel@tonic-gate 	CRYPTO_SW_PROVIDER,
235*0Sstevel@tonic-gate 	{&modlinkage},
236*0Sstevel@tonic-gate 	NULL,
237*0Sstevel@tonic-gate 	&blowfish_crypto_ops,
238*0Sstevel@tonic-gate 	sizeof (blowfish_mech_info_tab)/sizeof (crypto_mech_info_t),
239*0Sstevel@tonic-gate 	blowfish_mech_info_tab
240*0Sstevel@tonic-gate };
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate static int blowfish_encrypt_contiguous_blocks(blowfish_ctx_t *, char *, size_t,
243*0Sstevel@tonic-gate     crypto_data_t *);
244*0Sstevel@tonic-gate static int blowfish_decrypt_contiguous_blocks(blowfish_ctx_t *, char *, size_t,
245*0Sstevel@tonic-gate     crypto_data_t *);
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate static crypto_kcf_provider_handle_t blowfish_prov_handle = NULL;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate int
250*0Sstevel@tonic-gate _init(void)
251*0Sstevel@tonic-gate {
252*0Sstevel@tonic-gate 	int ret;
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	/*
255*0Sstevel@tonic-gate 	 * Register with KCF. If the registration fails, return error.
256*0Sstevel@tonic-gate 	 */
257*0Sstevel@tonic-gate 	if ((ret = crypto_register_provider(&blowfish_prov_info,
258*0Sstevel@tonic-gate 	    &blowfish_prov_handle)) != CRYPTO_SUCCESS) {
259*0Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s _init: crypto_register_provider() "
260*0Sstevel@tonic-gate 		    "failed (0x%x)", CRYPTO_PROVIDER_NAME, ret);
261*0Sstevel@tonic-gate 		return (EACCES);
262*0Sstevel@tonic-gate 	}
263*0Sstevel@tonic-gate 
264*0Sstevel@tonic-gate 	if ((ret = mod_install(&modlinkage)) != 0) {
265*0Sstevel@tonic-gate 		int rv;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 		ASSERT(blowfish_prov_handle != NULL);
268*0Sstevel@tonic-gate 		/* We should not return if the unregister returns busy. */
269*0Sstevel@tonic-gate 		while ((rv = crypto_unregister_provider(blowfish_prov_handle))
270*0Sstevel@tonic-gate 		    == CRYPTO_BUSY) {
271*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
272*0Sstevel@tonic-gate 			    "%s _init: crypto_unregister_provider() "
273*0Sstevel@tonic-gate 			    "failed (0x%x). Retrying.",
274*0Sstevel@tonic-gate 			    CRYPTO_PROVIDER_NAME, rv);
275*0Sstevel@tonic-gate 			/* wait 10 seconds and try again */
276*0Sstevel@tonic-gate 			delay(10 * drv_usectohz(1000000));
277*0Sstevel@tonic-gate 		}
278*0Sstevel@tonic-gate 	}
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	return (ret);
281*0Sstevel@tonic-gate }
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate int
284*0Sstevel@tonic-gate _fini(void)
285*0Sstevel@tonic-gate {
286*0Sstevel@tonic-gate 	int ret;
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	/*
289*0Sstevel@tonic-gate 	 * Unregister from KCF if previous registration succeeded.
290*0Sstevel@tonic-gate 	 */
291*0Sstevel@tonic-gate 	if (blowfish_prov_handle != NULL) {
292*0Sstevel@tonic-gate 		if ((ret = crypto_unregister_provider(blowfish_prov_handle)) !=
293*0Sstevel@tonic-gate 		    CRYPTO_SUCCESS) {
294*0Sstevel@tonic-gate 			cmn_err(CE_WARN,
295*0Sstevel@tonic-gate 			    "%s _fini: crypto_unregister_provider() "
296*0Sstevel@tonic-gate 			    "failed (0x%x)", CRYPTO_PROVIDER_NAME, ret);
297*0Sstevel@tonic-gate 			return (EBUSY);
298*0Sstevel@tonic-gate 		}
299*0Sstevel@tonic-gate 		blowfish_prov_handle = NULL;
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate int
306*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate /*
312*0Sstevel@tonic-gate  * Initialize key schedules for blowfish
313*0Sstevel@tonic-gate  */
314*0Sstevel@tonic-gate static int
315*0Sstevel@tonic-gate init_keysched(crypto_key_t *key, void *keysched)
316*0Sstevel@tonic-gate {
317*0Sstevel@tonic-gate /* EXPORT DELETE START */
318*0Sstevel@tonic-gate 	/*
319*0Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
320*0Sstevel@tonic-gate 	 */
321*0Sstevel@tonic-gate 	switch (key->ck_format) {
322*0Sstevel@tonic-gate 	case CRYPTO_KEY_RAW:
323*0Sstevel@tonic-gate 		if (key->ck_length < BLOWFISH_MINBITS ||
324*0Sstevel@tonic-gate 		    key->ck_length > BLOWFISH_MAXBITS) {
325*0Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
326*0Sstevel@tonic-gate 		}
327*0Sstevel@tonic-gate 		break;
328*0Sstevel@tonic-gate 	default:
329*0Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
330*0Sstevel@tonic-gate 	}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	blowfish_init_keysched(key->ck_data, key->ck_length, keysched);
333*0Sstevel@tonic-gate /* EXPORT DELETE END */
334*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
335*0Sstevel@tonic-gate }
336*0Sstevel@tonic-gate 
337*0Sstevel@tonic-gate /*
338*0Sstevel@tonic-gate  * KCF software provider control entry points.
339*0Sstevel@tonic-gate  */
340*0Sstevel@tonic-gate /* ARGSUSED */
341*0Sstevel@tonic-gate static void
342*0Sstevel@tonic-gate blowfish_provider_status(crypto_provider_handle_t provider, uint_t *status)
343*0Sstevel@tonic-gate {
344*0Sstevel@tonic-gate 	*status = CRYPTO_PROVIDER_READY;
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate /*
348*0Sstevel@tonic-gate  * KCF software provider encrypt entry points.
349*0Sstevel@tonic-gate  */
350*0Sstevel@tonic-gate static int
351*0Sstevel@tonic-gate blowfish_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
352*0Sstevel@tonic-gate     crypto_key_t *key, crypto_spi_ctx_template_t template,
353*0Sstevel@tonic-gate     crypto_req_handle_t req)
354*0Sstevel@tonic-gate {
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate /* EXPORT DELETE START */
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
359*0Sstevel@tonic-gate 	int rv;
360*0Sstevel@tonic-gate 	int kmflag;
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	/*
363*0Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
364*0Sstevel@tonic-gate 	 */
365*0Sstevel@tonic-gate 	if (key->ck_format != CRYPTO_KEY_RAW) {
366*0Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
367*0Sstevel@tonic-gate 	}
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
370*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
371*0Sstevel@tonic-gate 
372*0Sstevel@tonic-gate 	if (mechanism->cm_param != NULL &&
373*0Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
374*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 	/*
377*0Sstevel@tonic-gate 	 * Allocate a blowfish context.
378*0Sstevel@tonic-gate 	 */
379*0Sstevel@tonic-gate 	kmflag = crypto_kmflag(req);
380*0Sstevel@tonic-gate 	blowfish_ctx = kmem_zalloc(sizeof (blowfish_ctx_t), kmflag);
381*0Sstevel@tonic-gate 	if (blowfish_ctx == NULL)
382*0Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	rv = blowfish_common_init_ctx(blowfish_ctx, template, mechanism,
385*0Sstevel@tonic-gate 	    key, kmflag);
386*0Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
387*0Sstevel@tonic-gate 		kmem_free(blowfish_ctx, sizeof (blowfish_ctx_t));
388*0Sstevel@tonic-gate 		return (rv);
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 
391*0Sstevel@tonic-gate 	ctx->cc_provider_private = blowfish_ctx;
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate /* EXPORT DELETE END */
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
396*0Sstevel@tonic-gate }
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate /*
399*0Sstevel@tonic-gate  * Helper blowfish encrypt update function for iov input data.
400*0Sstevel@tonic-gate  */
401*0Sstevel@tonic-gate static int
402*0Sstevel@tonic-gate blowfish_cipher_update_iov(blowfish_ctx_t *blowfish_ctx, crypto_data_t *input,
403*0Sstevel@tonic-gate     crypto_data_t *output, int (*cipher)(blowfish_ctx_t *, caddr_t, size_t,
404*0Sstevel@tonic-gate     crypto_data_t *))
405*0Sstevel@tonic-gate {
406*0Sstevel@tonic-gate 	if (input->cd_miscdata != NULL) {
407*0Sstevel@tonic-gate 		if (IS_P2ALIGNED(input->cd_miscdata, sizeof (uint64_t))) {
408*0Sstevel@tonic-gate 			/* LINTED: pointer alignment */
409*0Sstevel@tonic-gate 			blowfish_ctx->bc_iv = *(uint64_t *)input->cd_miscdata;
410*0Sstevel@tonic-gate 		} else {
411*0Sstevel@tonic-gate 			uint8_t *miscdata8 = (uint8_t *)&input->cd_miscdata[0];
412*0Sstevel@tonic-gate 			uint8_t *iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 			BLOWFISH_COPY_BLOCK(miscdata8, iv8);
415*0Sstevel@tonic-gate 		}
416*0Sstevel@tonic-gate 	}
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 	if (input->cd_raw.iov_len < input->cd_length)
419*0Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	return (cipher)(blowfish_ctx, input->cd_raw.iov_base + input->cd_offset,
422*0Sstevel@tonic-gate 	    input->cd_length, (input == output) ? NULL : output);
423*0Sstevel@tonic-gate }
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate /*
426*0Sstevel@tonic-gate  * Helper blowfish encrypt update function for uio input data.
427*0Sstevel@tonic-gate  */
428*0Sstevel@tonic-gate static int
429*0Sstevel@tonic-gate blowfish_cipher_update_uio(blowfish_ctx_t *blowfish_ctx, crypto_data_t *input,
430*0Sstevel@tonic-gate     crypto_data_t *output, int (*cipher)(blowfish_ctx_t *, caddr_t, size_t,
431*0Sstevel@tonic-gate     crypto_data_t *))
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	uio_t *uiop = input->cd_uio;
434*0Sstevel@tonic-gate 	off_t offset = input->cd_offset;
435*0Sstevel@tonic-gate 	size_t length = input->cd_length;
436*0Sstevel@tonic-gate 	uint_t vec_idx;
437*0Sstevel@tonic-gate 	size_t cur_len;
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 	if (input->cd_miscdata != NULL) {
440*0Sstevel@tonic-gate 		if (IS_P2ALIGNED(input->cd_miscdata, sizeof (uint64_t))) {
441*0Sstevel@tonic-gate 			/*LINTED: pointer alignment */
442*0Sstevel@tonic-gate 			blowfish_ctx->bc_iv = *(uint64_t *)input->cd_miscdata;
443*0Sstevel@tonic-gate 		} else {
444*0Sstevel@tonic-gate 			uint8_t *miscdata8 = (uint8_t *)&input->cd_miscdata[0];
445*0Sstevel@tonic-gate 			uint8_t *iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 			BLOWFISH_COPY_BLOCK(miscdata8, iv8);
448*0Sstevel@tonic-gate 		}
449*0Sstevel@tonic-gate 	}
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 	if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
452*0Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
453*0Sstevel@tonic-gate 	}
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	/*
456*0Sstevel@tonic-gate 	 * Jump to the first iovec containing data to be
457*0Sstevel@tonic-gate 	 * processed.
458*0Sstevel@tonic-gate 	 */
459*0Sstevel@tonic-gate 	for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
460*0Sstevel@tonic-gate 	    offset >= uiop->uio_iov[vec_idx].iov_len;
461*0Sstevel@tonic-gate 	    offset -= uiop->uio_iov[vec_idx++].iov_len);
462*0Sstevel@tonic-gate 	if (vec_idx == uiop->uio_iovcnt) {
463*0Sstevel@tonic-gate 		/*
464*0Sstevel@tonic-gate 		 * The caller specified an offset that is larger than the
465*0Sstevel@tonic-gate 		 * total size of the buffers it provided.
466*0Sstevel@tonic-gate 		 */
467*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	/*
471*0Sstevel@tonic-gate 	 * Now process the iovecs.
472*0Sstevel@tonic-gate 	 */
473*0Sstevel@tonic-gate 	while (vec_idx < uiop->uio_iovcnt && length > 0) {
474*0Sstevel@tonic-gate 		cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
475*0Sstevel@tonic-gate 		    offset, length);
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 		(cipher)(blowfish_ctx, uiop->uio_iov[vec_idx].iov_base +
478*0Sstevel@tonic-gate 		    offset, cur_len, (input == output) ? NULL : output);
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate 		length -= cur_len;
481*0Sstevel@tonic-gate 		vec_idx++;
482*0Sstevel@tonic-gate 		offset = 0;
483*0Sstevel@tonic-gate 	}
484*0Sstevel@tonic-gate 
485*0Sstevel@tonic-gate 	if (vec_idx == uiop->uio_iovcnt && length > 0) {
486*0Sstevel@tonic-gate 		/*
487*0Sstevel@tonic-gate 		 * The end of the specified iovec's was reached but
488*0Sstevel@tonic-gate 		 * the length requested could not be processed, i.e.
489*0Sstevel@tonic-gate 		 * The caller requested to digest more data than it provided.
490*0Sstevel@tonic-gate 		 */
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
496*0Sstevel@tonic-gate }
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate /*
499*0Sstevel@tonic-gate  * Helper blowfish encrypt update function for mblk input data.
500*0Sstevel@tonic-gate  */
501*0Sstevel@tonic-gate static int
502*0Sstevel@tonic-gate blowfish_cipher_update_mp(blowfish_ctx_t *blowfish_ctx, crypto_data_t *input,
503*0Sstevel@tonic-gate     crypto_data_t *output, int (*cipher)(blowfish_ctx_t *, caddr_t, size_t,
504*0Sstevel@tonic-gate     crypto_data_t *))
505*0Sstevel@tonic-gate {
506*0Sstevel@tonic-gate 	off_t offset = input->cd_offset;
507*0Sstevel@tonic-gate 	size_t length = input->cd_length;
508*0Sstevel@tonic-gate 	mblk_t *mp;
509*0Sstevel@tonic-gate 	size_t cur_len;
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	if (input->cd_miscdata != NULL) {
512*0Sstevel@tonic-gate 		if (IS_P2ALIGNED(input->cd_miscdata, sizeof (uint64_t))) {
513*0Sstevel@tonic-gate 			/*LINTED: pointer alignment */
514*0Sstevel@tonic-gate 			blowfish_ctx->bc_iv = *(uint64_t *)input->cd_miscdata;
515*0Sstevel@tonic-gate 		} else {
516*0Sstevel@tonic-gate 			uint8_t *miscdata8 = (uint8_t *)&input->cd_miscdata[0];
517*0Sstevel@tonic-gate 			uint8_t *iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 			BLOWFISH_COPY_BLOCK(miscdata8, iv8);
520*0Sstevel@tonic-gate 		}
521*0Sstevel@tonic-gate 	}
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate 	/*
524*0Sstevel@tonic-gate 	 * Jump to the first mblk_t containing data to be processed.
525*0Sstevel@tonic-gate 	 */
526*0Sstevel@tonic-gate 	for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
527*0Sstevel@tonic-gate 	    offset -= MBLKL(mp), mp = mp->b_cont);
528*0Sstevel@tonic-gate 	if (mp == NULL) {
529*0Sstevel@tonic-gate 		/*
530*0Sstevel@tonic-gate 		 * The caller specified an offset that is larger than the
531*0Sstevel@tonic-gate 		 * total size of the buffers it provided.
532*0Sstevel@tonic-gate 		 */
533*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
534*0Sstevel@tonic-gate 	}
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 	/*
537*0Sstevel@tonic-gate 	 * Now do the processing on the mblk chain.
538*0Sstevel@tonic-gate 	 */
539*0Sstevel@tonic-gate 	while (mp != NULL && length > 0) {
540*0Sstevel@tonic-gate 		cur_len = MIN(MBLKL(mp) - offset, length);
541*0Sstevel@tonic-gate 		(cipher)(blowfish_ctx, (char *)(mp->b_rptr + offset), cur_len,
542*0Sstevel@tonic-gate 		    (input == output) ? NULL : output);
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 		length -= cur_len;
545*0Sstevel@tonic-gate 		offset = 0;
546*0Sstevel@tonic-gate 		mp = mp->b_cont;
547*0Sstevel@tonic-gate 	}
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	if (mp == NULL && length > 0) {
550*0Sstevel@tonic-gate 		/*
551*0Sstevel@tonic-gate 		 * The end of the mblk was reached but the length requested
552*0Sstevel@tonic-gate 		 * could not be processed, i.e. The caller requested
553*0Sstevel@tonic-gate 		 * to digest more data than it provided.
554*0Sstevel@tonic-gate 		 */
555*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
556*0Sstevel@tonic-gate 	}
557*0Sstevel@tonic-gate 
558*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
559*0Sstevel@tonic-gate }
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate /* ARGSUSED */
562*0Sstevel@tonic-gate static int
563*0Sstevel@tonic-gate blowfish_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
564*0Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
565*0Sstevel@tonic-gate {
566*0Sstevel@tonic-gate 	int ret;
567*0Sstevel@tonic-gate 
568*0Sstevel@tonic-gate /* EXPORT DELETE START */
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	/*
573*0Sstevel@tonic-gate 	 * Plaintext must be a multiple of blowfish block size.
574*0Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
575*0Sstevel@tonic-gate 	 * when blocksize is 2^N.
576*0Sstevel@tonic-gate 	 */
577*0Sstevel@tonic-gate 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
578*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
581*0Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	/*
586*0Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
587*0Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
588*0Sstevel@tonic-gate 	 */
589*0Sstevel@tonic-gate 	if (ciphertext->cd_length < plaintext->cd_length) {
590*0Sstevel@tonic-gate 		ciphertext->cd_length = plaintext->cd_length;
591*0Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	/*
595*0Sstevel@tonic-gate 	 * Do an update on the specified input data.
596*0Sstevel@tonic-gate 	 */
597*0Sstevel@tonic-gate 	ret = blowfish_encrypt_update(ctx, plaintext, ciphertext, req);
598*0Sstevel@tonic-gate 	ASSERT(blowfish_ctx->bc_remainder_len  == 0);
599*0Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate /* EXPORT DELETE END */
602*0Sstevel@tonic-gate 
603*0Sstevel@tonic-gate 	/* LINTED */
604*0Sstevel@tonic-gate 	return (ret);
605*0Sstevel@tonic-gate }
606*0Sstevel@tonic-gate 
607*0Sstevel@tonic-gate /* ARGSUSED */
608*0Sstevel@tonic-gate static int
609*0Sstevel@tonic-gate blowfish_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
610*0Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
611*0Sstevel@tonic-gate {
612*0Sstevel@tonic-gate 	int ret;
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate /* EXPORT DELETE START */
615*0Sstevel@tonic-gate 
616*0Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	/*
619*0Sstevel@tonic-gate 	 * Ciphertext must be a multiple of blowfish block size.
620*0Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
621*0Sstevel@tonic-gate 	 * when blocksize is 2^N.
622*0Sstevel@tonic-gate 	 */
623*0Sstevel@tonic-gate 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
624*0Sstevel@tonic-gate 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
625*0Sstevel@tonic-gate 
626*0Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
627*0Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	/*
632*0Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
633*0Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
634*0Sstevel@tonic-gate 	 */
635*0Sstevel@tonic-gate 	if (plaintext->cd_length < ciphertext->cd_length) {
636*0Sstevel@tonic-gate 		plaintext->cd_length = ciphertext->cd_length;
637*0Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
638*0Sstevel@tonic-gate 	}
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	/*
641*0Sstevel@tonic-gate 	 * Do an update on the specified input data.
642*0Sstevel@tonic-gate 	 */
643*0Sstevel@tonic-gate 	ret = blowfish_decrypt_update(ctx, ciphertext, plaintext, req);
644*0Sstevel@tonic-gate 	ASSERT(blowfish_ctx->bc_remainder_len == 0);
645*0Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
646*0Sstevel@tonic-gate 
647*0Sstevel@tonic-gate /* EXPORT DELETE END */
648*0Sstevel@tonic-gate 
649*0Sstevel@tonic-gate 	/* LINTED */
650*0Sstevel@tonic-gate 	return (ret);
651*0Sstevel@tonic-gate }
652*0Sstevel@tonic-gate 
653*0Sstevel@tonic-gate /* ARGSUSED */
654*0Sstevel@tonic-gate static int
655*0Sstevel@tonic-gate blowfish_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
656*0Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
657*0Sstevel@tonic-gate {
658*0Sstevel@tonic-gate 	off_t saved_offset;
659*0Sstevel@tonic-gate 	size_t saved_length, out_len;
660*0Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
661*0Sstevel@tonic-gate 
662*0Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	/* compute number of bytes that will hold the ciphertext */
667*0Sstevel@tonic-gate 	out_len =
668*0Sstevel@tonic-gate 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
669*0Sstevel@tonic-gate 	out_len += plaintext->cd_length;
670*0Sstevel@tonic-gate 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 	/* return length needed to store the output */
673*0Sstevel@tonic-gate 	if (ciphertext->cd_length < out_len) {
674*0Sstevel@tonic-gate 		ciphertext->cd_length = out_len;
675*0Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
676*0Sstevel@tonic-gate 	}
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
679*0Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/*
682*0Sstevel@tonic-gate 	 * Do the blowfish update on the specified input data.
683*0Sstevel@tonic-gate 	 */
684*0Sstevel@tonic-gate 	switch (plaintext->cd_format) {
685*0Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
686*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_iov(ctx->cc_provider_private,
687*0Sstevel@tonic-gate 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
688*0Sstevel@tonic-gate 		break;
689*0Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
690*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_uio(ctx->cc_provider_private,
691*0Sstevel@tonic-gate 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
692*0Sstevel@tonic-gate 		break;
693*0Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
694*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_mp(ctx->cc_provider_private,
695*0Sstevel@tonic-gate 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
696*0Sstevel@tonic-gate 		break;
697*0Sstevel@tonic-gate 	default:
698*0Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
699*0Sstevel@tonic-gate 	}
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
702*0Sstevel@tonic-gate 		if (plaintext != ciphertext)
703*0Sstevel@tonic-gate 			ciphertext->cd_length =
704*0Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
705*0Sstevel@tonic-gate 	} else {
706*0Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
707*0Sstevel@tonic-gate 	}
708*0Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	return (ret);
711*0Sstevel@tonic-gate }
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate /* ARGSUSED */
714*0Sstevel@tonic-gate static int
715*0Sstevel@tonic-gate blowfish_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
716*0Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
717*0Sstevel@tonic-gate {
718*0Sstevel@tonic-gate 	off_t saved_offset;
719*0Sstevel@tonic-gate 	size_t saved_length, out_len;
720*0Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	/* compute number of bytes that will hold the plaintext */
727*0Sstevel@tonic-gate 	out_len =
728*0Sstevel@tonic-gate 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
729*0Sstevel@tonic-gate 	out_len += ciphertext->cd_length;
730*0Sstevel@tonic-gate 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
731*0Sstevel@tonic-gate 
732*0Sstevel@tonic-gate 	/* return length needed to store the output */
733*0Sstevel@tonic-gate 	if (plaintext->cd_length < out_len) {
734*0Sstevel@tonic-gate 		plaintext->cd_length = out_len;
735*0Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
736*0Sstevel@tonic-gate 	}
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
739*0Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
740*0Sstevel@tonic-gate 
741*0Sstevel@tonic-gate 	/*
742*0Sstevel@tonic-gate 	 * Do the blowfish update on the specified input data.
743*0Sstevel@tonic-gate 	 */
744*0Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
745*0Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
746*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_iov(ctx->cc_provider_private,
747*0Sstevel@tonic-gate 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
748*0Sstevel@tonic-gate 		break;
749*0Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
750*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_uio(ctx->cc_provider_private,
751*0Sstevel@tonic-gate 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
752*0Sstevel@tonic-gate 		break;
753*0Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
754*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_mp(ctx->cc_provider_private,
755*0Sstevel@tonic-gate 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
756*0Sstevel@tonic-gate 		break;
757*0Sstevel@tonic-gate 	default:
758*0Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
759*0Sstevel@tonic-gate 	}
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
762*0Sstevel@tonic-gate 		if (ciphertext != plaintext)
763*0Sstevel@tonic-gate 			plaintext->cd_length =
764*0Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
765*0Sstevel@tonic-gate 	} else {
766*0Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
767*0Sstevel@tonic-gate 	}
768*0Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	return (ret);
771*0Sstevel@tonic-gate }
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate /* ARGSUSED */
774*0Sstevel@tonic-gate static int
775*0Sstevel@tonic-gate blowfish_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
776*0Sstevel@tonic-gate     crypto_req_handle_t req)
777*0Sstevel@tonic-gate {
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate /* EXPORT DELETE START */
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
782*0Sstevel@tonic-gate 
783*0Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
784*0Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 	/*
787*0Sstevel@tonic-gate 	 * There must be no unprocessed data.
788*0Sstevel@tonic-gate 	 * This happens if the length of the last data is
789*0Sstevel@tonic-gate 	 * not a multiple of the BLOWFISH block length.
790*0Sstevel@tonic-gate 	 */
791*0Sstevel@tonic-gate 	if (blowfish_ctx->bc_remainder_len > 0)
792*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
795*0Sstevel@tonic-gate 	data->cd_length = 0;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate /* EXPORT DELETE END */
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
800*0Sstevel@tonic-gate }
801*0Sstevel@tonic-gate 
802*0Sstevel@tonic-gate /* ARGSUSED */
803*0Sstevel@tonic-gate static int
804*0Sstevel@tonic-gate blowfish_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
805*0Sstevel@tonic-gate     crypto_req_handle_t req)
806*0Sstevel@tonic-gate {
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate /* EXPORT DELETE START */
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
813*0Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	/*
816*0Sstevel@tonic-gate 	 * There must be no unprocessed ciphertext.
817*0Sstevel@tonic-gate 	 * This happens if the length of the last ciphertext is
818*0Sstevel@tonic-gate 	 * not a multiple of the BLOWFISH block length.
819*0Sstevel@tonic-gate 	 */
820*0Sstevel@tonic-gate 	if (blowfish_ctx->bc_remainder_len > 0)
821*0Sstevel@tonic-gate 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
824*0Sstevel@tonic-gate 	data->cd_length = 0;
825*0Sstevel@tonic-gate 
826*0Sstevel@tonic-gate /* EXPORT DELETE END */
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
829*0Sstevel@tonic-gate }
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate /* ARGSUSED */
832*0Sstevel@tonic-gate static int
833*0Sstevel@tonic-gate blowfish_encrypt_atomic(crypto_provider_handle_t provider,
834*0Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
835*0Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
836*0Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
837*0Sstevel@tonic-gate {
838*0Sstevel@tonic-gate 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
839*0Sstevel@tonic-gate 	off_t saved_offset;
840*0Sstevel@tonic-gate 	size_t saved_length;
841*0Sstevel@tonic-gate 	int ret;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
844*0Sstevel@tonic-gate 
845*0Sstevel@tonic-gate 	/*
846*0Sstevel@tonic-gate 	 * Plaintext must be a multiple of blowfish block size.
847*0Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
848*0Sstevel@tonic-gate 	 * when blocksize is 2^N.
849*0Sstevel@tonic-gate 	 */
850*0Sstevel@tonic-gate 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
851*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 	/* return length needed to store the output */
854*0Sstevel@tonic-gate 	if (ciphertext->cd_length < plaintext->cd_length) {
855*0Sstevel@tonic-gate 		ciphertext->cd_length = plaintext->cd_length;
856*0Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
857*0Sstevel@tonic-gate 	}
858*0Sstevel@tonic-gate 
859*0Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
860*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 	if (mechanism->cm_param_len != 0 &&
863*0Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
864*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
869*0Sstevel@tonic-gate 	    key, crypto_kmflag(req));
870*0Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
871*0Sstevel@tonic-gate 		return (ret);
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
874*0Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
875*0Sstevel@tonic-gate 
876*0Sstevel@tonic-gate 	/*
877*0Sstevel@tonic-gate 	 * Do an update on the specified input data.
878*0Sstevel@tonic-gate 	 */
879*0Sstevel@tonic-gate 	switch (plaintext->cd_format) {
880*0Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
881*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_iov(&blowfish_ctx,
882*0Sstevel@tonic-gate 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
883*0Sstevel@tonic-gate 		break;
884*0Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
885*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_uio(&blowfish_ctx,
886*0Sstevel@tonic-gate 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
887*0Sstevel@tonic-gate 		break;
888*0Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
889*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_mp(&blowfish_ctx,
890*0Sstevel@tonic-gate 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
891*0Sstevel@tonic-gate 		break;
892*0Sstevel@tonic-gate 	default:
893*0Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
894*0Sstevel@tonic-gate 	}
895*0Sstevel@tonic-gate 
896*0Sstevel@tonic-gate 	if (blowfish_ctx.bc_flags & BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE) {
897*0Sstevel@tonic-gate 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
898*0Sstevel@tonic-gate 		kmem_free(blowfish_ctx.bc_keysched,
899*0Sstevel@tonic-gate 		    blowfish_ctx.bc_keysched_len);
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 
902*0Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
903*0Sstevel@tonic-gate 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
904*0Sstevel@tonic-gate 		if (plaintext != ciphertext)
905*0Sstevel@tonic-gate 			ciphertext->cd_length =
906*0Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
907*0Sstevel@tonic-gate 	} else {
908*0Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
909*0Sstevel@tonic-gate 	}
910*0Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 	return (ret);
913*0Sstevel@tonic-gate }
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate /* ARGSUSED */
916*0Sstevel@tonic-gate static int
917*0Sstevel@tonic-gate blowfish_decrypt_atomic(crypto_provider_handle_t provider,
918*0Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
919*0Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
920*0Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
921*0Sstevel@tonic-gate {
922*0Sstevel@tonic-gate 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
923*0Sstevel@tonic-gate 	off_t saved_offset;
924*0Sstevel@tonic-gate 	size_t saved_length;
925*0Sstevel@tonic-gate 	int ret;
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
928*0Sstevel@tonic-gate 
929*0Sstevel@tonic-gate 	/*
930*0Sstevel@tonic-gate 	 * Ciphertext must be a multiple of blowfish block size.
931*0Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
932*0Sstevel@tonic-gate 	 * when blocksize is 2^N.
933*0Sstevel@tonic-gate 	 */
934*0Sstevel@tonic-gate 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
935*0Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	/* return length needed to store the output */
938*0Sstevel@tonic-gate 	if (plaintext->cd_length < ciphertext->cd_length) {
939*0Sstevel@tonic-gate 		plaintext->cd_length = ciphertext->cd_length;
940*0Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
941*0Sstevel@tonic-gate 	}
942*0Sstevel@tonic-gate 
943*0Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
944*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 	if (mechanism->cm_param_len != 0 &&
947*0Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
948*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
949*0Sstevel@tonic-gate 
950*0Sstevel@tonic-gate 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
951*0Sstevel@tonic-gate 
952*0Sstevel@tonic-gate 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
953*0Sstevel@tonic-gate 	    key, crypto_kmflag(req));
954*0Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
955*0Sstevel@tonic-gate 		return (ret);
956*0Sstevel@tonic-gate 
957*0Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
958*0Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	/*
961*0Sstevel@tonic-gate 	 * Do an update on the specified input data.
962*0Sstevel@tonic-gate 	 */
963*0Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
964*0Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
965*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_iov(&blowfish_ctx,
966*0Sstevel@tonic-gate 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
967*0Sstevel@tonic-gate 		break;
968*0Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
969*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_uio(&blowfish_ctx,
970*0Sstevel@tonic-gate 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
971*0Sstevel@tonic-gate 		break;
972*0Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
973*0Sstevel@tonic-gate 		ret = blowfish_cipher_update_mp(&blowfish_ctx,
974*0Sstevel@tonic-gate 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
975*0Sstevel@tonic-gate 		break;
976*0Sstevel@tonic-gate 	default:
977*0Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
978*0Sstevel@tonic-gate 	}
979*0Sstevel@tonic-gate 
980*0Sstevel@tonic-gate 	if (blowfish_ctx.bc_flags & BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE) {
981*0Sstevel@tonic-gate 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
982*0Sstevel@tonic-gate 		kmem_free(blowfish_ctx.bc_keysched,
983*0Sstevel@tonic-gate 		    blowfish_ctx.bc_keysched_len);
984*0Sstevel@tonic-gate 	}
985*0Sstevel@tonic-gate 
986*0Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
987*0Sstevel@tonic-gate 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
988*0Sstevel@tonic-gate 		if (ciphertext != plaintext)
989*0Sstevel@tonic-gate 			plaintext->cd_length =
990*0Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
991*0Sstevel@tonic-gate 	} else {
992*0Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
993*0Sstevel@tonic-gate 	}
994*0Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 	return (ret);
997*0Sstevel@tonic-gate }
998*0Sstevel@tonic-gate 
999*0Sstevel@tonic-gate /*
1000*0Sstevel@tonic-gate  * KCF software provider context template entry points.
1001*0Sstevel@tonic-gate  */
1002*0Sstevel@tonic-gate /* ARGSUSED */
1003*0Sstevel@tonic-gate static int
1004*0Sstevel@tonic-gate blowfish_create_ctx_template(crypto_provider_handle_t provider,
1005*0Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key,
1006*0Sstevel@tonic-gate     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
1007*0Sstevel@tonic-gate {
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate /* EXPORT DELETE START */
1010*0Sstevel@tonic-gate 
1011*0Sstevel@tonic-gate 	void *keysched;
1012*0Sstevel@tonic-gate 	size_t size;
1013*0Sstevel@tonic-gate 	int rv;
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
1016*0Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	if ((keysched = blowfish_alloc_keysched(&size,
1019*0Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL) {
1020*0Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
1021*0Sstevel@tonic-gate 	}
1022*0Sstevel@tonic-gate 
1023*0Sstevel@tonic-gate 	/*
1024*0Sstevel@tonic-gate 	 * Initialize key schedule.  Key length information is stored
1025*0Sstevel@tonic-gate 	 * in the key.
1026*0Sstevel@tonic-gate 	 */
1027*0Sstevel@tonic-gate 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
1028*0Sstevel@tonic-gate 		bzero(keysched, size);
1029*0Sstevel@tonic-gate 		kmem_free(keysched, size);
1030*0Sstevel@tonic-gate 		return (rv);
1031*0Sstevel@tonic-gate 	}
1032*0Sstevel@tonic-gate 
1033*0Sstevel@tonic-gate 	*tmpl = keysched;
1034*0Sstevel@tonic-gate 	*tmpl_size = size;
1035*0Sstevel@tonic-gate 
1036*0Sstevel@tonic-gate /* EXPORT DELETE END */
1037*0Sstevel@tonic-gate 
1038*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1039*0Sstevel@tonic-gate }
1040*0Sstevel@tonic-gate 
1041*0Sstevel@tonic-gate /* ARGSUSED */
1042*0Sstevel@tonic-gate static int
1043*0Sstevel@tonic-gate blowfish_free_context(crypto_ctx_t *ctx)
1044*0Sstevel@tonic-gate {
1045*0Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx = ctx->cc_provider_private;
1046*0Sstevel@tonic-gate 
1047*0Sstevel@tonic-gate 	if (blowfish_ctx != NULL) {
1048*0Sstevel@tonic-gate 		if (blowfish_ctx->bc_flags &
1049*0Sstevel@tonic-gate 		    BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE) {
1050*0Sstevel@tonic-gate 			ASSERT(blowfish_ctx->bc_keysched_len != 0);
1051*0Sstevel@tonic-gate 			bzero(blowfish_ctx->bc_keysched,
1052*0Sstevel@tonic-gate 			    blowfish_ctx->bc_keysched_len);
1053*0Sstevel@tonic-gate 			kmem_free(blowfish_ctx->bc_keysched,
1054*0Sstevel@tonic-gate 			    blowfish_ctx->bc_keysched_len);
1055*0Sstevel@tonic-gate 		}
1056*0Sstevel@tonic-gate 		kmem_free(blowfish_ctx, sizeof (blowfish_ctx_t));
1057*0Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
1058*0Sstevel@tonic-gate 	}
1059*0Sstevel@tonic-gate 
1060*0Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
1061*0Sstevel@tonic-gate }
1062*0Sstevel@tonic-gate 
1063*0Sstevel@tonic-gate /*
1064*0Sstevel@tonic-gate  * Initialize by setting iov_or_mp to point to the current iovec or mp,
1065*0Sstevel@tonic-gate  * and by setting current_offset to an offset within the current iovec or mp .
1066*0Sstevel@tonic-gate  */
1067*0Sstevel@tonic-gate static void
1068*0Sstevel@tonic-gate blowfish_init_ptrs(crypto_data_t *out, void **iov_or_mp,
1069*0Sstevel@tonic-gate     offset_t *current_offset)
1070*0Sstevel@tonic-gate {
1071*0Sstevel@tonic-gate 	offset_t offset;
1072*0Sstevel@tonic-gate 
1073*0Sstevel@tonic-gate 	switch (out->cd_format) {
1074*0Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
1075*0Sstevel@tonic-gate 		*current_offset = out->cd_offset;
1076*0Sstevel@tonic-gate 		break;
1077*0Sstevel@tonic-gate 
1078*0Sstevel@tonic-gate 	case CRYPTO_DATA_UIO: {
1079*0Sstevel@tonic-gate 		uio_t *uiop = out->cd_uio;
1080*0Sstevel@tonic-gate 		uint_t vec_idx;
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 		offset = out->cd_offset;
1083*0Sstevel@tonic-gate 		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
1084*0Sstevel@tonic-gate 		    offset >= uiop->uio_iov[vec_idx].iov_len;
1085*0Sstevel@tonic-gate 		    offset -= uiop->uio_iov[vec_idx++].iov_len);
1086*0Sstevel@tonic-gate 
1087*0Sstevel@tonic-gate 		*current_offset = offset;
1088*0Sstevel@tonic-gate 		*iov_or_mp = (void *)(uintptr_t)vec_idx;
1089*0Sstevel@tonic-gate 		break;
1090*0Sstevel@tonic-gate 	}
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK: {
1093*0Sstevel@tonic-gate 		mblk_t *mp;
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 		offset = out->cd_offset;
1096*0Sstevel@tonic-gate 		for (mp = out->cd_mp; mp != NULL && offset >= MBLKL(mp);
1097*0Sstevel@tonic-gate 			offset -= MBLKL(mp), mp = mp->b_cont);
1098*0Sstevel@tonic-gate 
1099*0Sstevel@tonic-gate 		*current_offset = offset;
1100*0Sstevel@tonic-gate 		*iov_or_mp = mp;
1101*0Sstevel@tonic-gate 		break;
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 	}
1104*0Sstevel@tonic-gate 	} /* end switch */
1105*0Sstevel@tonic-gate }
1106*0Sstevel@tonic-gate 
1107*0Sstevel@tonic-gate /*
1108*0Sstevel@tonic-gate  * Get pointers for where in the output to copy a block of encrypted or
1109*0Sstevel@tonic-gate  * decrypted data.  The iov_or_mp argument stores a pointer to the current
1110*0Sstevel@tonic-gate  * iovec or mp, and offset stores an offset into the current iovec or mp.
1111*0Sstevel@tonic-gate  */
1112*0Sstevel@tonic-gate static void
1113*0Sstevel@tonic-gate blowfish_get_ptrs(crypto_data_t *out, void **iov_or_mp,
1114*0Sstevel@tonic-gate     offset_t *current_offset, uint8_t **out_data_1, size_t *out_data_1_len,
1115*0Sstevel@tonic-gate     uint8_t **out_data_2)
1116*0Sstevel@tonic-gate {
1117*0Sstevel@tonic-gate 	offset_t offset;
1118*0Sstevel@tonic-gate 
1119*0Sstevel@tonic-gate 	switch (out->cd_format) {
1120*0Sstevel@tonic-gate 	case CRYPTO_DATA_RAW: {
1121*0Sstevel@tonic-gate 		iovec_t *iov;
1122*0Sstevel@tonic-gate 
1123*0Sstevel@tonic-gate 		offset = *current_offset;
1124*0Sstevel@tonic-gate 		iov = &out->cd_raw;
1125*0Sstevel@tonic-gate 		if ((offset + BLOWFISH_BLOCK_LEN) <= iov->iov_len) {
1126*0Sstevel@tonic-gate 			/* one BLOWFISH block fits */
1127*0Sstevel@tonic-gate 			*out_data_1 = (uint8_t *)iov->iov_base + offset;
1128*0Sstevel@tonic-gate 			*out_data_1_len = BLOWFISH_BLOCK_LEN;
1129*0Sstevel@tonic-gate 			*out_data_2 = NULL;
1130*0Sstevel@tonic-gate 			*current_offset = offset + BLOWFISH_BLOCK_LEN;
1131*0Sstevel@tonic-gate 		}
1132*0Sstevel@tonic-gate 		break;
1133*0Sstevel@tonic-gate 	}
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate 	case CRYPTO_DATA_UIO: {
1136*0Sstevel@tonic-gate 		uio_t *uio = out->cd_uio;
1137*0Sstevel@tonic-gate 		iovec_t *iov;
1138*0Sstevel@tonic-gate 		offset_t offset;
1139*0Sstevel@tonic-gate 		uint_t vec_idx;
1140*0Sstevel@tonic-gate 		uint8_t *p;
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate 		offset = *current_offset;
1143*0Sstevel@tonic-gate 		vec_idx = (uint_t)(uintptr_t)(*iov_or_mp);
1144*0Sstevel@tonic-gate 		iov = &uio->uio_iov[vec_idx];
1145*0Sstevel@tonic-gate 		p = (uint8_t *)iov->iov_base + offset;
1146*0Sstevel@tonic-gate 		*out_data_1 = p;
1147*0Sstevel@tonic-gate 
1148*0Sstevel@tonic-gate 		if (offset + BLOWFISH_BLOCK_LEN <= iov->iov_len) {
1149*0Sstevel@tonic-gate 			/* can fit one BLOWFISH block into this iov */
1150*0Sstevel@tonic-gate 			*out_data_1_len = BLOWFISH_BLOCK_LEN;
1151*0Sstevel@tonic-gate 			*out_data_2 = NULL;
1152*0Sstevel@tonic-gate 			*current_offset = offset + BLOWFISH_BLOCK_LEN;
1153*0Sstevel@tonic-gate 		} else {
1154*0Sstevel@tonic-gate 			/* one BLOWFISH block spans two iovecs */
1155*0Sstevel@tonic-gate 			*out_data_1_len = iov->iov_len - offset;
1156*0Sstevel@tonic-gate 			if (vec_idx == uio->uio_iovcnt)
1157*0Sstevel@tonic-gate 				return;
1158*0Sstevel@tonic-gate 			vec_idx++;
1159*0Sstevel@tonic-gate 			iov = &uio->uio_iov[vec_idx];
1160*0Sstevel@tonic-gate 			*out_data_2 = (uint8_t *)iov->iov_base;
1161*0Sstevel@tonic-gate 			*current_offset = BLOWFISH_BLOCK_LEN - *out_data_1_len;
1162*0Sstevel@tonic-gate 		}
1163*0Sstevel@tonic-gate 		*iov_or_mp = (void *)(uintptr_t)vec_idx;
1164*0Sstevel@tonic-gate 		break;
1165*0Sstevel@tonic-gate 	}
1166*0Sstevel@tonic-gate 
1167*0Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK: {
1168*0Sstevel@tonic-gate 		mblk_t *mp;
1169*0Sstevel@tonic-gate 		uint8_t *p;
1170*0Sstevel@tonic-gate 
1171*0Sstevel@tonic-gate 		offset = *current_offset;
1172*0Sstevel@tonic-gate 		mp = (mblk_t *)*iov_or_mp;
1173*0Sstevel@tonic-gate 		p = mp->b_rptr + offset;
1174*0Sstevel@tonic-gate 		*out_data_1 = p;
1175*0Sstevel@tonic-gate 		if ((p + BLOWFISH_BLOCK_LEN) <= mp->b_wptr) {
1176*0Sstevel@tonic-gate 			/* can fit one BLOWFISH block into this mblk */
1177*0Sstevel@tonic-gate 			*out_data_1_len = BLOWFISH_BLOCK_LEN;
1178*0Sstevel@tonic-gate 			*out_data_2 = NULL;
1179*0Sstevel@tonic-gate 			*current_offset = offset + BLOWFISH_BLOCK_LEN;
1180*0Sstevel@tonic-gate 		} else {
1181*0Sstevel@tonic-gate 			/* one BLOWFISH block spans two mblks */
1182*0Sstevel@tonic-gate 			*out_data_1_len = mp->b_wptr - p;
1183*0Sstevel@tonic-gate 			if ((mp = mp->b_cont) == NULL)
1184*0Sstevel@tonic-gate 				return;
1185*0Sstevel@tonic-gate 			*out_data_2 = mp->b_rptr;
1186*0Sstevel@tonic-gate 			*current_offset = BLOWFISH_BLOCK_LEN - *out_data_1_len;
1187*0Sstevel@tonic-gate 		}
1188*0Sstevel@tonic-gate 		*iov_or_mp = mp;
1189*0Sstevel@tonic-gate 		break;
1190*0Sstevel@tonic-gate 	}
1191*0Sstevel@tonic-gate 	} /* end switch */
1192*0Sstevel@tonic-gate }
1193*0Sstevel@tonic-gate 
1194*0Sstevel@tonic-gate /*
1195*0Sstevel@tonic-gate  * Encrypt multiple blocks of data.
1196*0Sstevel@tonic-gate  */
1197*0Sstevel@tonic-gate static int
1198*0Sstevel@tonic-gate blowfish_encrypt_contiguous_blocks(blowfish_ctx_t *ctx, char *data,
1199*0Sstevel@tonic-gate     size_t length, crypto_data_t *out)
1200*0Sstevel@tonic-gate {
1201*0Sstevel@tonic-gate /* EXPORT DELETE START */
1202*0Sstevel@tonic-gate 	size_t remainder = length;
1203*0Sstevel@tonic-gate 	size_t need;
1204*0Sstevel@tonic-gate 	uint8_t *datap = (uint8_t *)data;
1205*0Sstevel@tonic-gate 	uint8_t *blockp;
1206*0Sstevel@tonic-gate 	uint8_t *lastp;
1207*0Sstevel@tonic-gate 	uint32_t tmp[2];
1208*0Sstevel@tonic-gate 	void *iov_or_mp;
1209*0Sstevel@tonic-gate 	offset_t offset;
1210*0Sstevel@tonic-gate 	uint8_t *out_data_1;
1211*0Sstevel@tonic-gate 	uint8_t *out_data_2;
1212*0Sstevel@tonic-gate 	size_t out_data_1_len;
1213*0Sstevel@tonic-gate 
1214*0Sstevel@tonic-gate 	if (length + ctx->bc_remainder_len < BLOWFISH_BLOCK_LEN) {
1215*0Sstevel@tonic-gate 		/* accumulate bytes here and return */
1216*0Sstevel@tonic-gate 		bcopy(datap,
1217*0Sstevel@tonic-gate 		    (uint8_t *)&ctx->bc_remainder + ctx->bc_remainder_len,
1218*0Sstevel@tonic-gate 		    length);
1219*0Sstevel@tonic-gate 		ctx->bc_remainder_len += length;
1220*0Sstevel@tonic-gate 		ctx->bc_copy_to = datap;
1221*0Sstevel@tonic-gate 		return (0);
1222*0Sstevel@tonic-gate 	}
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 	lastp = (uint8_t *)&ctx->bc_iv;
1225*0Sstevel@tonic-gate 	if (out != NULL)
1226*0Sstevel@tonic-gate 		blowfish_init_ptrs(out, &iov_or_mp, &offset);
1227*0Sstevel@tonic-gate 
1228*0Sstevel@tonic-gate 	do {
1229*0Sstevel@tonic-gate 		/* Unprocessed data from last call. */
1230*0Sstevel@tonic-gate 		if (ctx->bc_remainder_len > 0) {
1231*0Sstevel@tonic-gate 			need = BLOWFISH_BLOCK_LEN - ctx->bc_remainder_len;
1232*0Sstevel@tonic-gate 
1233*0Sstevel@tonic-gate 			if (need > remainder)
1234*0Sstevel@tonic-gate 				return (1);
1235*0Sstevel@tonic-gate 
1236*0Sstevel@tonic-gate 			bcopy(datap, &((uint8_t *)&ctx->bc_remainder)
1237*0Sstevel@tonic-gate 			    [ctx->bc_remainder_len], need);
1238*0Sstevel@tonic-gate 
1239*0Sstevel@tonic-gate 			blockp = (uint8_t *)&ctx->bc_remainder;
1240*0Sstevel@tonic-gate 		} else {
1241*0Sstevel@tonic-gate 			blockp = datap;
1242*0Sstevel@tonic-gate 		}
1243*0Sstevel@tonic-gate 
1244*0Sstevel@tonic-gate 		/* don't write on the plaintext */
1245*0Sstevel@tonic-gate 		if (out != NULL) {
1246*0Sstevel@tonic-gate 			if (IS_P2ALIGNED(blockp, sizeof (uint32_t))) {
1247*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1248*0Sstevel@tonic-gate 				tmp[0] = *(uint32_t *)blockp;
1249*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1250*0Sstevel@tonic-gate 				tmp[1] = *(uint32_t *)&blockp[4];
1251*0Sstevel@tonic-gate 			} else {
1252*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN
1253*0Sstevel@tonic-gate 				tmp[0] = (((uint32_t)blockp[0] << 24) |
1254*0Sstevel@tonic-gate 				    ((uint32_t)blockp[1] << 16) |
1255*0Sstevel@tonic-gate 				    ((uint32_t)blockp[2] << 8) |
1256*0Sstevel@tonic-gate 				    (uint32_t)blockp[3]);
1257*0Sstevel@tonic-gate 
1258*0Sstevel@tonic-gate 				tmp[1] = (((uint32_t)blockp[4] << 24) |
1259*0Sstevel@tonic-gate 				    ((uint32_t)blockp[5] << 16) |
1260*0Sstevel@tonic-gate 				    ((uint32_t)blockp[6] << 8) |
1261*0Sstevel@tonic-gate 				    (uint32_t)blockp[7]);
1262*0Sstevel@tonic-gate #else
1263*0Sstevel@tonic-gate 				tmp[0] = (((uint32_t)blockp[7] << 24) |
1264*0Sstevel@tonic-gate 				    ((uint32_t)blockp[6] << 16) |
1265*0Sstevel@tonic-gate 				    ((uint32_t)blockp[5] << 8) |
1266*0Sstevel@tonic-gate 				    (uint32_t)blockp[4]);
1267*0Sstevel@tonic-gate 
1268*0Sstevel@tonic-gate 				tmp[1] = (((uint32_t)blockp[3] << 24) |
1269*0Sstevel@tonic-gate 				    ((uint32_t)blockp[2] << 16) |
1270*0Sstevel@tonic-gate 				    ((uint32_t)blockp[1] << 8) |
1271*0Sstevel@tonic-gate 				    (uint32_t)blockp[0]);
1272*0Sstevel@tonic-gate #endif /* _BIG_ENDIAN */
1273*0Sstevel@tonic-gate 			}
1274*0Sstevel@tonic-gate 			blockp = (uint8_t *)tmp;
1275*0Sstevel@tonic-gate 		}
1276*0Sstevel@tonic-gate 
1277*0Sstevel@tonic-gate 		if (ctx->bc_flags & BLOWFISH_CBC_MODE) {
1278*0Sstevel@tonic-gate 			/*
1279*0Sstevel@tonic-gate 			 * XOR the previous cipher block or IV with the
1280*0Sstevel@tonic-gate 			 * current clear block. Check for alignment.
1281*0Sstevel@tonic-gate 			 */
1282*0Sstevel@tonic-gate 			if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
1283*0Sstevel@tonic-gate 			    IS_P2ALIGNED(lastp, sizeof (uint32_t))) {
1284*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1285*0Sstevel@tonic-gate 				*(uint32_t *)&blockp[0] ^=
1286*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1287*0Sstevel@tonic-gate 				    *(uint32_t *)&lastp[0];
1288*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1289*0Sstevel@tonic-gate 				*(uint32_t *)&blockp[4] ^=
1290*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1291*0Sstevel@tonic-gate 				    *(uint32_t *)&lastp[4];
1292*0Sstevel@tonic-gate 			} else {
1293*0Sstevel@tonic-gate 				BLOWFISH_XOR_BLOCK(lastp, blockp);
1294*0Sstevel@tonic-gate 			}
1295*0Sstevel@tonic-gate 		}
1296*0Sstevel@tonic-gate 
1297*0Sstevel@tonic-gate 		if (out == NULL) {
1298*0Sstevel@tonic-gate 			blowfish_encrypt_block(ctx->bc_keysched, blockp,
1299*0Sstevel@tonic-gate 			    blockp);
1300*0Sstevel@tonic-gate 
1301*0Sstevel@tonic-gate 			ctx->bc_lastp = blockp;
1302*0Sstevel@tonic-gate 			lastp = blockp;
1303*0Sstevel@tonic-gate 
1304*0Sstevel@tonic-gate 			if (ctx->bc_remainder_len > 0) {
1305*0Sstevel@tonic-gate 				bcopy(blockp, ctx->bc_copy_to,
1306*0Sstevel@tonic-gate 				    ctx->bc_remainder_len);
1307*0Sstevel@tonic-gate 				bcopy(blockp + ctx->bc_remainder_len, datap,
1308*0Sstevel@tonic-gate 				    need);
1309*0Sstevel@tonic-gate 			}
1310*0Sstevel@tonic-gate 		} else {
1311*0Sstevel@tonic-gate 			blowfish_encrypt_block(ctx->bc_keysched, blockp, lastp);
1312*0Sstevel@tonic-gate 			blowfish_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
1313*0Sstevel@tonic-gate 			    &out_data_1_len, &out_data_2);
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 			/* copy block to where it belongs */
1316*0Sstevel@tonic-gate 			bcopy(lastp, out_data_1, out_data_1_len);
1317*0Sstevel@tonic-gate 			if (out_data_2 != NULL) {
1318*0Sstevel@tonic-gate 				bcopy(lastp + out_data_1_len, out_data_2,
1319*0Sstevel@tonic-gate 				    BLOWFISH_BLOCK_LEN - out_data_1_len);
1320*0Sstevel@tonic-gate 			}
1321*0Sstevel@tonic-gate 
1322*0Sstevel@tonic-gate 			/* update offset */
1323*0Sstevel@tonic-gate 			out->cd_offset += BLOWFISH_BLOCK_LEN;
1324*0Sstevel@tonic-gate 		}
1325*0Sstevel@tonic-gate 
1326*0Sstevel@tonic-gate 		/* Update pointer to next block of data to be processed. */
1327*0Sstevel@tonic-gate 		if (ctx->bc_remainder_len != 0) {
1328*0Sstevel@tonic-gate 			datap += need;
1329*0Sstevel@tonic-gate 			ctx->bc_remainder_len = 0;
1330*0Sstevel@tonic-gate 		} else {
1331*0Sstevel@tonic-gate 			datap += BLOWFISH_BLOCK_LEN;
1332*0Sstevel@tonic-gate 		}
1333*0Sstevel@tonic-gate 
1334*0Sstevel@tonic-gate 		remainder = (size_t)&data[length] - (size_t)datap;
1335*0Sstevel@tonic-gate 
1336*0Sstevel@tonic-gate 		/* Incomplete last block. */
1337*0Sstevel@tonic-gate 		if (remainder > 0 && remainder < BLOWFISH_BLOCK_LEN) {
1338*0Sstevel@tonic-gate 			bcopy(datap, &ctx->bc_remainder, remainder);
1339*0Sstevel@tonic-gate 			ctx->bc_remainder_len = remainder;
1340*0Sstevel@tonic-gate 			ctx->bc_copy_to = datap;
1341*0Sstevel@tonic-gate 			goto out;
1342*0Sstevel@tonic-gate 		}
1343*0Sstevel@tonic-gate 		ctx->bc_copy_to = NULL;
1344*0Sstevel@tonic-gate 
1345*0Sstevel@tonic-gate 	} while (remainder > 0);
1346*0Sstevel@tonic-gate 
1347*0Sstevel@tonic-gate out:
1348*0Sstevel@tonic-gate 	if (ctx->bc_lastp != NULL) {
1349*0Sstevel@tonic-gate 		if (IS_P2ALIGNED(ctx->bc_lastp, sizeof (uint32_t))) {
1350*0Sstevel@tonic-gate 			uint8_t *iv8 = (uint8_t *)&ctx->bc_iv;
1351*0Sstevel@tonic-gate 			uint8_t *last8 = (uint8_t *)ctx->bc_lastp;
1352*0Sstevel@tonic-gate 
1353*0Sstevel@tonic-gate 			/* LINTED: pointer alignment */
1354*0Sstevel@tonic-gate 			*(uint32_t *)iv8 = *(uint32_t *)last8;
1355*0Sstevel@tonic-gate 			/* LINTED: pointer alignment */
1356*0Sstevel@tonic-gate 			*(uint32_t *)&iv8[4] = *(uint32_t *)&last8[4];
1357*0Sstevel@tonic-gate 		} else {
1358*0Sstevel@tonic-gate 			uint8_t *iv8 = (uint8_t *)&ctx->bc_iv;
1359*0Sstevel@tonic-gate 			uint8_t *last8 = ctx->bc_lastp;
1360*0Sstevel@tonic-gate 
1361*0Sstevel@tonic-gate 			BLOWFISH_COPY_BLOCK(last8, iv8);
1362*0Sstevel@tonic-gate 		}
1363*0Sstevel@tonic-gate 		ctx->bc_lastp = (uint8_t *)&ctx->bc_iv;
1364*0Sstevel@tonic-gate 	}
1365*0Sstevel@tonic-gate /* EXPORT DELETE END */
1366*0Sstevel@tonic-gate 
1367*0Sstevel@tonic-gate 	return (0);
1368*0Sstevel@tonic-gate }
1369*0Sstevel@tonic-gate 
1370*0Sstevel@tonic-gate #define	OTHER(a, ctx) \
1371*0Sstevel@tonic-gate 	(((a) == &(ctx)->bc_lastblock) ? &(ctx)->bc_iv : &(ctx)->bc_lastblock)
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate static int
1374*0Sstevel@tonic-gate blowfish_decrypt_contiguous_blocks(blowfish_ctx_t *ctx, char *data,
1375*0Sstevel@tonic-gate     size_t length, crypto_data_t *out)
1376*0Sstevel@tonic-gate {
1377*0Sstevel@tonic-gate /* EXPORT DELETE START */
1378*0Sstevel@tonic-gate 	size_t remainder = length;
1379*0Sstevel@tonic-gate 	size_t need;
1380*0Sstevel@tonic-gate 	uint8_t *datap = (uint8_t *)data;
1381*0Sstevel@tonic-gate 	uint8_t *blockp;
1382*0Sstevel@tonic-gate 	uint8_t *lastp;
1383*0Sstevel@tonic-gate 	uint32_t tmp[2];
1384*0Sstevel@tonic-gate 	void *iov_or_mp;
1385*0Sstevel@tonic-gate 	offset_t offset;
1386*0Sstevel@tonic-gate 	uint8_t *out_data_1;
1387*0Sstevel@tonic-gate 	uint8_t *out_data_2;
1388*0Sstevel@tonic-gate 	size_t out_data_1_len;
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 	if (length + ctx->bc_remainder_len < BLOWFISH_BLOCK_LEN) {
1391*0Sstevel@tonic-gate 		/* accumulate bytes here and return */
1392*0Sstevel@tonic-gate 		bcopy(datap,
1393*0Sstevel@tonic-gate 		    (uint8_t *)&ctx->bc_remainder + ctx->bc_remainder_len,
1394*0Sstevel@tonic-gate 		    length);
1395*0Sstevel@tonic-gate 		ctx->bc_remainder_len += length;
1396*0Sstevel@tonic-gate 		ctx->bc_copy_to = datap;
1397*0Sstevel@tonic-gate 		return (0);
1398*0Sstevel@tonic-gate 	}
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 	lastp = ctx->bc_lastp;
1401*0Sstevel@tonic-gate 	if (out != NULL)
1402*0Sstevel@tonic-gate 		blowfish_init_ptrs(out, &iov_or_mp, &offset);
1403*0Sstevel@tonic-gate 
1404*0Sstevel@tonic-gate 	do {
1405*0Sstevel@tonic-gate 		/* Unprocessed data from last call. */
1406*0Sstevel@tonic-gate 		if (ctx->bc_remainder_len > 0) {
1407*0Sstevel@tonic-gate 			need = BLOWFISH_BLOCK_LEN - ctx->bc_remainder_len;
1408*0Sstevel@tonic-gate 
1409*0Sstevel@tonic-gate 			if (need > remainder)
1410*0Sstevel@tonic-gate 				return (1);
1411*0Sstevel@tonic-gate 
1412*0Sstevel@tonic-gate 			bcopy(datap, &((uint8_t *)&ctx->bc_remainder)
1413*0Sstevel@tonic-gate 			    [ctx->bc_remainder_len], need);
1414*0Sstevel@tonic-gate 
1415*0Sstevel@tonic-gate 			blockp = (uint8_t *)&ctx->bc_remainder;
1416*0Sstevel@tonic-gate 		} else {
1417*0Sstevel@tonic-gate 			blockp = datap;
1418*0Sstevel@tonic-gate 		}
1419*0Sstevel@tonic-gate 
1420*0Sstevel@tonic-gate 		if (ctx->bc_flags & BLOWFISH_CBC_MODE) {
1421*0Sstevel@tonic-gate 
1422*0Sstevel@tonic-gate 			/* Save current ciphertext block */
1423*0Sstevel@tonic-gate 			if (IS_P2ALIGNED(blockp, sizeof (uint32_t))) {
1424*0Sstevel@tonic-gate 				uint32_t *tmp32;
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1427*0Sstevel@tonic-gate 				tmp32 = (uint32_t *)OTHER((uint64_t *)lastp,
1428*0Sstevel@tonic-gate 				    ctx);
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1431*0Sstevel@tonic-gate 				*tmp32++ = *(uint32_t *)blockp;
1432*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1433*0Sstevel@tonic-gate 				*tmp32++ = *(uint32_t *)&blockp[4];
1434*0Sstevel@tonic-gate 			} else {
1435*0Sstevel@tonic-gate 				uint8_t *tmp8;
1436*0Sstevel@tonic-gate 				tmp8 = (uint8_t *)OTHER((uint64_t *)lastp, ctx);
1437*0Sstevel@tonic-gate 
1438*0Sstevel@tonic-gate 				BLOWFISH_COPY_BLOCK(blockp, tmp8);
1439*0Sstevel@tonic-gate 			}
1440*0Sstevel@tonic-gate 		}
1441*0Sstevel@tonic-gate 
1442*0Sstevel@tonic-gate 		if (out != NULL) {
1443*0Sstevel@tonic-gate 			blowfish_decrypt_block(ctx->bc_keysched, blockp,
1444*0Sstevel@tonic-gate 			    (uint8_t *)tmp);
1445*0Sstevel@tonic-gate 			blockp = (uint8_t *)tmp;
1446*0Sstevel@tonic-gate 		} else {
1447*0Sstevel@tonic-gate 			blowfish_decrypt_block(ctx->bc_keysched, blockp,
1448*0Sstevel@tonic-gate 			    blockp);
1449*0Sstevel@tonic-gate 		}
1450*0Sstevel@tonic-gate 
1451*0Sstevel@tonic-gate 		if (ctx->bc_flags & BLOWFISH_CBC_MODE) {
1452*0Sstevel@tonic-gate 			/*
1453*0Sstevel@tonic-gate 			 * XOR the previous cipher block or IV with the
1454*0Sstevel@tonic-gate 			 * currently decrypted block.  Check for alignment.
1455*0Sstevel@tonic-gate 			 */
1456*0Sstevel@tonic-gate 			if (IS_P2ALIGNED(blockp, sizeof (uint32_t)) &&
1457*0Sstevel@tonic-gate 			    IS_P2ALIGNED(lastp, sizeof (uint32_t))) {
1458*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1459*0Sstevel@tonic-gate 				*(uint32_t *)blockp ^= *(uint32_t *)lastp;
1460*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1461*0Sstevel@tonic-gate 				*(uint32_t *)&blockp[4] ^=
1462*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1463*0Sstevel@tonic-gate 				    *(uint32_t *)&lastp[4];
1464*0Sstevel@tonic-gate 			} else {
1465*0Sstevel@tonic-gate 				BLOWFISH_XOR_BLOCK(lastp, blockp);
1466*0Sstevel@tonic-gate 			}
1467*0Sstevel@tonic-gate 
1468*0Sstevel@tonic-gate 			/* LINTED: pointer alignment */
1469*0Sstevel@tonic-gate 			lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx);
1470*0Sstevel@tonic-gate 		}
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 		if (out != NULL) {
1473*0Sstevel@tonic-gate 			blowfish_get_ptrs(out, &iov_or_mp, &offset, &out_data_1,
1474*0Sstevel@tonic-gate 			    &out_data_1_len, &out_data_2);
1475*0Sstevel@tonic-gate 			/* copy temporary block to where it belongs */
1476*0Sstevel@tonic-gate 			bcopy(&tmp, out_data_1, out_data_1_len);
1477*0Sstevel@tonic-gate 			if (out_data_2 != NULL) {
1478*0Sstevel@tonic-gate 				bcopy((uint8_t *)&tmp + out_data_1_len,
1479*0Sstevel@tonic-gate 				    out_data_2,
1480*0Sstevel@tonic-gate 				    BLOWFISH_BLOCK_LEN - out_data_1_len);
1481*0Sstevel@tonic-gate 			}
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate 			/* update offset */
1484*0Sstevel@tonic-gate 			out->cd_offset += BLOWFISH_BLOCK_LEN;
1485*0Sstevel@tonic-gate 		} else if (ctx->bc_remainder_len > 0) {
1486*0Sstevel@tonic-gate 			/* copy temporary block to where it belongs */
1487*0Sstevel@tonic-gate 			bcopy(blockp, ctx->bc_copy_to, ctx->bc_remainder_len);
1488*0Sstevel@tonic-gate 			bcopy(blockp + ctx->bc_remainder_len, datap, need);
1489*0Sstevel@tonic-gate 		}
1490*0Sstevel@tonic-gate 
1491*0Sstevel@tonic-gate 		/* Update pointer to next block of data to be processed. */
1492*0Sstevel@tonic-gate 		if (ctx->bc_remainder_len != 0) {
1493*0Sstevel@tonic-gate 			datap += need;
1494*0Sstevel@tonic-gate 			ctx->bc_remainder_len = 0;
1495*0Sstevel@tonic-gate 		} else {
1496*0Sstevel@tonic-gate 			datap += BLOWFISH_BLOCK_LEN;
1497*0Sstevel@tonic-gate 		}
1498*0Sstevel@tonic-gate 
1499*0Sstevel@tonic-gate 		remainder = (size_t)&data[length] - (size_t)datap;
1500*0Sstevel@tonic-gate 
1501*0Sstevel@tonic-gate 		/* Incomplete last block. */
1502*0Sstevel@tonic-gate 		if (remainder > 0 && remainder < BLOWFISH_BLOCK_LEN) {
1503*0Sstevel@tonic-gate 			bcopy(datap, (uchar_t *)&ctx->bc_remainder, remainder);
1504*0Sstevel@tonic-gate 			ctx->bc_remainder_len = remainder;
1505*0Sstevel@tonic-gate 			ctx->bc_lastp = lastp;
1506*0Sstevel@tonic-gate 			ctx->bc_copy_to = datap;
1507*0Sstevel@tonic-gate 			return (0);
1508*0Sstevel@tonic-gate 		}
1509*0Sstevel@tonic-gate 		ctx->bc_copy_to = NULL;
1510*0Sstevel@tonic-gate 
1511*0Sstevel@tonic-gate 	} while (remainder > 0);
1512*0Sstevel@tonic-gate 
1513*0Sstevel@tonic-gate 	ctx->bc_lastp = lastp;
1514*0Sstevel@tonic-gate /* EXPORT DELETE END */
1515*0Sstevel@tonic-gate 	return (0);
1516*0Sstevel@tonic-gate }
1517*0Sstevel@tonic-gate 
1518*0Sstevel@tonic-gate /* ARGSUSED */
1519*0Sstevel@tonic-gate static int
1520*0Sstevel@tonic-gate blowfish_common_init_ctx(blowfish_ctx_t *blowfish_ctx,
1521*0Sstevel@tonic-gate     crypto_spi_ctx_template_t *template, crypto_mechanism_t *mechanism,
1522*0Sstevel@tonic-gate     crypto_key_t *key, int kmflag)
1523*0Sstevel@tonic-gate {
1524*0Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
1525*0Sstevel@tonic-gate 
1526*0Sstevel@tonic-gate /* EXPORT DELETE START */
1527*0Sstevel@tonic-gate 
1528*0Sstevel@tonic-gate 	void *keysched;
1529*0Sstevel@tonic-gate 	size_t size;
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	if (template == NULL) {
1532*0Sstevel@tonic-gate 		if ((keysched = blowfish_alloc_keysched(&size, kmflag)) == NULL)
1533*0Sstevel@tonic-gate 			return (CRYPTO_HOST_MEMORY);
1534*0Sstevel@tonic-gate 		/*
1535*0Sstevel@tonic-gate 		 * Initialize key schedule.
1536*0Sstevel@tonic-gate 		 * Key length is stored in the key.
1537*0Sstevel@tonic-gate 		 */
1538*0Sstevel@tonic-gate 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS)
1539*0Sstevel@tonic-gate 			kmem_free(keysched, size);
1540*0Sstevel@tonic-gate 
1541*0Sstevel@tonic-gate 		blowfish_ctx->bc_flags = BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE;
1542*0Sstevel@tonic-gate 		blowfish_ctx->bc_keysched_len = size;
1543*0Sstevel@tonic-gate 	} else {
1544*0Sstevel@tonic-gate 		keysched = template;
1545*0Sstevel@tonic-gate 	}
1546*0Sstevel@tonic-gate 
1547*0Sstevel@tonic-gate 	if (mechanism->cm_type == BF_CBC_MECH_INFO_TYPE) {
1548*0Sstevel@tonic-gate 		/*
1549*0Sstevel@tonic-gate 		 * Copy IV into BLOWFISH context.
1550*0Sstevel@tonic-gate 		 *
1551*0Sstevel@tonic-gate 		 * If cm_param == NULL then the IV comes from the
1552*0Sstevel@tonic-gate 		 * cd_miscdata field in the crypto_data structure.
1553*0Sstevel@tonic-gate 		 */
1554*0Sstevel@tonic-gate 		if (mechanism->cm_param != NULL) {
1555*0Sstevel@tonic-gate 			ASSERT(mechanism->cm_param_len == BLOWFISH_BLOCK_LEN);
1556*0Sstevel@tonic-gate 			if (IS_P2ALIGNED(mechanism->cm_param,
1557*0Sstevel@tonic-gate 			    sizeof (uint64_t))) {
1558*0Sstevel@tonic-gate 				/* LINTED: pointer alignment */
1559*0Sstevel@tonic-gate 				blowfish_ctx->bc_iv =
1560*0Sstevel@tonic-gate 				    *(uint64_t *)mechanism->cm_param;
1561*0Sstevel@tonic-gate 			} else {
1562*0Sstevel@tonic-gate 				uint8_t *iv8;
1563*0Sstevel@tonic-gate 				uint8_t *p8;
1564*0Sstevel@tonic-gate 				iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
1565*0Sstevel@tonic-gate 				p8 = (uint8_t *)&mechanism->cm_param[0];
1566*0Sstevel@tonic-gate 
1567*0Sstevel@tonic-gate 				BLOWFISH_COPY_BLOCK(p8, iv8);
1568*0Sstevel@tonic-gate 			}
1569*0Sstevel@tonic-gate 		}
1570*0Sstevel@tonic-gate 
1571*0Sstevel@tonic-gate 		blowfish_ctx->bc_lastp = (uint8_t *)&blowfish_ctx->bc_iv;
1572*0Sstevel@tonic-gate 		blowfish_ctx->bc_flags |= BLOWFISH_CBC_MODE;
1573*0Sstevel@tonic-gate 	}
1574*0Sstevel@tonic-gate 	blowfish_ctx->bc_keysched = keysched;
1575*0Sstevel@tonic-gate 
1576*0Sstevel@tonic-gate /* EXPORT DELETE END */
1577*0Sstevel@tonic-gate 
1578*0Sstevel@tonic-gate 	return (rv);
1579*0Sstevel@tonic-gate }
1580