mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-23 02:44:41 +03:00
OpenZFS 4185 - add new cryptographic checksums to ZFS: SHA-512, Skein, Edon-R
Reviewed by: George Wilson <george.wilson@delphix.com> Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com> Reviewed by: Richard Lowe <richlowe@richlowe.net> Approved by: Garrett D'Amore <garrett@damore.org> Ported by: Tony Hutter <hutter2@llnl.gov> OpenZFS-issue: https://www.illumos.org/issues/4185 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/45818ee Porting Notes: This code is ported on top of the Illumos Crypto Framework code: https://github.com/zfsonlinux/zfs/pull/4329/commits/b5e030c8dbb9cd393d313571dee4756fbba8c22d The list of porting changes includes: - Copied module/icp/include/sha2/sha2.h directly from illumos - Removed from module/icp/algs/sha2/sha2.c: #pragma inline(SHA256Init, SHA384Init, SHA512Init) - Added 'ctx' to lib/libzfs/libzfs_sendrecv.c:zio_checksum_SHA256() since it now takes in an extra parameter. - Added CTASSERT() to assert.h from for module/zfs/edonr_zfs.c - Added skein & edonr to libicp/Makefile.am - Added sha512.S. It was generated from sha512-x86_64.pl in Illumos. - Updated ztest.c with new fletcher_4_*() args; used NULL for new CTX argument. - In icp/algs/edonr/edonr_byteorder.h, Removed the #if defined(__linux) section to not #include the non-existant endian.h. - In skein_test.c, renane NULL to 0 in "no test vector" array entries to get around a compiler warning. - Fixup test files: - Rename <sys/varargs.h> -> <varargs.h>, <strings.h> -> <string.h>, - Remove <note.h> and define NOTE() as NOP. - Define u_longlong_t - Rename "#!/usr/bin/ksh" -> "#!/bin/ksh -p" - Rename NULL to 0 in "no test vector" array entries to get around a compiler warning. - Remove "for isa in $($ISAINFO); do" stuff - Add/update Makefiles - Add some userspace headers like stdio.h/stdlib.h in places of sys/types.h. - EXPORT_SYMBOL *_Init/*_Update/*_Final... routines in ICP modules. - Update scripts/zfs2zol-patch.sed - include <sys/sha2.h> in sha2_impl.h - Add sha2.h to include/sys/Makefile.am - Add skein and edonr dirs to icp Makefile - Add new checksums to zpool_get.cfg - Move checksum switch block from zfs_secpolicy_setprop() to zfs_check_settable() - Fix -Wuninitialized error in edonr_byteorder.h on PPC - Fix stack frame size errors on ARM32 - Don't unroll loops in Skein on 32-bit to save stack space - Add memory barriers in sha2.c on 32-bit to save stack space - Add filetest_001_pos.ksh checksum sanity test - Add option to write psudorandom data in file_write utility
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://opensource.org/licenses/CDDL-1.0.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/modctl.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/edonr.h>
|
||||
|
||||
/*
|
||||
* Unlike sha2 or skein, we won't expose edonr via the Kernel Cryptographic
|
||||
* Framework (KCF), because Edon-R is *NOT* suitable for general-purpose
|
||||
* cryptographic use. Users of Edon-R must interface directly to this module.
|
||||
*/
|
||||
|
||||
static struct modlmisc modlmisc = {
|
||||
&mod_cryptoops,
|
||||
"Edon-R Message-Digest Algorithm"
|
||||
};
|
||||
|
||||
static struct modlinkage modlinkage = {
|
||||
MODREV_1, {&modlmisc, NULL}
|
||||
};
|
||||
|
||||
int
|
||||
edonr_mod_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = mod_install(&modlinkage)) != 0)
|
||||
return (error);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
edonr_mod_fini(void) {
|
||||
return (mod_remove(&modlinkage));
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <sys/crypto/spi.h>
|
||||
#include <sys/crypto/icp.h>
|
||||
#define _SHA2_IMPL
|
||||
#include <sha2/sha2.h>
|
||||
#include <sys/sha2.h>
|
||||
#include <sha2/sha2_impl.h>
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* CDDL HEADER START
|
||||
*
|
||||
* The contents of this file are subject to the terms of the
|
||||
* Common Development and Distribution License (the "License").
|
||||
* You may not use this file except in compliance with the License.
|
||||
*
|
||||
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
||||
* or http://opensource.org/licenses/CDDL-1.0.
|
||||
* See the License for the specific language governing permissions
|
||||
* and limitations under the License.
|
||||
*
|
||||
* When distributing Covered Code, include this CDDL HEADER in each
|
||||
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||
* If applicable, add the following below this CDDL HEADER, with the
|
||||
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||
*
|
||||
* CDDL HEADER END
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/modctl.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/systm.h>
|
||||
#define SKEIN_MODULE_IMPL
|
||||
#include <sys/skein.h>
|
||||
|
||||
/*
|
||||
* Like the sha2 module, we create the skein module with two modlinkages:
|
||||
* - modlmisc to allow direct calls to Skein_* API functions.
|
||||
* - modlcrypto to integrate well into the Kernel Crypto Framework (KCF).
|
||||
*/
|
||||
static struct modlmisc modlmisc = {
|
||||
&mod_cryptoops,
|
||||
"Skein Message-Digest Algorithm"
|
||||
};
|
||||
|
||||
static struct modlcrypto modlcrypto = {
|
||||
&mod_cryptoops,
|
||||
"Skein Kernel SW Provider"
|
||||
};
|
||||
|
||||
static struct modlinkage modlinkage = {
|
||||
MODREV_1, {&modlmisc, &modlcrypto, NULL}
|
||||
};
|
||||
|
||||
static crypto_mech_info_t skein_mech_info_tab[] = {
|
||||
{CKM_SKEIN_256, SKEIN_256_MECH_INFO_TYPE,
|
||||
CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
|
||||
0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
|
||||
{CKM_SKEIN_256_MAC, SKEIN_256_MAC_MECH_INFO_TYPE,
|
||||
CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
|
||||
CRYPTO_KEYSIZE_UNIT_IN_BYTES},
|
||||
{CKM_SKEIN_512, SKEIN_512_MECH_INFO_TYPE,
|
||||
CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
|
||||
0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
|
||||
{CKM_SKEIN_512_MAC, SKEIN_512_MAC_MECH_INFO_TYPE,
|
||||
CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
|
||||
CRYPTO_KEYSIZE_UNIT_IN_BYTES},
|
||||
{CKM_SKEIN1024, SKEIN1024_MECH_INFO_TYPE,
|
||||
CRYPTO_FG_DIGEST | CRYPTO_FG_DIGEST_ATOMIC,
|
||||
0, 0, CRYPTO_KEYSIZE_UNIT_IN_BITS},
|
||||
{CKM_SKEIN1024_MAC, SKEIN1024_MAC_MECH_INFO_TYPE,
|
||||
CRYPTO_FG_MAC | CRYPTO_FG_MAC_ATOMIC, 1, INT_MAX,
|
||||
CRYPTO_KEYSIZE_UNIT_IN_BYTES}
|
||||
};
|
||||
|
||||
static void skein_provider_status(crypto_provider_handle_t, uint_t *);
|
||||
|
||||
static crypto_control_ops_t skein_control_ops = {
|
||||
skein_provider_status
|
||||
};
|
||||
|
||||
static int skein_digest_init(crypto_ctx_t *, crypto_mechanism_t *,
|
||||
crypto_req_handle_t);
|
||||
static int skein_digest(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
static int skein_update(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
static int skein_final(crypto_ctx_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
static int skein_digest_atomic(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
|
||||
static crypto_digest_ops_t skein_digest_ops = {
|
||||
skein_digest_init,
|
||||
skein_digest,
|
||||
skein_update,
|
||||
NULL,
|
||||
skein_final,
|
||||
skein_digest_atomic
|
||||
};
|
||||
|
||||
static int skein_mac_init(crypto_ctx_t *, crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
static int skein_mac_atomic(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *, crypto_data_t *,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
|
||||
static crypto_mac_ops_t skein_mac_ops = {
|
||||
skein_mac_init,
|
||||
NULL,
|
||||
skein_update, /* using regular digest update is OK here */
|
||||
skein_final, /* using regular digest final is OK here */
|
||||
skein_mac_atomic,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int skein_create_ctx_template(crypto_provider_handle_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t *,
|
||||
size_t *, crypto_req_handle_t);
|
||||
static int skein_free_context(crypto_ctx_t *);
|
||||
|
||||
static crypto_ctx_ops_t skein_ctx_ops = {
|
||||
skein_create_ctx_template,
|
||||
skein_free_context
|
||||
};
|
||||
|
||||
static crypto_ops_t skein_crypto_ops = {{{{{
|
||||
&skein_control_ops,
|
||||
&skein_digest_ops,
|
||||
NULL,
|
||||
&skein_mac_ops,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&skein_ctx_ops,
|
||||
}}}}};
|
||||
|
||||
static crypto_provider_info_t skein_prov_info = {{{{
|
||||
CRYPTO_SPI_VERSION_1,
|
||||
"Skein Software Provider",
|
||||
CRYPTO_SW_PROVIDER,
|
||||
NULL,
|
||||
&skein_crypto_ops,
|
||||
sizeof (skein_mech_info_tab) / sizeof (crypto_mech_info_t),
|
||||
skein_mech_info_tab
|
||||
}}}};
|
||||
|
||||
static crypto_kcf_provider_handle_t skein_prov_handle = 0;
|
||||
|
||||
typedef struct skein_ctx {
|
||||
skein_mech_type_t sc_mech_type;
|
||||
size_t sc_digest_bitlen;
|
||||
/*LINTED(E_ANONYMOUS_UNION_DECL)*/
|
||||
union {
|
||||
Skein_256_Ctxt_t sc_256;
|
||||
Skein_512_Ctxt_t sc_512;
|
||||
Skein1024_Ctxt_t sc_1024;
|
||||
};
|
||||
} skein_ctx_t;
|
||||
#define SKEIN_CTX(_ctx_) ((skein_ctx_t *)((_ctx_)->cc_provider_private))
|
||||
#define SKEIN_CTX_LVALUE(_ctx_) (_ctx_)->cc_provider_private
|
||||
#define SKEIN_OP(_skein_ctx, _op, ...) \
|
||||
do { \
|
||||
skein_ctx_t *sc = (_skein_ctx); \
|
||||
switch (sc->sc_mech_type) { \
|
||||
case SKEIN_256_MECH_INFO_TYPE: \
|
||||
case SKEIN_256_MAC_MECH_INFO_TYPE: \
|
||||
(void) Skein_256_ ## _op(&sc->sc_256, __VA_ARGS__);\
|
||||
break; \
|
||||
case SKEIN_512_MECH_INFO_TYPE: \
|
||||
case SKEIN_512_MAC_MECH_INFO_TYPE: \
|
||||
(void) Skein_512_ ## _op(&sc->sc_512, __VA_ARGS__);\
|
||||
break; \
|
||||
case SKEIN1024_MECH_INFO_TYPE: \
|
||||
case SKEIN1024_MAC_MECH_INFO_TYPE: \
|
||||
(void) Skein1024_ ## _op(&sc->sc_1024, __VA_ARGS__);\
|
||||
break; \
|
||||
} \
|
||||
_NOTE(CONSTCOND) \
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
skein_get_digest_bitlen(const crypto_mechanism_t *mechanism, size_t *result)
|
||||
{
|
||||
if (mechanism->cm_param != NULL) {
|
||||
/*LINTED(E_BAD_PTR_CAST_ALIGN)*/
|
||||
skein_param_t *param = (skein_param_t *)mechanism->cm_param;
|
||||
|
||||
if (mechanism->cm_param_len != sizeof (*param) ||
|
||||
param->sp_digest_bitlen == 0) {
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
}
|
||||
*result = param->sp_digest_bitlen;
|
||||
} else {
|
||||
switch (mechanism->cm_type) {
|
||||
case SKEIN_256_MECH_INFO_TYPE:
|
||||
*result = 256;
|
||||
break;
|
||||
case SKEIN_512_MECH_INFO_TYPE:
|
||||
*result = 512;
|
||||
break;
|
||||
case SKEIN1024_MECH_INFO_TYPE:
|
||||
*result = 1024;
|
||||
break;
|
||||
default:
|
||||
return (CRYPTO_MECHANISM_INVALID);
|
||||
}
|
||||
}
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
skein_mod_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = mod_install(&modlinkage)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Try to register with KCF - failure shouldn't unload us, since we
|
||||
* still may want to continue providing misc/skein functionality.
|
||||
*/
|
||||
(void) crypto_register_provider(&skein_prov_info, &skein_prov_handle);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
skein_mod_fini(void) {
|
||||
return (mod_remove(&modlinkage));
|
||||
}
|
||||
|
||||
/*
|
||||
* KCF software provider control entry points.
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
skein_provider_status(crypto_provider_handle_t provider, uint_t *status)
|
||||
{
|
||||
*status = CRYPTO_PROVIDER_READY;
|
||||
}
|
||||
|
||||
/*
|
||||
* General Skein hashing helper functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Performs an Update on a context with uio input data.
|
||||
*/
|
||||
static int
|
||||
skein_digest_update_uio(skein_ctx_t *ctx, const crypto_data_t *data)
|
||||
{
|
||||
off_t offset = data->cd_offset;
|
||||
size_t length = data->cd_length;
|
||||
uint_t vec_idx;
|
||||
size_t cur_len;
|
||||
const uio_t *uio = data->cd_uio;
|
||||
|
||||
/* we support only kernel buffer */
|
||||
if (uio->uio_segflg != UIO_SYSSPACE)
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
|
||||
/*
|
||||
* Jump to the first iovec containing data to be
|
||||
* digested.
|
||||
*/
|
||||
for (vec_idx = 0; vec_idx < uio->uio_iovcnt &&
|
||||
offset >= uio->uio_iov[vec_idx].iov_len;
|
||||
offset -= uio->uio_iov[vec_idx++].iov_len)
|
||||
;
|
||||
if (vec_idx == uio->uio_iovcnt) {
|
||||
/*
|
||||
* The caller specified an offset that is larger than the
|
||||
* total size of the buffers it provided.
|
||||
*/
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now do the digesting on the iovecs.
|
||||
*/
|
||||
while (vec_idx < uio->uio_iovcnt && length > 0) {
|
||||
cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset, length);
|
||||
SKEIN_OP(ctx, Update, (uint8_t *)uio->uio_iov[vec_idx].iov_base
|
||||
+ offset, cur_len);
|
||||
length -= cur_len;
|
||||
vec_idx++;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (vec_idx == uio->uio_iovcnt && length > 0) {
|
||||
/*
|
||||
* The end of the specified iovec's was reached but
|
||||
* the length requested could not be processed, i.e.
|
||||
* The caller requested to digest more data than it provided.
|
||||
*/
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a Final on a context and writes to a uio digest output.
|
||||
*/
|
||||
static int
|
||||
skein_digest_final_uio(skein_ctx_t *ctx, crypto_data_t *digest,
|
||||
crypto_req_handle_t req)
|
||||
{
|
||||
off_t offset = digest->cd_offset;
|
||||
uint_t vec_idx;
|
||||
uio_t *uio = digest->cd_uio;
|
||||
|
||||
/* we support only kernel buffer */
|
||||
if (uio->uio_segflg != UIO_SYSSPACE)
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
|
||||
/*
|
||||
* Jump to the first iovec containing ptr to the digest to be returned.
|
||||
*/
|
||||
for (vec_idx = 0; offset >= uio->uio_iov[vec_idx].iov_len &&
|
||||
vec_idx < uio->uio_iovcnt;
|
||||
offset -= uio->uio_iov[vec_idx++].iov_len)
|
||||
;
|
||||
if (vec_idx == uio->uio_iovcnt) {
|
||||
/*
|
||||
* The caller specified an offset that is larger than the
|
||||
* total size of the buffers it provided.
|
||||
*/
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
if (offset + CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen) <=
|
||||
uio->uio_iov[vec_idx].iov_len) {
|
||||
/* The computed digest will fit in the current iovec. */
|
||||
SKEIN_OP(ctx, Final,
|
||||
(uchar_t *)uio->uio_iov[vec_idx].iov_base + offset);
|
||||
} else {
|
||||
uint8_t *digest_tmp;
|
||||
off_t scratch_offset = 0;
|
||||
size_t length = CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen);
|
||||
size_t cur_len;
|
||||
|
||||
digest_tmp = kmem_alloc(CRYPTO_BITS2BYTES(
|
||||
ctx->sc_digest_bitlen), crypto_kmflag(req));
|
||||
if (digest_tmp == NULL)
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
SKEIN_OP(ctx, Final, digest_tmp);
|
||||
while (vec_idx < uio->uio_iovcnt && length > 0) {
|
||||
cur_len = MIN(uio->uio_iov[vec_idx].iov_len - offset,
|
||||
length);
|
||||
bcopy(digest_tmp + scratch_offset,
|
||||
uio->uio_iov[vec_idx].iov_base + offset, cur_len);
|
||||
|
||||
length -= cur_len;
|
||||
vec_idx++;
|
||||
scratch_offset += cur_len;
|
||||
offset = 0;
|
||||
}
|
||||
kmem_free(digest_tmp, CRYPTO_BITS2BYTES(ctx->sc_digest_bitlen));
|
||||
|
||||
if (vec_idx == uio->uio_iovcnt && length > 0) {
|
||||
/*
|
||||
* The end of the specified iovec's was reached but
|
||||
* the length requested could not be processed, i.e.
|
||||
* The caller requested to digest more data than it
|
||||
* provided.
|
||||
*/
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* KCF software provider digest entry points.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Initializes a skein digest context to the configuration in `mechanism'.
|
||||
* The mechanism cm_type must be one of SKEIN_*_MECH_INFO_TYPE. The cm_param
|
||||
* field may contain a skein_param_t structure indicating the length of the
|
||||
* digest the algorithm should produce. Otherwise the default output lengths
|
||||
* are applied (32 bytes for Skein-256, 64 bytes for Skein-512 and 128 bytes
|
||||
* for Skein-1024).
|
||||
*/
|
||||
static int
|
||||
skein_digest_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
|
||||
crypto_req_handle_t req)
|
||||
{
|
||||
int error = CRYPTO_SUCCESS;
|
||||
|
||||
if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
|
||||
return (CRYPTO_MECHANISM_INVALID);
|
||||
|
||||
SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
|
||||
crypto_kmflag(req));
|
||||
if (SKEIN_CTX(ctx) == NULL)
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
|
||||
SKEIN_CTX(ctx)->sc_mech_type = mechanism->cm_type;
|
||||
error = skein_get_digest_bitlen(mechanism,
|
||||
&SKEIN_CTX(ctx)->sc_digest_bitlen);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
goto errout;
|
||||
SKEIN_OP(SKEIN_CTX(ctx), Init, SKEIN_CTX(ctx)->sc_digest_bitlen);
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
errout:
|
||||
bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
SKEIN_CTX_LVALUE(ctx) = NULL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Executes a skein_update and skein_digest on a pre-initialized crypto
|
||||
* context in a single step. See the documentation to these functions to
|
||||
* see what to pass here.
|
||||
*/
|
||||
static int
|
||||
skein_digest(crypto_ctx_t *ctx, crypto_data_t *data, crypto_data_t *digest,
|
||||
crypto_req_handle_t req)
|
||||
{
|
||||
int error = CRYPTO_SUCCESS;
|
||||
|
||||
ASSERT(SKEIN_CTX(ctx) != NULL);
|
||||
|
||||
if (digest->cd_length <
|
||||
CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
|
||||
digest->cd_length =
|
||||
CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
|
||||
return (CRYPTO_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
error = skein_update(ctx, data, req);
|
||||
if (error != CRYPTO_SUCCESS) {
|
||||
bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
SKEIN_CTX_LVALUE(ctx) = NULL;
|
||||
digest->cd_length = 0;
|
||||
return (error);
|
||||
}
|
||||
error = skein_final(ctx, digest, req);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a skein Update with the input message in `data' (successive calls
|
||||
* can push more data). This is used both for digest and MAC operation.
|
||||
* Supported input data formats are raw, uio and mblk.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
skein_update(crypto_ctx_t *ctx, crypto_data_t *data, crypto_req_handle_t req)
|
||||
{
|
||||
int error = CRYPTO_SUCCESS;
|
||||
|
||||
ASSERT(SKEIN_CTX(ctx) != NULL);
|
||||
|
||||
switch (data->cd_format) {
|
||||
case CRYPTO_DATA_RAW:
|
||||
SKEIN_OP(SKEIN_CTX(ctx), Update,
|
||||
(uint8_t *)data->cd_raw.iov_base + data->cd_offset,
|
||||
data->cd_length);
|
||||
break;
|
||||
case CRYPTO_DATA_UIO:
|
||||
error = skein_digest_update_uio(SKEIN_CTX(ctx), data);
|
||||
break;
|
||||
default:
|
||||
error = CRYPTO_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a skein Final, writing the output to `digest'. This is used both
|
||||
* for digest and MAC operation.
|
||||
* Supported output digest formats are raw, uio and mblk.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
skein_final(crypto_ctx_t *ctx, crypto_data_t *digest, crypto_req_handle_t req)
|
||||
{
|
||||
int error = CRYPTO_SUCCESS;
|
||||
|
||||
ASSERT(SKEIN_CTX(ctx) != NULL);
|
||||
|
||||
if (digest->cd_length <
|
||||
CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen)) {
|
||||
digest->cd_length =
|
||||
CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
|
||||
return (CRYPTO_BUFFER_TOO_SMALL);
|
||||
}
|
||||
|
||||
switch (digest->cd_format) {
|
||||
case CRYPTO_DATA_RAW:
|
||||
SKEIN_OP(SKEIN_CTX(ctx), Final,
|
||||
(uint8_t *)digest->cd_raw.iov_base + digest->cd_offset);
|
||||
break;
|
||||
case CRYPTO_DATA_UIO:
|
||||
error = skein_digest_final_uio(SKEIN_CTX(ctx), digest, req);
|
||||
break;
|
||||
default:
|
||||
error = CRYPTO_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
if (error == CRYPTO_SUCCESS)
|
||||
digest->cd_length =
|
||||
CRYPTO_BITS2BYTES(SKEIN_CTX(ctx)->sc_digest_bitlen);
|
||||
else
|
||||
digest->cd_length = 0;
|
||||
|
||||
bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
kmem_free(SKEIN_CTX(ctx), sizeof (*(SKEIN_CTX(ctx))));
|
||||
SKEIN_CTX_LVALUE(ctx) = NULL;
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a full skein digest computation in a single call, configuring the
|
||||
* algorithm according to `mechanism', reading the input to be digested from
|
||||
* `data' and writing the output to `digest'.
|
||||
* Supported input/output formats are raw, uio and mblk.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
skein_digest_atomic(crypto_provider_handle_t provider,
|
||||
crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
|
||||
crypto_data_t *data, crypto_data_t *digest, crypto_req_handle_t req)
|
||||
{
|
||||
int error;
|
||||
skein_ctx_t skein_ctx;
|
||||
crypto_ctx_t ctx;
|
||||
SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
|
||||
|
||||
/* Init */
|
||||
if (!VALID_SKEIN_DIGEST_MECH(mechanism->cm_type))
|
||||
return (CRYPTO_MECHANISM_INVALID);
|
||||
skein_ctx.sc_mech_type = mechanism->cm_type;
|
||||
error = skein_get_digest_bitlen(mechanism, &skein_ctx.sc_digest_bitlen);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
goto out;
|
||||
SKEIN_OP(&skein_ctx, Init, skein_ctx.sc_digest_bitlen);
|
||||
|
||||
if ((error = skein_update(&ctx, data, digest)) != CRYPTO_SUCCESS)
|
||||
goto out;
|
||||
if ((error = skein_final(&ctx, data, digest)) != CRYPTO_SUCCESS)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (error == CRYPTO_SUCCESS)
|
||||
digest->cd_length =
|
||||
CRYPTO_BITS2BYTES(skein_ctx.sc_digest_bitlen);
|
||||
else
|
||||
digest->cd_length = 0;
|
||||
bzero(&skein_ctx, sizeof (skein_ctx));
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function that builds a Skein MAC context from the provided
|
||||
* mechanism and key.
|
||||
*/
|
||||
static int
|
||||
skein_mac_ctx_build(skein_ctx_t *ctx, crypto_mechanism_t *mechanism,
|
||||
crypto_key_t *key)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!VALID_SKEIN_MAC_MECH(mechanism->cm_type))
|
||||
return (CRYPTO_MECHANISM_INVALID);
|
||||
if (key->ck_format != CRYPTO_KEY_RAW)
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
ctx->sc_mech_type = mechanism->cm_type;
|
||||
error = skein_get_digest_bitlen(mechanism, &ctx->sc_digest_bitlen);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
return (error);
|
||||
SKEIN_OP(ctx, InitExt, ctx->sc_digest_bitlen, 0, key->ck_data,
|
||||
CRYPTO_BITS2BYTES(key->ck_length));
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* KCF software provide mac entry points.
|
||||
*/
|
||||
/*
|
||||
* Initializes a skein MAC context. You may pass a ctx_template, in which
|
||||
* case the template will be reused to make initialization more efficient.
|
||||
* Otherwise a new context will be constructed. The mechanism cm_type must
|
||||
* be one of SKEIN_*_MAC_MECH_INFO_TYPE. Same as in skein_digest_init, you
|
||||
* may pass a skein_param_t in cm_param to configure the length of the
|
||||
* digest. The key must be in raw format.
|
||||
*/
|
||||
static int
|
||||
skein_mac_init(crypto_ctx_t *ctx, crypto_mechanism_t *mechanism,
|
||||
crypto_key_t *key, crypto_spi_ctx_template_t ctx_template,
|
||||
crypto_req_handle_t req)
|
||||
{
|
||||
int error;
|
||||
|
||||
SKEIN_CTX_LVALUE(ctx) = kmem_alloc(sizeof (*SKEIN_CTX(ctx)),
|
||||
crypto_kmflag(req));
|
||||
if (SKEIN_CTX(ctx) == NULL)
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
|
||||
if (ctx_template != NULL) {
|
||||
bcopy(ctx_template, SKEIN_CTX(ctx),
|
||||
sizeof (*SKEIN_CTX(ctx)));
|
||||
} else {
|
||||
error = skein_mac_ctx_build(SKEIN_CTX(ctx), mechanism, key);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
errout:
|
||||
bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* The MAC update and final calls are reused from the regular digest code.
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
/*
|
||||
* Same as skein_digest_atomic, performs an atomic Skein MAC operation in
|
||||
* one step. All the same properties apply to the arguments of this
|
||||
* function as to those of the partial operations above.
|
||||
*/
|
||||
static int
|
||||
skein_mac_atomic(crypto_provider_handle_t provider,
|
||||
crypto_session_id_t session_id, crypto_mechanism_t *mechanism,
|
||||
crypto_key_t *key, crypto_data_t *data, crypto_data_t *mac,
|
||||
crypto_spi_ctx_template_t ctx_template, crypto_req_handle_t req)
|
||||
{
|
||||
/* faux crypto context just for skein_digest_{update,final} */
|
||||
int error;
|
||||
crypto_ctx_t ctx;
|
||||
skein_ctx_t skein_ctx;
|
||||
SKEIN_CTX_LVALUE(&ctx) = &skein_ctx;
|
||||
|
||||
if (ctx_template != NULL) {
|
||||
bcopy(ctx_template, &skein_ctx, sizeof (skein_ctx));
|
||||
} else {
|
||||
error = skein_mac_ctx_build(&skein_ctx, mechanism, key);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if ((error = skein_update(&ctx, data, req)) != CRYPTO_SUCCESS)
|
||||
goto errout;
|
||||
if ((error = skein_final(&ctx, mac, req)) != CRYPTO_SUCCESS)
|
||||
goto errout;
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
errout:
|
||||
bzero(&skein_ctx, sizeof (skein_ctx));
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* KCF software provider context management entry points.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Constructs a context template for the Skein MAC algorithm. The same
|
||||
* properties apply to the arguments of this function as to those of
|
||||
* skein_mac_init.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static int
|
||||
skein_create_ctx_template(crypto_provider_handle_t provider,
|
||||
crypto_mechanism_t *mechanism, crypto_key_t *key,
|
||||
crypto_spi_ctx_template_t *ctx_template, size_t *ctx_template_size,
|
||||
crypto_req_handle_t req)
|
||||
{
|
||||
int error;
|
||||
skein_ctx_t *ctx_tmpl;
|
||||
|
||||
ctx_tmpl = kmem_alloc(sizeof (*ctx_tmpl), crypto_kmflag(req));
|
||||
if (ctx_tmpl == NULL)
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
error = skein_mac_ctx_build(ctx_tmpl, mechanism, key);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
goto errout;
|
||||
*ctx_template = ctx_tmpl;
|
||||
*ctx_template_size = sizeof (*ctx_tmpl);
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
errout:
|
||||
bzero(ctx_tmpl, sizeof (*ctx_tmpl));
|
||||
kmem_free(ctx_tmpl, sizeof (*ctx_tmpl));
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees a skein context in a parent crypto context.
|
||||
*/
|
||||
static int
|
||||
skein_free_context(crypto_ctx_t *ctx)
|
||||
{
|
||||
if (SKEIN_CTX(ctx) != NULL) {
|
||||
bzero(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
kmem_free(SKEIN_CTX(ctx), sizeof (*SKEIN_CTX(ctx)));
|
||||
SKEIN_CTX_LVALUE(ctx) = NULL;
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
Reference in New Issue
Block a user