xref: /illumos-gate/usr/src/uts/common/crypto/io/skein_mod.c (revision 45818ee124adeaaf947698996b4f4c722afc6d1f)
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://opensource.org/licenses/CDDL-1.0.
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 /*
23  * Copyright 2013 Saso Kiselkov. All rights reserved.
24  */
25 
26 #include <sys/modctl.h>
27 #include <sys/crypto/common.h>
28 #include <sys/crypto/spi.h>
29 #include <sys/strsun.h>
30 #include <sys/sysmacros.h>
31 #include <sys/systm.h>
32 #define	SKEIN_MODULE_IMPL
33 #include <sys/skein.h>
34 
35 /*
36  * Like the sha2 module, we create the skein module with two modlinkages:
37  * - modlmisc to allow direct calls to Skein_* API functions.
38  * - modlcrypto to integrate well into the Kernel Crypto Framework (KCF).
39  */
40 static struct modlmisc modlmisc = {
41 	&mod_miscops,
42 	"Skein Message-Digest Algorithm"
43 };
44 
45 static struct modlcrypto modlcrypto = {
46 	&mod_cryptoops,
47 	"Skein Kernel SW Provider"
48 };
49 
50 static struct modlinkage modlinkage = {
51 	MODREV_1, &modlmisc, &modlcrypto, NULL
52 };
53 
54 static crypto_mech_info_t skein_mech_info_tab[] = {
55 	{CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE,
56 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
57 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
58 	{CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE,
59 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
60 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
61 	{CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE,
62 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
63 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
64 	{CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE,
65 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
66 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES},
67 	{CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE,
68 	    CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
69 	    0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
70 	{CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE,
71 	    CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
72 	    CRYPTO_KEYSIZE_UNIT_IN_BYTES}
73 };
74 
75 static void skein_provider_status(crypto_provider_handle_t, uint_t *);
76 
77 static crypto_control_ops_t skein_control_ops = {
78 	skein_provider_status
79 };
80 
81 static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
82     crypto_req_handle_t);
83 static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
84     crypto_req_handle_t);
85 static int skein_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
86 static int skein_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
87 static int skein_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
88     crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
89     crypto_req_handle_t);
90 
91 static crypto_digest_ops_t skein_digest_ops = {
92 	skein_digest_init,
93 	skein_digest,
94 	skein_update,
95 	NULL,
96 	skein_final,
97 	skein_digest_atomic
98 };
99 
100 static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
101     crypto_spi_ctx_template_t, crypto_req_handle_t);
102 static int skein_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
103     crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
104     crypto_spi_ctx_template_t, crypto_req_handle_t);
105 
106 static crypto_mac_ops_t skein_mac_ops = {
107 	skein_mac_init,
108 	NULL,
109 	skein_update,	/* using regular digest update is OK here */
110 	skein_final,	/* using regular digest final is OK here */
111 	skein_mac_atomic,
112 	NULL
113 };
114 
115 static int skein_create_ctx_template(crypto_provider_handle_t,
116     crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
117     size_t *, crypto_req_handle_t);
118 static int skein_free_context(crypto_ctx_t *);
119 
120 static crypto_ctx_ops_t skein_ctx_ops = {
121 	skein_create_ctx_template,
122 	skein_free_context
123 };
124 
125 static crypto_ops_t skein_crypto_ops = {
126 	&skein_control_ops,
127 	&skein_digest_ops,
128 	NULL,
129 	&skein_mac_ops,
130 	NULL,
131 	NULL,
132 	NULL,
133 	NULL,
134 	NULL,
135 	NULL,
136 	NULL,
137 	NULL,
138 	NULL,
139 	&skein_ctx_ops,
140 	NULL,
141 	NULL,
142 	NULL
143 };
144 
145 static crypto_provider_info_t skein_prov_info = {
146 	CRYPTO_SPI_VERSION_4,
147 	"Skein Software Provider",
148 	CRYPTO_SW_PROVIDER,
149 	{&modlinkage},
150 	NULL,
151 	&skein_crypto_ops,
152 	sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t),
153 	skein_mech_info_tab
154 };
155 
156 static crypto_kcf_provider_handle_t skein_prov_handle = NULL;
157 
158 typedef struct skein_ctx {
159 	skein_mech_type_t		sc_mech_type;
160 	size_t				sc_digest_bitlen;
161 	/*LINTED(E_ANONYMOUS_UNION_DECL)*/
162 	union {
163 		Skein_256_Ctxt_t	sc_256;
164 		Skein_512_Ctxt_t	sc_512;
165 		Skein1024_Ctxt_t	sc_1024;
166 	};
167 } skein_ctx_t;
168 #define	SKEIN_CTX(_ctx_)	((skein_ctx_t *)((_ctx_)->cc_provider_private))
169 #define	SKEIN_CTX_LVALUE(_ctx_)	(_ctx_)->cc_provider_private
170 #define	SKEIN_OP(_skein_ctx, _op, ...)					\
171 	do {								\
172 		skein_ctx_t	*sc = (_skein_ctx);			\
173 		switch (sc->sc_mech_type) {				\
174 		case SKEIN_256_MECH_INFO_TYPE:				\
175 		case SKEIN_256_MAC_MECH_INFO_TYPE:			\
176 			(void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\
177 			break;						\
178 		case SKEIN_512_MECH_INFO_TYPE:				\
179 		case SKEIN_512_MAC_MECH_INFO_TYPE:			\
180 			(void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\
181 			break;						\
182 		case SKEIN1024_MECH_INFO_TYPE:				\
183 		case SKEIN1024_MAC_MECH_INFO_TYPE:			\
184 			(void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\
185 			break;						\
186 		}							\
187 		_NOTE(CONSTCOND)					\
188 	} while (0)
189 
190 static int
191 skein_get_digest_bitlen(const crypto_mechanism_t *mechanism, size_t *result)
192 {
193 	if (mechanism->cm_param != NULL) {
194 		/*LINTED(E_BAD_PTR_CAST_ALIGN)*/
195 		skein_param_t	*param = (skein_param_t *)mechanism->cm_param;
196 
197 		if (mechanism->cm_param_len != sizeof (*param) ||
198 		    param->sp_digest_bitlen == 0) {
199 			return (CRYPTO_MECHANISM_PARAM_INVALID);
200 		}
201 		*result = param->sp_digest_bitlen;
202 	} else {
203 		switch (mechanism->cm_type) {
204 		case SKEIN_256_MECH_INFO_TYPE:
205 			*result = 256;
206 			break;
207 		case SKEIN_512_MECH_INFO_TYPE:
208 			*result = 512;
209 			break;
210 		case SKEIN1024_MECH_INFO_TYPE:
211 			*result = 1024;
212 			break;
213 		default:
214 			return (CRYPTO_MECHANISM_INVALID);
215 		}
216 	}
217 	return (CRYPTO_SUCCESS);
218 }
219 
220 int
221 _init(void)
222 {
223 	int error;
224 
225 	if ((error = mod_install(&modlinkage)) != 0)
226 		return (error);
227 
228 	/*
229 	 * Try to register with KCF - failure shouldn't unload us, since we
230 	 * still may want to continue providing misc/skein functionality.
231 	 */
232 	(void) crypto_register_provider(&skein_prov_info, &skein_prov_handle);
233 
234 	return (0);
235 }
236 
237 int
238 _info(struct modinfo *modinfop)
239 {
240 	return (mod_info(&modlinkage, modinfop));
241 }
242 
243 /*
244  * KCF software provider control entry points.
245  */
246 /* ARGSUSED */
247 static void
248 skein_provider_status(crypto_provider_handle_t provider, uint_t *status)
249 {
250 	*status = CRYPTO_PROVIDER_READY;
251 }
252 
253 /*
254  * General Skein hashing helper functions.
255  */
256 
257 /*
258  * Performs an Update on a context with uio input data.
259  */
260 static int
261 skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data)
262 {
263 	off_t		offset = data->cd_offset;
264 	size_t		length = data->cd_length;
265 	uint_t		vec_idx;
266 	size_t		cur_len;
267 	const uio_t	*uio = data->cd_uio;
268 
269 	/* we support only kernel buffer */
270 	if (uio->uio_segflg != UIO_SYSSPACE)
271 		return (CRYPTO_ARGUMENTS_BAD);
272 
273 	/*
274 	 * Jump to the first iovec containing data to be
275 	 * digested.
276 	 */
277 	for (vec_idx = 0; vec_idx < uio->uio_iovcnt &&
278 	    offset >= uio->uio_iov[vec_idx].iov_len;
279 	    offset -= uio->uio_iov[vec_idx++].iov_len)
280 		;
281 	if (vec_idx == uio->uio_iovcnt) {
282 		/*
283 		 * The caller specified an offset that is larger than the
284 		 * total size of the buffers it provided.
285 		 */
286 		return (CRYPTO_DATA_LEN_RANGE);
287 	}
288 
289 	/*
290 	 * Now do the digesting on the iovecs.
291 	 */
292 	while (vec_idx < uio->uio_iovcnt && length > 0) {
293 		cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset, length);
294 		SKEIN_OP(ctx, Update, (uint8_t *)uio->uio_iov[vec_idx].iov_base
295 		    + offset, cur_len);
296 		length -= cur_len;
297 		vec_idx++;
298 		offset = 0;
299 	}
300 
301 	if (vec_idx == uio->uio_iovcnt && length > 0) {
302 		/*
303 		 * The end of the specified iovec's was reached but
304 		 * the length requested could not be processed, i.e.
305 		 * The caller requested to digest more data than it provided.
306 		 */
307 		return (CRYPTO_DATA_LEN_RANGE);
308 	}
309 
310 	return (CRYPTO_SUCCESS);
311 }
312 
313 /*
314  * Performs a Final on a context and writes to a uio digest output.
315  */
316 static int
317 skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
318     crypto_req_handle_t req)
319 {
320 	off_t	offset = digest->cd_offset;
321 	uint_t	vec_idx;
322 	uio_t	*uio = digest->cd_uio;
323 
324 	/* we support only kernel buffer */
325 	if (uio->uio_segflg != UIO_SYSSPACE)
326 		return (CRYPTO_ARGUMENTS_BAD);
327 
328 	/*
329 	 * Jump to the first iovec containing ptr to the digest to be returned.
330 	 */
331 	for (vec_idx = 0; offset >= uio->uio_iov[vec_idx].iov_len &&
332 	    vec_idx < uio->uio_iovcnt;
333 	    offset -= uio->uio_iov[vec_idx++].iov_len)
334 		;
335 	if (vec_idx == uio->uio_iovcnt) {
336 		/*
337 		 * The caller specified an offset that is larger than the
338 		 * total size of the buffers it provided.
339 		 */
340 		return (CRYPTO_DATA_LEN_RANGE);
341 	}
342 	if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <=
343 	    uio->uio_iov[vec_idx].iov_len) {
344 		/* The computed digest will fit in the current iovec. */
345 		SKEIN_OP(ctx, Final,
346 		    (uchar_t *)uio->uio_iov[vec_idx].iov_base + offset);
347 	} else {
348 		uint8_t *digest_tmp;
349 		off_t scratch_offset = 0;
350 		size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen);
351 		size_t cur_len;
352 
353 		digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES(
354 		    ctx->sc_digest_bitlen), crypto_kmflag(req));
355 		if (digest_tmp == NULL)
356 			return (CRYPTO_HOST_MEMORY);
357 		SKEIN_OP(ctx, Final, digest_tmp);
358 		while (vec_idx < uio->uio_iovcnt && length > 0) {
359 			cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset,
360 			    length);
361 			bcopy(digest_tmp + scratch_offset,
362 			    uio->uio_iov[vec_idx].iov_base + offset, cur_len);
363 
364 			length -= cur_len;
365 			vec_idx++;
366 			scratch_offset += cur_len;
367 			offset = 0;
368 		}
369 		kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen));
370 
371 		if (vec_idx == uio->uio_iovcnt && length > 0) {
372 			/*
373 			 * The end of the specified iovec's was reached but
374 			 * the length requested could not be processed, i.e.
375 			 * The caller requested to digest more data than it
376 			 * provided.
377 			 */
378 			return (CRYPTO_DATA_LEN_RANGE);
379 		}
380 	}
381 
382 	return (CRYPTO_SUCCESS);
383 }
384 
385 /*
386  * Performs an Update on a context with mblk input data.
387  */
388 static int
389 skein_digest_update_mblk(skein_ctx_t *ctx, crypto_data_t *data)
390 {
391 	off_t offset = data->cd_offset;
392 	size_t length = data->cd_length;
393 	mblk_t *mp;
394 	size_t cur_len;
395 
396 	/* Jump to the first mblk_t containing data to be digested. */
397 	for (mp = data->cd_mp; mp != NULL && offset >= MBLKL(mp);
398 	    offset -= MBLKL(mp), mp = mp->b_cont)
399 		;
400 	if (mp == NULL) {
401 		/*
402 		 * The caller specified an offset that is larger than the
403 		 * total size of the buffers it provided.
404 		 */
405 		return (CRYPTO_DATA_LEN_RANGE);
406 	}
407 
408 	/* Now do the digesting on the mblk chain. */
409 	while (mp != NULL && length > 0) {
410 		cur_len = MIN(MBLKL(mp) - offset, length);
411 		SKEIN_OP(ctx, Update, mp->b_rptr + offset, cur_len);
412 		length -= cur_len;
413 		offset = 0;
414 		mp = mp->b_cont;
415 	}
416 
417 	if (mp == NULL && length > 0) {
418 		/*
419 		 * The end of the mblk was reached but the length requested
420 		 * could not be processed, i.e. The caller requested
421 		 * to digest more data than it provided.
422 		 */
423 		return (CRYPTO_DATA_LEN_RANGE);
424 	}
425 
426 	return (CRYPTO_SUCCESS);
427 }
428 
429 /*
430  * Performs a Final on a context and writes to an mblk digest output.
431  */
432 static int
433 skein_digest_final_mblk(skein_ctx_t *ctx, crypto_data_t *digest,
434     crypto_req_handle_t req)
435 {
436 	off_t	offset = digest->cd_offset;
437 	mblk_t	*mp;
438 
439 	/* Jump to the first mblk_t that will be used to store the digest. */
440 	for (mp = digest->cd_mp; mp != NULL && offset >= MBLKL(mp);
441 	    offset -= MBLKL(mp), mp = mp->b_cont)
442 		;
443 	if (mp == NULL) {
444 		/* caller specified offset is too large */
445 		return (CRYPTO_DATA_LEN_RANGE);
446 	}
447 
448 	if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <= MBLKL(mp)) {
449 		/* The digest will fit in the current mblk. */
450 		SKEIN_OP(ctx, Final, mp->b_rptr + offset);
451 	} else {
452 		/* Split the digest up between the individual buffers. */
453 		uint8_t *digest_tmp;
454 		off_t scratch_offset = 0;
455 		size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen);
456 		size_t cur_len;
457 
458 		digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES(
459 		    ctx->sc_digest_bitlen), crypto_kmflag(req));
460 		if (digest_tmp == NULL)
461 			return (CRYPTO_HOST_MEMORY);
462 		SKEIN_OP(ctx, Final, digest_tmp);
463 		while (mp != NULL && length > 0) {
464 			cur_len = MIN(MBLKL(mp) - offset, length);
465 			bcopy(digest_tmp + scratch_offset,
466 			    mp->b_rptr + offset, cur_len);
467 			length -= cur_len;
468 			mp = mp->b_cont;
469 			scratch_offset += cur_len;
470 			offset = 0;
471 		}
472 		kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen));
473 		if (mp == NULL && length > 0) {
474 			/* digest too long to fit in the mblk buffers */
475 			return (CRYPTO_DATA_LEN_RANGE);
476 		}
477 	}
478 
479 	return (CRYPTO_SUCCESS);
480 }
481 
482 /*
483  * KCF software provider digest entry points.
484  */
485 
486 /*
487  * Initializes a skein digest context to the configuration in `mechanism'.
488  * The mechanism cm_type must be one of SKEIN_*_MECH_INFO_TYPE. The cm_param
489  * field may contain a skein_param_t structure indicating the length of the
490  * digest the algorithm should produce. Otherwise the default output lengths
491  * are applied (32 bytes for Skein-256, 64 bytes for Skein-512 and 128 bytes
492  * for Skein-1024).
493  */
494 static int
495 skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
496     crypto_req_handle_t req)
497 {
498 	int	error = CRYPTO_SUCCESS;
499 
500 	if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
501 		return (CRYPTO_MECHANISM_INVALID);
502 
503 	SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
504 	    crypto_kmflag(req));
505 	if (SKEIN_CTX(ctx) == NULL)
506 		return (CRYPTO_HOST_MEMORY);
507 
508 	SKEIN_CTX(ctx)->sc_mech_type = mechanism->cm_type;
509 	error = skein_get_digest_bitlen(mechanism,
510 	    &SKEIN_CTX(ctx)->sc_digest_bitlen);
511 	if (error != CRYPTO_SUCCESS)
512 		goto errout;
513 	SKEIN_OP(SKEIN_CTX(ctx), Init, SKEIN_CTX(ctx)->sc_digest_bitlen);
514 
515 	return (CRYPTO_SUCCESS);
516 errout:
517 	bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
518 	kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
519 	SKEIN_CTX_LVALUE(ctx) = NULL;
520 	return (error);
521 }
522 
523 /*
524  * Executes a skein_update and skein_digest on a pre-initialized crypto
525  * context in a single step. See the documentation to these functions to
526  * see what to pass here.
527  */
528 static int
529 skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
530     crypto_req_handle_t req)
531 {
532 	int error = CRYPTO_SUCCESS;
533 
534 	ASSERT(SKEIN_CTX(ctx) != NULL);
535 
536 	if (digest->cd_length <
537 	    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
538 		digest->cd_length =
539 		    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
540 		return (CRYPTO_BUFFER_TOO_SMALL);
541 	}
542 
543 	error = skein_update(ctx, data, req);
544 	if (error != CRYPTO_SUCCESS) {
545 		bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
546 		kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
547 		SKEIN_CTX_LVALUE(ctx) = NULL;
548 		digest->cd_length = 0;
549 		return (error);
550 	}
551 	error = skein_final(ctx, digest, req);
552 
553 	return (error);
554 }
555 
556 /*
557  * Performs a skein Update with the input message in `data' (successive calls
558  * can push more data). This is used both for digest and MAC operation.
559  * Supported input data formats are raw, uio and mblk.
560  */
561 /*ARGSUSED*/
562 static int
563 skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
564 {
565 	int error = CRYPTO_SUCCESS;
566 
567 	ASSERT(SKEIN_CTX(ctx) != NULL);
568 
569 	switch (data->cd_format) {
570 	case CRYPTO_DATA_RAW:
571 		SKEIN_OP(SKEIN_CTX(ctx), Update,
572 		    (uint8_t *)data->cd_raw.iov_base + data->cd_offset,
573 		    data->cd_length);
574 		break;
575 	case CRYPTO_DATA_UIO:
576 		error = skein_digest_update_uio(SKEIN_CTX(ctx), data);
577 		break;
578 	case CRYPTO_DATA_MBLK:
579 		error = skein_digest_update_mblk(SKEIN_CTX(ctx), data);
580 		break;
581 	default:
582 		error = CRYPTO_ARGUMENTS_BAD;
583 	}
584 
585 	return (error);
586 }
587 
588 /*
589  * Performs a skein Final, writing the output to `digest'. This is used both
590  * for digest and MAC operation.
591  * Supported output digest formats are raw, uio and mblk.
592  */
593 /*ARGSUSED*/
594 static int
595 skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
596 {
597 	int error = CRYPTO_SUCCESS;
598 
599 	ASSERT(SKEIN_CTX(ctx) != NULL);
600 
601 	if (digest->cd_length <
602 	    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
603 		digest->cd_length =
604 		    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
605 		return (CRYPTO_BUFFER_TOO_SMALL);
606 	}
607 
608 	switch (digest->cd_format) {
609 	case CRYPTO_DATA_RAW:
610 		SKEIN_OP(SKEIN_CTX(ctx), Final,
611 		    (uint8_t *)digest->cd_raw.iov_base + digest->cd_offset);
612 		break;
613 	case CRYPTO_DATA_UIO:
614 		error = skein_digest_final_uio(SKEIN_CTX(ctx), digest, req);
615 		break;
616 	case CRYPTO_DATA_MBLK:
617 		error = skein_digest_final_mblk(SKEIN_CTX(ctx), digest, req);
618 		break;
619 	default:
620 		error = CRYPTO_ARGUMENTS_BAD;
621 	}
622 
623 	if (error == CRYPTO_SUCCESS)
624 		digest->cd_length =
625 		    CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
626 	else
627 		digest->cd_length = 0;
628 
629 	bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
630 	kmem_free(SKEIN_CTX(ctx), sizeof (*(SKEIN_CTX(ctx))));
631 	SKEIN_CTX_LVALUE(ctx) = NULL;
632 
633 	return (error);
634 }
635 
636 /*
637  * Performs a full skein digest computation in a single call, configuring the
638  * algorithm according to `mechanism', reading the input to be digested from
639  * `data' and writing the output to `digest'.
640  * Supported input/output formats are raw, uio and mblk.
641  */
642 /*ARGSUSED*/
643 static int
644 skein_digest_atomic(crypto_provider_handle_t provider,
645     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
646     crypto_data_t *data, crypto_data_t *digest, crypto_req_handle_t req)
647 {
648 	int		error;
649 	skein_ctx_t	skein_ctx;
650 	crypto_ctx_t	ctx;
651 	SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
652 
653 	/* Init */
654 	if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
655 		return (CRYPTO_MECHANISM_INVALID);
656 	skein_ctx.sc_mech_type = mechanism->cm_type;
657 	error = skein_get_digest_bitlen(mechanism, &skein_ctx.sc_digest_bitlen);
658 	if (error != CRYPTO_SUCCESS)
659 		goto out;
660 	SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen);
661 
662 	if ((error = skein_update(&ctx, data, digest)) != CRYPTO_SUCCESS)
663 		goto out;
664 	if ((error = skein_final(&ctx, data, digest)) != CRYPTO_SUCCESS)
665 		goto out;
666 
667 out:
668 	if (error == CRYPTO_SUCCESS)
669 		digest->cd_length =
670 		    CRYPTO_BITS2BYTES(skein_ctx.sc_digest_bitlen);
671 	else
672 		digest->cd_length = 0;
673 	bzero(&skein_ctx, sizeof (skein_ctx));
674 
675 	return (error);
676 }
677 
678 /*
679  * Helper function that builds a Skein MAC context from the provided
680  * mechanism and key.
681  */
682 static int
683 skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism,
684     crypto_key_t *key)
685 {
686 	int error;
687 
688 	if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type))
689 		return (CRYPTO_MECHANISM_INVALID);
690 	if (key->ck_format != CRYPTO_KEY_RAW)
691 		return (CRYPTO_ARGUMENTS_BAD);
692 	ctx->sc_mech_type = mechanism->cm_type;
693 	error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen);
694 	if (error != CRYPTO_SUCCESS)
695 		return (error);
696 	SKEIN_OP(ctx, InitExt, ctx->sc_digest_bitlen, 0, key->ck_data,
697 	    CRYPTO_BITS2BYTES(key->ck_length));
698 
699 	return (CRYPTO_SUCCESS);
700 }
701 
702 /*
703  * KCF software provide mac entry points.
704  */
705 /*
706  * Initializes a skein MAC context. You may pass a ctx_template, in which
707  * case the template will be reused to make initialization more efficient.
708  * Otherwise a new context will be constructed. The mechanism cm_type must
709  * be one of SKEIN_*_MAC_MECH_INFO_TYPE. Same as in skein_digest_init, you
710  * may pass a skein_param_t in cm_param to configure the length of the
711  * digest. The key must be in raw format.
712  */
713 static int
714 skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
715     crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
716     crypto_req_handle_t req)
717 {
718 	int	error;
719 
720 	SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
721 	    crypto_kmflag(req));
722 	if (SKEIN_CTX(ctx) == NULL)
723 		return (CRYPTO_HOST_MEMORY);
724 
725 	if (ctx_template != NULL) {
726 		bcopy(ctx_template, SKEIN_CTX(ctx),
727 		    sizeof (*SKEIN_CTX(ctx)));
728 	} else {
729 		error = skein_mac_ctx_build(SKEIN_CTX(ctx), mechanism, key);
730 		if (error != CRYPTO_SUCCESS)
731 			goto errout;
732 	}
733 
734 	return (CRYPTO_SUCCESS);
735 errout:
736 	bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
737 	kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
738 	return (error);
739 }
740 
741 /*
742  * The MAC update and final calls are reused from the regular digest code.
743  */
744 
745 /*ARGSUSED*/
746 /*
747  * Same as skein_digest_atomic, performs an atomic Skein MAC operation in
748  * one step. All the same properties apply to the arguments of this
749  * function as to those of the partial operations above.
750  */
751 static int
752 skein_mac_atomic(crypto_provider_handle_t provider,
753     crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
754     crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
755     crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
756 {
757 	/* faux crypto context just for skein_digest_{update,final} */
758 	int		error;
759 	crypto_ctx_t	ctx;
760 	skein_ctx_t	skein_ctx;
761 	SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
762 
763 	if (ctx_template != NULL) {
764 		bcopy(ctx_template, &skein_ctx, sizeof (skein_ctx));
765 	} else {
766 		error = skein_mac_ctx_build(&skein_ctx, mechanism, key);
767 		if (error != CRYPTO_SUCCESS)
768 			goto errout;
769 	}
770 
771 	if ((error = skein_update(&ctx, data, req)) != CRYPTO_SUCCESS)
772 		goto errout;
773 	if ((error = skein_final(&ctx, mac, req)) != CRYPTO_SUCCESS)
774 		goto errout;
775 
776 	return (CRYPTO_SUCCESS);
777 errout:
778 	bzero(&skein_ctx, sizeof (skein_ctx));
779 	return (error);
780 }
781 
782 /*
783  * KCF software provider context management entry points.
784  */
785 
786 /*
787  * Constructs a context template for the Skein MAC algorithm. The same
788  * properties apply to the arguments of this function as to those of
789  * skein_mac_init.
790  */
791 /*ARGSUSED*/
792 static int
793 skein_create_ctx_template(crypto_provider_handle_t provider,
794     crypto_mechanism_t *mechanism, crypto_key_t *key,
795     crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
796     crypto_req_handle_t req)
797 {
798 	int		error;
799 	skein_ctx_t	*ctx_tmpl;
800 
801 	ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), crypto_kmflag(req));
802 	if (ctx_tmpl == NULL)
803 		return (CRYPTO_HOST_MEMORY);
804 	error = skein_mac_ctx_build(ctx_tmpl, mechanism, key);
805 	if (error != CRYPTO_SUCCESS)
806 		goto errout;
807 	*ctx_template = ctx_tmpl;
808 	*ctx_template_size = sizeof (*ctx_tmpl);
809 
810 	return (CRYPTO_SUCCESS);
811 errout:
812 	bzero(ctx_tmpl, sizeof (*ctx_tmpl));
813 	kmem_free(ctx_tmpl, sizeof (*ctx_tmpl));
814 	return (error);
815 }
816 
817 /*
818  * Frees a skein context in a parent crypto context.
819  */
820 static int
821 skein_free_context(crypto_ctx_t *ctx)
822 {
823 	if (SKEIN_CTX(ctx) != NULL) {
824 		bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
825 		kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
826 		SKEIN_CTX_LVALUE(ctx) = NULL;
827 	}
828 
829 	return (CRYPTO_SUCCESS);
830 }
831