xref: /titanic_52/usr/src/uts/common/crypto/io/blowfish.c (revision 694c35faa87b858ecdadfe4fc592615f4eefbb07)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5d2b32306Smcpowers  * Common Development and Distribution License (the "License").
6d2b32306Smcpowers  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*d3b2efc7SAnthony Scarpino  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Blowfish provider for the Kernel Cryptographic Framework (KCF)
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/systm.h>
327c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
337c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
347c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
357c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
367c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
397c478bd9Sstevel@tonic-gate #include <sys/note.h>
4023c57df7Smcpowers #include <modes/modes.h>
4123c57df7Smcpowers #include <blowfish/blowfish_impl.h>
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate extern struct mod_ops mod_cryptoops;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate static struct modlcrypto modlcrypto = {
497c478bd9Sstevel@tonic-gate 	&mod_cryptoops,
50d2b32306Smcpowers 	"Blowfish Kernel SW Provider"
517c478bd9Sstevel@tonic-gate };
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
547c478bd9Sstevel@tonic-gate 	MODREV_1,
557c478bd9Sstevel@tonic-gate 	(void *)&modlcrypto,
567c478bd9Sstevel@tonic-gate 	NULL
577c478bd9Sstevel@tonic-gate };
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * CSPI information (entry points, provider info, etc.)
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate typedef enum blowfish_mech_type {
63f66d273dSizick 	BLOWFISH_ECB_MECH_INFO_TYPE,		/* SUN_CKM_BLOWFISH_ECB */
64f66d273dSizick 	BLOWFISH_CBC_MECH_INFO_TYPE		/* SUN_CKM_BLOWFISH_CBC */
657c478bd9Sstevel@tonic-gate } blowfish_mech_type_t;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #define	BLOWFISH_COPY_BLOCK(src, dst) \
697c478bd9Sstevel@tonic-gate 	(dst)[0] = (src)[0]; \
707c478bd9Sstevel@tonic-gate 	(dst)[1] = (src)[1]; \
717c478bd9Sstevel@tonic-gate 	(dst)[2] = (src)[2]; \
727c478bd9Sstevel@tonic-gate 	(dst)[3] = (src)[3]; \
737c478bd9Sstevel@tonic-gate 	(dst)[4] = (src)[4]; \
747c478bd9Sstevel@tonic-gate 	(dst)[5] = (src)[5]; \
757c478bd9Sstevel@tonic-gate 	(dst)[6] = (src)[6]; \
767c478bd9Sstevel@tonic-gate 	(dst)[7] = (src)[7]
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #define	BLOWFISH_XOR_BLOCK(src, dst) \
797c478bd9Sstevel@tonic-gate 	(dst)[0] ^= (src)[0]; \
807c478bd9Sstevel@tonic-gate 	(dst)[1] ^= (src)[1]; \
817c478bd9Sstevel@tonic-gate 	(dst)[2] ^= (src)[2]; \
827c478bd9Sstevel@tonic-gate 	(dst)[3] ^= (src)[3]; \
837c478bd9Sstevel@tonic-gate 	(dst)[4] ^= (src)[4]; \
847c478bd9Sstevel@tonic-gate 	(dst)[5] ^= (src)[5]; \
857c478bd9Sstevel@tonic-gate 	(dst)[6] ^= (src)[6]; \
867c478bd9Sstevel@tonic-gate 	(dst)[7] ^= (src)[7]
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /*
897c478bd9Sstevel@tonic-gate  * Mechanism info structure passed to KCF during registration.
907c478bd9Sstevel@tonic-gate  */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate static crypto_mech_info_t blowfish_mech_info_tab[] = {
937c478bd9Sstevel@tonic-gate 	/* BLOWFISH_ECB */
94f66d273dSizick 	{SUN_CKM_BLOWFISH_ECB, BLOWFISH_ECB_MECH_INFO_TYPE,
957c478bd9Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
967c478bd9Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
977c478bd9Sstevel@tonic-gate 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS},
987c478bd9Sstevel@tonic-gate 	/* BLOWFISH_CBC */
99f66d273dSizick 	{SUN_CKM_BLOWFISH_CBC, BLOWFISH_CBC_MECH_INFO_TYPE,
1007c478bd9Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
1017c478bd9Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
1027c478bd9Sstevel@tonic-gate 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS}
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate #define	BLOWFISH_VALID_MECH(mech)				\
106f66d273dSizick 	(((mech)->cm_type == BLOWFISH_ECB_MECH_INFO_TYPE ||		\
107f66d273dSizick 	(mech)->cm_type == BLOWFISH_CBC_MECH_INFO_TYPE) ? 1 : 0)
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /* operations are in-place if the output buffer is NULL */
1107c478bd9Sstevel@tonic-gate #define	BLOWFISH_ARG_INPLACE(input, output)			\
1117c478bd9Sstevel@tonic-gate 	if ((output) == NULL)					\
1127c478bd9Sstevel@tonic-gate 		(output) = (input);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static void blowfish_provider_status(crypto_provider_handle_t, uint_t *);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static crypto_control_ops_t blowfish_control_ops = {
1177c478bd9Sstevel@tonic-gate 	blowfish_provider_status
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static int blowfish_common_init(crypto_ctx_t *, crypto_mechanism_t *,
1217c478bd9Sstevel@tonic-gate     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1227c478bd9Sstevel@tonic-gate static int blowfish_common_init_ctx(blowfish_ctx_t *,
1237c478bd9Sstevel@tonic-gate     crypto_spi_ctx_template_t *, crypto_mechanism_t *, crypto_key_t *, int);
1247c478bd9Sstevel@tonic-gate static int blowfish_encrypt_final(crypto_ctx_t *, crypto_data_t *,
1257c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
1267c478bd9Sstevel@tonic-gate static int blowfish_decrypt_final(crypto_ctx_t *, crypto_data_t *,
1277c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate static int blowfish_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1307c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
1317c478bd9Sstevel@tonic-gate static int blowfish_encrypt_update(crypto_ctx_t *, crypto_data_t *,
1327c478bd9Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1337c478bd9Sstevel@tonic-gate static int blowfish_encrypt_atomic(crypto_provider_handle_t,
1347c478bd9Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1357c478bd9Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static int blowfish_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1387c478bd9Sstevel@tonic-gate     crypto_req_handle_t);
1397c478bd9Sstevel@tonic-gate static int blowfish_decrypt_update(crypto_ctx_t *, crypto_data_t *,
1407c478bd9Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1417c478bd9Sstevel@tonic-gate static int blowfish_decrypt_atomic(crypto_provider_handle_t,
1427c478bd9Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1437c478bd9Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate static crypto_cipher_ops_t blowfish_cipher_ops = {
1467c478bd9Sstevel@tonic-gate 	blowfish_common_init,
1477c478bd9Sstevel@tonic-gate 	blowfish_encrypt,
1487c478bd9Sstevel@tonic-gate 	blowfish_encrypt_update,
1497c478bd9Sstevel@tonic-gate 	blowfish_encrypt_final,
1507c478bd9Sstevel@tonic-gate 	blowfish_encrypt_atomic,
1517c478bd9Sstevel@tonic-gate 	blowfish_common_init,
1527c478bd9Sstevel@tonic-gate 	blowfish_decrypt,
1537c478bd9Sstevel@tonic-gate 	blowfish_decrypt_update,
1547c478bd9Sstevel@tonic-gate 	blowfish_decrypt_final,
1557c478bd9Sstevel@tonic-gate 	blowfish_decrypt_atomic
1567c478bd9Sstevel@tonic-gate };
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static int blowfish_create_ctx_template(crypto_provider_handle_t,
1597c478bd9Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
1607c478bd9Sstevel@tonic-gate     size_t *, crypto_req_handle_t);
1617c478bd9Sstevel@tonic-gate static int blowfish_free_context(crypto_ctx_t *);
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate static crypto_ctx_ops_t blowfish_ctx_ops = {
1647c478bd9Sstevel@tonic-gate 	blowfish_create_ctx_template,
1657c478bd9Sstevel@tonic-gate 	blowfish_free_context
1667c478bd9Sstevel@tonic-gate };
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate static crypto_ops_t blowfish_crypto_ops = {
1697c478bd9Sstevel@tonic-gate 	&blowfish_control_ops,
1707c478bd9Sstevel@tonic-gate 	NULL,
1717c478bd9Sstevel@tonic-gate 	&blowfish_cipher_ops,
1727c478bd9Sstevel@tonic-gate 	NULL,
1737c478bd9Sstevel@tonic-gate 	NULL,
1747c478bd9Sstevel@tonic-gate 	NULL,
1757c478bd9Sstevel@tonic-gate 	NULL,
1767c478bd9Sstevel@tonic-gate 	NULL,
1777c478bd9Sstevel@tonic-gate 	NULL,
1787c478bd9Sstevel@tonic-gate 	NULL,
1797c478bd9Sstevel@tonic-gate 	NULL,
1807c478bd9Sstevel@tonic-gate 	NULL,
1817c478bd9Sstevel@tonic-gate 	NULL,
1827c478bd9Sstevel@tonic-gate 	&blowfish_ctx_ops
1837c478bd9Sstevel@tonic-gate };
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate static crypto_provider_info_t blowfish_prov_info = {
1867c478bd9Sstevel@tonic-gate 	CRYPTO_SPI_VERSION_1,
1877c478bd9Sstevel@tonic-gate 	"Blowfish Software Provider",
1887c478bd9Sstevel@tonic-gate 	CRYPTO_SW_PROVIDER,
1897c478bd9Sstevel@tonic-gate 	{&modlinkage},
1907c478bd9Sstevel@tonic-gate 	NULL,
1917c478bd9Sstevel@tonic-gate 	&blowfish_crypto_ops,
1927c478bd9Sstevel@tonic-gate 	sizeof (blowfish_mech_info_tab)/sizeof (crypto_mech_info_t),
1937c478bd9Sstevel@tonic-gate 	blowfish_mech_info_tab
1947c478bd9Sstevel@tonic-gate };
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate static crypto_kcf_provider_handle_t blowfish_prov_handle = NULL;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate int
2007c478bd9Sstevel@tonic-gate _init(void)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	int ret;
2037c478bd9Sstevel@tonic-gate 
204*d3b2efc7SAnthony Scarpino 	if ((ret = mod_install(&modlinkage)) != 0)
205*d3b2efc7SAnthony Scarpino 		return (ret);
206*d3b2efc7SAnthony Scarpino 
207*d3b2efc7SAnthony Scarpino 	/* Register with KCF.  If the registration fails, remove the module. */
208*d3b2efc7SAnthony Scarpino 	if (crypto_register_provider(&blowfish_prov_info,
209*d3b2efc7SAnthony Scarpino 	    &blowfish_prov_handle)) {
210*d3b2efc7SAnthony Scarpino 		(void) mod_remove(&modlinkage);
2117c478bd9Sstevel@tonic-gate 		return (EACCES);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
214*d3b2efc7SAnthony Scarpino 	return (0);
2157c478bd9Sstevel@tonic-gate }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate int
2187c478bd9Sstevel@tonic-gate _fini(void)
2197c478bd9Sstevel@tonic-gate {
220*d3b2efc7SAnthony Scarpino 	/* Unregister from KCF if module is registered */
2217c478bd9Sstevel@tonic-gate 	if (blowfish_prov_handle != NULL) {
222*d3b2efc7SAnthony Scarpino 		if (crypto_unregister_provider(blowfish_prov_handle))
2237c478bd9Sstevel@tonic-gate 			return (EBUSY);
224*d3b2efc7SAnthony Scarpino 
2257c478bd9Sstevel@tonic-gate 		blowfish_prov_handle = NULL;
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate int
2327c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * Initialize key schedules for blowfish
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate static int
2417c478bd9Sstevel@tonic-gate init_keysched(crypto_key_t *key, void *keysched)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	switch (key->ck_format) {
2477c478bd9Sstevel@tonic-gate 	case CRYPTO_KEY_RAW:
2487c478bd9Sstevel@tonic-gate 		if (key->ck_length < BLOWFISH_MINBITS ||
2497c478bd9Sstevel@tonic-gate 		    key->ck_length > BLOWFISH_MAXBITS) {
2507c478bd9Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
2517c478bd9Sstevel@tonic-gate 		}
2527c478bd9Sstevel@tonic-gate 		break;
2537c478bd9Sstevel@tonic-gate 	default:
2547c478bd9Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	blowfish_init_keysched(key->ck_data, key->ck_length, keysched);
2587c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * KCF software provider control entry points.
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate /* ARGSUSED */
2657c478bd9Sstevel@tonic-gate static void
2667c478bd9Sstevel@tonic-gate blowfish_provider_status(crypto_provider_handle_t provider, uint_t *status)
2677c478bd9Sstevel@tonic-gate {
2687c478bd9Sstevel@tonic-gate 	*status = CRYPTO_PROVIDER_READY;
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * KCF software provider encrypt entry points.
2737c478bd9Sstevel@tonic-gate  */
2747c478bd9Sstevel@tonic-gate static int
2757c478bd9Sstevel@tonic-gate blowfish_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
2767c478bd9Sstevel@tonic-gate     crypto_key_t *key, crypto_spi_ctx_template_t template,
2777c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
2787c478bd9Sstevel@tonic-gate {
2797c478bd9Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
2807c478bd9Sstevel@tonic-gate 	int rv;
2817c478bd9Sstevel@tonic-gate 	int kmflag;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/*
2847c478bd9Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
2857c478bd9Sstevel@tonic-gate 	 */
2867c478bd9Sstevel@tonic-gate 	if (key->ck_format != CRYPTO_KEY_RAW) {
2877c478bd9Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
2917c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	if (mechanism->cm_param != NULL &&
2947c478bd9Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
2957c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	kmflag = crypto_kmflag(req);
29823c57df7Smcpowers 	switch (mechanism->cm_type) {
29923c57df7Smcpowers 	case BLOWFISH_ECB_MECH_INFO_TYPE:
30023c57df7Smcpowers 		blowfish_ctx = ecb_alloc_ctx(kmflag);
30123c57df7Smcpowers 		break;
30223c57df7Smcpowers 	case BLOWFISH_CBC_MECH_INFO_TYPE:
30323c57df7Smcpowers 		blowfish_ctx = cbc_alloc_ctx(kmflag);
30423c57df7Smcpowers 		break;
30523c57df7Smcpowers 	}
3067c478bd9Sstevel@tonic-gate 	if (blowfish_ctx == NULL)
3077c478bd9Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	rv = blowfish_common_init_ctx(blowfish_ctx, template, mechanism,
3107c478bd9Sstevel@tonic-gate 	    key, kmflag);
3117c478bd9Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
31223c57df7Smcpowers 		crypto_free_mode_ctx(blowfish_ctx);
3137c478bd9Sstevel@tonic-gate 		return (rv);
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	ctx->cc_provider_private = blowfish_ctx;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate 
32123c57df7Smcpowers static void
32223c57df7Smcpowers blowfish_copy_block64(uint8_t *in, uint64_t *out)
3237c478bd9Sstevel@tonic-gate {
32423c57df7Smcpowers 	if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
3257c478bd9Sstevel@tonic-gate 		/* LINTED: pointer alignment */
32623c57df7Smcpowers 		out[0] = *(uint64_t *)&in[0];
3277c478bd9Sstevel@tonic-gate 	} else {
32823c57df7Smcpowers 		uint8_t *iv8 = (uint8_t *)&out[0];
3297c478bd9Sstevel@tonic-gate 
33023c57df7Smcpowers 		BLOWFISH_COPY_BLOCK(in, iv8);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /* ARGSUSED */
3357c478bd9Sstevel@tonic-gate static int
3367c478bd9Sstevel@tonic-gate blowfish_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
3377c478bd9Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
3387c478bd9Sstevel@tonic-gate {
3397c478bd9Sstevel@tonic-gate 	int ret;
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/*
3447c478bd9Sstevel@tonic-gate 	 * Plaintext must be a multiple of blowfish block size.
3457c478bd9Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
3467c478bd9Sstevel@tonic-gate 	 * when blocksize is 2^N.
3477c478bd9Sstevel@tonic-gate 	 */
3487c478bd9Sstevel@tonic-gate 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
3497c478bd9Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
3527c478bd9Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	/*
3577c478bd9Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
3587c478bd9Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
3597c478bd9Sstevel@tonic-gate 	 */
3607c478bd9Sstevel@tonic-gate 	if (ciphertext->cd_length < plaintext->cd_length) {
3617c478bd9Sstevel@tonic-gate 		ciphertext->cd_length = plaintext->cd_length;
3627c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
3637c478bd9Sstevel@tonic-gate 	}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/*
3667c478bd9Sstevel@tonic-gate 	 * Do an update on the specified input data.
3677c478bd9Sstevel@tonic-gate 	 */
3687c478bd9Sstevel@tonic-gate 	ret = blowfish_encrypt_update(ctx, plaintext, ciphertext, req);
3697c478bd9Sstevel@tonic-gate 	ASSERT(blowfish_ctx->bc_remainder_len  == 0);
3707c478bd9Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	/* LINTED */
3737c478bd9Sstevel@tonic-gate 	return (ret);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /* ARGSUSED */
3777c478bd9Sstevel@tonic-gate static int
3787c478bd9Sstevel@tonic-gate blowfish_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
3797c478bd9Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
3807c478bd9Sstevel@tonic-gate {
3817c478bd9Sstevel@tonic-gate 	int ret;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/*
3867c478bd9Sstevel@tonic-gate 	 * Ciphertext must be a multiple of blowfish block size.
3877c478bd9Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
3887c478bd9Sstevel@tonic-gate 	 * when blocksize is 2^N.
3897c478bd9Sstevel@tonic-gate 	 */
3907c478bd9Sstevel@tonic-gate 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
3917c478bd9Sstevel@tonic-gate 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
3947c478bd9Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	/*
3997c478bd9Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
4007c478bd9Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
4017c478bd9Sstevel@tonic-gate 	 */
4027c478bd9Sstevel@tonic-gate 	if (plaintext->cd_length < ciphertext->cd_length) {
4037c478bd9Sstevel@tonic-gate 		plaintext->cd_length = ciphertext->cd_length;
4047c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	/*
4087c478bd9Sstevel@tonic-gate 	 * Do an update on the specified input data.
4097c478bd9Sstevel@tonic-gate 	 */
4107c478bd9Sstevel@tonic-gate 	ret = blowfish_decrypt_update(ctx, ciphertext, plaintext, req);
4117c478bd9Sstevel@tonic-gate 	ASSERT(blowfish_ctx->bc_remainder_len == 0);
4127c478bd9Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/* LINTED */
4157c478bd9Sstevel@tonic-gate 	return (ret);
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /* ARGSUSED */
4197c478bd9Sstevel@tonic-gate static int
4207c478bd9Sstevel@tonic-gate blowfish_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
4217c478bd9Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate 	off_t saved_offset;
4247c478bd9Sstevel@tonic-gate 	size_t saved_length, out_len;
4257c478bd9Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	/* compute number of bytes that will hold the ciphertext */
4327c478bd9Sstevel@tonic-gate 	out_len =
4337c478bd9Sstevel@tonic-gate 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
4347c478bd9Sstevel@tonic-gate 	out_len += plaintext->cd_length;
4357c478bd9Sstevel@tonic-gate 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	/* return length needed to store the output */
4387c478bd9Sstevel@tonic-gate 	if (ciphertext->cd_length < out_len) {
4397c478bd9Sstevel@tonic-gate 		ciphertext->cd_length = out_len;
4407c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
4417c478bd9Sstevel@tonic-gate 	}
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
4447c478bd9Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/*
4477c478bd9Sstevel@tonic-gate 	 * Do the blowfish update on the specified input data.
4487c478bd9Sstevel@tonic-gate 	 */
4497c478bd9Sstevel@tonic-gate 	switch (plaintext->cd_format) {
4507c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
45123c57df7Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
45223c57df7Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
45323c57df7Smcpowers 		    blowfish_copy_block64);
4547c478bd9Sstevel@tonic-gate 		break;
4557c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
45623c57df7Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
45723c57df7Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
45823c57df7Smcpowers 		    blowfish_copy_block64);
4597c478bd9Sstevel@tonic-gate 		break;
4607c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
46123c57df7Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
46223c57df7Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
46323c57df7Smcpowers 		    blowfish_copy_block64);
4647c478bd9Sstevel@tonic-gate 		break;
4657c478bd9Sstevel@tonic-gate 	default:
4667c478bd9Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
4707c478bd9Sstevel@tonic-gate 		if (plaintext != ciphertext)
4717c478bd9Sstevel@tonic-gate 			ciphertext->cd_length =
4727c478bd9Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
4737c478bd9Sstevel@tonic-gate 	} else {
4747c478bd9Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
4757c478bd9Sstevel@tonic-gate 	}
4767c478bd9Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	return (ret);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /* ARGSUSED */
4827c478bd9Sstevel@tonic-gate static int
4837c478bd9Sstevel@tonic-gate blowfish_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
4847c478bd9Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	off_t saved_offset;
4877c478bd9Sstevel@tonic-gate 	size_t saved_length, out_len;
4887c478bd9Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	/* compute number of bytes that will hold the plaintext */
4957c478bd9Sstevel@tonic-gate 	out_len =
4967c478bd9Sstevel@tonic-gate 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
4977c478bd9Sstevel@tonic-gate 	out_len += ciphertext->cd_length;
4987c478bd9Sstevel@tonic-gate 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/* return length needed to store the output */
5017c478bd9Sstevel@tonic-gate 	if (plaintext->cd_length < out_len) {
5027c478bd9Sstevel@tonic-gate 		plaintext->cd_length = out_len;
5037c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
5077c478bd9Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/*
5107c478bd9Sstevel@tonic-gate 	 * Do the blowfish update on the specified input data.
5117c478bd9Sstevel@tonic-gate 	 */
5127c478bd9Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
5137c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
51423c57df7Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
51523c57df7Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
51623c57df7Smcpowers 		    blowfish_copy_block64);
5177c478bd9Sstevel@tonic-gate 		break;
5187c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
51923c57df7Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
52023c57df7Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
52123c57df7Smcpowers 		    blowfish_copy_block64);
5227c478bd9Sstevel@tonic-gate 		break;
5237c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
52423c57df7Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
52523c57df7Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
52623c57df7Smcpowers 		    blowfish_copy_block64);
5277c478bd9Sstevel@tonic-gate 		break;
5287c478bd9Sstevel@tonic-gate 	default:
5297c478bd9Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
5337c478bd9Sstevel@tonic-gate 		if (ciphertext != plaintext)
5347c478bd9Sstevel@tonic-gate 			plaintext->cd_length =
5357c478bd9Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
5367c478bd9Sstevel@tonic-gate 	} else {
5377c478bd9Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
5387c478bd9Sstevel@tonic-gate 	}
5397c478bd9Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	return (ret);
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /* ARGSUSED */
5457c478bd9Sstevel@tonic-gate static int
5467c478bd9Sstevel@tonic-gate blowfish_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
5477c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5527c478bd9Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * There must be no unprocessed data.
5567c478bd9Sstevel@tonic-gate 	 * This happens if the length of the last data is
5577c478bd9Sstevel@tonic-gate 	 * not a multiple of the BLOWFISH block length.
5587c478bd9Sstevel@tonic-gate 	 */
5597c478bd9Sstevel@tonic-gate 	if (blowfish_ctx->bc_remainder_len > 0)
5607c478bd9Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
5637c478bd9Sstevel@tonic-gate 	data->cd_length = 0;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate /* ARGSUSED */
5697c478bd9Sstevel@tonic-gate static int
5707c478bd9Sstevel@tonic-gate blowfish_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
5717c478bd9Sstevel@tonic-gate     crypto_req_handle_t req)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5767c478bd9Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	/*
5797c478bd9Sstevel@tonic-gate 	 * There must be no unprocessed ciphertext.
5807c478bd9Sstevel@tonic-gate 	 * This happens if the length of the last ciphertext is
5817c478bd9Sstevel@tonic-gate 	 * not a multiple of the BLOWFISH block length.
5827c478bd9Sstevel@tonic-gate 	 */
5837c478bd9Sstevel@tonic-gate 	if (blowfish_ctx->bc_remainder_len > 0)
5847c478bd9Sstevel@tonic-gate 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
5877c478bd9Sstevel@tonic-gate 	data->cd_length = 0;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate /* ARGSUSED */
5937c478bd9Sstevel@tonic-gate static int
5947c478bd9Sstevel@tonic-gate blowfish_encrypt_atomic(crypto_provider_handle_t provider,
5957c478bd9Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
5967c478bd9Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
5977c478bd9Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
6007c478bd9Sstevel@tonic-gate 	off_t saved_offset;
6017c478bd9Sstevel@tonic-gate 	size_t saved_length;
6027c478bd9Sstevel@tonic-gate 	int ret;
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	/*
6077c478bd9Sstevel@tonic-gate 	 * Plaintext must be a multiple of blowfish block size.
6087c478bd9Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
6097c478bd9Sstevel@tonic-gate 	 * when blocksize is 2^N.
6107c478bd9Sstevel@tonic-gate 	 */
6117c478bd9Sstevel@tonic-gate 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
6127c478bd9Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	/* return length needed to store the output */
6157c478bd9Sstevel@tonic-gate 	if (ciphertext->cd_length < plaintext->cd_length) {
6167c478bd9Sstevel@tonic-gate 		ciphertext->cd_length = plaintext->cd_length;
6177c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
6217c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	if (mechanism->cm_param_len != 0 &&
6247c478bd9Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
6257c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
6307c478bd9Sstevel@tonic-gate 	    key, crypto_kmflag(req));
6317c478bd9Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
6327c478bd9Sstevel@tonic-gate 		return (ret);
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
6357c478bd9Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	/*
6387c478bd9Sstevel@tonic-gate 	 * Do an update on the specified input data.
6397c478bd9Sstevel@tonic-gate 	 */
6407c478bd9Sstevel@tonic-gate 	switch (plaintext->cd_format) {
6417c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
64223c57df7Smcpowers 		ret = crypto_update_iov(&blowfish_ctx,
64323c57df7Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
64423c57df7Smcpowers 		    blowfish_copy_block64);
6457c478bd9Sstevel@tonic-gate 		break;
6467c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
64723c57df7Smcpowers 		ret = crypto_update_uio(&blowfish_ctx,
64823c57df7Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
64923c57df7Smcpowers 		    blowfish_copy_block64);
6507c478bd9Sstevel@tonic-gate 		break;
6517c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
65223c57df7Smcpowers 		ret = crypto_update_mp((void *)&blowfish_ctx,
65323c57df7Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
65423c57df7Smcpowers 		    blowfish_copy_block64);
6557c478bd9Sstevel@tonic-gate 		break;
6567c478bd9Sstevel@tonic-gate 	default:
6577c478bd9Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
66023c57df7Smcpowers 	if (blowfish_ctx.bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
6617c478bd9Sstevel@tonic-gate 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
6627c478bd9Sstevel@tonic-gate 		kmem_free(blowfish_ctx.bc_keysched,
6637c478bd9Sstevel@tonic-gate 		    blowfish_ctx.bc_keysched_len);
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
6677c478bd9Sstevel@tonic-gate 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
6687c478bd9Sstevel@tonic-gate 		if (plaintext != ciphertext)
6697c478bd9Sstevel@tonic-gate 			ciphertext->cd_length =
6707c478bd9Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
6717c478bd9Sstevel@tonic-gate 	} else {
6727c478bd9Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
6737c478bd9Sstevel@tonic-gate 	}
6747c478bd9Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	return (ret);
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /* ARGSUSED */
6807c478bd9Sstevel@tonic-gate static int
6817c478bd9Sstevel@tonic-gate blowfish_decrypt_atomic(crypto_provider_handle_t provider,
6827c478bd9Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
6837c478bd9Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
6847c478bd9Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
6857c478bd9Sstevel@tonic-gate {
6867c478bd9Sstevel@tonic-gate 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
6877c478bd9Sstevel@tonic-gate 	off_t saved_offset;
6887c478bd9Sstevel@tonic-gate 	size_t saved_length;
6897c478bd9Sstevel@tonic-gate 	int ret;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/*
6947c478bd9Sstevel@tonic-gate 	 * Ciphertext must be a multiple of blowfish block size.
6957c478bd9Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
6967c478bd9Sstevel@tonic-gate 	 * when blocksize is 2^N.
6977c478bd9Sstevel@tonic-gate 	 */
6987c478bd9Sstevel@tonic-gate 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
6997c478bd9Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/* return length needed to store the output */
7027c478bd9Sstevel@tonic-gate 	if (plaintext->cd_length < ciphertext->cd_length) {
7037c478bd9Sstevel@tonic-gate 		plaintext->cd_length = ciphertext->cd_length;
7047c478bd9Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
7087c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (mechanism->cm_param_len != 0 &&
7117c478bd9Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
7127c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
7177c478bd9Sstevel@tonic-gate 	    key, crypto_kmflag(req));
7187c478bd9Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
7197c478bd9Sstevel@tonic-gate 		return (ret);
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
7227c478bd9Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	/*
7257c478bd9Sstevel@tonic-gate 	 * Do an update on the specified input data.
7267c478bd9Sstevel@tonic-gate 	 */
7277c478bd9Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
7287c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
72923c57df7Smcpowers 		ret = crypto_update_iov(&blowfish_ctx,
73023c57df7Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
73123c57df7Smcpowers 		    blowfish_copy_block64);
7327c478bd9Sstevel@tonic-gate 		break;
7337c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
73423c57df7Smcpowers 		ret = crypto_update_uio(&blowfish_ctx,
73523c57df7Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
73623c57df7Smcpowers 		    blowfish_copy_block64);
7377c478bd9Sstevel@tonic-gate 		break;
7387c478bd9Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
73923c57df7Smcpowers 		ret = crypto_update_mp(&blowfish_ctx,
74023c57df7Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
74123c57df7Smcpowers 		    blowfish_copy_block64);
7427c478bd9Sstevel@tonic-gate 		break;
7437c478bd9Sstevel@tonic-gate 	default:
7447c478bd9Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
74723c57df7Smcpowers 	if (blowfish_ctx.bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
7487c478bd9Sstevel@tonic-gate 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
7497c478bd9Sstevel@tonic-gate 		kmem_free(blowfish_ctx.bc_keysched,
7507c478bd9Sstevel@tonic-gate 		    blowfish_ctx.bc_keysched_len);
7517c478bd9Sstevel@tonic-gate 	}
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
7547c478bd9Sstevel@tonic-gate 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
7557c478bd9Sstevel@tonic-gate 		if (ciphertext != plaintext)
7567c478bd9Sstevel@tonic-gate 			plaintext->cd_length =
7577c478bd9Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
7587c478bd9Sstevel@tonic-gate 	} else {
7597c478bd9Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	return (ret);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate /*
7677c478bd9Sstevel@tonic-gate  * KCF software provider context template entry points.
7687c478bd9Sstevel@tonic-gate  */
7697c478bd9Sstevel@tonic-gate /* ARGSUSED */
7707c478bd9Sstevel@tonic-gate static int
7717c478bd9Sstevel@tonic-gate blowfish_create_ctx_template(crypto_provider_handle_t provider,
7727c478bd9Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key,
7737c478bd9Sstevel@tonic-gate     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
7747c478bd9Sstevel@tonic-gate {
7757c478bd9Sstevel@tonic-gate 	void *keysched;
7767c478bd9Sstevel@tonic-gate 	size_t size;
7777c478bd9Sstevel@tonic-gate 	int rv;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
7807c478bd9Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	if ((keysched = blowfish_alloc_keysched(&size,
7837c478bd9Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL) {
7847c478bd9Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/*
7887c478bd9Sstevel@tonic-gate 	 * Initialize key schedule.  Key length information is stored
7897c478bd9Sstevel@tonic-gate 	 * in the key.
7907c478bd9Sstevel@tonic-gate 	 */
7917c478bd9Sstevel@tonic-gate 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
7927c478bd9Sstevel@tonic-gate 		bzero(keysched, size);
7937c478bd9Sstevel@tonic-gate 		kmem_free(keysched, size);
7947c478bd9Sstevel@tonic-gate 		return (rv);
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	*tmpl = keysched;
7987c478bd9Sstevel@tonic-gate 	*tmpl_size = size;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate /* ARGSUSED */
8047c478bd9Sstevel@tonic-gate static int
8057c478bd9Sstevel@tonic-gate blowfish_free_context(crypto_ctx_t *ctx)
8067c478bd9Sstevel@tonic-gate {
8077c478bd9Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx = ctx->cc_provider_private;
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	if (blowfish_ctx != NULL) {
81023c57df7Smcpowers 		if (blowfish_ctx->bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
8117c478bd9Sstevel@tonic-gate 			ASSERT(blowfish_ctx->bc_keysched_len != 0);
8127c478bd9Sstevel@tonic-gate 			bzero(blowfish_ctx->bc_keysched,
8137c478bd9Sstevel@tonic-gate 			    blowfish_ctx->bc_keysched_len);
8147c478bd9Sstevel@tonic-gate 			kmem_free(blowfish_ctx->bc_keysched,
8157c478bd9Sstevel@tonic-gate 			    blowfish_ctx->bc_keysched_len);
8167c478bd9Sstevel@tonic-gate 		}
81723c57df7Smcpowers 		crypto_free_mode_ctx(blowfish_ctx);
8187c478bd9Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
8227c478bd9Sstevel@tonic-gate }
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate /* ARGSUSED */
8257c478bd9Sstevel@tonic-gate static int
8267c478bd9Sstevel@tonic-gate blowfish_common_init_ctx(blowfish_ctx_t *blowfish_ctx,
8277c478bd9Sstevel@tonic-gate     crypto_spi_ctx_template_t *template, crypto_mechanism_t *mechanism,
8287c478bd9Sstevel@tonic-gate     crypto_key_t *key, int kmflag)
8297c478bd9Sstevel@tonic-gate {
8307c478bd9Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	void *keysched;
8337c478bd9Sstevel@tonic-gate 	size_t size;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	if (template == NULL) {
8367c478bd9Sstevel@tonic-gate 		if ((keysched = blowfish_alloc_keysched(&size, kmflag)) == NULL)
8377c478bd9Sstevel@tonic-gate 			return (CRYPTO_HOST_MEMORY);
8387c478bd9Sstevel@tonic-gate 		/*
8397c478bd9Sstevel@tonic-gate 		 * Initialize key schedule.
8407c478bd9Sstevel@tonic-gate 		 * Key length is stored in the key.
8417c478bd9Sstevel@tonic-gate 		 */
8427c478bd9Sstevel@tonic-gate 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS)
8437c478bd9Sstevel@tonic-gate 			kmem_free(keysched, size);
8447c478bd9Sstevel@tonic-gate 
84523c57df7Smcpowers 		blowfish_ctx->bc_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
8467c478bd9Sstevel@tonic-gate 		blowfish_ctx->bc_keysched_len = size;
8477c478bd9Sstevel@tonic-gate 	} else {
8487c478bd9Sstevel@tonic-gate 		keysched = template;
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 	blowfish_ctx->bc_keysched = keysched;
8517c478bd9Sstevel@tonic-gate 
85223c57df7Smcpowers 	switch (mechanism->cm_type) {
85323c57df7Smcpowers 	case BLOWFISH_CBC_MECH_INFO_TYPE:
85423c57df7Smcpowers 		rv = cbc_init_ctx((cbc_ctx_t *)blowfish_ctx,
85523c57df7Smcpowers 		    mechanism->cm_param, mechanism->cm_param_len,
85623c57df7Smcpowers 		    BLOWFISH_BLOCK_LEN, blowfish_copy_block64);
85723c57df7Smcpowers 		break;
85823c57df7Smcpowers 	case BLOWFISH_ECB_MECH_INFO_TYPE:
85923c57df7Smcpowers 		blowfish_ctx->bc_flags |= ECB_MODE;
86023c57df7Smcpowers 	}
86123c57df7Smcpowers 
86223c57df7Smcpowers 	if (rv != CRYPTO_SUCCESS) {
86323c57df7Smcpowers 		if (blowfish_ctx->bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
86423c57df7Smcpowers 			bzero(keysched, size);
86523c57df7Smcpowers 			kmem_free(keysched, size);
86623c57df7Smcpowers 		}
86723c57df7Smcpowers 	}
86823c57df7Smcpowers 
8697c478bd9Sstevel@tonic-gate 	return (rv);
8707c478bd9Sstevel@tonic-gate }
871