xref: /onnv-gate/usr/src/uts/common/crypto/io/blowfish.c (revision 11751:58c0c8f4305f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55072Smcpowers  * Common Development and Distribution License (the "License").
65072Smcpowers  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11751SAnthony.Scarpino@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Blowfish provider for the Kernel Cryptographic Framework (KCF)
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/types.h>
310Sstevel@tonic-gate #include <sys/systm.h>
320Sstevel@tonic-gate #include <sys/modctl.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/crypto/common.h>
360Sstevel@tonic-gate #include <sys/crypto/spi.h>
370Sstevel@tonic-gate #include <sys/sysmacros.h>
380Sstevel@tonic-gate #include <sys/strsun.h>
390Sstevel@tonic-gate #include <sys/note.h>
407188Smcpowers #include <modes/modes.h>
417188Smcpowers #include <blowfish/blowfish_impl.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate extern struct mod_ops mod_cryptoops;
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * Module linkage information for the kernel.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate static struct modlcrypto modlcrypto = {
490Sstevel@tonic-gate 	&mod_cryptoops,
505072Smcpowers 	"Blowfish Kernel SW Provider"
510Sstevel@tonic-gate };
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static struct modlinkage modlinkage = {
540Sstevel@tonic-gate 	MODREV_1,
550Sstevel@tonic-gate 	(void *)&modlcrypto,
560Sstevel@tonic-gate 	NULL
570Sstevel@tonic-gate };
580Sstevel@tonic-gate 
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate  * CSPI information (entry points, provider info, etc.)
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate typedef enum blowfish_mech_type {
63676Sizick 	BLOWFISH_ECB_MECH_INFO_TYPE,		/* SUN_CKM_BLOWFISH_ECB */
64676Sizick 	BLOWFISH_CBC_MECH_INFO_TYPE		/* SUN_CKM_BLOWFISH_CBC */
650Sstevel@tonic-gate } blowfish_mech_type_t;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 
680Sstevel@tonic-gate #define	BLOWFISH_COPY_BLOCK(src, dst) \
690Sstevel@tonic-gate 	(dst)[0] = (src)[0]; \
700Sstevel@tonic-gate 	(dst)[1] = (src)[1]; \
710Sstevel@tonic-gate 	(dst)[2] = (src)[2]; \
720Sstevel@tonic-gate 	(dst)[3] = (src)[3]; \
730Sstevel@tonic-gate 	(dst)[4] = (src)[4]; \
740Sstevel@tonic-gate 	(dst)[5] = (src)[5]; \
750Sstevel@tonic-gate 	(dst)[6] = (src)[6]; \
760Sstevel@tonic-gate 	(dst)[7] = (src)[7]
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #define	BLOWFISH_XOR_BLOCK(src, dst) \
790Sstevel@tonic-gate 	(dst)[0] ^= (src)[0]; \
800Sstevel@tonic-gate 	(dst)[1] ^= (src)[1]; \
810Sstevel@tonic-gate 	(dst)[2] ^= (src)[2]; \
820Sstevel@tonic-gate 	(dst)[3] ^= (src)[3]; \
830Sstevel@tonic-gate 	(dst)[4] ^= (src)[4]; \
840Sstevel@tonic-gate 	(dst)[5] ^= (src)[5]; \
850Sstevel@tonic-gate 	(dst)[6] ^= (src)[6]; \
860Sstevel@tonic-gate 	(dst)[7] ^= (src)[7]
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * Mechanism info structure passed to KCF during registration.
900Sstevel@tonic-gate  */
910Sstevel@tonic-gate 
920Sstevel@tonic-gate static crypto_mech_info_t blowfish_mech_info_tab[] = {
930Sstevel@tonic-gate 	/* BLOWFISH_ECB */
94676Sizick 	{SUN_CKM_BLOWFISH_ECB, BLOWFISH_ECB_MECH_INFO_TYPE,
950Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
960Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
970Sstevel@tonic-gate 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS},
980Sstevel@tonic-gate 	/* BLOWFISH_CBC */
99676Sizick 	{SUN_CKM_BLOWFISH_CBC, BLOWFISH_CBC_MECH_INFO_TYPE,
1000Sstevel@tonic-gate 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
1010Sstevel@tonic-gate 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
1020Sstevel@tonic-gate 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS}
1030Sstevel@tonic-gate };
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate #define	BLOWFISH_VALID_MECH(mech)				\
106676Sizick 	(((mech)->cm_type == BLOWFISH_ECB_MECH_INFO_TYPE ||		\
107676Sizick 	(mech)->cm_type == BLOWFISH_CBC_MECH_INFO_TYPE) ? 1 : 0)
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /* operations are in-place if the output buffer is NULL */
1100Sstevel@tonic-gate #define	BLOWFISH_ARG_INPLACE(input, output)			\
1110Sstevel@tonic-gate 	if ((output) == NULL)					\
1120Sstevel@tonic-gate 		(output) = (input);
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate static void blowfish_provider_status(crypto_provider_handle_t, uint_t *);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static crypto_control_ops_t blowfish_control_ops = {
1170Sstevel@tonic-gate 	blowfish_provider_status
1180Sstevel@tonic-gate };
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate static int blowfish_common_init(crypto_ctx_t *, crypto_mechanism_t *,
1210Sstevel@tonic-gate     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1220Sstevel@tonic-gate static int blowfish_common_init_ctx(blowfish_ctx_t *,
1230Sstevel@tonic-gate     crypto_spi_ctx_template_t *, crypto_mechanism_t *, crypto_key_t *, int);
1240Sstevel@tonic-gate static int blowfish_encrypt_final(crypto_ctx_t *, crypto_data_t *,
1250Sstevel@tonic-gate     crypto_req_handle_t);
1260Sstevel@tonic-gate static int blowfish_decrypt_final(crypto_ctx_t *, crypto_data_t *,
1270Sstevel@tonic-gate     crypto_req_handle_t);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static int blowfish_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1300Sstevel@tonic-gate     crypto_req_handle_t);
1310Sstevel@tonic-gate static int blowfish_encrypt_update(crypto_ctx_t *, crypto_data_t *,
1320Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1330Sstevel@tonic-gate static int blowfish_encrypt_atomic(crypto_provider_handle_t,
1340Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1350Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static int blowfish_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
1380Sstevel@tonic-gate     crypto_req_handle_t);
1390Sstevel@tonic-gate static int blowfish_decrypt_update(crypto_ctx_t *, crypto_data_t *,
1400Sstevel@tonic-gate     crypto_data_t *, crypto_req_handle_t);
1410Sstevel@tonic-gate static int blowfish_decrypt_atomic(crypto_provider_handle_t,
1420Sstevel@tonic-gate     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
1430Sstevel@tonic-gate     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate static crypto_cipher_ops_t blowfish_cipher_ops = {
1460Sstevel@tonic-gate 	blowfish_common_init,
1470Sstevel@tonic-gate 	blowfish_encrypt,
1480Sstevel@tonic-gate 	blowfish_encrypt_update,
1490Sstevel@tonic-gate 	blowfish_encrypt_final,
1500Sstevel@tonic-gate 	blowfish_encrypt_atomic,
1510Sstevel@tonic-gate 	blowfish_common_init,
1520Sstevel@tonic-gate 	blowfish_decrypt,
1530Sstevel@tonic-gate 	blowfish_decrypt_update,
1540Sstevel@tonic-gate 	blowfish_decrypt_final,
1550Sstevel@tonic-gate 	blowfish_decrypt_atomic
1560Sstevel@tonic-gate };
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate static int blowfish_create_ctx_template(crypto_provider_handle_t,
1590Sstevel@tonic-gate     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
1600Sstevel@tonic-gate     size_t *, crypto_req_handle_t);
1610Sstevel@tonic-gate static int blowfish_free_context(crypto_ctx_t *);
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate static crypto_ctx_ops_t blowfish_ctx_ops = {
1640Sstevel@tonic-gate 	blowfish_create_ctx_template,
1650Sstevel@tonic-gate 	blowfish_free_context
1660Sstevel@tonic-gate };
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate static crypto_ops_t blowfish_crypto_ops = {
1690Sstevel@tonic-gate 	&blowfish_control_ops,
1700Sstevel@tonic-gate 	NULL,
1710Sstevel@tonic-gate 	&blowfish_cipher_ops,
1720Sstevel@tonic-gate 	NULL,
1730Sstevel@tonic-gate 	NULL,
1740Sstevel@tonic-gate 	NULL,
1750Sstevel@tonic-gate 	NULL,
1760Sstevel@tonic-gate 	NULL,
1770Sstevel@tonic-gate 	NULL,
1780Sstevel@tonic-gate 	NULL,
1790Sstevel@tonic-gate 	NULL,
1800Sstevel@tonic-gate 	NULL,
1810Sstevel@tonic-gate 	NULL,
1820Sstevel@tonic-gate 	&blowfish_ctx_ops
1830Sstevel@tonic-gate };
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate static crypto_provider_info_t blowfish_prov_info = {
1860Sstevel@tonic-gate 	CRYPTO_SPI_VERSION_1,
1870Sstevel@tonic-gate 	"Blowfish Software Provider",
1880Sstevel@tonic-gate 	CRYPTO_SW_PROVIDER,
1890Sstevel@tonic-gate 	{&modlinkage},
1900Sstevel@tonic-gate 	NULL,
1910Sstevel@tonic-gate 	&blowfish_crypto_ops,
1920Sstevel@tonic-gate 	sizeof (blowfish_mech_info_tab)/sizeof (crypto_mech_info_t),
1930Sstevel@tonic-gate 	blowfish_mech_info_tab
1940Sstevel@tonic-gate };
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate static crypto_kcf_provider_handle_t blowfish_prov_handle = NULL;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate int
_init(void)2000Sstevel@tonic-gate _init(void)
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	int ret;
2030Sstevel@tonic-gate 
204*11751SAnthony.Scarpino@Sun.COM 	if ((ret = mod_install(&modlinkage)) != 0)
205*11751SAnthony.Scarpino@Sun.COM 		return (ret);
206*11751SAnthony.Scarpino@Sun.COM 
207*11751SAnthony.Scarpino@Sun.COM 	/* Register with KCF.  If the registration fails, remove the module. */
208*11751SAnthony.Scarpino@Sun.COM 	if (crypto_register_provider(&blowfish_prov_info,
209*11751SAnthony.Scarpino@Sun.COM 	    &blowfish_prov_handle)) {
210*11751SAnthony.Scarpino@Sun.COM 		(void) mod_remove(&modlinkage);
2110Sstevel@tonic-gate 		return (EACCES);
2120Sstevel@tonic-gate 	}
2130Sstevel@tonic-gate 
214*11751SAnthony.Scarpino@Sun.COM 	return (0);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate int
_fini(void)2180Sstevel@tonic-gate _fini(void)
2190Sstevel@tonic-gate {
220*11751SAnthony.Scarpino@Sun.COM 	/* Unregister from KCF if module is registered */
2210Sstevel@tonic-gate 	if (blowfish_prov_handle != NULL) {
222*11751SAnthony.Scarpino@Sun.COM 		if (crypto_unregister_provider(blowfish_prov_handle))
2230Sstevel@tonic-gate 			return (EBUSY);
224*11751SAnthony.Scarpino@Sun.COM 
2250Sstevel@tonic-gate 		blowfish_prov_handle = NULL;
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
2290Sstevel@tonic-gate }
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2320Sstevel@tonic-gate _info(struct modinfo *modinfop)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /*
2380Sstevel@tonic-gate  * Initialize key schedules for blowfish
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate static int
init_keysched(crypto_key_t * key,void * keysched)2410Sstevel@tonic-gate init_keysched(crypto_key_t *key, void *keysched)
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate /* EXPORT DELETE START */
2440Sstevel@tonic-gate 	/*
2450Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
2460Sstevel@tonic-gate 	 */
2470Sstevel@tonic-gate 	switch (key->ck_format) {
2480Sstevel@tonic-gate 	case CRYPTO_KEY_RAW:
2490Sstevel@tonic-gate 		if (key->ck_length < BLOWFISH_MINBITS ||
2500Sstevel@tonic-gate 		    key->ck_length > BLOWFISH_MAXBITS) {
2510Sstevel@tonic-gate 			return (CRYPTO_KEY_SIZE_RANGE);
2520Sstevel@tonic-gate 		}
2530Sstevel@tonic-gate 		break;
2540Sstevel@tonic-gate 	default:
2550Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
2560Sstevel@tonic-gate 	}
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	blowfish_init_keysched(key->ck_data, key->ck_length, keysched);
2590Sstevel@tonic-gate /* EXPORT DELETE END */
2600Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate  * KCF software provider control entry points.
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate /* ARGSUSED */
2670Sstevel@tonic-gate static void
blowfish_provider_status(crypto_provider_handle_t provider,uint_t * status)2680Sstevel@tonic-gate blowfish_provider_status(crypto_provider_handle_t provider, uint_t *status)
2690Sstevel@tonic-gate {
2700Sstevel@tonic-gate 	*status = CRYPTO_PROVIDER_READY;
2710Sstevel@tonic-gate }
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate /*
2740Sstevel@tonic-gate  * KCF software provider encrypt entry points.
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate static int
blowfish_common_init(crypto_ctx_t * ctx,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t template,crypto_req_handle_t req)2770Sstevel@tonic-gate blowfish_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
2780Sstevel@tonic-gate     crypto_key_t *key, crypto_spi_ctx_template_t template,
2790Sstevel@tonic-gate     crypto_req_handle_t req)
2800Sstevel@tonic-gate {
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate /* EXPORT DELETE START */
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
2850Sstevel@tonic-gate 	int rv;
2860Sstevel@tonic-gate 	int kmflag;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/*
2890Sstevel@tonic-gate 	 * Only keys by value are supported by this module.
2900Sstevel@tonic-gate 	 */
2910Sstevel@tonic-gate 	if (key->ck_format != CRYPTO_KEY_RAW) {
2920Sstevel@tonic-gate 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
2930Sstevel@tonic-gate 	}
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
2960Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	if (mechanism->cm_param != NULL &&
2990Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
3000Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	kmflag = crypto_kmflag(req);
3037188Smcpowers 	switch (mechanism->cm_type) {
3047188Smcpowers 	case BLOWFISH_ECB_MECH_INFO_TYPE:
3057188Smcpowers 		blowfish_ctx = ecb_alloc_ctx(kmflag);
3067188Smcpowers 		break;
3077188Smcpowers 	case BLOWFISH_CBC_MECH_INFO_TYPE:
3087188Smcpowers 		blowfish_ctx = cbc_alloc_ctx(kmflag);
3097188Smcpowers 		break;
3107188Smcpowers 	}
3110Sstevel@tonic-gate 	if (blowfish_ctx == NULL)
3120Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate 	rv = blowfish_common_init_ctx(blowfish_ctx, template, mechanism,
3150Sstevel@tonic-gate 	    key, kmflag);
3160Sstevel@tonic-gate 	if (rv != CRYPTO_SUCCESS) {
3177188Smcpowers 		crypto_free_mode_ctx(blowfish_ctx);
3180Sstevel@tonic-gate 		return (rv);
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	ctx->cc_provider_private = blowfish_ctx;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate /* EXPORT DELETE END */
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate 
3287188Smcpowers static void
blowfish_copy_block64(uint8_t * in,uint64_t * out)3297188Smcpowers blowfish_copy_block64(uint8_t *in, uint64_t *out)
3300Sstevel@tonic-gate {
3317188Smcpowers 	if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
3327188Smcpowers 		/* LINTED: pointer alignment */
3337188Smcpowers 		out[0] = *(uint64_t *)&in[0];
3347188Smcpowers 	} else {
3357188Smcpowers 		uint8_t *iv8 = (uint8_t *)&out[0];
3360Sstevel@tonic-gate 
3377188Smcpowers 		BLOWFISH_COPY_BLOCK(in, iv8);
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate /* ARGSUSED */
3420Sstevel@tonic-gate static int
blowfish_encrypt(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)3430Sstevel@tonic-gate blowfish_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
3440Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
3450Sstevel@tonic-gate {
3460Sstevel@tonic-gate 	int ret;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate /* EXPORT DELETE START */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	/*
3530Sstevel@tonic-gate 	 * Plaintext must be a multiple of blowfish block size.
3540Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
3550Sstevel@tonic-gate 	 * when blocksize is 2^N.
3560Sstevel@tonic-gate 	 */
3570Sstevel@tonic-gate 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
3580Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
3610Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
3670Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
3680Sstevel@tonic-gate 	 */
3690Sstevel@tonic-gate 	if (ciphertext->cd_length < plaintext->cd_length) {
3700Sstevel@tonic-gate 		ciphertext->cd_length = plaintext->cd_length;
3710Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	/*
3750Sstevel@tonic-gate 	 * Do an update on the specified input data.
3760Sstevel@tonic-gate 	 */
3770Sstevel@tonic-gate 	ret = blowfish_encrypt_update(ctx, plaintext, ciphertext, req);
3780Sstevel@tonic-gate 	ASSERT(blowfish_ctx->bc_remainder_len  == 0);
3790Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /* EXPORT DELETE END */
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate 	/* LINTED */
3840Sstevel@tonic-gate 	return (ret);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate /* ARGSUSED */
3880Sstevel@tonic-gate static int
blowfish_decrypt(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)3890Sstevel@tonic-gate blowfish_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
3900Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	int ret;
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate /* EXPORT DELETE START */
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/*
3990Sstevel@tonic-gate 	 * Ciphertext must be a multiple of blowfish block size.
4000Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
4010Sstevel@tonic-gate 	 * when blocksize is 2^N.
4020Sstevel@tonic-gate 	 */
4030Sstevel@tonic-gate 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
4040Sstevel@tonic-gate 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
4070Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/*
4120Sstevel@tonic-gate 	 * We need to just return the length needed to store the output.
4130Sstevel@tonic-gate 	 * We should not destroy the context for the following case.
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	if (plaintext->cd_length < ciphertext->cd_length) {
4160Sstevel@tonic-gate 		plaintext->cd_length = ciphertext->cd_length;
4170Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	/*
4210Sstevel@tonic-gate 	 * Do an update on the specified input data.
4220Sstevel@tonic-gate 	 */
4230Sstevel@tonic-gate 	ret = blowfish_decrypt_update(ctx, ciphertext, plaintext, req);
4240Sstevel@tonic-gate 	ASSERT(blowfish_ctx->bc_remainder_len == 0);
4250Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate /* EXPORT DELETE END */
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	/* LINTED */
4300Sstevel@tonic-gate 	return (ret);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /* ARGSUSED */
4340Sstevel@tonic-gate static int
blowfish_encrypt_update(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)4350Sstevel@tonic-gate blowfish_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
4360Sstevel@tonic-gate     crypto_data_t *ciphertext, crypto_req_handle_t req)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	off_t saved_offset;
4390Sstevel@tonic-gate 	size_t saved_length, out_len;
4400Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/* compute number of bytes that will hold the ciphertext */
4470Sstevel@tonic-gate 	out_len =
4480Sstevel@tonic-gate 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
4490Sstevel@tonic-gate 	out_len += plaintext->cd_length;
4500Sstevel@tonic-gate 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* return length needed to store the output */
4530Sstevel@tonic-gate 	if (ciphertext->cd_length < out_len) {
4540Sstevel@tonic-gate 		ciphertext->cd_length = out_len;
4550Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
4590Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	/*
4620Sstevel@tonic-gate 	 * Do the blowfish update on the specified input data.
4630Sstevel@tonic-gate 	 */
4640Sstevel@tonic-gate 	switch (plaintext->cd_format) {
4650Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
4667188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
4677188Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
4687188Smcpowers 		    blowfish_copy_block64);
4690Sstevel@tonic-gate 		break;
4700Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
4717188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
4727188Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
4737188Smcpowers 		    blowfish_copy_block64);
4740Sstevel@tonic-gate 		break;
4750Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
4767188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
4777188Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
4787188Smcpowers 		    blowfish_copy_block64);
4790Sstevel@tonic-gate 		break;
4800Sstevel@tonic-gate 	default:
4810Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
4820Sstevel@tonic-gate 	}
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
4850Sstevel@tonic-gate 		if (plaintext != ciphertext)
4860Sstevel@tonic-gate 			ciphertext->cd_length =
4870Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
4880Sstevel@tonic-gate 	} else {
4890Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
4900Sstevel@tonic-gate 	}
4910Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	return (ret);
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate /* ARGSUSED */
4970Sstevel@tonic-gate static int
blowfish_decrypt_update(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)4980Sstevel@tonic-gate blowfish_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
4990Sstevel@tonic-gate     crypto_data_t *plaintext, crypto_req_handle_t req)
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	off_t saved_offset;
5020Sstevel@tonic-gate 	size_t saved_length, out_len;
5030Sstevel@tonic-gate 	int ret = CRYPTO_SUCCESS;
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	/* compute number of bytes that will hold the plaintext */
5100Sstevel@tonic-gate 	out_len =
5110Sstevel@tonic-gate 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
5120Sstevel@tonic-gate 	out_len += ciphertext->cd_length;
5130Sstevel@tonic-gate 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	/* return length needed to store the output */
5160Sstevel@tonic-gate 	if (plaintext->cd_length < out_len) {
5170Sstevel@tonic-gate 		plaintext->cd_length = out_len;
5180Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
5220Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
5230Sstevel@tonic-gate 
5240Sstevel@tonic-gate 	/*
5250Sstevel@tonic-gate 	 * Do the blowfish update on the specified input data.
5260Sstevel@tonic-gate 	 */
5270Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
5280Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
5297188Smcpowers 		ret = crypto_update_iov(ctx->cc_provider_private,
5307188Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
5317188Smcpowers 		    blowfish_copy_block64);
5320Sstevel@tonic-gate 		break;
5330Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
5347188Smcpowers 		ret = crypto_update_uio(ctx->cc_provider_private,
5357188Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
5367188Smcpowers 		    blowfish_copy_block64);
5370Sstevel@tonic-gate 		break;
5380Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
5397188Smcpowers 		ret = crypto_update_mp(ctx->cc_provider_private,
5407188Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
5417188Smcpowers 		    blowfish_copy_block64);
5420Sstevel@tonic-gate 		break;
5430Sstevel@tonic-gate 	default:
5440Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
5450Sstevel@tonic-gate 	}
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
5480Sstevel@tonic-gate 		if (ciphertext != plaintext)
5490Sstevel@tonic-gate 			plaintext->cd_length =
5500Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
5510Sstevel@tonic-gate 	} else {
5520Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	return (ret);
5570Sstevel@tonic-gate }
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate /* ARGSUSED */
5600Sstevel@tonic-gate static int
blowfish_encrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)5610Sstevel@tonic-gate blowfish_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
5620Sstevel@tonic-gate     crypto_req_handle_t req)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate /* EXPORT DELETE START */
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5700Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	/*
5730Sstevel@tonic-gate 	 * There must be no unprocessed data.
5740Sstevel@tonic-gate 	 * This happens if the length of the last data is
5750Sstevel@tonic-gate 	 * not a multiple of the BLOWFISH block length.
5760Sstevel@tonic-gate 	 */
5770Sstevel@tonic-gate 	if (blowfish_ctx->bc_remainder_len > 0)
5780Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
5810Sstevel@tonic-gate 	data->cd_length = 0;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate /* EXPORT DELETE END */
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate /* ARGSUSED */
5890Sstevel@tonic-gate static int
blowfish_decrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)5900Sstevel@tonic-gate blowfish_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
5910Sstevel@tonic-gate     crypto_req_handle_t req)
5920Sstevel@tonic-gate {
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate /* EXPORT DELETE START */
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 	ASSERT(ctx->cc_provider_private != NULL);
5990Sstevel@tonic-gate 	blowfish_ctx = ctx->cc_provider_private;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/*
6020Sstevel@tonic-gate 	 * There must be no unprocessed ciphertext.
6030Sstevel@tonic-gate 	 * This happens if the length of the last ciphertext is
6040Sstevel@tonic-gate 	 * not a multiple of the BLOWFISH block length.
6050Sstevel@tonic-gate 	 */
6060Sstevel@tonic-gate 	if (blowfish_ctx->bc_remainder_len > 0)
6070Sstevel@tonic-gate 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	(void) blowfish_free_context(ctx);
6100Sstevel@tonic-gate 	data->cd_length = 0;
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate /* EXPORT DELETE END */
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /* ARGSUSED */
6180Sstevel@tonic-gate static int
blowfish_encrypt_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_spi_ctx_template_t template,crypto_req_handle_t req)6190Sstevel@tonic-gate blowfish_encrypt_atomic(crypto_provider_handle_t provider,
6200Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
6210Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
6220Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
6250Sstevel@tonic-gate 	off_t saved_offset;
6260Sstevel@tonic-gate 	size_t saved_length;
6270Sstevel@tonic-gate 	int ret;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/*
6320Sstevel@tonic-gate 	 * Plaintext must be a multiple of blowfish block size.
6330Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
6340Sstevel@tonic-gate 	 * when blocksize is 2^N.
6350Sstevel@tonic-gate 	 */
6360Sstevel@tonic-gate 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
6370Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 	/* return length needed to store the output */
6400Sstevel@tonic-gate 	if (ciphertext->cd_length < plaintext->cd_length) {
6410Sstevel@tonic-gate 		ciphertext->cd_length = plaintext->cd_length;
6420Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
6460Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	if (mechanism->cm_param_len != 0 &&
6490Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
6500Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
6550Sstevel@tonic-gate 	    key, crypto_kmflag(req));
6560Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
6570Sstevel@tonic-gate 		return (ret);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	saved_offset = ciphertext->cd_offset;
6600Sstevel@tonic-gate 	saved_length = ciphertext->cd_length;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	/*
6630Sstevel@tonic-gate 	 * Do an update on the specified input data.
6640Sstevel@tonic-gate 	 */
6650Sstevel@tonic-gate 	switch (plaintext->cd_format) {
6660Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
6677188Smcpowers 		ret = crypto_update_iov(&blowfish_ctx,
6687188Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
6697188Smcpowers 		    blowfish_copy_block64);
6700Sstevel@tonic-gate 		break;
6710Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
6727188Smcpowers 		ret = crypto_update_uio(&blowfish_ctx,
6737188Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
6747188Smcpowers 		    blowfish_copy_block64);
6750Sstevel@tonic-gate 		break;
6760Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
6777188Smcpowers 		ret = crypto_update_mp((void *)&blowfish_ctx,
6787188Smcpowers 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
6797188Smcpowers 		    blowfish_copy_block64);
6800Sstevel@tonic-gate 		break;
6810Sstevel@tonic-gate 	default:
6820Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
6830Sstevel@tonic-gate 	}
6840Sstevel@tonic-gate 
6857188Smcpowers 	if (blowfish_ctx.bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
6860Sstevel@tonic-gate 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
6870Sstevel@tonic-gate 		kmem_free(blowfish_ctx.bc_keysched,
6880Sstevel@tonic-gate 		    blowfish_ctx.bc_keysched_len);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
6920Sstevel@tonic-gate 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
6930Sstevel@tonic-gate 		if (plaintext != ciphertext)
6940Sstevel@tonic-gate 			ciphertext->cd_length =
6950Sstevel@tonic-gate 			    ciphertext->cd_offset - saved_offset;
6960Sstevel@tonic-gate 	} else {
6970Sstevel@tonic-gate 		ciphertext->cd_length = saved_length;
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 	ciphertext->cd_offset = saved_offset;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	return (ret);
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /* ARGSUSED */
7050Sstevel@tonic-gate static int
blowfish_decrypt_atomic(crypto_provider_handle_t provider,crypto_session_id_t session_id,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_spi_ctx_template_t template,crypto_req_handle_t req)7060Sstevel@tonic-gate blowfish_decrypt_atomic(crypto_provider_handle_t provider,
7070Sstevel@tonic-gate     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
7080Sstevel@tonic-gate     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
7090Sstevel@tonic-gate     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
7120Sstevel@tonic-gate 	off_t saved_offset;
7130Sstevel@tonic-gate 	size_t saved_length;
7140Sstevel@tonic-gate 	int ret;
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	/*
7190Sstevel@tonic-gate 	 * Ciphertext must be a multiple of blowfish block size.
7200Sstevel@tonic-gate 	 * This test only works for non-padded mechanisms
7210Sstevel@tonic-gate 	 * when blocksize is 2^N.
7220Sstevel@tonic-gate 	 */
7230Sstevel@tonic-gate 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
7240Sstevel@tonic-gate 		return (CRYPTO_DATA_LEN_RANGE);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/* return length needed to store the output */
7270Sstevel@tonic-gate 	if (plaintext->cd_length < ciphertext->cd_length) {
7280Sstevel@tonic-gate 		plaintext->cd_length = ciphertext->cd_length;
7290Sstevel@tonic-gate 		return (CRYPTO_BUFFER_TOO_SMALL);
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
7330Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	if (mechanism->cm_param_len != 0 &&
7360Sstevel@tonic-gate 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
7370Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_PARAM_INVALID);
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
7420Sstevel@tonic-gate 	    key, crypto_kmflag(req));
7430Sstevel@tonic-gate 	if (ret != CRYPTO_SUCCESS)
7440Sstevel@tonic-gate 		return (ret);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	saved_offset = plaintext->cd_offset;
7470Sstevel@tonic-gate 	saved_length = plaintext->cd_length;
7480Sstevel@tonic-gate 
7490Sstevel@tonic-gate 	/*
7500Sstevel@tonic-gate 	 * Do an update on the specified input data.
7510Sstevel@tonic-gate 	 */
7520Sstevel@tonic-gate 	switch (ciphertext->cd_format) {
7530Sstevel@tonic-gate 	case CRYPTO_DATA_RAW:
7547188Smcpowers 		ret = crypto_update_iov(&blowfish_ctx,
7557188Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
7567188Smcpowers 		    blowfish_copy_block64);
7570Sstevel@tonic-gate 		break;
7580Sstevel@tonic-gate 	case CRYPTO_DATA_UIO:
7597188Smcpowers 		ret = crypto_update_uio(&blowfish_ctx,
7607188Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
7617188Smcpowers 		    blowfish_copy_block64);
7620Sstevel@tonic-gate 		break;
7630Sstevel@tonic-gate 	case CRYPTO_DATA_MBLK:
7647188Smcpowers 		ret = crypto_update_mp(&blowfish_ctx,
7657188Smcpowers 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
7667188Smcpowers 		    blowfish_copy_block64);
7670Sstevel@tonic-gate 		break;
7680Sstevel@tonic-gate 	default:
7690Sstevel@tonic-gate 		ret = CRYPTO_ARGUMENTS_BAD;
7700Sstevel@tonic-gate 	}
7710Sstevel@tonic-gate 
7727188Smcpowers 	if (blowfish_ctx.bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
7730Sstevel@tonic-gate 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
7740Sstevel@tonic-gate 		kmem_free(blowfish_ctx.bc_keysched,
7750Sstevel@tonic-gate 		    blowfish_ctx.bc_keysched_len);
7760Sstevel@tonic-gate 	}
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	if (ret == CRYPTO_SUCCESS) {
7790Sstevel@tonic-gate 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
7800Sstevel@tonic-gate 		if (ciphertext != plaintext)
7810Sstevel@tonic-gate 			plaintext->cd_length =
7820Sstevel@tonic-gate 			    plaintext->cd_offset - saved_offset;
7830Sstevel@tonic-gate 	} else {
7840Sstevel@tonic-gate 		plaintext->cd_length = saved_length;
7850Sstevel@tonic-gate 	}
7860Sstevel@tonic-gate 	plaintext->cd_offset = saved_offset;
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	return (ret);
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate  * KCF software provider context template entry points.
7930Sstevel@tonic-gate  */
7940Sstevel@tonic-gate /* ARGSUSED */
7950Sstevel@tonic-gate static int
blowfish_create_ctx_template(crypto_provider_handle_t provider,crypto_mechanism_t * mechanism,crypto_key_t * key,crypto_spi_ctx_template_t * tmpl,size_t * tmpl_size,crypto_req_handle_t req)7960Sstevel@tonic-gate blowfish_create_ctx_template(crypto_provider_handle_t provider,
7970Sstevel@tonic-gate     crypto_mechanism_t *mechanism, crypto_key_t *key,
7980Sstevel@tonic-gate     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
7990Sstevel@tonic-gate {
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate /* EXPORT DELETE START */
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	void *keysched;
8040Sstevel@tonic-gate 	size_t size;
8050Sstevel@tonic-gate 	int rv;
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate 	if (!BLOWFISH_VALID_MECH(mechanism))
8080Sstevel@tonic-gate 		return (CRYPTO_MECHANISM_INVALID);
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	if ((keysched = blowfish_alloc_keysched(&size,
8110Sstevel@tonic-gate 	    crypto_kmflag(req))) == NULL) {
8120Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
8130Sstevel@tonic-gate 	}
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	/*
8160Sstevel@tonic-gate 	 * Initialize key schedule.  Key length information is stored
8170Sstevel@tonic-gate 	 * in the key.
8180Sstevel@tonic-gate 	 */
8190Sstevel@tonic-gate 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
8200Sstevel@tonic-gate 		bzero(keysched, size);
8210Sstevel@tonic-gate 		kmem_free(keysched, size);
8220Sstevel@tonic-gate 		return (rv);
8230Sstevel@tonic-gate 	}
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 	*tmpl = keysched;
8260Sstevel@tonic-gate 	*tmpl_size = size;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate /* EXPORT DELETE END */
8290Sstevel@tonic-gate 
8300Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate /* ARGSUSED */
8340Sstevel@tonic-gate static int
blowfish_free_context(crypto_ctx_t * ctx)8350Sstevel@tonic-gate blowfish_free_context(crypto_ctx_t *ctx)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate 	blowfish_ctx_t *blowfish_ctx = ctx->cc_provider_private;
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 	if (blowfish_ctx != NULL) {
8407188Smcpowers 		if (blowfish_ctx->bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
8410Sstevel@tonic-gate 			ASSERT(blowfish_ctx->bc_keysched_len != 0);
8420Sstevel@tonic-gate 			bzero(blowfish_ctx->bc_keysched,
8430Sstevel@tonic-gate 			    blowfish_ctx->bc_keysched_len);
8440Sstevel@tonic-gate 			kmem_free(blowfish_ctx->bc_keysched,
8450Sstevel@tonic-gate 			    blowfish_ctx->bc_keysched_len);
8460Sstevel@tonic-gate 		}
8477188Smcpowers 		crypto_free_mode_ctx(blowfish_ctx);
8480Sstevel@tonic-gate 		ctx->cc_provider_private = NULL;
8490Sstevel@tonic-gate 	}
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
8520Sstevel@tonic-gate }
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate /* ARGSUSED */
8550Sstevel@tonic-gate static int
blowfish_common_init_ctx(blowfish_ctx_t * blowfish_ctx,crypto_spi_ctx_template_t * template,crypto_mechanism_t * mechanism,crypto_key_t * key,int kmflag)8560Sstevel@tonic-gate blowfish_common_init_ctx(blowfish_ctx_t *blowfish_ctx,
8570Sstevel@tonic-gate     crypto_spi_ctx_template_t *template, crypto_mechanism_t *mechanism,
8580Sstevel@tonic-gate     crypto_key_t *key, int kmflag)
8590Sstevel@tonic-gate {
8600Sstevel@tonic-gate 	int rv = CRYPTO_SUCCESS;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /* EXPORT DELETE START */
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	void *keysched;
8650Sstevel@tonic-gate 	size_t size;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	if (template == NULL) {
8680Sstevel@tonic-gate 		if ((keysched = blowfish_alloc_keysched(&size, kmflag)) == NULL)
8690Sstevel@tonic-gate 			return (CRYPTO_HOST_MEMORY);
8700Sstevel@tonic-gate 		/*
8710Sstevel@tonic-gate 		 * Initialize key schedule.
8720Sstevel@tonic-gate 		 * Key length is stored in the key.
8730Sstevel@tonic-gate 		 */
8740Sstevel@tonic-gate 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS)
8750Sstevel@tonic-gate 			kmem_free(keysched, size);
8760Sstevel@tonic-gate 
8777188Smcpowers 		blowfish_ctx->bc_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
8780Sstevel@tonic-gate 		blowfish_ctx->bc_keysched_len = size;
8790Sstevel@tonic-gate 	} else {
8800Sstevel@tonic-gate 		keysched = template;
8810Sstevel@tonic-gate 	}
8827188Smcpowers 	blowfish_ctx->bc_keysched = keysched;
8830Sstevel@tonic-gate 
8847188Smcpowers 	switch (mechanism->cm_type) {
8857188Smcpowers 	case BLOWFISH_CBC_MECH_INFO_TYPE:
8867188Smcpowers 		rv = cbc_init_ctx((cbc_ctx_t *)blowfish_ctx,
8877188Smcpowers 		    mechanism->cm_param, mechanism->cm_param_len,
8887188Smcpowers 		    BLOWFISH_BLOCK_LEN, blowfish_copy_block64);
8897188Smcpowers 		break;
8907188Smcpowers 	case BLOWFISH_ECB_MECH_INFO_TYPE:
8917188Smcpowers 		blowfish_ctx->bc_flags |= ECB_MODE;
8927188Smcpowers 	}
8930Sstevel@tonic-gate 
8947188Smcpowers 	if (rv != CRYPTO_SUCCESS) {
8957188Smcpowers 		if (blowfish_ctx->bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
8967188Smcpowers 			bzero(keysched, size);
8977188Smcpowers 			kmem_free(keysched, size);
8980Sstevel@tonic-gate 		}
8990Sstevel@tonic-gate 	}
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate /* EXPORT DELETE END */
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	return (rv);
9040Sstevel@tonic-gate }
905