]>
Commit | Line | Data |
---|---|---|
3c67d83a TH |
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 | ||
3c67d83a | 26 | #include <sys/crypto/common.h> |
60356b1a | 27 | #include <sys/crypto/icp.h> |
3c67d83a TH |
28 | #include <sys/crypto/spi.h> |
29 | #include <sys/sysmacros.h> | |
3c67d83a TH |
30 | #define SKEIN_MODULE_IMPL |
31 | #include <sys/skein.h> | |
32 | ||
18168da7 | 33 | static const crypto_mech_info_t skein_mech_info_tab[] = { |
3c67d83a | 34 | {CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE, |
cf497e18 | 35 | CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC}, |
3c67d83a | 36 | {CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE, |
cf497e18 | 37 | CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, |
3c67d83a | 38 | {CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE, |
cf497e18 | 39 | CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC}, |
3c67d83a | 40 | {CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE, |
cf497e18 | 41 | CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, |
3c67d83a | 42 | {CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE, |
cf497e18 | 43 | CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC}, |
3c67d83a | 44 | {CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE, |
cf497e18 | 45 | CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC}, |
3c67d83a TH |
46 | }; |
47 | ||
df7b54f1 AZ |
48 | static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *); |
49 | static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *); | |
50 | static int skein_update(crypto_ctx_t *, crypto_data_t *); | |
51 | static int skein_final(crypto_ctx_t *, crypto_data_t *); | |
de0ec5e7 AZ |
52 | static int skein_digest_atomic(crypto_mechanism_t *, crypto_data_t *, |
53 | crypto_data_t *); | |
3c67d83a | 54 | |
18168da7 | 55 | static const crypto_digest_ops_t skein_digest_ops = { |
56d8d8ac MW |
56 | .digest_init = skein_digest_init, |
57 | .digest = skein_digest, | |
58 | .digest_update = skein_update, | |
56d8d8ac MW |
59 | .digest_final = skein_final, |
60 | .digest_atomic = skein_digest_atomic | |
3c67d83a TH |
61 | }; |
62 | ||
63 | static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *, | |
df7b54f1 | 64 | crypto_spi_ctx_template_t); |
de0ec5e7 AZ |
65 | static int skein_mac_atomic(crypto_mechanism_t *, crypto_key_t *, |
66 | crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t); | |
3c67d83a | 67 | |
18168da7 | 68 | static const crypto_mac_ops_t skein_mac_ops = { |
56d8d8ac MW |
69 | .mac_init = skein_mac_init, |
70 | .mac = NULL, | |
71 | .mac_update = skein_update, /* using regular digest update is OK here */ | |
72 | .mac_final = skein_final, /* using regular digest final is OK here */ | |
73 | .mac_atomic = skein_mac_atomic, | |
74 | .mac_verify_atomic = NULL | |
3c67d83a TH |
75 | }; |
76 | ||
11320b4c AZ |
77 | static int skein_create_ctx_template(crypto_mechanism_t *, crypto_key_t *, |
78 | crypto_spi_ctx_template_t *, size_t *); | |
3c67d83a TH |
79 | static int skein_free_context(crypto_ctx_t *); |
80 | ||
18168da7 | 81 | static const crypto_ctx_ops_t skein_ctx_ops = { |
56d8d8ac MW |
82 | .create_ctx_template = skein_create_ctx_template, |
83 | .free_context = skein_free_context | |
3c67d83a TH |
84 | }; |
85 | ||
f5896e2b | 86 | static const crypto_ops_t skein_crypto_ops = { |
3c67d83a TH |
87 | &skein_digest_ops, |
88 | NULL, | |
89 | &skein_mac_ops, | |
3c67d83a | 90 | &skein_ctx_ops, |
f5896e2b | 91 | }; |
3c67d83a | 92 | |
f5896e2b | 93 | static const crypto_provider_info_t skein_prov_info = { |
3c67d83a | 94 | "Skein Software Provider", |
3c67d83a TH |
95 | &skein_crypto_ops, |
96 | sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t), | |
97 | skein_mech_info_tab | |
f5896e2b | 98 | }; |
3c67d83a TH |
99 | |
100 | static crypto_kcf_provider_handle_t skein_prov_handle = 0; | |
101 | ||
102 | typedef struct skein_ctx { | |
103 | skein_mech_type_t sc_mech_type; | |
104 | size_t sc_digest_bitlen; | |
105 | /*LINTED(E_ANONYMOUS_UNION_DECL)*/ | |
106 | union { | |
107 | Skein_256_Ctxt_t sc_256; | |
108 | Skein_512_Ctxt_t sc_512; | |
109 | Skein1024_Ctxt_t sc_1024; | |
110 | }; | |
111 | } skein_ctx_t; | |
112 | #define SKEIN_CTX(_ctx_) ((skein_ctx_t *)((_ctx_)->cc_provider_private)) | |
113 | #define SKEIN_CTX_LVALUE(_ctx_) (_ctx_)->cc_provider_private | |
114 | #define SKEIN_OP(_skein_ctx, _op, ...) \ | |
115 | do { \ | |
116 | skein_ctx_t *sc = (_skein_ctx); \ | |
117 | switch (sc->sc_mech_type) { \ | |
118 | case SKEIN_256_MECH_INFO_TYPE: \ | |
119 | case SKEIN_256_MAC_MECH_INFO_TYPE: \ | |
120 | (void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\ | |
121 | break; \ | |
122 | case SKEIN_512_MECH_INFO_TYPE: \ | |
123 | case SKEIN_512_MAC_MECH_INFO_TYPE: \ | |
124 | (void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\ | |
125 | break; \ | |
126 | case SKEIN1024_MECH_INFO_TYPE: \ | |
127 | case SKEIN1024_MAC_MECH_INFO_TYPE: \ | |
128 | (void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\ | |
129 | break; \ | |
130 | } \ | |
3c67d83a TH |
131 | } while (0) |
132 | ||
133 | static int | |
134 | skein_get_digest_bitlen(const crypto_mechanism_t *mechanism, size_t *result) | |
135 | { | |
136 | if (mechanism->cm_param != NULL) { | |
137 | /*LINTED(E_BAD_PTR_CAST_ALIGN)*/ | |
138 | skein_param_t *param = (skein_param_t *)mechanism->cm_param; | |
139 | ||
140 | if (mechanism->cm_param_len != sizeof (*param) || | |
141 | param->sp_digest_bitlen == 0) { | |
142 | return (CRYPTO_MECHANISM_PARAM_INVALID); | |
143 | } | |
144 | *result = param->sp_digest_bitlen; | |
145 | } else { | |
146 | switch (mechanism->cm_type) { | |
147 | case SKEIN_256_MECH_INFO_TYPE: | |
148 | *result = 256; | |
149 | break; | |
150 | case SKEIN_512_MECH_INFO_TYPE: | |
151 | *result = 512; | |
152 | break; | |
153 | case SKEIN1024_MECH_INFO_TYPE: | |
154 | *result = 1024; | |
155 | break; | |
156 | default: | |
157 | return (CRYPTO_MECHANISM_INVALID); | |
158 | } | |
159 | } | |
160 | return (CRYPTO_SUCCESS); | |
161 | } | |
162 | ||
163 | int | |
164 | skein_mod_init(void) | |
165 | { | |
3c67d83a TH |
166 | /* |
167 | * Try to register with KCF - failure shouldn't unload us, since we | |
168 | * still may want to continue providing misc/skein functionality. | |
169 | */ | |
170 | (void) crypto_register_provider(&skein_prov_info, &skein_prov_handle); | |
171 | ||
172 | return (0); | |
173 | } | |
174 | ||
175 | int | |
4ea3f864 GM |
176 | skein_mod_fini(void) |
177 | { | |
5c8389a8 | 178 | int ret = 0; |
ef78750d TC |
179 | |
180 | if (skein_prov_handle != 0) { | |
181 | if ((ret = crypto_unregister_provider(skein_prov_handle)) != | |
182 | CRYPTO_SUCCESS) { | |
183 | cmn_err(CE_WARN, | |
184 | "skein _fini: crypto_unregister_provider() " | |
185 | "failed (0x%x)", ret); | |
186 | return (EBUSY); | |
187 | } | |
188 | skein_prov_handle = 0; | |
189 | } | |
190 | ||
5c8389a8 | 191 | return (0); |
3c67d83a TH |
192 | } |
193 | ||
3c67d83a TH |
194 | /* |
195 | * General Skein hashing helper functions. | |
196 | */ | |
197 | ||
198 | /* | |
199 | * Performs an Update on a context with uio input data. | |
200 | */ | |
201 | static int | |
202 | skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data) | |
203 | { | |
204 | off_t offset = data->cd_offset; | |
205 | size_t length = data->cd_length; | |
59f6594c | 206 | uint_t vec_idx = 0; |
3c67d83a | 207 | size_t cur_len; |
d0cd9a5c | 208 | zfs_uio_t *uio = data->cd_uio; |
3c67d83a TH |
209 | |
210 | /* we support only kernel buffer */ | |
d0cd9a5c | 211 | if (zfs_uio_segflg(uio) != UIO_SYSSPACE) |
3c67d83a TH |
212 | return (CRYPTO_ARGUMENTS_BAD); |
213 | ||
214 | /* | |
215 | * Jump to the first iovec containing data to be | |
216 | * digested. | |
217 | */ | |
d0cd9a5c BA |
218 | offset = zfs_uio_index_at_offset(uio, offset, &vec_idx); |
219 | if (vec_idx == zfs_uio_iovcnt(uio)) { | |
3c67d83a TH |
220 | /* |
221 | * The caller specified an offset that is larger than the | |
222 | * total size of the buffers it provided. | |
223 | */ | |
224 | return (CRYPTO_DATA_LEN_RANGE); | |
225 | } | |
226 | ||
227 | /* | |
228 | * Now do the digesting on the iovecs. | |
229 | */ | |
d0cd9a5c BA |
230 | while (vec_idx < zfs_uio_iovcnt(uio) && length > 0) { |
231 | cur_len = MIN(zfs_uio_iovlen(uio, vec_idx) - offset, length); | |
232 | SKEIN_OP(ctx, Update, (uint8_t *)zfs_uio_iovbase(uio, vec_idx) | |
3c67d83a TH |
233 | + offset, cur_len); |
234 | length -= cur_len; | |
235 | vec_idx++; | |
236 | offset = 0; | |
237 | } | |
238 | ||
d0cd9a5c | 239 | if (vec_idx == zfs_uio_iovcnt(uio) && length > 0) { |
3c67d83a TH |
240 | /* |
241 | * The end of the specified iovec's was reached but | |
242 | * the length requested could not be processed, i.e. | |
243 | * The caller requested to digest more data than it provided. | |
244 | */ | |
245 | return (CRYPTO_DATA_LEN_RANGE); | |
246 | } | |
247 | ||
248 | return (CRYPTO_SUCCESS); | |
249 | } | |
250 | ||
251 | /* | |
252 | * Performs a Final on a context and writes to a uio digest output. | |
253 | */ | |
254 | static int | |
df7b54f1 | 255 | skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest) |
3c67d83a | 256 | { |
d0cd9a5c BA |
257 | off_t offset = digest->cd_offset; |
258 | uint_t vec_idx = 0; | |
259 | zfs_uio_t *uio = digest->cd_uio; | |
3c67d83a TH |
260 | |
261 | /* we support only kernel buffer */ | |
d0cd9a5c | 262 | if (zfs_uio_segflg(uio) != UIO_SYSSPACE) |
3c67d83a TH |
263 | return (CRYPTO_ARGUMENTS_BAD); |
264 | ||
265 | /* | |
266 | * Jump to the first iovec containing ptr to the digest to be returned. | |
267 | */ | |
d0cd9a5c BA |
268 | offset = zfs_uio_index_at_offset(uio, offset, &vec_idx); |
269 | if (vec_idx == zfs_uio_iovcnt(uio)) { | |
3c67d83a TH |
270 | /* |
271 | * The caller specified an offset that is larger than the | |
272 | * total size of the buffers it provided. | |
273 | */ | |
274 | return (CRYPTO_DATA_LEN_RANGE); | |
275 | } | |
276 | if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <= | |
d0cd9a5c | 277 | zfs_uio_iovlen(uio, vec_idx)) { |
3c67d83a TH |
278 | /* The computed digest will fit in the current iovec. */ |
279 | SKEIN_OP(ctx, Final, | |
d0cd9a5c | 280 | (uchar_t *)zfs_uio_iovbase(uio, vec_idx) + offset); |
3c67d83a TH |
281 | } else { |
282 | uint8_t *digest_tmp; | |
283 | off_t scratch_offset = 0; | |
284 | size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen); | |
285 | size_t cur_len; | |
286 | ||
287 | digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES( | |
df7b54f1 | 288 | ctx->sc_digest_bitlen), KM_SLEEP); |
3c67d83a TH |
289 | if (digest_tmp == NULL) |
290 | return (CRYPTO_HOST_MEMORY); | |
291 | SKEIN_OP(ctx, Final, digest_tmp); | |
d0cd9a5c BA |
292 | while (vec_idx < zfs_uio_iovcnt(uio) && length > 0) { |
293 | cur_len = MIN(zfs_uio_iovlen(uio, vec_idx) - offset, | |
3c67d83a | 294 | length); |
861166b0 AZ |
295 | memcpy(zfs_uio_iovbase(uio, vec_idx) + offset, |
296 | digest_tmp + scratch_offset, cur_len); | |
3c67d83a TH |
297 | |
298 | length -= cur_len; | |
299 | vec_idx++; | |
300 | scratch_offset += cur_len; | |
301 | offset = 0; | |
302 | } | |
303 | kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen)); | |
304 | ||
d0cd9a5c | 305 | if (vec_idx == zfs_uio_iovcnt(uio) && length > 0) { |
3c67d83a TH |
306 | /* |
307 | * The end of the specified iovec's was reached but | |
308 | * the length requested could not be processed, i.e. | |
309 | * The caller requested to digest more data than it | |
310 | * provided. | |
311 | */ | |
312 | return (CRYPTO_DATA_LEN_RANGE); | |
313 | } | |
314 | } | |
315 | ||
316 | return (CRYPTO_SUCCESS); | |
317 | } | |
318 | ||
319 | /* | |
320 | * KCF software provider digest entry points. | |
321 | */ | |
322 | ||
323 | /* | |
324 | * Initializes a skein digest context to the configuration in `mechanism'. | |
325 | * The mechanism cm_type must be one of SKEIN_*_MECH_INFO_TYPE. The cm_param | |
326 | * field may contain a skein_param_t structure indicating the length of the | |
327 | * digest the algorithm should produce. Otherwise the default output lengths | |
328 | * are applied (32 bytes for Skein-256, 64 bytes for Skein-512 and 128 bytes | |
329 | * for Skein-1024). | |
330 | */ | |
331 | static int | |
df7b54f1 | 332 | skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism) |
3c67d83a TH |
333 | { |
334 | int error = CRYPTO_SUCCESS; | |
335 | ||
336 | if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type)) | |
337 | return (CRYPTO_MECHANISM_INVALID); | |
338 | ||
df7b54f1 | 339 | SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)), KM_SLEEP); |
3c67d83a TH |
340 | if (SKEIN_CTX(ctx) == NULL) |
341 | return (CRYPTO_HOST_MEMORY); | |
342 | ||
343 | SKEIN_CTX(ctx)->sc_mech_type = mechanism->cm_type; | |
344 | error = skein_get_digest_bitlen(mechanism, | |
345 | &SKEIN_CTX(ctx)->sc_digest_bitlen); | |
346 | if (error != CRYPTO_SUCCESS) | |
347 | goto errout; | |
348 | SKEIN_OP(SKEIN_CTX(ctx), Init, SKEIN_CTX(ctx)->sc_digest_bitlen); | |
349 | ||
350 | return (CRYPTO_SUCCESS); | |
351 | errout: | |
861166b0 | 352 | memset(SKEIN_CTX(ctx), 0, sizeof (*SKEIN_CTX(ctx))); |
3c67d83a TH |
353 | kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); |
354 | SKEIN_CTX_LVALUE(ctx) = NULL; | |
355 | return (error); | |
356 | } | |
357 | ||
358 | /* | |
359 | * Executes a skein_update and skein_digest on a pre-initialized crypto | |
360 | * context in a single step. See the documentation to these functions to | |
361 | * see what to pass here. | |
362 | */ | |
363 | static int | |
df7b54f1 | 364 | skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest) |
3c67d83a TH |
365 | { |
366 | int error = CRYPTO_SUCCESS; | |
367 | ||
368 | ASSERT(SKEIN_CTX(ctx) != NULL); | |
369 | ||
370 | if (digest->cd_length < | |
371 | CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) { | |
372 | digest->cd_length = | |
373 | CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen); | |
374 | return (CRYPTO_BUFFER_TOO_SMALL); | |
375 | } | |
376 | ||
df7b54f1 | 377 | error = skein_update(ctx, data); |
3c67d83a | 378 | if (error != CRYPTO_SUCCESS) { |
861166b0 | 379 | memset(SKEIN_CTX(ctx), 0, sizeof (*SKEIN_CTX(ctx))); |
3c67d83a TH |
380 | kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); |
381 | SKEIN_CTX_LVALUE(ctx) = NULL; | |
382 | digest->cd_length = 0; | |
383 | return (error); | |
384 | } | |
df7b54f1 | 385 | error = skein_final(ctx, digest); |
3c67d83a TH |
386 | |
387 | return (error); | |
388 | } | |
389 | ||
390 | /* | |
391 | * Performs a skein Update with the input message in `data' (successive calls | |
392 | * can push more data). This is used both for digest and MAC operation. | |
393 | * Supported input data formats are raw, uio and mblk. | |
394 | */ | |
3c67d83a | 395 | static int |
df7b54f1 | 396 | skein_update(crypto_ctx_t *ctx, crypto_data_t *data) |
3c67d83a TH |
397 | { |
398 | int error = CRYPTO_SUCCESS; | |
399 | ||
400 | ASSERT(SKEIN_CTX(ctx) != NULL); | |
401 | ||
402 | switch (data->cd_format) { | |
403 | case CRYPTO_DATA_RAW: | |
404 | SKEIN_OP(SKEIN_CTX(ctx), Update, | |
405 | (uint8_t *)data->cd_raw.iov_base + data->cd_offset, | |
406 | data->cd_length); | |
407 | break; | |
408 | case CRYPTO_DATA_UIO: | |
409 | error = skein_digest_update_uio(SKEIN_CTX(ctx), data); | |
410 | break; | |
411 | default: | |
412 | error = CRYPTO_ARGUMENTS_BAD; | |
413 | } | |
414 | ||
415 | return (error); | |
416 | } | |
417 | ||
418 | /* | |
419 | * Performs a skein Final, writing the output to `digest'. This is used both | |
420 | * for digest and MAC operation. | |
421 | * Supported output digest formats are raw, uio and mblk. | |
422 | */ | |
3c67d83a | 423 | static int |
a2163a96 | 424 | skein_final_nofree(crypto_ctx_t *ctx, crypto_data_t *digest) |
3c67d83a TH |
425 | { |
426 | int error = CRYPTO_SUCCESS; | |
427 | ||
428 | ASSERT(SKEIN_CTX(ctx) != NULL); | |
429 | ||
430 | if (digest->cd_length < | |
431 | CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) { | |
432 | digest->cd_length = | |
433 | CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen); | |
434 | return (CRYPTO_BUFFER_TOO_SMALL); | |
435 | } | |
436 | ||
437 | switch (digest->cd_format) { | |
438 | case CRYPTO_DATA_RAW: | |
439 | SKEIN_OP(SKEIN_CTX(ctx), Final, | |
440 | (uint8_t *)digest->cd_raw.iov_base + digest->cd_offset); | |
441 | break; | |
442 | case CRYPTO_DATA_UIO: | |
df7b54f1 | 443 | error = skein_digest_final_uio(SKEIN_CTX(ctx), digest); |
3c67d83a TH |
444 | break; |
445 | default: | |
446 | error = CRYPTO_ARGUMENTS_BAD; | |
447 | } | |
448 | ||
449 | if (error == CRYPTO_SUCCESS) | |
450 | digest->cd_length = | |
451 | CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen); | |
452 | else | |
453 | digest->cd_length = 0; | |
454 | ||
a2163a96 RY |
455 | return (error); |
456 | } | |
457 | ||
458 | static int | |
459 | skein_final(crypto_ctx_t *ctx, crypto_data_t *digest) | |
460 | { | |
461 | int error = skein_final_nofree(ctx, digest); | |
462 | ||
463 | if (error == CRYPTO_BUFFER_TOO_SMALL) | |
464 | return (error); | |
465 | ||
861166b0 | 466 | memset(SKEIN_CTX(ctx), 0, sizeof (*SKEIN_CTX(ctx))); |
3c67d83a TH |
467 | kmem_free(SKEIN_CTX(ctx), sizeof (*(SKEIN_CTX(ctx)))); |
468 | SKEIN_CTX_LVALUE(ctx) = NULL; | |
469 | ||
470 | return (error); | |
471 | } | |
472 | ||
473 | /* | |
474 | * Performs a full skein digest computation in a single call, configuring the | |
475 | * algorithm according to `mechanism', reading the input to be digested from | |
476 | * `data' and writing the output to `digest'. | |
477 | * Supported input/output formats are raw, uio and mblk. | |
478 | */ | |
3c67d83a | 479 | static int |
de0ec5e7 AZ |
480 | skein_digest_atomic(crypto_mechanism_t *mechanism, crypto_data_t *data, |
481 | crypto_data_t *digest) | |
3c67d83a | 482 | { |
18e4f679 AZ |
483 | int error; |
484 | skein_ctx_t skein_ctx; | |
485 | crypto_ctx_t ctx; | |
3c67d83a TH |
486 | SKEIN_CTX_LVALUE(&ctx) = &skein_ctx; |
487 | ||
488 | /* Init */ | |
489 | if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type)) | |
490 | return (CRYPTO_MECHANISM_INVALID); | |
491 | skein_ctx.sc_mech_type = mechanism->cm_type; | |
492 | error = skein_get_digest_bitlen(mechanism, &skein_ctx.sc_digest_bitlen); | |
493 | if (error != CRYPTO_SUCCESS) | |
494 | goto out; | |
495 | SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen); | |
496 | ||
df7b54f1 | 497 | if ((error = skein_update(&ctx, data)) != CRYPTO_SUCCESS) |
3c67d83a | 498 | goto out; |
a2163a96 | 499 | if ((error = skein_final_nofree(&ctx, data)) != CRYPTO_SUCCESS) |
3c67d83a TH |
500 | goto out; |
501 | ||
502 | out: | |
503 | if (error == CRYPTO_SUCCESS) | |
504 | digest->cd_length = | |
505 | CRYPTO_BITS2BYTES(skein_ctx.sc_digest_bitlen); | |
506 | else | |
507 | digest->cd_length = 0; | |
861166b0 | 508 | memset(&skein_ctx, 0, sizeof (skein_ctx)); |
3c67d83a TH |
509 | |
510 | return (error); | |
511 | } | |
512 | ||
513 | /* | |
514 | * Helper function that builds a Skein MAC context from the provided | |
515 | * mechanism and key. | |
516 | */ | |
517 | static int | |
518 | skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism, | |
519 | crypto_key_t *key) | |
520 | { | |
521 | int error; | |
522 | ||
523 | if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type)) | |
524 | return (CRYPTO_MECHANISM_INVALID); | |
3c67d83a TH |
525 | ctx->sc_mech_type = mechanism->cm_type; |
526 | error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen); | |
527 | if (error != CRYPTO_SUCCESS) | |
528 | return (error); | |
529 | SKEIN_OP(ctx, InitExt, ctx->sc_digest_bitlen, 0, key->ck_data, | |
530 | CRYPTO_BITS2BYTES(key->ck_length)); | |
531 | ||
532 | return (CRYPTO_SUCCESS); | |
533 | } | |
534 | ||
535 | /* | |
536 | * KCF software provide mac entry points. | |
537 | */ | |
538 | /* | |
539 | * Initializes a skein MAC context. You may pass a ctx_template, in which | |
540 | * case the template will be reused to make initialization more efficient. | |
541 | * Otherwise a new context will be constructed. The mechanism cm_type must | |
542 | * be one of SKEIN_*_MAC_MECH_INFO_TYPE. Same as in skein_digest_init, you | |
543 | * may pass a skein_param_t in cm_param to configure the length of the | |
544 | * digest. The key must be in raw format. | |
545 | */ | |
546 | static int | |
547 | skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism, | |
df7b54f1 | 548 | crypto_key_t *key, crypto_spi_ctx_template_t ctx_template) |
3c67d83a TH |
549 | { |
550 | int error; | |
551 | ||
df7b54f1 | 552 | SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)), KM_SLEEP); |
3c67d83a TH |
553 | if (SKEIN_CTX(ctx) == NULL) |
554 | return (CRYPTO_HOST_MEMORY); | |
555 | ||
556 | if (ctx_template != NULL) { | |
861166b0 | 557 | memcpy(SKEIN_CTX(ctx), ctx_template, |
3c67d83a TH |
558 | sizeof (*SKEIN_CTX(ctx))); |
559 | } else { | |
560 | error = skein_mac_ctx_build(SKEIN_CTX(ctx), mechanism, key); | |
561 | if (error != CRYPTO_SUCCESS) | |
562 | goto errout; | |
563 | } | |
564 | ||
565 | return (CRYPTO_SUCCESS); | |
566 | errout: | |
861166b0 | 567 | memset(SKEIN_CTX(ctx), 0, sizeof (*SKEIN_CTX(ctx))); |
3c67d83a TH |
568 | kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); |
569 | return (error); | |
570 | } | |
571 | ||
572 | /* | |
573 | * The MAC update and final calls are reused from the regular digest code. | |
574 | */ | |
575 | ||
3c67d83a TH |
576 | /* |
577 | * Same as skein_digest_atomic, performs an atomic Skein MAC operation in | |
578 | * one step. All the same properties apply to the arguments of this | |
579 | * function as to those of the partial operations above. | |
580 | */ | |
581 | static int | |
de0ec5e7 | 582 | skein_mac_atomic(crypto_mechanism_t *mechanism, |
3c67d83a | 583 | crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac, |
df7b54f1 | 584 | crypto_spi_ctx_template_t ctx_template) |
3c67d83a TH |
585 | { |
586 | /* faux crypto context just for skein_digest_{update,final} */ | |
861166b0 | 587 | int error; |
18e4f679 AZ |
588 | crypto_ctx_t ctx; |
589 | skein_ctx_t skein_ctx; | |
3c67d83a TH |
590 | SKEIN_CTX_LVALUE(&ctx) = &skein_ctx; |
591 | ||
592 | if (ctx_template != NULL) { | |
861166b0 | 593 | memcpy(&skein_ctx, ctx_template, sizeof (skein_ctx)); |
3c67d83a TH |
594 | } else { |
595 | error = skein_mac_ctx_build(&skein_ctx, mechanism, key); | |
596 | if (error != CRYPTO_SUCCESS) | |
597 | goto errout; | |
598 | } | |
599 | ||
df7b54f1 | 600 | if ((error = skein_update(&ctx, data)) != CRYPTO_SUCCESS) |
3c67d83a | 601 | goto errout; |
a2163a96 | 602 | if ((error = skein_final_nofree(&ctx, mac)) != CRYPTO_SUCCESS) |
3c67d83a TH |
603 | goto errout; |
604 | ||
605 | return (CRYPTO_SUCCESS); | |
606 | errout: | |
861166b0 | 607 | memset(&skein_ctx, 0, sizeof (skein_ctx)); |
3c67d83a TH |
608 | return (error); |
609 | } | |
610 | ||
611 | /* | |
612 | * KCF software provider context management entry points. | |
613 | */ | |
614 | ||
615 | /* | |
616 | * Constructs a context template for the Skein MAC algorithm. The same | |
617 | * properties apply to the arguments of this function as to those of | |
618 | * skein_mac_init. | |
619 | */ | |
3c67d83a | 620 | static int |
11320b4c | 621 | skein_create_ctx_template(crypto_mechanism_t *mechanism, crypto_key_t *key, |
df7b54f1 | 622 | crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size) |
3c67d83a | 623 | { |
18e4f679 AZ |
624 | int error; |
625 | skein_ctx_t *ctx_tmpl; | |
3c67d83a | 626 | |
df7b54f1 | 627 | ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), KM_SLEEP); |
3c67d83a TH |
628 | if (ctx_tmpl == NULL) |
629 | return (CRYPTO_HOST_MEMORY); | |
630 | error = skein_mac_ctx_build(ctx_tmpl, mechanism, key); | |
631 | if (error != CRYPTO_SUCCESS) | |
632 | goto errout; | |
633 | *ctx_template = ctx_tmpl; | |
634 | *ctx_template_size = sizeof (*ctx_tmpl); | |
635 | ||
636 | return (CRYPTO_SUCCESS); | |
637 | errout: | |
861166b0 | 638 | memset(ctx_tmpl, 0, sizeof (*ctx_tmpl)); |
3c67d83a TH |
639 | kmem_free(ctx_tmpl, sizeof (*ctx_tmpl)); |
640 | return (error); | |
641 | } | |
642 | ||
643 | /* | |
644 | * Frees a skein context in a parent crypto context. | |
645 | */ | |
646 | static int | |
647 | skein_free_context(crypto_ctx_t *ctx) | |
648 | { | |
649 | if (SKEIN_CTX(ctx) != NULL) { | |
861166b0 | 650 | memset(SKEIN_CTX(ctx), 0, sizeof (*SKEIN_CTX(ctx))); |
3c67d83a TH |
651 | kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx))); |
652 | SKEIN_CTX_LVALUE(ctx) = NULL; | |
653 | } | |
654 | ||
655 | return (CRYPTO_SUCCESS); | |
656 | } |