xref: /illumos-gate/usr/src/uts/common/crypto/io/blowfish.c (revision c8b1c8bdff5c74b45e33257ed7499ca0f475ebe0)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Blowfish provider for the Kernel Cryptographic Framework (KCF)
28  */
29 
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/modctl.h>
33 #include <sys/cmn_err.h>
34 #include <sys/ddi.h>
35 #include <sys/crypto/common.h>
36 #include <sys/crypto/spi.h>
37 #include <sys/sysmacros.h>
38 #include <sys/strsun.h>
39 #include <sys/note.h>
40 #include <modes/modes.h>
41 #include <blowfish/blowfish_impl.h>
42 
43 extern struct mod_ops mod_cryptoops;
44 
45 /*
46  * Module linkage information for the kernel.
47  */
48 static struct modlcrypto modlcrypto = {
49 	&mod_cryptoops,
50 	"Blowfish Kernel SW Provider"
51 };
52 
53 static struct modlinkage modlinkage = {
54 	MODREV_1,
55 	(void *)&modlcrypto,
56 	NULL
57 };
58 
59 /*
60  * CSPI information (entry points, provider info, etc.)
61  */
62 typedef enum blowfish_mech_type {
63 	BLOWFISH_ECB_MECH_INFO_TYPE,		/* SUN_CKM_BLOWFISH_ECB */
64 	BLOWFISH_CBC_MECH_INFO_TYPE		/* SUN_CKM_BLOWFISH_CBC */
65 } blowfish_mech_type_t;
66 
67 
68 #define	BLOWFISH_COPY_BLOCK(src, dst) \
69 	(dst)[0] = (src)[0]; \
70 	(dst)[1] = (src)[1]; \
71 	(dst)[2] = (src)[2]; \
72 	(dst)[3] = (src)[3]; \
73 	(dst)[4] = (src)[4]; \
74 	(dst)[5] = (src)[5]; \
75 	(dst)[6] = (src)[6]; \
76 	(dst)[7] = (src)[7]
77 
78 #define	BLOWFISH_XOR_BLOCK(src, dst) \
79 	(dst)[0] ^= (src)[0]; \
80 	(dst)[1] ^= (src)[1]; \
81 	(dst)[2] ^= (src)[2]; \
82 	(dst)[3] ^= (src)[3]; \
83 	(dst)[4] ^= (src)[4]; \
84 	(dst)[5] ^= (src)[5]; \
85 	(dst)[6] ^= (src)[6]; \
86 	(dst)[7] ^= (src)[7]
87 
88 /*
89  * Mechanism info structure passed to KCF during registration.
90  */
91 
92 static crypto_mech_info_t blowfish_mech_info_tab[] = {
93 	/* BLOWFISH_ECB */
94 	{SUN_CKM_BLOWFISH_ECB, BLOWFISH_ECB_MECH_INFO_TYPE,
95 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
96 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
97 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS},
98 	/* BLOWFISH_CBC */
99 	{SUN_CKM_BLOWFISH_CBC, BLOWFISH_CBC_MECH_INFO_TYPE,
100 	    CRYPTO_FG_ENCRYPT | CRYPTO_FG_ENCRYPT_ATOMIC |
101 	    CRYPTO_FG_DECRYPT | CRYPTO_FG_DECRYPT_ATOMIC,
102 	    BLOWFISH_MINBITS, BLOWFISH_MAXBITS, CRYPTO_KEYSIZE_UNIT_IN_BITS}
103 };
104 
105 #define	BLOWFISH_VALID_MECH(mech)				\
106 	(((mech)->cm_type == BLOWFISH_ECB_MECH_INFO_TYPE ||		\
107 	(mech)->cm_type == BLOWFISH_CBC_MECH_INFO_TYPE) ? 1 : 0)
108 
109 /* operations are in-place if the output buffer is NULL */
110 #define	BLOWFISH_ARG_INPLACE(input, output)			\
111 	if ((output) == NULL)					\
112 		(output) = (input);
113 
114 static void blowfish_provider_status(crypto_provider_handle_t, uint_t *);
115 
116 static crypto_control_ops_t blowfish_control_ops = {
117 	blowfish_provider_status
118 };
119 
120 static int blowfish_common_init(crypto_ctx_t *, crypto_mechanism_t *,
121     crypto_key_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
122 static int blowfish_common_init_ctx(blowfish_ctx_t *,
123     crypto_spi_ctx_template_t *, crypto_mechanism_t *, crypto_key_t *, int);
124 static int blowfish_encrypt_final(crypto_ctx_t *, crypto_data_t *,
125     crypto_req_handle_t);
126 static int blowfish_decrypt_final(crypto_ctx_t *, crypto_data_t *,
127     crypto_req_handle_t);
128 
129 static int blowfish_encrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
130     crypto_req_handle_t);
131 static int blowfish_encrypt_update(crypto_ctx_t *, crypto_data_t *,
132     crypto_data_t *, crypto_req_handle_t);
133 static int blowfish_encrypt_atomic(crypto_provider_handle_t,
134     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
135     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
136 
137 static int blowfish_decrypt(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
138     crypto_req_handle_t);
139 static int blowfish_decrypt_update(crypto_ctx_t *, crypto_data_t *,
140     crypto_data_t *, crypto_req_handle_t);
141 static int blowfish_decrypt_atomic(crypto_provider_handle_t,
142     crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
143     crypto_data_t *, crypto_spi_ctx_template_t, crypto_req_handle_t);
144 
145 static crypto_cipher_ops_t blowfish_cipher_ops = {
146 	blowfish_common_init,
147 	blowfish_encrypt,
148 	blowfish_encrypt_update,
149 	blowfish_encrypt_final,
150 	blowfish_encrypt_atomic,
151 	blowfish_common_init,
152 	blowfish_decrypt,
153 	blowfish_decrypt_update,
154 	blowfish_decrypt_final,
155 	blowfish_decrypt_atomic
156 };
157 
158 static int blowfish_create_ctx_template(crypto_provider_handle_t,
159     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
160     size_t *, crypto_req_handle_t);
161 static int blowfish_free_context(crypto_ctx_t *);
162 
163 static crypto_ctx_ops_t blowfish_ctx_ops = {
164 	blowfish_create_ctx_template,
165 	blowfish_free_context
166 };
167 
168 static crypto_ops_t blowfish_crypto_ops = {
169 	&blowfish_control_ops,
170 	NULL,
171 	&blowfish_cipher_ops,
172 	NULL,
173 	NULL,
174 	NULL,
175 	NULL,
176 	NULL,
177 	NULL,
178 	NULL,
179 	NULL,
180 	NULL,
181 	NULL,
182 	&blowfish_ctx_ops
183 };
184 
185 static crypto_provider_info_t blowfish_prov_info = {
186 	CRYPTO_SPI_VERSION_1,
187 	"Blowfish Software Provider",
188 	CRYPTO_SW_PROVIDER,
189 	{&modlinkage},
190 	NULL,
191 	&blowfish_crypto_ops,
192 	sizeof (blowfish_mech_info_tab)/sizeof (crypto_mech_info_t),
193 	blowfish_mech_info_tab
194 };
195 
196 
197 static crypto_kcf_provider_handle_t blowfish_prov_handle = 0;
198 
199 int
_init(void)200 _init(void)
201 {
202 	int ret;
203 
204 	if ((ret = mod_install(&modlinkage)) != 0)
205 		return (ret);
206 
207 	/* Register with KCF.  If the registration fails, remove the module. */
208 	if (crypto_register_provider(&blowfish_prov_info,
209 	    &blowfish_prov_handle)) {
210 		(void) mod_remove(&modlinkage);
211 		return (EACCES);
212 	}
213 
214 	return (0);
215 }
216 
217 int
_fini(void)218 _fini(void)
219 {
220 	/* Unregister from KCF if module is registered */
221 	if (blowfish_prov_handle != 0) {
222 		if (crypto_unregister_provider(blowfish_prov_handle))
223 			return (EBUSY);
224 
225 		blowfish_prov_handle = 0;
226 	}
227 
228 	return (mod_remove(&modlinkage));
229 }
230 
231 int
_info(struct modinfo * modinfop)232 _info(struct modinfo *modinfop)
233 {
234 	return (mod_info(&modlinkage, modinfop));
235 }
236 
237 /*
238  * Initialize key schedules for blowfish
239  */
240 static int
init_keysched(crypto_key_t * key,void * keysched)241 init_keysched(crypto_key_t *key, void *keysched)
242 {
243 	/*
244 	 * Only keys by value are supported by this module.
245 	 */
246 	switch (key->ck_format) {
247 	case CRYPTO_KEY_RAW:
248 		if (key->ck_length < BLOWFISH_MINBITS ||
249 		    key->ck_length > BLOWFISH_MAXBITS) {
250 			return (CRYPTO_KEY_SIZE_RANGE);
251 		}
252 		break;
253 	default:
254 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
255 	}
256 
257 	blowfish_init_keysched(key->ck_data, key->ck_length, keysched);
258 	return (CRYPTO_SUCCESS);
259 }
260 
261 /*
262  * KCF software provider control entry points.
263  */
264 /* ARGSUSED */
265 static void
blowfish_provider_status(crypto_provider_handle_t provider,uint_t * status)266 blowfish_provider_status(crypto_provider_handle_t provider, uint_t *status)
267 {
268 	*status = CRYPTO_PROVIDER_READY;
269 }
270 
271 /*
272  * KCF software provider encrypt entry points.
273  */
274 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)275 blowfish_common_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
276     crypto_key_t *key, crypto_spi_ctx_template_t template,
277     crypto_req_handle_t req)
278 {
279 	blowfish_ctx_t *blowfish_ctx;
280 	int rv;
281 	int kmflag;
282 
283 	/*
284 	 * Only keys by value are supported by this module.
285 	 */
286 	if (key->ck_format != CRYPTO_KEY_RAW) {
287 		return (CRYPTO_KEY_TYPE_INCONSISTENT);
288 	}
289 
290 	if (!BLOWFISH_VALID_MECH(mechanism))
291 		return (CRYPTO_MECHANISM_INVALID);
292 
293 	if (mechanism->cm_param != NULL &&
294 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
295 		return (CRYPTO_MECHANISM_PARAM_INVALID);
296 
297 	kmflag = crypto_kmflag(req);
298 	switch (mechanism->cm_type) {
299 	case BLOWFISH_ECB_MECH_INFO_TYPE:
300 		blowfish_ctx = ecb_alloc_ctx(kmflag);
301 		break;
302 	case BLOWFISH_CBC_MECH_INFO_TYPE:
303 		blowfish_ctx = cbc_alloc_ctx(kmflag);
304 		break;
305 	}
306 	if (blowfish_ctx == NULL)
307 		return (CRYPTO_HOST_MEMORY);
308 
309 	rv = blowfish_common_init_ctx(blowfish_ctx, template, mechanism,
310 	    key, kmflag);
311 	if (rv != CRYPTO_SUCCESS) {
312 		crypto_free_mode_ctx(blowfish_ctx);
313 		return (rv);
314 	}
315 
316 	ctx->cc_provider_private = blowfish_ctx;
317 
318 	return (CRYPTO_SUCCESS);
319 }
320 
321 static void
blowfish_copy_block64(uint8_t * in,uint64_t * out)322 blowfish_copy_block64(uint8_t *in, uint64_t *out)
323 {
324 	if (IS_P2ALIGNED(in, sizeof (uint64_t))) {
325 		/* LINTED: pointer alignment */
326 		out[0] = *(uint64_t *)&in[0];
327 	} else {
328 		uint8_t *iv8 = (uint8_t *)&out[0];
329 
330 		BLOWFISH_COPY_BLOCK(in, iv8);
331 	}
332 }
333 
334 /* ARGSUSED */
335 static int
blowfish_encrypt(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)336 blowfish_encrypt(crypto_ctx_t *ctx, crypto_data_t *plaintext,
337     crypto_data_t *ciphertext, crypto_req_handle_t req)
338 {
339 	int ret;
340 
341 	blowfish_ctx_t *blowfish_ctx;
342 
343 	/*
344 	 * Plaintext must be a multiple of blowfish block size.
345 	 * This test only works for non-padded mechanisms
346 	 * when blocksize is 2^N.
347 	 */
348 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
349 		return (CRYPTO_DATA_LEN_RANGE);
350 
351 	ASSERT(ctx->cc_provider_private != NULL);
352 	blowfish_ctx = ctx->cc_provider_private;
353 
354 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
355 
356 	/*
357 	 * We need to just return the length needed to store the output.
358 	 * We should not destroy the context for the following case.
359 	 */
360 	if (ciphertext->cd_length < plaintext->cd_length) {
361 		ciphertext->cd_length = plaintext->cd_length;
362 		return (CRYPTO_BUFFER_TOO_SMALL);
363 	}
364 
365 	/*
366 	 * Do an update on the specified input data.
367 	 */
368 	ret = blowfish_encrypt_update(ctx, plaintext, ciphertext, req);
369 	ASSERT(blowfish_ctx->bc_remainder_len  == 0);
370 	(void) blowfish_free_context(ctx);
371 
372 	/* LINTED */
373 	return (ret);
374 }
375 
376 /* ARGSUSED */
377 static int
blowfish_decrypt(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)378 blowfish_decrypt(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
379     crypto_data_t *plaintext, crypto_req_handle_t req)
380 {
381 	int ret;
382 
383 	blowfish_ctx_t *blowfish_ctx;
384 
385 	/*
386 	 * Ciphertext must be a multiple of blowfish block size.
387 	 * This test only works for non-padded mechanisms
388 	 * when blocksize is 2^N.
389 	 */
390 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
391 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
392 
393 	ASSERT(ctx->cc_provider_private != NULL);
394 	blowfish_ctx = ctx->cc_provider_private;
395 
396 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
397 
398 	/*
399 	 * We need to just return the length needed to store the output.
400 	 * We should not destroy the context for the following case.
401 	 */
402 	if (plaintext->cd_length < ciphertext->cd_length) {
403 		plaintext->cd_length = ciphertext->cd_length;
404 		return (CRYPTO_BUFFER_TOO_SMALL);
405 	}
406 
407 	/*
408 	 * Do an update on the specified input data.
409 	 */
410 	ret = blowfish_decrypt_update(ctx, ciphertext, plaintext, req);
411 	ASSERT(blowfish_ctx->bc_remainder_len == 0);
412 	(void) blowfish_free_context(ctx);
413 
414 	/* LINTED */
415 	return (ret);
416 }
417 
418 /* ARGSUSED */
419 static int
blowfish_encrypt_update(crypto_ctx_t * ctx,crypto_data_t * plaintext,crypto_data_t * ciphertext,crypto_req_handle_t req)420 blowfish_encrypt_update(crypto_ctx_t *ctx, crypto_data_t *plaintext,
421     crypto_data_t *ciphertext, crypto_req_handle_t req)
422 {
423 	off_t saved_offset;
424 	size_t saved_length, out_len;
425 	int ret = CRYPTO_SUCCESS;
426 
427 	ASSERT(ctx->cc_provider_private != NULL);
428 
429 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
430 
431 	/* compute number of bytes that will hold the ciphertext */
432 	out_len =
433 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
434 	out_len += plaintext->cd_length;
435 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
436 
437 	/* return length needed to store the output */
438 	if (ciphertext->cd_length < out_len) {
439 		ciphertext->cd_length = out_len;
440 		return (CRYPTO_BUFFER_TOO_SMALL);
441 	}
442 
443 	saved_offset = ciphertext->cd_offset;
444 	saved_length = ciphertext->cd_length;
445 
446 	/*
447 	 * Do the blowfish update on the specified input data.
448 	 */
449 	switch (plaintext->cd_format) {
450 	case CRYPTO_DATA_RAW:
451 		ret = crypto_update_iov(ctx->cc_provider_private,
452 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
453 		    blowfish_copy_block64);
454 		break;
455 	case CRYPTO_DATA_UIO:
456 		ret = crypto_update_uio(ctx->cc_provider_private,
457 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
458 		    blowfish_copy_block64);
459 		break;
460 	case CRYPTO_DATA_MBLK:
461 		ret = crypto_update_mp(ctx->cc_provider_private,
462 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
463 		    blowfish_copy_block64);
464 		break;
465 	default:
466 		ret = CRYPTO_ARGUMENTS_BAD;
467 	}
468 
469 	if (ret == CRYPTO_SUCCESS) {
470 		if (plaintext != ciphertext)
471 			ciphertext->cd_length =
472 			    ciphertext->cd_offset - saved_offset;
473 	} else {
474 		ciphertext->cd_length = saved_length;
475 	}
476 	ciphertext->cd_offset = saved_offset;
477 
478 	return (ret);
479 }
480 
481 /* ARGSUSED */
482 static int
blowfish_decrypt_update(crypto_ctx_t * ctx,crypto_data_t * ciphertext,crypto_data_t * plaintext,crypto_req_handle_t req)483 blowfish_decrypt_update(crypto_ctx_t *ctx, crypto_data_t *ciphertext,
484     crypto_data_t *plaintext, crypto_req_handle_t req)
485 {
486 	off_t saved_offset;
487 	size_t saved_length, out_len;
488 	int ret = CRYPTO_SUCCESS;
489 
490 	ASSERT(ctx->cc_provider_private != NULL);
491 
492 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
493 
494 	/* compute number of bytes that will hold the plaintext */
495 	out_len =
496 	    ((blowfish_ctx_t *)ctx->cc_provider_private)->bc_remainder_len;
497 	out_len += ciphertext->cd_length;
498 	out_len &= ~(BLOWFISH_BLOCK_LEN - 1);
499 
500 	/* return length needed to store the output */
501 	if (plaintext->cd_length < out_len) {
502 		plaintext->cd_length = out_len;
503 		return (CRYPTO_BUFFER_TOO_SMALL);
504 	}
505 
506 	saved_offset = plaintext->cd_offset;
507 	saved_length = plaintext->cd_length;
508 
509 	/*
510 	 * Do the blowfish update on the specified input data.
511 	 */
512 	switch (ciphertext->cd_format) {
513 	case CRYPTO_DATA_RAW:
514 		ret = crypto_update_iov(ctx->cc_provider_private,
515 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
516 		    blowfish_copy_block64);
517 		break;
518 	case CRYPTO_DATA_UIO:
519 		ret = crypto_update_uio(ctx->cc_provider_private,
520 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
521 		    blowfish_copy_block64);
522 		break;
523 	case CRYPTO_DATA_MBLK:
524 		ret = crypto_update_mp(ctx->cc_provider_private,
525 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
526 		    blowfish_copy_block64);
527 		break;
528 	default:
529 		ret = CRYPTO_ARGUMENTS_BAD;
530 	}
531 
532 	if (ret == CRYPTO_SUCCESS) {
533 		if (ciphertext != plaintext)
534 			plaintext->cd_length =
535 			    plaintext->cd_offset - saved_offset;
536 	} else {
537 		plaintext->cd_length = saved_length;
538 	}
539 	plaintext->cd_offset = saved_offset;
540 
541 	return (ret);
542 }
543 
544 /* ARGSUSED */
545 static int
blowfish_encrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)546 blowfish_encrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
547     crypto_req_handle_t req)
548 {
549 	blowfish_ctx_t *blowfish_ctx;
550 
551 	ASSERT(ctx->cc_provider_private != NULL);
552 	blowfish_ctx = ctx->cc_provider_private;
553 
554 	/*
555 	 * There must be no unprocessed data.
556 	 * This happens if the length of the last data is
557 	 * not a multiple of the BLOWFISH block length.
558 	 */
559 	if (blowfish_ctx->bc_remainder_len > 0)
560 		return (CRYPTO_DATA_LEN_RANGE);
561 
562 	(void) blowfish_free_context(ctx);
563 	data->cd_length = 0;
564 
565 	return (CRYPTO_SUCCESS);
566 }
567 
568 /* ARGSUSED */
569 static int
blowfish_decrypt_final(crypto_ctx_t * ctx,crypto_data_t * data,crypto_req_handle_t req)570 blowfish_decrypt_final(crypto_ctx_t *ctx, crypto_data_t *data,
571     crypto_req_handle_t req)
572 {
573 	blowfish_ctx_t *blowfish_ctx;
574 
575 	ASSERT(ctx->cc_provider_private != NULL);
576 	blowfish_ctx = ctx->cc_provider_private;
577 
578 	/*
579 	 * There must be no unprocessed ciphertext.
580 	 * This happens if the length of the last ciphertext is
581 	 * not a multiple of the BLOWFISH block length.
582 	 */
583 	if (blowfish_ctx->bc_remainder_len > 0)
584 		return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
585 
586 	(void) blowfish_free_context(ctx);
587 	data->cd_length = 0;
588 
589 	return (CRYPTO_SUCCESS);
590 }
591 
592 /* ARGSUSED */
593 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)594 blowfish_encrypt_atomic(crypto_provider_handle_t provider,
595     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
596     crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
597     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
598 {
599 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
600 	off_t saved_offset;
601 	size_t saved_length;
602 	int ret;
603 
604 	BLOWFISH_ARG_INPLACE(plaintext, ciphertext);
605 
606 	/*
607 	 * Plaintext must be a multiple of blowfish block size.
608 	 * This test only works for non-padded mechanisms
609 	 * when blocksize is 2^N.
610 	 */
611 	if ((plaintext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
612 		return (CRYPTO_DATA_LEN_RANGE);
613 
614 	/* return length needed to store the output */
615 	if (ciphertext->cd_length < plaintext->cd_length) {
616 		ciphertext->cd_length = plaintext->cd_length;
617 		return (CRYPTO_BUFFER_TOO_SMALL);
618 	}
619 
620 	if (!BLOWFISH_VALID_MECH(mechanism))
621 		return (CRYPTO_MECHANISM_INVALID);
622 
623 	if (mechanism->cm_param_len != 0 &&
624 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
625 		return (CRYPTO_MECHANISM_PARAM_INVALID);
626 
627 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
628 
629 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
630 	    key, crypto_kmflag(req));
631 	if (ret != CRYPTO_SUCCESS)
632 		return (ret);
633 
634 	saved_offset = ciphertext->cd_offset;
635 	saved_length = ciphertext->cd_length;
636 
637 	/*
638 	 * Do an update on the specified input data.
639 	 */
640 	switch (plaintext->cd_format) {
641 	case CRYPTO_DATA_RAW:
642 		ret = crypto_update_iov(&blowfish_ctx,
643 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
644 		    blowfish_copy_block64);
645 		break;
646 	case CRYPTO_DATA_UIO:
647 		ret = crypto_update_uio(&blowfish_ctx,
648 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
649 		    blowfish_copy_block64);
650 		break;
651 	case CRYPTO_DATA_MBLK:
652 		ret = crypto_update_mp((void *)&blowfish_ctx,
653 		    plaintext, ciphertext, blowfish_encrypt_contiguous_blocks,
654 		    blowfish_copy_block64);
655 		break;
656 	default:
657 		ret = CRYPTO_ARGUMENTS_BAD;
658 	}
659 
660 	if (blowfish_ctx.bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
661 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
662 		kmem_free(blowfish_ctx.bc_keysched,
663 		    blowfish_ctx.bc_keysched_len);
664 	}
665 
666 	if (ret == CRYPTO_SUCCESS) {
667 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
668 		if (plaintext != ciphertext)
669 			ciphertext->cd_length =
670 			    ciphertext->cd_offset - saved_offset;
671 	} else {
672 		ciphertext->cd_length = saved_length;
673 	}
674 	ciphertext->cd_offset = saved_offset;
675 
676 	return (ret);
677 }
678 
679 /* ARGSUSED */
680 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)681 blowfish_decrypt_atomic(crypto_provider_handle_t provider,
682     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
683     crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
684     crypto_spi_ctx_template_t template, crypto_req_handle_t req)
685 {
686 	blowfish_ctx_t blowfish_ctx;	/* on the stack */
687 	off_t saved_offset;
688 	size_t saved_length;
689 	int ret;
690 
691 	BLOWFISH_ARG_INPLACE(ciphertext, plaintext);
692 
693 	/*
694 	 * Ciphertext must be a multiple of blowfish block size.
695 	 * This test only works for non-padded mechanisms
696 	 * when blocksize is 2^N.
697 	 */
698 	if ((ciphertext->cd_length & (BLOWFISH_BLOCK_LEN - 1)) != 0)
699 		return (CRYPTO_DATA_LEN_RANGE);
700 
701 	/* return length needed to store the output */
702 	if (plaintext->cd_length < ciphertext->cd_length) {
703 		plaintext->cd_length = ciphertext->cd_length;
704 		return (CRYPTO_BUFFER_TOO_SMALL);
705 	}
706 
707 	if (!BLOWFISH_VALID_MECH(mechanism))
708 		return (CRYPTO_MECHANISM_INVALID);
709 
710 	if (mechanism->cm_param_len != 0 &&
711 	    mechanism->cm_param_len != BLOWFISH_BLOCK_LEN)
712 		return (CRYPTO_MECHANISM_PARAM_INVALID);
713 
714 	bzero(&blowfish_ctx, sizeof (blowfish_ctx_t));
715 
716 	ret = blowfish_common_init_ctx(&blowfish_ctx, template, mechanism,
717 	    key, crypto_kmflag(req));
718 	if (ret != CRYPTO_SUCCESS)
719 		return (ret);
720 
721 	saved_offset = plaintext->cd_offset;
722 	saved_length = plaintext->cd_length;
723 
724 	/*
725 	 * Do an update on the specified input data.
726 	 */
727 	switch (ciphertext->cd_format) {
728 	case CRYPTO_DATA_RAW:
729 		ret = crypto_update_iov(&blowfish_ctx,
730 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
731 		    blowfish_copy_block64);
732 		break;
733 	case CRYPTO_DATA_UIO:
734 		ret = crypto_update_uio(&blowfish_ctx,
735 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
736 		    blowfish_copy_block64);
737 		break;
738 	case CRYPTO_DATA_MBLK:
739 		ret = crypto_update_mp(&blowfish_ctx,
740 		    ciphertext, plaintext, blowfish_decrypt_contiguous_blocks,
741 		    blowfish_copy_block64);
742 		break;
743 	default:
744 		ret = CRYPTO_ARGUMENTS_BAD;
745 	}
746 
747 	if (blowfish_ctx.bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
748 		bzero(blowfish_ctx.bc_keysched, blowfish_ctx.bc_keysched_len);
749 		kmem_free(blowfish_ctx.bc_keysched,
750 		    blowfish_ctx.bc_keysched_len);
751 	}
752 
753 	if (ret == CRYPTO_SUCCESS) {
754 		ASSERT(blowfish_ctx.bc_remainder_len == 0);
755 		if (ciphertext != plaintext)
756 			plaintext->cd_length =
757 			    plaintext->cd_offset - saved_offset;
758 	} else {
759 		plaintext->cd_length = saved_length;
760 	}
761 	plaintext->cd_offset = saved_offset;
762 
763 	return (ret);
764 }
765 
766 /*
767  * KCF software provider context template entry points.
768  */
769 /* ARGSUSED */
770 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)771 blowfish_create_ctx_template(crypto_provider_handle_t provider,
772     crypto_mechanism_t *mechanism, crypto_key_t *key,
773     crypto_spi_ctx_template_t *tmpl, size_t *tmpl_size, crypto_req_handle_t req)
774 {
775 	void *keysched;
776 	size_t size;
777 	int rv;
778 
779 	if (!BLOWFISH_VALID_MECH(mechanism))
780 		return (CRYPTO_MECHANISM_INVALID);
781 
782 	if ((keysched = blowfish_alloc_keysched(&size,
783 	    crypto_kmflag(req))) == NULL) {
784 		return (CRYPTO_HOST_MEMORY);
785 	}
786 
787 	/*
788 	 * Initialize key schedule.  Key length information is stored
789 	 * in the key.
790 	 */
791 	if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS) {
792 		bzero(keysched, size);
793 		kmem_free(keysched, size);
794 		return (rv);
795 	}
796 
797 	*tmpl = keysched;
798 	*tmpl_size = size;
799 
800 	return (CRYPTO_SUCCESS);
801 }
802 
803 /* ARGSUSED */
804 static int
blowfish_free_context(crypto_ctx_t * ctx)805 blowfish_free_context(crypto_ctx_t *ctx)
806 {
807 	blowfish_ctx_t *blowfish_ctx = ctx->cc_provider_private;
808 
809 	if (blowfish_ctx != NULL) {
810 		if (blowfish_ctx->bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
811 			ASSERT(blowfish_ctx->bc_keysched_len != 0);
812 			bzero(blowfish_ctx->bc_keysched,
813 			    blowfish_ctx->bc_keysched_len);
814 			kmem_free(blowfish_ctx->bc_keysched,
815 			    blowfish_ctx->bc_keysched_len);
816 		}
817 		crypto_free_mode_ctx(blowfish_ctx);
818 		ctx->cc_provider_private = NULL;
819 	}
820 
821 	return (CRYPTO_SUCCESS);
822 }
823 
824 /* ARGSUSED */
825 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)826 blowfish_common_init_ctx(blowfish_ctx_t *blowfish_ctx,
827     crypto_spi_ctx_template_t *template, crypto_mechanism_t *mechanism,
828     crypto_key_t *key, int kmflag)
829 {
830 	int rv = CRYPTO_SUCCESS;
831 
832 	void *keysched;
833 	size_t size;
834 
835 	if (template == NULL) {
836 		if ((keysched = blowfish_alloc_keysched(&size, kmflag)) == NULL)
837 			return (CRYPTO_HOST_MEMORY);
838 		/*
839 		 * Initialize key schedule.
840 		 * Key length is stored in the key.
841 		 */
842 		if ((rv = init_keysched(key, keysched)) != CRYPTO_SUCCESS)
843 			kmem_free(keysched, size);
844 
845 		blowfish_ctx->bc_flags |= PROVIDER_OWNS_KEY_SCHEDULE;
846 		blowfish_ctx->bc_keysched_len = size;
847 	} else {
848 		keysched = template;
849 	}
850 	blowfish_ctx->bc_keysched = keysched;
851 
852 	switch (mechanism->cm_type) {
853 	case BLOWFISH_CBC_MECH_INFO_TYPE:
854 		rv = cbc_init_ctx((cbc_ctx_t *)blowfish_ctx,
855 		    mechanism->cm_param, mechanism->cm_param_len,
856 		    BLOWFISH_BLOCK_LEN, blowfish_copy_block64);
857 		break;
858 	case BLOWFISH_ECB_MECH_INFO_TYPE:
859 		blowfish_ctx->bc_flags |= ECB_MODE;
860 	}
861 
862 	if (rv != CRYPTO_SUCCESS) {
863 		if (blowfish_ctx->bc_flags & PROVIDER_OWNS_KEY_SCHEDULE) {
864 			bzero(keysched, size);
865 			kmem_free(keysched, size);
866 		}
867 	}
868 
869 	return (rv);
870 }
871