xref: /illumos-gate/usr/src/uts/common/crypto/io/blowfish.c (revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Blowfish provider for the Kernel Cryptographic Framework (KCF)
31  */
32 
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/modctl.h>
36 #include <sys/cmn_err.h>
37 #include <sys/ddi.h>
38 #include <sys/crypto/common.h>
39 #include <sys/crypto/spi.h>
40 #include <sys/sysmacros.h>
41 #include <sys/strsun.h>
42 #include <sys/note.h>
43 #include <blowfish_impl.h>
44 #include <blowfish_cbc_crypt.h>
45 
46 extern struct mod_ops mod_cryptoops;
47 
48 /*
49  * Module linkage information for the kernel.
50  */
51 static struct modlcrypto modlcrypto = {
52 	&mod_cryptoops,
53 	"Blowfish Kernel SW Provider %I%"
54 };
55 
56 static struct modlinkage modlinkage = {
57 	MODREV_1,
58 	(void *)&modlcrypto,
59 	NULL
60 };
61 
62 /*
63  * CSPI information (entry points, provider info, etc.)
64  */
65 typedef enum blowfish_mech_type {
66 	BLOWFISH_ECB_MECH_INFO_TYPE,		/* SUN_CKM_BLOWFISH_ECB */
67 	BLOWFISH_CBC_MECH_INFO_TYPE		/* SUN_CKM_BLOWFISH_CBC */
68 } blowfish_mech_type_t;
69 
70 
71 #define	BLOWFISH_COPY_BLOCK(src, dst) \
72 	(dst)[0] = (src)[0]; \
73 	(dst)[1] = (src)[1]; \
74 	(dst)[2] = (src)[2]; \
75 	(dst)[3] = (src)[3]; \
76 	(dst)[4] = (src)[4]; \
77 	(dst)[5] = (src)[5]; \
78 	(dst)[6] = (src)[6]; \
79 	(dst)[7] = (src)[7]
80 
81 #define	BLOWFISH_XOR_BLOCK(src, dst) \
82 	(dst)[0] ^= (src)[0]; \
83 	(dst)[1] ^= (src)[1]; \
84 	(dst)[2] ^= (src)[2]; \
85 	(dst)[3] ^= (src)[3]; \
86 	(dst)[4] ^= (src)[4]; \
87 	(dst)[5] ^= (src)[5]; \
88 	(dst)[6] ^= (src)[6]; \
89 	(dst)[7] ^= (src)[7]
90 
91 /*
92  * Mechanism info structure passed to KCF during registration.
93  */
94 
95 static crypto_mech_info_t blowfish_mech_info_tab[] = {
96 	/* BLOWFISH_ECB */
97 	{SUN_CKM_BLOWFISH_ECB, BLOWFISH_ECB_MECH_INFO_TYPE,
98 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
99 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
100 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS},
101 	/* BLOWFISH_CBC */
102 	{SUN_CKM_BLOWFISH_CBC, BLOWFISH_CBC_MECH_INFO_TYPE,
103 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
104 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
105 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS}
106 };
107 
108 #define	BLOWFISH_VALID_MECH(mech)				\
109 	(((mech)->cm_type == BLOWFISH_ECB_MECH_INFO_TYPE ||		\
110 	(mech)->cm_type == BLOWFISH_CBC_MECH_INFO_TYPE) ? 1 : 0)
111 
112 /* operations are in-place if the output buffer is NULL */
113 #define	BLOWFISH_ARG_INPLACE(input, output)			\
114 	if ((output) == NULL)					\
115 		(output) = (input);
116 
117 static void blowfish_provider_status(crypto_provider_handle_t, uint_t *);
118 
119 static crypto_control_ops_t blowfish_control_ops = {
120 	blowfish_provider_status
121 };
122 
123 static int blowfish_common_init(crypto_ctx_t *, crypto_mechanism_t *,
124     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
125 static int blowfish_common_init_ctx(blowfish_ctx_t *,
126     crypto_spi_ctx_template_t *, crypto_mechanism_t *, crypto_key_t *, int);
127 static int blowfish_encrypt_final(crypto_ctx_t *, crypto_data_t *,
128     crypto_req_handle_t);
129 static int blowfish_decrypt_final(crypto_ctx_t *, crypto_data_t *,
130     crypto_req_handle_t);
131 
132 static int blowfish_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
133     crypto_req_handle_t);
134 static int blowfish_encrypt_update(crypto_ctx_t *, crypto_data_t *,
135     crypto_data_t *, crypto_req_handle_t);
136 static int blowfish_encrypt_atomic(crypto_provider_handle_t,
137     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
138     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
139 
140 static int blowfish_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
141     crypto_req_handle_t);
142 static int blowfish_decrypt_update(crypto_ctx_t *, crypto_data_t *,
143     crypto_data_t *, crypto_req_handle_t);
144 static int blowfish_decrypt_atomic(crypto_provider_handle_t,
145     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
146     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
147 
148 static crypto_cipher_ops_t blowfish_cipher_ops = {
149 	blowfish_common_init,
150 	blowfish_encrypt,
151 	blowfish_encrypt_update,
152 	blowfish_encrypt_final,
153 	blowfish_encrypt_atomic,
154 	blowfish_common_init,
155 	blowfish_decrypt,
156 	blowfish_decrypt_update,
157 	blowfish_decrypt_final,
158 	blowfish_decrypt_atomic
159 };
160 
161 static int blowfish_create_ctx_template(crypto_provider_handle_t,
162     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
163     size_t *, crypto_req_handle_t);
164 static int blowfish_free_context(crypto_ctx_t *);
165 
166 static crypto_ctx_ops_t blowfish_ctx_ops = {
167 	blowfish_create_ctx_template,
168 	blowfish_free_context
169 };
170 
171 static crypto_ops_t blowfish_crypto_ops = {
172 	&blowfish_control_ops,
173 	NULL,
174 	&blowfish_cipher_ops,
175 	NULL,
176 	NULL,
177 	NULL,
178 	NULL,
179 	NULL,
180 	NULL,
181 	NULL,
182 	NULL,
183 	NULL,
184 	NULL,
185 	&blowfish_ctx_ops
186 };
187 
188 static crypto_provider_info_t blowfish_prov_info = {
189 	CRYPTO_SPI_VERSION_1,
190 	"Blowfish Software Provider",
191 	CRYPTO_SW_PROVIDER,
192 	{&modlinkage},
193 	NULL,
194 	&blowfish_crypto_ops,
195 	sizeof (blowfish_mech_info_tab)/sizeof (crypto_mech_info_t),
196 	blowfish_mech_info_tab
197 };
198 
199 
200 static crypto_kcf_provider_handle_t blowfish_prov_handle = NULL;
201 
202 int
203 _init(void)
204 {
205 	int ret;
206 
207 	/*
208 	 * Register with KCF. If the registration fails, return error.
209 	 */
210 	if ((ret = crypto_register_provider(&blowfish_prov_info,
211 	    &blowfish_prov_handle)) != CRYPTO_SUCCESS) {
212 		cmn_err(CE_WARN, "%s _init: crypto_register_provider() "
213 		    "failed (0x%x)", CRYPTO_PROVIDER_NAME, ret);
214 		return (EACCES);
215 	}
216 
217 	if ((ret = mod_install(&modlinkage)) != 0) {
218 		int rv;
219 
220 		ASSERT(blowfish_prov_handle != NULL);
221 		/* We should not return if the unregister returns busy. */
222 		while ((rv = crypto_unregister_provider(blowfish_prov_handle))
223 		    == CRYPTO_BUSY) {
224 			cmn_err(CE_WARN,
225 			    "%s _init: crypto_unregister_provider() "
226 			    "failed (0x%x). Retrying.",
227 			    CRYPTO_PROVIDER_NAME, rv);
228 			/* wait 10 seconds and try again */
229 			delay(10 * drv_usectohz(1000000));
230 		}
231 	}
232 
233 	return (ret);
234 }
235 
236 int
237 _fini(void)
238 {
239 	int ret;
240 
241 	/*
242 	 * Unregister from KCF if previous registration succeeded.
243 	 */
244 	if (blowfish_prov_handle != NULL) {
245 		if ((ret = crypto_unregister_provider(blowfish_prov_handle)) !=
246 		    CRYPTO_SUCCESS) {
247 			cmn_err(CE_WARN,
248 			    "%s _fini: crypto_unregister_provider() "
249 			    "failed (0x%x)", CRYPTO_PROVIDER_NAME, ret);
250 			return (EBUSY);
251 		}
252 		blowfish_prov_handle = NULL;
253 	}
254 
255 	return (mod_remove(&modlinkage));
256 }
257 
258 int
259 _info(struct modinfo *modinfop)
260 {
261 	return (mod_info(&modlinkage, modinfop));
262 }
263 
264 /*
265  * Initialize key schedules for blowfish
266  */
267 static int
268 init_keysched(crypto_key_t *key, void *keysched)
269 {
270 /* EXPORT DELETE START */
271 	/*
272 	 * Only keys by value are supported by this module.
273 	 */
274 	switch (key->ck_format) {
275 	case CRYPTO_KEY_RAW:
276 		if (key->ck_length < BLOWFISH_MINBITS ||
277 		    key->ck_length > BLOWFISH_MAXBITS) {
278 			return (CRYPTO_KEY_SIZE_RANGE);
279 		}
280 		break;
281 	default:
282 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
283 	}
284 
285 	blowfish_init_keysched(key->ck_data, key->ck_length, keysched);
286 /* EXPORT DELETE END */
287 	return (CRYPTO_SUCCESS);
288 }
289 
290 /*
291  * KCF software provider control entry points.
292  */
293 /* ARGSUSED */
294 static void
295 blowfish_provider_status(crypto_provider_handle_t provider, uint_t *status)
296 {
297 	*status = CRYPTO_PROVIDER_READY;
298 }
299 
300 /*
301  * KCF software provider encrypt entry points.
302  */
303 static int
304 blowfish_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
305     crypto_key_t *key, crypto_spi_ctx_template_t template,
306     crypto_req_handle_t req)
307 {
308 
309 /* EXPORT DELETE START */
310 
311 	blowfish_ctx_t *blowfish_ctx;
312 	int rv;
313 	int kmflag;
314 
315 	/*
316 	 * Only keys by value are supported by this module.
317 	 */
318 	if (key->ck_format != CRYPTO_KEY_RAW) {
319 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
320 	}
321 
322 	if (!BLOWFISH_VALID_MECH(mechanism))
323 		return (CRYPTO_MECHANISM_INVALID);
324 
325 	if (mechanism->cm_param != NULL &&
326 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
327 		return (CRYPTO_MECHANISM_PARAM_INVALID);
328 
329 	/*
330 	 * Allocate a blowfish context.
331 	 */
332 	kmflag = crypto_kmflag(req);
333 	blowfish_ctx = kmem_zalloc(sizeof (blowfish_ctx_t), kmflag);
334 	if (blowfish_ctx == NULL)
335 		return (CRYPTO_HOST_MEMORY);
336 
337 	rv = blowfish_common_init_ctx(blowfish_ctx, template, mechanism,
338 	    key, kmflag);
339 	if (rv != CRYPTO_SUCCESS) {
340 		kmem_free(blowfish_ctx, sizeof (blowfish_ctx_t));
341 		return (rv);
342 	}
343 
344 	ctx->cc_provider_private = blowfish_ctx;
345 
346 /* EXPORT DELETE END */
347 
348 	return (CRYPTO_SUCCESS);
349 }
350 
351 /*
352  * Helper blowfish encrypt update function for iov input data.
353  */
354 static int
355 blowfish_cipher_update_iov(blowfish_ctx_t *blowfish_ctx, crypto_data_t *input,
356     crypto_data_t *output, int (*cipher)(blowfish_ctx_t *, caddr_t, size_t,
357     crypto_data_t *))
358 {
359 	if (input->cd_miscdata != NULL) {
360 		if (IS_P2ALIGNED(input->cd_miscdata, sizeof (uint64_t))) {
361 			/* LINTED: pointer alignment */
362 			blowfish_ctx->bc_iv = *(uint64_t *)input->cd_miscdata;
363 		} else {
364 			uint8_t *miscdata8 = (uint8_t *)&input->cd_miscdata[0];
365 			uint8_t *iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
366 
367 			BLOWFISH_COPY_BLOCK(miscdata8, iv8);
368 		}
369 	}
370 
371 	if (input->cd_raw.iov_len < input->cd_length)
372 		return (CRYPTO_ARGUMENTS_BAD);
373 
374 	return (cipher)(blowfish_ctx, input->cd_raw.iov_base + input->cd_offset,
375 	    input->cd_length, (input == output) ? NULL : output);
376 }
377 
378 /*
379  * Helper blowfish encrypt update function for uio input data.
380  */
381 static int
382 blowfish_cipher_update_uio(blowfish_ctx_t *blowfish_ctx, crypto_data_t *input,
383     crypto_data_t *output, int (*cipher)(blowfish_ctx_t *, caddr_t, size_t,
384     crypto_data_t *))
385 {
386 	uio_t *uiop = input->cd_uio;
387 	off_t offset = input->cd_offset;
388 	size_t length = input->cd_length;
389 	uint_t vec_idx;
390 	size_t cur_len;
391 
392 	if (input->cd_miscdata != NULL) {
393 		if (IS_P2ALIGNED(input->cd_miscdata, sizeof (uint64_t))) {
394 			/*LINTED: pointer alignment */
395 			blowfish_ctx->bc_iv = *(uint64_t *)input->cd_miscdata;
396 		} else {
397 			uint8_t *miscdata8 = (uint8_t *)&input->cd_miscdata[0];
398 			uint8_t *iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
399 
400 			BLOWFISH_COPY_BLOCK(miscdata8, iv8);
401 		}
402 	}
403 
404 	if (input->cd_uio->uio_segflg != UIO_SYSSPACE) {
405 		return (CRYPTO_ARGUMENTS_BAD);
406 	}
407 
408 	/*
409 	 * Jump to the first iovec containing data to be
410 	 * processed.
411 	 */
412 	for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
413 	    offset >= uiop->uio_iov[vec_idx].iov_len;
414 	    offset -= uiop->uio_iov[vec_idx++].iov_len);
415 	if (vec_idx == uiop->uio_iovcnt) {
416 		/*
417 		 * The caller specified an offset that is larger than the
418 		 * total size of the buffers it provided.
419 		 */
420 		return (CRYPTO_DATA_LEN_RANGE);
421 	}
422 
423 	/*
424 	 * Now process the iovecs.
425 	 */
426 	while (vec_idx < uiop->uio_iovcnt && length > 0) {
427 		cur_len = MIN(uiop->uio_iov[vec_idx].iov_len -
428 		    offset, length);
429 
430 		(cipher)(blowfish_ctx, uiop->uio_iov[vec_idx].iov_base +
431 		    offset, cur_len, (input == output) ? NULL : output);
432 
433 		length -= cur_len;
434 		vec_idx++;
435 		offset = 0;
436 	}
437 
438 	if (vec_idx == uiop->uio_iovcnt && length > 0) {
439 		/*
440 		 * The end of the specified iovec's was reached but
441 		 * the length requested could not be processed, i.e.
442 		 * The caller requested to digest more data than it provided.
443 		 */
444 
445 		return (CRYPTO_DATA_LEN_RANGE);
446 	}
447 
448 	return (CRYPTO_SUCCESS);
449 }
450 
451 /*
452  * Helper blowfish encrypt update function for mblk input data.
453  */
454 static int
455 blowfish_cipher_update_mp(blowfish_ctx_t *blowfish_ctx, crypto_data_t *input,
456     crypto_data_t *output, int (*cipher)(blowfish_ctx_t *, caddr_t, size_t,
457     crypto_data_t *))
458 {
459 	off_t offset = input->cd_offset;
460 	size_t length = input->cd_length;
461 	mblk_t *mp;
462 	size_t cur_len;
463 
464 	if (input->cd_miscdata != NULL) {
465 		if (IS_P2ALIGNED(input->cd_miscdata, sizeof (uint64_t))) {
466 			/*LINTED: pointer alignment */
467 			blowfish_ctx->bc_iv = *(uint64_t *)input->cd_miscdata;
468 		} else {
469 			uint8_t *miscdata8 = (uint8_t *)&input->cd_miscdata[0];
470 			uint8_t *iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
471 
472 			BLOWFISH_COPY_BLOCK(miscdata8, iv8);
473 		}
474 	}
475 
476 	/*
477 	 * Jump to the first mblk_t containing data to be processed.
478 	 */
479 	for (mp = input->cd_mp; mp != NULL && offset >= MBLKL(mp);
480 	    offset -= MBLKL(mp), mp = mp->b_cont);
481 	if (mp == NULL) {
482 		/*
483 		 * The caller specified an offset that is larger than the
484 		 * total size of the buffers it provided.
485 		 */
486 		return (CRYPTO_DATA_LEN_RANGE);
487 	}
488 
489 	/*
490 	 * Now do the processing on the mblk chain.
491 	 */
492 	while (mp != NULL && length > 0) {
493 		cur_len = MIN(MBLKL(mp) - offset, length);
494 		(cipher)(blowfish_ctx, (char *)(mp->b_rptr + offset), cur_len,
495 		    (input == output) ? NULL : output);
496 
497 		length -= cur_len;
498 		offset = 0;
499 		mp = mp->b_cont;
500 	}
501 
502 	if (mp == NULL && length > 0) {
503 		/*
504 		 * The end of the mblk was reached but the length requested
505 		 * could not be processed, i.e. The caller requested
506 		 * to digest more data than it provided.
507 		 */
508 		return (CRYPTO_DATA_LEN_RANGE);
509 	}
510 
511 	return (CRYPTO_SUCCESS);
512 }
513 
514 /* ARGSUSED */
515 static int
516 blowfish_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
517     crypto_data_t *ciphertext, crypto_req_handle_t req)
518 {
519 	int ret;
520 
521 /* EXPORT DELETE START */
522 
523 	blowfish_ctx_t *blowfish_ctx;
524 
525 	/*
526 	 * Plaintext must be a multiple of blowfish block size.
527 	 * This test only works for non-padded mechanisms
528 	 * when blocksize is 2^N.
529 	 */
530 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
531 		return (CRYPTO_DATA_LEN_RANGE);
532 
533 	ASSERT(ctx->cc_provider_private != NULL);
534 	blowfish_ctx = ctx->cc_provider_private;
535 
536 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
537 
538 	/*
539 	 * We need to just return the length needed to store the output.
540 	 * We should not destroy the context for the following case.
541 	 */
542 	if (ciphertext->cd_length < plaintext->cd_length) {
543 		ciphertext->cd_length = plaintext->cd_length;
544 		return (CRYPTO_BUFFER_TOO_SMALL);
545 	}
546 
547 	/*
548 	 * Do an update on the specified input data.
549 	 */
550 	ret = blowfish_encrypt_update(ctx, plaintext, ciphertext, req);
551 	ASSERT(blowfish_ctx->bc_remainder_len  == 0);
552 	(void) blowfish_free_context(ctx);
553 
554 /* EXPORT DELETE END */
555 
556 	/* LINTED */
557 	return (ret);
558 }
559 
560 /* ARGSUSED */
561 static int
562 blowfish_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
563     crypto_data_t *plaintext, crypto_req_handle_t req)
564 {
565 	int ret;
566 
567 /* EXPORT DELETE START */
568 
569 	blowfish_ctx_t *blowfish_ctx;
570 
571 	/*
572 	 * Ciphertext must be a multiple of blowfish block size.
573 	 * This test only works for non-padded mechanisms
574 	 * when blocksize is 2^N.
575 	 */
576 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
577 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
578 
579 	ASSERT(ctx->cc_provider_private != NULL);
580 	blowfish_ctx = ctx->cc_provider_private;
581 
582 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
583 
584 	/*
585 	 * We need to just return the length needed to store the output.
586 	 * We should not destroy the context for the following case.
587 	 */
588 	if (plaintext->cd_length < ciphertext->cd_length) {
589 		plaintext->cd_length = ciphertext->cd_length;
590 		return (CRYPTO_BUFFER_TOO_SMALL);
591 	}
592 
593 	/*
594 	 * Do an update on the specified input data.
595 	 */
596 	ret = blowfish_decrypt_update(ctx, ciphertext, plaintext, req);
597 	ASSERT(blowfish_ctx->bc_remainder_len == 0);
598 	(void) blowfish_free_context(ctx);
599 
600 /* EXPORT DELETE END */
601 
602 	/* LINTED */
603 	return (ret);
604 }
605 
606 /* ARGSUSED */
607 static int
608 blowfish_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
609     crypto_data_t *ciphertext, crypto_req_handle_t req)
610 {
611 	off_t saved_offset;
612 	size_t saved_length, out_len;
613 	int ret = CRYPTO_SUCCESS;
614 
615 	ASSERT(ctx->cc_provider_private != NULL);
616 
617 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
618 
619 	/* compute number of bytes that will hold the ciphertext */
620 	out_len =
621 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
622 	out_len += plaintext->cd_length;
623 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
624 
625 	/* return length needed to store the output */
626 	if (ciphertext->cd_length < out_len) {
627 		ciphertext->cd_length = out_len;
628 		return (CRYPTO_BUFFER_TOO_SMALL);
629 	}
630 
631 	saved_offset = ciphertext->cd_offset;
632 	saved_length = ciphertext->cd_length;
633 
634 	/*
635 	 * Do the blowfish update on the specified input data.
636 	 */
637 	switch (plaintext->cd_format) {
638 	case CRYPTO_DATA_RAW:
639 		ret = blowfish_cipher_update_iov(ctx->cc_provider_private,
640 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
641 		break;
642 	case CRYPTO_DATA_UIO:
643 		ret = blowfish_cipher_update_uio(ctx->cc_provider_private,
644 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
645 		break;
646 	case CRYPTO_DATA_MBLK:
647 		ret = blowfish_cipher_update_mp(ctx->cc_provider_private,
648 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
649 		break;
650 	default:
651 		ret = CRYPTO_ARGUMENTS_BAD;
652 	}
653 
654 	if (ret == CRYPTO_SUCCESS) {
655 		if (plaintext != ciphertext)
656 			ciphertext->cd_length =
657 			    ciphertext->cd_offset - saved_offset;
658 	} else {
659 		ciphertext->cd_length = saved_length;
660 	}
661 	ciphertext->cd_offset = saved_offset;
662 
663 	return (ret);
664 }
665 
666 /* ARGSUSED */
667 static int
668 blowfish_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
669     crypto_data_t *plaintext, crypto_req_handle_t req)
670 {
671 	off_t saved_offset;
672 	size_t saved_length, out_len;
673 	int ret = CRYPTO_SUCCESS;
674 
675 	ASSERT(ctx->cc_provider_private != NULL);
676 
677 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
678 
679 	/* compute number of bytes that will hold the plaintext */
680 	out_len =
681 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
682 	out_len += ciphertext->cd_length;
683 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
684 
685 	/* return length needed to store the output */
686 	if (plaintext->cd_length < out_len) {
687 		plaintext->cd_length = out_len;
688 		return (CRYPTO_BUFFER_TOO_SMALL);
689 	}
690 
691 	saved_offset = plaintext->cd_offset;
692 	saved_length = plaintext->cd_length;
693 
694 	/*
695 	 * Do the blowfish update on the specified input data.
696 	 */
697 	switch (ciphertext->cd_format) {
698 	case CRYPTO_DATA_RAW:
699 		ret = blowfish_cipher_update_iov(ctx->cc_provider_private,
700 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
701 		break;
702 	case CRYPTO_DATA_UIO:
703 		ret = blowfish_cipher_update_uio(ctx->cc_provider_private,
704 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
705 		break;
706 	case CRYPTO_DATA_MBLK:
707 		ret = blowfish_cipher_update_mp(ctx->cc_provider_private,
708 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
709 		break;
710 	default:
711 		ret = CRYPTO_ARGUMENTS_BAD;
712 	}
713 
714 	if (ret == CRYPTO_SUCCESS) {
715 		if (ciphertext != plaintext)
716 			plaintext->cd_length =
717 			    plaintext->cd_offset - saved_offset;
718 	} else {
719 		plaintext->cd_length = saved_length;
720 	}
721 	plaintext->cd_offset = saved_offset;
722 
723 	return (ret);
724 }
725 
726 /* ARGSUSED */
727 static int
728 blowfish_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
729     crypto_req_handle_t req)
730 {
731 
732 /* EXPORT DELETE START */
733 
734 	blowfish_ctx_t *blowfish_ctx;
735 
736 	ASSERT(ctx->cc_provider_private != NULL);
737 	blowfish_ctx = ctx->cc_provider_private;
738 
739 	/*
740 	 * There must be no unprocessed data.
741 	 * This happens if the length of the last data is
742 	 * not a multiple of the BLOWFISH block length.
743 	 */
744 	if (blowfish_ctx->bc_remainder_len > 0)
745 		return (CRYPTO_DATA_LEN_RANGE);
746 
747 	(void) blowfish_free_context(ctx);
748 	data->cd_length = 0;
749 
750 /* EXPORT DELETE END */
751 
752 	return (CRYPTO_SUCCESS);
753 }
754 
755 /* ARGSUSED */
756 static int
757 blowfish_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
758     crypto_req_handle_t req)
759 {
760 
761 /* EXPORT DELETE START */
762 
763 	blowfish_ctx_t *blowfish_ctx;
764 
765 	ASSERT(ctx->cc_provider_private != NULL);
766 	blowfish_ctx = ctx->cc_provider_private;
767 
768 	/*
769 	 * There must be no unprocessed ciphertext.
770 	 * This happens if the length of the last ciphertext is
771 	 * not a multiple of the BLOWFISH block length.
772 	 */
773 	if (blowfish_ctx->bc_remainder_len > 0)
774 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
775 
776 	(void) blowfish_free_context(ctx);
777 	data->cd_length = 0;
778 
779 /* EXPORT DELETE END */
780 
781 	return (CRYPTO_SUCCESS);
782 }
783 
784 /* ARGSUSED */
785 static int
786 blowfish_encrypt_atomic(crypto_provider_handle_t provider,
787     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
788     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
789     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
790 {
791 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
792 	off_t saved_offset;
793 	size_t saved_length;
794 	int ret;
795 
796 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
797 
798 	/*
799 	 * Plaintext must be a multiple of blowfish block size.
800 	 * This test only works for non-padded mechanisms
801 	 * when blocksize is 2^N.
802 	 */
803 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
804 		return (CRYPTO_DATA_LEN_RANGE);
805 
806 	/* return length needed to store the output */
807 	if (ciphertext->cd_length < plaintext->cd_length) {
808 		ciphertext->cd_length = plaintext->cd_length;
809 		return (CRYPTO_BUFFER_TOO_SMALL);
810 	}
811 
812 	if (!BLOWFISH_VALID_MECH(mechanism))
813 		return (CRYPTO_MECHANISM_INVALID);
814 
815 	if (mechanism->cm_param_len != 0 &&
816 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
817 		return (CRYPTO_MECHANISM_PARAM_INVALID);
818 
819 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
820 
821 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
822 	    key, crypto_kmflag(req));
823 	if (ret != CRYPTO_SUCCESS)
824 		return (ret);
825 
826 	saved_offset = ciphertext->cd_offset;
827 	saved_length = ciphertext->cd_length;
828 
829 	/*
830 	 * Do an update on the specified input data.
831 	 */
832 	switch (plaintext->cd_format) {
833 	case CRYPTO_DATA_RAW:
834 		ret = blowfish_cipher_update_iov(&blowfish_ctx,
835 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
836 		break;
837 	case CRYPTO_DATA_UIO:
838 		ret = blowfish_cipher_update_uio(&blowfish_ctx,
839 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
840 		break;
841 	case CRYPTO_DATA_MBLK:
842 		ret = blowfish_cipher_update_mp(&blowfish_ctx,
843 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks);
844 		break;
845 	default:
846 		ret = CRYPTO_ARGUMENTS_BAD;
847 	}
848 
849 	if (blowfish_ctx.bc_flags & BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE) {
850 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
851 		kmem_free(blowfish_ctx.bc_keysched,
852 		    blowfish_ctx.bc_keysched_len);
853 	}
854 
855 	if (ret == CRYPTO_SUCCESS) {
856 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
857 		if (plaintext != ciphertext)
858 			ciphertext->cd_length =
859 			    ciphertext->cd_offset - saved_offset;
860 	} else {
861 		ciphertext->cd_length = saved_length;
862 	}
863 	ciphertext->cd_offset = saved_offset;
864 
865 	return (ret);
866 }
867 
868 /* ARGSUSED */
869 static int
870 blowfish_decrypt_atomic(crypto_provider_handle_t provider,
871     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
872     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
873     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
874 {
875 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
876 	off_t saved_offset;
877 	size_t saved_length;
878 	int ret;
879 
880 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
881 
882 	/*
883 	 * Ciphertext must be a multiple of blowfish block size.
884 	 * This test only works for non-padded mechanisms
885 	 * when blocksize is 2^N.
886 	 */
887 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
888 		return (CRYPTO_DATA_LEN_RANGE);
889 
890 	/* return length needed to store the output */
891 	if (plaintext->cd_length < ciphertext->cd_length) {
892 		plaintext->cd_length = ciphertext->cd_length;
893 		return (CRYPTO_BUFFER_TOO_SMALL);
894 	}
895 
896 	if (!BLOWFISH_VALID_MECH(mechanism))
897 		return (CRYPTO_MECHANISM_INVALID);
898 
899 	if (mechanism->cm_param_len != 0 &&
900 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
901 		return (CRYPTO_MECHANISM_PARAM_INVALID);
902 
903 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
904 
905 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
906 	    key, crypto_kmflag(req));
907 	if (ret != CRYPTO_SUCCESS)
908 		return (ret);
909 
910 	saved_offset = plaintext->cd_offset;
911 	saved_length = plaintext->cd_length;
912 
913 	/*
914 	 * Do an update on the specified input data.
915 	 */
916 	switch (ciphertext->cd_format) {
917 	case CRYPTO_DATA_RAW:
918 		ret = blowfish_cipher_update_iov(&blowfish_ctx,
919 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
920 		break;
921 	case CRYPTO_DATA_UIO:
922 		ret = blowfish_cipher_update_uio(&blowfish_ctx,
923 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
924 		break;
925 	case CRYPTO_DATA_MBLK:
926 		ret = blowfish_cipher_update_mp(&blowfish_ctx,
927 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks);
928 		break;
929 	default:
930 		ret = CRYPTO_ARGUMENTS_BAD;
931 	}
932 
933 	if (blowfish_ctx.bc_flags & BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE) {
934 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
935 		kmem_free(blowfish_ctx.bc_keysched,
936 		    blowfish_ctx.bc_keysched_len);
937 	}
938 
939 	if (ret == CRYPTO_SUCCESS) {
940 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
941 		if (ciphertext != plaintext)
942 			plaintext->cd_length =
943 			    plaintext->cd_offset - saved_offset;
944 	} else {
945 		plaintext->cd_length = saved_length;
946 	}
947 	plaintext->cd_offset = saved_offset;
948 
949 	return (ret);
950 }
951 
952 /*
953  * KCF software provider context template entry points.
954  */
955 /* ARGSUSED */
956 static int
957 blowfish_create_ctx_template(crypto_provider_handle_t provider,
958     crypto_mechanism_t *mechanism, crypto_key_t *key,
959     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
960 {
961 
962 /* EXPORT DELETE START */
963 
964 	void *keysched;
965 	size_t size;
966 	int rv;
967 
968 	if (!BLOWFISH_VALID_MECH(mechanism))
969 		return (CRYPTO_MECHANISM_INVALID);
970 
971 	if ((keysched = blowfish_alloc_keysched(&size,
972 	    crypto_kmflag(req))) == NULL) {
973 		return (CRYPTO_HOST_MEMORY);
974 	}
975 
976 	/*
977 	 * Initialize key schedule.  Key length information is stored
978 	 * in the key.
979 	 */
980 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
981 		bzero(keysched, size);
982 		kmem_free(keysched, size);
983 		return (rv);
984 	}
985 
986 	*tmpl = keysched;
987 	*tmpl_size = size;
988 
989 /* EXPORT DELETE END */
990 
991 	return (CRYPTO_SUCCESS);
992 }
993 
994 /* ARGSUSED */
995 static int
996 blowfish_free_context(crypto_ctx_t *ctx)
997 {
998 	blowfish_ctx_t *blowfish_ctx = ctx->cc_provider_private;
999 
1000 	if (blowfish_ctx != NULL) {
1001 		if (blowfish_ctx->bc_flags &
1002 		    BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE) {
1003 			ASSERT(blowfish_ctx->bc_keysched_len != 0);
1004 			bzero(blowfish_ctx->bc_keysched,
1005 			    blowfish_ctx->bc_keysched_len);
1006 			kmem_free(blowfish_ctx->bc_keysched,
1007 			    blowfish_ctx->bc_keysched_len);
1008 		}
1009 		kmem_free(blowfish_ctx, sizeof (blowfish_ctx_t));
1010 		ctx->cc_provider_private = NULL;
1011 	}
1012 
1013 	return (CRYPTO_SUCCESS);
1014 }
1015 
1016 /* ARGSUSED */
1017 static int
1018 blowfish_common_init_ctx(blowfish_ctx_t *blowfish_ctx,
1019     crypto_spi_ctx_template_t *template, crypto_mechanism_t *mechanism,
1020     crypto_key_t *key, int kmflag)
1021 {
1022 	int rv = CRYPTO_SUCCESS;
1023 
1024 /* EXPORT DELETE START */
1025 
1026 	void *keysched;
1027 	size_t size;
1028 
1029 	if (template == NULL) {
1030 		if ((keysched = blowfish_alloc_keysched(&size, kmflag)) == NULL)
1031 			return (CRYPTO_HOST_MEMORY);
1032 		/*
1033 		 * Initialize key schedule.
1034 		 * Key length is stored in the key.
1035 		 */
1036 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS)
1037 			kmem_free(keysched, size);
1038 
1039 		blowfish_ctx->bc_flags = BLOWFISH_PROVIDER_OWNS_KEY_SCHEDULE;
1040 		blowfish_ctx->bc_keysched_len = size;
1041 	} else {
1042 		keysched = template;
1043 	}
1044 
1045 	if (mechanism->cm_type == BLOWFISH_CBC_MECH_INFO_TYPE) {
1046 		/*
1047 		 * Copy IV into BLOWFISH context.
1048 		 *
1049 		 * If cm_param == NULL then the IV comes from the
1050 		 * cd_miscdata field in the crypto_data structure.
1051 		 */
1052 		if (mechanism->cm_param != NULL) {
1053 			ASSERT(mechanism->cm_param_len == BLOWFISH_BLOCK_LEN);
1054 			if (IS_P2ALIGNED(mechanism->cm_param,
1055 			    sizeof (uint64_t))) {
1056 				/* LINTED: pointer alignment */
1057 				blowfish_ctx->bc_iv =
1058 				    *(uint64_t *)mechanism->cm_param;
1059 			} else {
1060 				uint8_t *iv8;
1061 				uint8_t *p8;
1062 				iv8 = (uint8_t *)&blowfish_ctx->bc_iv;
1063 				p8 = (uint8_t *)&mechanism->cm_param[0];
1064 
1065 				BLOWFISH_COPY_BLOCK(p8, iv8);
1066 			}
1067 		}
1068 
1069 		blowfish_ctx->bc_lastp = (uint8_t *)&blowfish_ctx->bc_iv;
1070 		blowfish_ctx->bc_flags |= BLOWFISH_CBC_MODE;
1071 	}
1072 	blowfish_ctx->bc_keysched = keysched;
1073 
1074 /* EXPORT DELETE END */
1075 
1076 	return (rv);
1077 }
1078