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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
init_keysched(crypto_key_t * key,void * keysched)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
blowfish_provider_status(crypto_provider_handle_t provider,uint_t * status)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
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)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
blowfish_copy_block64(uint8_t * in,uint64_t * out)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
blowfish_encrypt(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)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
blowfish_decrypt(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)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
blowfish_encrypt_update(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)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
blowfish_decrypt_update(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)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
blowfish_encrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)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
blowfish_decrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)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
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)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
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)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
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)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
blowfish_free_context(crypto_ctx_t * ctx)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
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)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