| @@ -0,0 +1,41 @@ | ||
| /* | ||
| * CDDL HEADER START | ||
| * | ||
| * The contents of this file are subject to the terms of the | ||
| * Common Development and Distribution License, Version 1.0 only | ||
| * (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://www.opensolaris.org/os/licensing. | ||
| * 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 (c) 2016, Datto, Inc. All rights reserved. | ||
| */ | ||
| #ifndef _SYS_CRYPTO_ALGS_H | ||
| #define _SYS_CRYPTO_ALGS_H | ||
| int aes_mod_init(void); | ||
| int aes_mod_fini(void); | ||
| int sha1_mod_init(void); | ||
| int sha1_mod_fini(void); | ||
| int sha2_mod_init(void); | ||
| int sha2_mod_fini(void); | ||
| int icp_init(void); | ||
| void icp_fini(void); | ||
| #endif /* _SYS_CRYPTO_ALGS_H */ |
| @@ -1,7 +1,7 @@ | ||
| # NB: GNU Automake Manual, Chapter 8.3.5: Libtool Convenience Libraries | ||
| # These five libraries are intermediary build components. | ||
| SUBDIRS = libspl libavl libefi libshare libunicode | ||
| # These six libraries are intermediary build components. | ||
| SUBDIRS = libspl libavl libefi libshare libunicode libicp | ||
| # These four libraries, which are installed as the final build product, | ||
| # incorporate the five convenience libraries given above. | ||
| # incorporate the six convenience libraries given above. | ||
| SUBDIRS += libuutil libnvpair libzpool libzfs_core libzfs |
| @@ -0,0 +1,78 @@ | ||
| include $(top_srcdir)/config/Rules.am | ||
| VPATH = \ | ||
| $(top_srcdir)/module/icp \ | ||
| $(top_srcdir)/lib/libicp | ||
| AM_CFLAGS += $(DEBUG_STACKFLAGS) $(FRAME_LARGER_THAN) | ||
| DEFAULT_INCLUDES += \ | ||
| -I$(top_srcdir)/include \ | ||
| -I$(top_srcdir)/module/icp/include \ | ||
| -I$(top_srcdir)/lib/libspl/include | ||
| noinst_LTLIBRARIES = libicp.la | ||
| if TARGET_ASM_X86_64 | ||
| ASM_SOURCES_C = asm-x86_64/aes/aeskey.c | ||
| ASM_SOURCES_AS = \ | ||
| asm-x86_64/aes/aes_amd64.S \ | ||
| asm-x86_64/aes/aes_intel.S \ | ||
| asm-x86_64/modes/gcm_intel.S \ | ||
| asm-x86_64/sha1/sha1-x86_64.S \ | ||
| asm-x86_64/sha2/sha256_impl.S | ||
| endif | ||
| if TARGET_ASM_I386 | ||
| ASM_SOURCES_C = | ||
| ASM_SOURCES_AS = | ||
| endif | ||
| if TARGET_ASM_GENERIC | ||
| ASM_SOURCES_C = | ||
| ASM_SOURCES_AS = | ||
| endif | ||
| USER_C = | ||
| USER_ASM = | ||
| KERNEL_C = \ | ||
| spi/kcf_spi.c \ | ||
| api/kcf_ctxops.c \ | ||
| api/kcf_digest.c \ | ||
| api/kcf_cipher.c \ | ||
| api/kcf_miscapi.c \ | ||
| api/kcf_mac.c \ | ||
| algs/aes/aes_impl.c \ | ||
| algs/aes/aes_modes.c \ | ||
| algs/modes/modes.c \ | ||
| algs/modes/cbc.c \ | ||
| algs/modes/gcm.c \ | ||
| algs/modes/ctr.c \ | ||
| algs/modes/ccm.c \ | ||
| algs/modes/ecb.c \ | ||
| algs/sha1/sha1.c \ | ||
| algs/sha2/sha2.c \ | ||
| illumos-crypto.c \ | ||
| io/aes.c \ | ||
| io/sha1_mod.c \ | ||
| io/sha2_mod.c \ | ||
| os/modhash.c \ | ||
| os/modconf.c \ | ||
| core/kcf_sched.c \ | ||
| core/kcf_prov_lib.c \ | ||
| core/kcf_callprov.c \ | ||
| core/kcf_mech_tabs.c \ | ||
| core/kcf_prov_tabs.c \ | ||
| $(ASM_SOURCES_C) | ||
| KERNEL_ASM = $(ASM_SOURCES_AS) | ||
| nodist_libicp_la_SOURCES = \ | ||
| $(USER_C) \ | ||
| $(USER_ASM) \ | ||
| $(KERNEL_C) \ | ||
| $(KERNEL_ASM) | ||
| libicp_la_LIBADD = -lrt |
| @@ -0,0 +1,82 @@ | ||
| src = @abs_top_srcdir@/module/icp | ||
| obj = @abs_builddir@ | ||
| MODULE := icp | ||
| TARGET_ASM_DIR = @TARGET_ASM_DIR@ | ||
| ifeq ($(TARGET_ASM_DIR), asm-x86_64) | ||
| ASM_SOURCES := asm-x86_64/aes/aeskey.o | ||
| ASM_SOURCES += asm-x86_64/aes/aes_amd64.o | ||
| ASM_SOURCES += asm-x86_64/aes/aes_intel.o | ||
| ASM_SOURCES += asm-x86_64/modes/gcm_intel.o | ||
| ASM_SOURCES += asm-x86_64/sha1/sha1-x86_64.o | ||
| ASM_SOURCES += asm-x86_64/sha2/sha256_impl.o | ||
| endif | ||
| ifeq ($(TARGET_ASM_DIR), asm-i386) | ||
| ASM_SOURCES := | ||
| endif | ||
| ifeq ($(TARGET_ASM_DIR), asm-generic) | ||
| ASM_SOURCES := | ||
| endif | ||
| EXTRA_CFLAGS = $(ZFS_MODULE_CFLAGS) @KERNELCPPFLAGS@ | ||
| obj-$(CONFIG_ZFS) := $(MODULE).o | ||
| ccflags-y += -I$(src)/include | ||
| asflags-y += -I$(src)/include | ||
| asflags-y += $(ZFS_MODULE_CFLAGS) | ||
| $(MODULE)-objs += illumos-crypto.o | ||
| $(MODULE)-objs += api/kcf_cipher.o | ||
| $(MODULE)-objs += api/kcf_digest.o | ||
| $(MODULE)-objs += api/kcf_mac.o | ||
| $(MODULE)-objs += api/kcf_miscapi.o | ||
| $(MODULE)-objs += api/kcf_ctxops.o | ||
| $(MODULE)-objs += core/kcf_callprov.o | ||
| $(MODULE)-objs += core/kcf_prov_tabs.o | ||
| $(MODULE)-objs += core/kcf_sched.o | ||
| $(MODULE)-objs += core/kcf_mech_tabs.o | ||
| $(MODULE)-objs += core/kcf_prov_lib.o | ||
| $(MODULE)-objs += spi/kcf_spi.o | ||
| $(MODULE)-objs += io/aes.o | ||
| $(MODULE)-objs += io/sha1_mod.o | ||
| $(MODULE)-objs += io/sha2_mod.o | ||
| $(MODULE)-objs += os/modhash.o | ||
| $(MODULE)-objs += os/modconf.o | ||
| $(MODULE)-objs += algs/modes/cbc.o | ||
| $(MODULE)-objs += algs/modes/ccm.o | ||
| $(MODULE)-objs += algs/modes/ctr.o | ||
| $(MODULE)-objs += algs/modes/ecb.o | ||
| $(MODULE)-objs += algs/modes/gcm.o | ||
| $(MODULE)-objs += algs/modes/modes.o | ||
| $(MODULE)-objs += algs/aes/aes_impl.o | ||
| $(MODULE)-objs += algs/aes/aes_modes.o | ||
| $(MODULE)-objs += algs/sha1/sha1.o | ||
| $(MODULE)-objs += algs/sha2/sha2.o | ||
| $(MODULE)-objs += $(ASM_SOURCES) | ||
| ICP_DIRS = \ | ||
| api \ | ||
| core \ | ||
| spi \ | ||
| io \ | ||
| os \ | ||
| algs \ | ||
| algs/aes \ | ||
| algs/modes \ | ||
| algs/sha1 \ | ||
| algs/sha2 \ | ||
| asm-x86_64 \ | ||
| asm-x86_64/aes \ | ||
| asm-x86_64/modes \ | ||
| asm-x86_64/sha1 \ | ||
| asm-x86_64/sha2 \ | ||
| asm-i386 \ | ||
| asm-generic | ||
| all: | ||
| mkdir -p $(ICP_DIRS) |
| @@ -0,0 +1,135 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2009 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <modes/modes.h> | ||
| #include <aes/aes_impl.h> | ||
| /* Copy a 16-byte AES block from "in" to "out" */ | ||
| void | ||
| aes_copy_block(uint8_t *in, uint8_t *out) | ||
| { | ||
| if (IS_P2ALIGNED2(in, out, sizeof (uint32_t))) { | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&out[0] = *(uint32_t *)&in[0]; | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&out[4] = *(uint32_t *)&in[4]; | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&out[8] = *(uint32_t *)&in[8]; | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&out[12] = *(uint32_t *)&in[12]; | ||
| } else { | ||
| AES_COPY_BLOCK(in, out); | ||
| } | ||
| } | ||
| /* XOR a 16-byte AES block of data into dst */ | ||
| void | ||
| aes_xor_block(uint8_t *data, uint8_t *dst) | ||
| { | ||
| if (IS_P2ALIGNED2(dst, data, sizeof (uint32_t))) { | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&dst[0] ^= *(uint32_t *)&data[0]; | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&dst[4] ^= *(uint32_t *)&data[4]; | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&dst[8] ^= *(uint32_t *)&data[8]; | ||
| /* LINTED: pointer alignment */ | ||
| *(uint32_t *)&dst[12] ^= *(uint32_t *)&data[12]; | ||
| } else { | ||
| AES_XOR_BLOCK(data, dst); | ||
| } | ||
| } | ||
| /* | ||
| * Encrypt multiple blocks of data according to mode. | ||
| */ | ||
| int | ||
| aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length, | ||
| crypto_data_t *out) | ||
| { | ||
| aes_ctx_t *aes_ctx = ctx; | ||
| int rv; | ||
| if (aes_ctx->ac_flags & CTR_MODE) { | ||
| rv = ctr_mode_contiguous_blocks(ctx, data, length, out, | ||
| AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block); | ||
| } else if (aes_ctx->ac_flags & CCM_MODE) { | ||
| rv = ccm_mode_encrypt_contiguous_blocks(ctx, data, length, | ||
| out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, | ||
| aes_xor_block); | ||
| } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) { | ||
| rv = gcm_mode_encrypt_contiguous_blocks(ctx, data, length, | ||
| out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, | ||
| aes_xor_block); | ||
| } else if (aes_ctx->ac_flags & CBC_MODE) { | ||
| rv = cbc_encrypt_contiguous_blocks(ctx, | ||
| data, length, out, AES_BLOCK_LEN, aes_encrypt_block, | ||
| aes_copy_block, aes_xor_block); | ||
| } else { | ||
| rv = ecb_cipher_contiguous_blocks(ctx, data, length, out, | ||
| AES_BLOCK_LEN, aes_encrypt_block); | ||
| } | ||
| return (rv); | ||
| } | ||
| /* | ||
| * Decrypt multiple blocks of data according to mode. | ||
| */ | ||
| int | ||
| aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length, | ||
| crypto_data_t *out) | ||
| { | ||
| aes_ctx_t *aes_ctx = ctx; | ||
| int rv; | ||
| if (aes_ctx->ac_flags & CTR_MODE) { | ||
| rv = ctr_mode_contiguous_blocks(ctx, data, length, out, | ||
| AES_BLOCK_LEN, aes_encrypt_block, aes_xor_block); | ||
| if (rv == CRYPTO_DATA_LEN_RANGE) | ||
| rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; | ||
| } else if (aes_ctx->ac_flags & CCM_MODE) { | ||
| rv = ccm_mode_decrypt_contiguous_blocks(ctx, data, length, | ||
| out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, | ||
| aes_xor_block); | ||
| } else if (aes_ctx->ac_flags & (GCM_MODE|GMAC_MODE)) { | ||
| rv = gcm_mode_decrypt_contiguous_blocks(ctx, data, length, | ||
| out, AES_BLOCK_LEN, aes_encrypt_block, aes_copy_block, | ||
| aes_xor_block); | ||
| } else if (aes_ctx->ac_flags & CBC_MODE) { | ||
| rv = cbc_decrypt_contiguous_blocks(ctx, data, length, out, | ||
| AES_BLOCK_LEN, aes_decrypt_block, aes_copy_block, | ||
| aes_xor_block); | ||
| } else { | ||
| rv = ecb_cipher_contiguous_blocks(ctx, data, length, out, | ||
| AES_BLOCK_LEN, aes_decrypt_block); | ||
| if (rv == CRYPTO_DATA_LEN_RANGE) | ||
| rv = CRYPTO_ENCRYPTED_DATA_LEN_RANGE; | ||
| } | ||
| return (rv); | ||
| } |
| @@ -0,0 +1,305 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2008 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <modes/modes.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/impl.h> | ||
| /* | ||
| * Algorithm independent CBC functions. | ||
| */ | ||
| int | ||
| cbc_encrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, | ||
| crypto_data_t *out, size_t block_size, | ||
| int (*encrypt)(const void *, const uint8_t *, uint8_t *), | ||
| void (*copy_block)(uint8_t *, uint8_t *), | ||
| void (*xor_block)(uint8_t *, uint8_t *)) | ||
| { | ||
| size_t remainder = length; | ||
| size_t need = 0; | ||
| uint8_t *datap = (uint8_t *)data; | ||
| uint8_t *blockp; | ||
| uint8_t *lastp; | ||
| void *iov_or_mp; | ||
| offset_t offset; | ||
| uint8_t *out_data_1; | ||
| uint8_t *out_data_2; | ||
| size_t out_data_1_len; | ||
| if (length + ctx->cbc_remainder_len < block_size) { | ||
| /* accumulate bytes here and return */ | ||
| bcopy(datap, | ||
| (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len, | ||
| length); | ||
| ctx->cbc_remainder_len += length; | ||
| ctx->cbc_copy_to = datap; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| lastp = (uint8_t *)ctx->cbc_iv; | ||
| if (out != NULL) | ||
| crypto_init_ptrs(out, &iov_or_mp, &offset); | ||
| do { | ||
| /* Unprocessed data from last call. */ | ||
| if (ctx->cbc_remainder_len > 0) { | ||
| need = block_size - ctx->cbc_remainder_len; | ||
| if (need > remainder) | ||
| return (CRYPTO_DATA_LEN_RANGE); | ||
| bcopy(datap, &((uint8_t *)ctx->cbc_remainder) | ||
| [ctx->cbc_remainder_len], need); | ||
| blockp = (uint8_t *)ctx->cbc_remainder; | ||
| } else { | ||
| blockp = datap; | ||
| } | ||
| if (out == NULL) { | ||
| /* | ||
| * XOR the previous cipher block or IV with the | ||
| * current clear block. | ||
| */ | ||
| xor_block(lastp, blockp); | ||
| encrypt(ctx->cbc_keysched, blockp, blockp); | ||
| ctx->cbc_lastp = blockp; | ||
| lastp = blockp; | ||
| if (ctx->cbc_remainder_len > 0) { | ||
| bcopy(blockp, ctx->cbc_copy_to, | ||
| ctx->cbc_remainder_len); | ||
| bcopy(blockp + ctx->cbc_remainder_len, datap, | ||
| need); | ||
| } | ||
| } else { | ||
| /* | ||
| * XOR the previous cipher block or IV with the | ||
| * current clear block. | ||
| */ | ||
| xor_block(blockp, lastp); | ||
| encrypt(ctx->cbc_keysched, lastp, lastp); | ||
| crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, | ||
| &out_data_1_len, &out_data_2, block_size); | ||
| /* copy block to where it belongs */ | ||
| if (out_data_1_len == block_size) { | ||
| copy_block(lastp, out_data_1); | ||
| } else { | ||
| bcopy(lastp, out_data_1, out_data_1_len); | ||
| if (out_data_2 != NULL) { | ||
| bcopy(lastp + out_data_1_len, | ||
| out_data_2, | ||
| block_size - out_data_1_len); | ||
| } | ||
| } | ||
| /* update offset */ | ||
| out->cd_offset += block_size; | ||
| } | ||
| /* Update pointer to next block of data to be processed. */ | ||
| if (ctx->cbc_remainder_len != 0) { | ||
| datap += need; | ||
| ctx->cbc_remainder_len = 0; | ||
| } else { | ||
| datap += block_size; | ||
| } | ||
| remainder = (size_t)&data[length] - (size_t)datap; | ||
| /* Incomplete last block. */ | ||
| if (remainder > 0 && remainder < block_size) { | ||
| bcopy(datap, ctx->cbc_remainder, remainder); | ||
| ctx->cbc_remainder_len = remainder; | ||
| ctx->cbc_copy_to = datap; | ||
| goto out; | ||
| } | ||
| ctx->cbc_copy_to = NULL; | ||
| } while (remainder > 0); | ||
| out: | ||
| /* | ||
| * Save the last encrypted block in the context. | ||
| */ | ||
| if (ctx->cbc_lastp != NULL) { | ||
| copy_block((uint8_t *)ctx->cbc_lastp, (uint8_t *)ctx->cbc_iv); | ||
| ctx->cbc_lastp = (uint8_t *)ctx->cbc_iv; | ||
| } | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| #define OTHER(a, ctx) \ | ||
| (((a) == (ctx)->cbc_lastblock) ? (ctx)->cbc_iv : (ctx)->cbc_lastblock) | ||
| /* ARGSUSED */ | ||
| int | ||
| cbc_decrypt_contiguous_blocks(cbc_ctx_t *ctx, char *data, size_t length, | ||
| crypto_data_t *out, size_t block_size, | ||
| int (*decrypt)(const void *, const uint8_t *, uint8_t *), | ||
| void (*copy_block)(uint8_t *, uint8_t *), | ||
| void (*xor_block)(uint8_t *, uint8_t *)) | ||
| { | ||
| size_t remainder = length; | ||
| size_t need = 0; | ||
| uint8_t *datap = (uint8_t *)data; | ||
| uint8_t *blockp; | ||
| uint8_t *lastp; | ||
| void *iov_or_mp; | ||
| offset_t offset; | ||
| uint8_t *out_data_1; | ||
| uint8_t *out_data_2; | ||
| size_t out_data_1_len; | ||
| if (length + ctx->cbc_remainder_len < block_size) { | ||
| /* accumulate bytes here and return */ | ||
| bcopy(datap, | ||
| (uint8_t *)ctx->cbc_remainder + ctx->cbc_remainder_len, | ||
| length); | ||
| ctx->cbc_remainder_len += length; | ||
| ctx->cbc_copy_to = datap; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| lastp = ctx->cbc_lastp; | ||
| if (out != NULL) | ||
| crypto_init_ptrs(out, &iov_or_mp, &offset); | ||
| do { | ||
| /* Unprocessed data from last call. */ | ||
| if (ctx->cbc_remainder_len > 0) { | ||
| need = block_size - ctx->cbc_remainder_len; | ||
| if (need > remainder) | ||
| return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE); | ||
| bcopy(datap, &((uint8_t *)ctx->cbc_remainder) | ||
| [ctx->cbc_remainder_len], need); | ||
| blockp = (uint8_t *)ctx->cbc_remainder; | ||
| } else { | ||
| blockp = datap; | ||
| } | ||
| /* LINTED: pointer alignment */ | ||
| copy_block(blockp, (uint8_t *)OTHER((uint64_t *)lastp, ctx)); | ||
| if (out != NULL) { | ||
| decrypt(ctx->cbc_keysched, blockp, | ||
| (uint8_t *)ctx->cbc_remainder); | ||
| blockp = (uint8_t *)ctx->cbc_remainder; | ||
| } else { | ||
| decrypt(ctx->cbc_keysched, blockp, blockp); | ||
| } | ||
| /* | ||
| * XOR the previous cipher block or IV with the | ||
| * currently decrypted block. | ||
| */ | ||
| xor_block(lastp, blockp); | ||
| /* LINTED: pointer alignment */ | ||
| lastp = (uint8_t *)OTHER((uint64_t *)lastp, ctx); | ||
| if (out != NULL) { | ||
| crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, | ||
| &out_data_1_len, &out_data_2, block_size); | ||
| bcopy(blockp, out_data_1, out_data_1_len); | ||
| if (out_data_2 != NULL) { | ||
| bcopy(blockp + out_data_1_len, out_data_2, | ||
| block_size - out_data_1_len); | ||
| } | ||
| /* update offset */ | ||
| out->cd_offset += block_size; | ||
| } else if (ctx->cbc_remainder_len > 0) { | ||
| /* copy temporary block to where it belongs */ | ||
| bcopy(blockp, ctx->cbc_copy_to, ctx->cbc_remainder_len); | ||
| bcopy(blockp + ctx->cbc_remainder_len, datap, need); | ||
| } | ||
| /* Update pointer to next block of data to be processed. */ | ||
| if (ctx->cbc_remainder_len != 0) { | ||
| datap += need; | ||
| ctx->cbc_remainder_len = 0; | ||
| } else { | ||
| datap += block_size; | ||
| } | ||
| remainder = (size_t)&data[length] - (size_t)datap; | ||
| /* Incomplete last block. */ | ||
| if (remainder > 0 && remainder < block_size) { | ||
| bcopy(datap, ctx->cbc_remainder, remainder); | ||
| ctx->cbc_remainder_len = remainder; | ||
| ctx->cbc_lastp = lastp; | ||
| ctx->cbc_copy_to = datap; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| ctx->cbc_copy_to = NULL; | ||
| } while (remainder > 0); | ||
| ctx->cbc_lastp = lastp; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| int | ||
| cbc_init_ctx(cbc_ctx_t *cbc_ctx, char *param, size_t param_len, | ||
| size_t block_size, void (*copy_block)(uint8_t *, uint64_t *)) | ||
| { | ||
| /* | ||
| * Copy IV into context. | ||
| * | ||
| * If cm_param == NULL then the IV comes from the | ||
| * cd_miscdata field in the crypto_data structure. | ||
| */ | ||
| if (param != NULL) { | ||
| ASSERT(param_len == block_size); | ||
| copy_block((uchar_t *)param, cbc_ctx->cbc_iv); | ||
| } | ||
| cbc_ctx->cbc_lastp = (uint8_t *)&cbc_ctx->cbc_iv[0]; | ||
| cbc_ctx->cbc_flags |= CBC_MODE; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| /* ARGSUSED */ | ||
| void * | ||
| cbc_alloc_ctx(int kmflag) | ||
| { | ||
| cbc_ctx_t *cbc_ctx; | ||
| if ((cbc_ctx = kmem_zalloc(sizeof (cbc_ctx_t), kmflag)) == NULL) | ||
| return (NULL); | ||
| cbc_ctx->cbc_flags = CBC_MODE; | ||
| return (cbc_ctx); | ||
| } |
| @@ -0,0 +1,238 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2008 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <modes/modes.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/impl.h> | ||
| #include <sys/byteorder.h> | ||
| /* | ||
| * Encrypt and decrypt multiple blocks of data in counter mode. | ||
| */ | ||
| int | ||
| ctr_mode_contiguous_blocks(ctr_ctx_t *ctx, char *data, size_t length, | ||
| crypto_data_t *out, size_t block_size, | ||
| int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct), | ||
| void (*xor_block)(uint8_t *, uint8_t *)) | ||
| { | ||
| size_t remainder = length; | ||
| size_t need = 0; | ||
| uint8_t *datap = (uint8_t *)data; | ||
| uint8_t *blockp; | ||
| uint8_t *lastp; | ||
| void *iov_or_mp; | ||
| offset_t offset; | ||
| uint8_t *out_data_1; | ||
| uint8_t *out_data_2; | ||
| size_t out_data_1_len; | ||
| uint64_t lower_counter, upper_counter; | ||
| if (length + ctx->ctr_remainder_len < block_size) { | ||
| /* accumulate bytes here and return */ | ||
| bcopy(datap, | ||
| (uint8_t *)ctx->ctr_remainder + ctx->ctr_remainder_len, | ||
| length); | ||
| ctx->ctr_remainder_len += length; | ||
| ctx->ctr_copy_to = datap; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| lastp = (uint8_t *)ctx->ctr_cb; | ||
| if (out != NULL) | ||
| crypto_init_ptrs(out, &iov_or_mp, &offset); | ||
| do { | ||
| /* Unprocessed data from last call. */ | ||
| if (ctx->ctr_remainder_len > 0) { | ||
| need = block_size - ctx->ctr_remainder_len; | ||
| if (need > remainder) | ||
| return (CRYPTO_DATA_LEN_RANGE); | ||
| bcopy(datap, &((uint8_t *)ctx->ctr_remainder) | ||
| [ctx->ctr_remainder_len], need); | ||
| blockp = (uint8_t *)ctx->ctr_remainder; | ||
| } else { | ||
| blockp = datap; | ||
| } | ||
| /* ctr_cb is the counter block */ | ||
| cipher(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, | ||
| (uint8_t *)ctx->ctr_tmp); | ||
| lastp = (uint8_t *)ctx->ctr_tmp; | ||
| /* | ||
| * Increment Counter. | ||
| */ | ||
| lower_counter = ntohll(ctx->ctr_cb[1] & ctx->ctr_lower_mask); | ||
| lower_counter = htonll(lower_counter + 1); | ||
| lower_counter &= ctx->ctr_lower_mask; | ||
| ctx->ctr_cb[1] = (ctx->ctr_cb[1] & ~(ctx->ctr_lower_mask)) | | ||
| lower_counter; | ||
| /* wrap around */ | ||
| if (lower_counter == 0) { | ||
| upper_counter = | ||
| ntohll(ctx->ctr_cb[0] & ctx->ctr_upper_mask); | ||
| upper_counter = htonll(upper_counter + 1); | ||
| upper_counter &= ctx->ctr_upper_mask; | ||
| ctx->ctr_cb[0] = | ||
| (ctx->ctr_cb[0] & ~(ctx->ctr_upper_mask)) | | ||
| upper_counter; | ||
| } | ||
| /* | ||
| * XOR encrypted counter block with the current clear block. | ||
| */ | ||
| xor_block(blockp, lastp); | ||
| if (out == NULL) { | ||
| if (ctx->ctr_remainder_len > 0) { | ||
| bcopy(lastp, ctx->ctr_copy_to, | ||
| ctx->ctr_remainder_len); | ||
| bcopy(lastp + ctx->ctr_remainder_len, datap, | ||
| need); | ||
| } | ||
| } else { | ||
| crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, | ||
| &out_data_1_len, &out_data_2, block_size); | ||
| /* copy block to where it belongs */ | ||
| bcopy(lastp, out_data_1, out_data_1_len); | ||
| if (out_data_2 != NULL) { | ||
| bcopy(lastp + out_data_1_len, out_data_2, | ||
| block_size - out_data_1_len); | ||
| } | ||
| /* update offset */ | ||
| out->cd_offset += block_size; | ||
| } | ||
| /* Update pointer to next block of data to be processed. */ | ||
| if (ctx->ctr_remainder_len != 0) { | ||
| datap += need; | ||
| ctx->ctr_remainder_len = 0; | ||
| } else { | ||
| datap += block_size; | ||
| } | ||
| remainder = (size_t)&data[length] - (size_t)datap; | ||
| /* Incomplete last block. */ | ||
| if (remainder > 0 && remainder < block_size) { | ||
| bcopy(datap, ctx->ctr_remainder, remainder); | ||
| ctx->ctr_remainder_len = remainder; | ||
| ctx->ctr_copy_to = datap; | ||
| goto out; | ||
| } | ||
| ctx->ctr_copy_to = NULL; | ||
| } while (remainder > 0); | ||
| out: | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| int | ||
| ctr_mode_final(ctr_ctx_t *ctx, crypto_data_t *out, | ||
| int (*encrypt_block)(const void *, const uint8_t *, uint8_t *)) | ||
| { | ||
| uint8_t *lastp; | ||
| void *iov_or_mp; | ||
| offset_t offset; | ||
| uint8_t *out_data_1; | ||
| uint8_t *out_data_2; | ||
| size_t out_data_1_len; | ||
| uint8_t *p; | ||
| int i; | ||
| if (out->cd_length < ctx->ctr_remainder_len) | ||
| return (CRYPTO_DATA_LEN_RANGE); | ||
| encrypt_block(ctx->ctr_keysched, (uint8_t *)ctx->ctr_cb, | ||
| (uint8_t *)ctx->ctr_tmp); | ||
| lastp = (uint8_t *)ctx->ctr_tmp; | ||
| p = (uint8_t *)ctx->ctr_remainder; | ||
| for (i = 0; i < ctx->ctr_remainder_len; i++) { | ||
| p[i] ^= lastp[i]; | ||
| } | ||
| crypto_init_ptrs(out, &iov_or_mp, &offset); | ||
| crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, | ||
| &out_data_1_len, &out_data_2, ctx->ctr_remainder_len); | ||
| bcopy(p, out_data_1, out_data_1_len); | ||
| if (out_data_2 != NULL) { | ||
| bcopy((uint8_t *)p + out_data_1_len, | ||
| out_data_2, ctx->ctr_remainder_len - out_data_1_len); | ||
| } | ||
| out->cd_offset += ctx->ctr_remainder_len; | ||
| ctx->ctr_remainder_len = 0; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| int | ||
| ctr_init_ctx(ctr_ctx_t *ctr_ctx, ulong_t count, uint8_t *cb, | ||
| void (*copy_block)(uint8_t *, uint8_t *)) | ||
| { | ||
| uint64_t upper_mask = 0; | ||
| uint64_t lower_mask = 0; | ||
| if (count == 0 || count > 128) { | ||
| return (CRYPTO_MECHANISM_PARAM_INVALID); | ||
| } | ||
| /* upper 64 bits of the mask */ | ||
| if (count >= 64) { | ||
| count -= 64; | ||
| upper_mask = (count == 64) ? UINT64_MAX : (1ULL << count) - 1; | ||
| lower_mask = UINT64_MAX; | ||
| } else { | ||
| /* now the lower 63 bits */ | ||
| lower_mask = (1ULL << count) - 1; | ||
| } | ||
| ctr_ctx->ctr_lower_mask = htonll(lower_mask); | ||
| ctr_ctx->ctr_upper_mask = htonll(upper_mask); | ||
| copy_block(cb, (uchar_t *)ctr_ctx->ctr_cb); | ||
| ctr_ctx->ctr_lastp = (uint8_t *)&ctr_ctx->ctr_cb[0]; | ||
| ctr_ctx->ctr_flags |= CTR_MODE; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| /* ARGSUSED */ | ||
| void * | ||
| ctr_alloc_ctx(int kmflag) | ||
| { | ||
| ctr_ctx_t *ctr_ctx; | ||
| if ((ctr_ctx = kmem_zalloc(sizeof (ctr_ctx_t), kmflag)) == NULL) | ||
| return (NULL); | ||
| ctr_ctx->ctr_flags = CTR_MODE; | ||
| return (ctr_ctx); | ||
| } |
| @@ -0,0 +1,143 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2008 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <modes/modes.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/impl.h> | ||
| /* | ||
| * Algorithm independent ECB functions. | ||
| */ | ||
| int | ||
| ecb_cipher_contiguous_blocks(ecb_ctx_t *ctx, char *data, size_t length, | ||
| crypto_data_t *out, size_t block_size, | ||
| int (*cipher)(const void *ks, const uint8_t *pt, uint8_t *ct)) | ||
| { | ||
| size_t remainder = length; | ||
| size_t need = 0; | ||
| uint8_t *datap = (uint8_t *)data; | ||
| uint8_t *blockp; | ||
| uint8_t *lastp; | ||
| void *iov_or_mp; | ||
| offset_t offset; | ||
| uint8_t *out_data_1; | ||
| uint8_t *out_data_2; | ||
| size_t out_data_1_len; | ||
| if (length + ctx->ecb_remainder_len < block_size) { | ||
| /* accumulate bytes here and return */ | ||
| bcopy(datap, | ||
| (uint8_t *)ctx->ecb_remainder + ctx->ecb_remainder_len, | ||
| length); | ||
| ctx->ecb_remainder_len += length; | ||
| ctx->ecb_copy_to = datap; | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| lastp = (uint8_t *)ctx->ecb_iv; | ||
| if (out != NULL) | ||
| crypto_init_ptrs(out, &iov_or_mp, &offset); | ||
| do { | ||
| /* Unprocessed data from last call. */ | ||
| if (ctx->ecb_remainder_len > 0) { | ||
| need = block_size - ctx->ecb_remainder_len; | ||
| if (need > remainder) | ||
| return (CRYPTO_DATA_LEN_RANGE); | ||
| bcopy(datap, &((uint8_t *)ctx->ecb_remainder) | ||
| [ctx->ecb_remainder_len], need); | ||
| blockp = (uint8_t *)ctx->ecb_remainder; | ||
| } else { | ||
| blockp = datap; | ||
| } | ||
| if (out == NULL) { | ||
| cipher(ctx->ecb_keysched, blockp, blockp); | ||
| ctx->ecb_lastp = blockp; | ||
| lastp = blockp; | ||
| if (ctx->ecb_remainder_len > 0) { | ||
| bcopy(blockp, ctx->ecb_copy_to, | ||
| ctx->ecb_remainder_len); | ||
| bcopy(blockp + ctx->ecb_remainder_len, datap, | ||
| need); | ||
| } | ||
| } else { | ||
| cipher(ctx->ecb_keysched, blockp, lastp); | ||
| crypto_get_ptrs(out, &iov_or_mp, &offset, &out_data_1, | ||
| &out_data_1_len, &out_data_2, block_size); | ||
| /* copy block to where it belongs */ | ||
| bcopy(lastp, out_data_1, out_data_1_len); | ||
| if (out_data_2 != NULL) { | ||
| bcopy(lastp + out_data_1_len, out_data_2, | ||
| block_size - out_data_1_len); | ||
| } | ||
| /* update offset */ | ||
| out->cd_offset += block_size; | ||
| } | ||
| /* Update pointer to next block of data to be processed. */ | ||
| if (ctx->ecb_remainder_len != 0) { | ||
| datap += need; | ||
| ctx->ecb_remainder_len = 0; | ||
| } else { | ||
| datap += block_size; | ||
| } | ||
| remainder = (size_t)&data[length] - (size_t)datap; | ||
| /* Incomplete last block. */ | ||
| if (remainder > 0 && remainder < block_size) { | ||
| bcopy(datap, ctx->ecb_remainder, remainder); | ||
| ctx->ecb_remainder_len = remainder; | ||
| ctx->ecb_copy_to = datap; | ||
| goto out; | ||
| } | ||
| ctx->ecb_copy_to = NULL; | ||
| } while (remainder > 0); | ||
| out: | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| /* ARGSUSED */ | ||
| void * | ||
| ecb_alloc_ctx(int kmflag) | ||
| { | ||
| ecb_ctx_t *ecb_ctx; | ||
| if ((ecb_ctx = kmem_zalloc(sizeof (ecb_ctx_t), kmflag)) == NULL) | ||
| return (NULL); | ||
| ecb_ctx->ecb_flags = ECB_MODE; | ||
| return (ecb_ctx); | ||
| } |
| @@ -0,0 +1,159 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2009 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <modes/modes.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/impl.h> | ||
| /* | ||
| * Initialize by setting iov_or_mp to point to the current iovec or mp, | ||
| * and by setting current_offset to an offset within the current iovec or mp. | ||
| */ | ||
| void | ||
| crypto_init_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset) | ||
| { | ||
| offset_t offset; | ||
| switch (out->cd_format) { | ||
| case CRYPTO_DATA_RAW: | ||
| *current_offset = out->cd_offset; | ||
| break; | ||
| case CRYPTO_DATA_UIO: { | ||
| uio_t *uiop = out->cd_uio; | ||
| uintptr_t vec_idx; | ||
| offset = out->cd_offset; | ||
| for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && | ||
| offset >= uiop->uio_iov[vec_idx].iov_len; | ||
| offset -= uiop->uio_iov[vec_idx++].iov_len) | ||
| ; | ||
| *current_offset = offset; | ||
| *iov_or_mp = (void *)vec_idx; | ||
| break; | ||
| } | ||
| } /* end switch */ | ||
| } | ||
| /* | ||
| * Get pointers for where in the output to copy a block of encrypted or | ||
| * decrypted data. The iov_or_mp argument stores a pointer to the current | ||
| * iovec or mp, and offset stores an offset into the current iovec or mp. | ||
| */ | ||
| void | ||
| crypto_get_ptrs(crypto_data_t *out, void **iov_or_mp, offset_t *current_offset, | ||
| uint8_t **out_data_1, size_t *out_data_1_len, uint8_t **out_data_2, | ||
| size_t amt) | ||
| { | ||
| offset_t offset; | ||
| switch (out->cd_format) { | ||
| case CRYPTO_DATA_RAW: { | ||
| iovec_t *iov; | ||
| offset = *current_offset; | ||
| iov = &out->cd_raw; | ||
| if ((offset + amt) <= iov->iov_len) { | ||
| /* one block fits */ | ||
| *out_data_1 = (uint8_t *)iov->iov_base + offset; | ||
| *out_data_1_len = amt; | ||
| *out_data_2 = NULL; | ||
| *current_offset = offset + amt; | ||
| } | ||
| break; | ||
| } | ||
| case CRYPTO_DATA_UIO: { | ||
| uio_t *uio = out->cd_uio; | ||
| iovec_t *iov; | ||
| offset_t offset; | ||
| uintptr_t vec_idx; | ||
| uint8_t *p; | ||
| offset = *current_offset; | ||
| vec_idx = (uintptr_t)(*iov_or_mp); | ||
| iov = (iovec_t *)&uio->uio_iov[vec_idx]; | ||
| p = (uint8_t *)iov->iov_base + offset; | ||
| *out_data_1 = p; | ||
| if (offset + amt <= iov->iov_len) { | ||
| /* can fit one block into this iov */ | ||
| *out_data_1_len = amt; | ||
| *out_data_2 = NULL; | ||
| *current_offset = offset + amt; | ||
| } else { | ||
| /* one block spans two iovecs */ | ||
| *out_data_1_len = iov->iov_len - offset; | ||
| if (vec_idx == uio->uio_iovcnt) | ||
| return; | ||
| vec_idx++; | ||
| iov = (iovec_t *)&uio->uio_iov[vec_idx]; | ||
| *out_data_2 = (uint8_t *)iov->iov_base; | ||
| *current_offset = amt - *out_data_1_len; | ||
| } | ||
| *iov_or_mp = (void *)vec_idx; | ||
| break; | ||
| } | ||
| } /* end switch */ | ||
| } | ||
| void | ||
| crypto_free_mode_ctx(void *ctx) | ||
| { | ||
| common_ctx_t *common_ctx = (common_ctx_t *)ctx; | ||
| switch (common_ctx->cc_flags & | ||
| (ECB_MODE|CBC_MODE|CTR_MODE|CCM_MODE|GCM_MODE|GMAC_MODE)) { | ||
| case ECB_MODE: | ||
| kmem_free(common_ctx, sizeof (ecb_ctx_t)); | ||
| break; | ||
| case CBC_MODE: | ||
| kmem_free(common_ctx, sizeof (cbc_ctx_t)); | ||
| break; | ||
| case CTR_MODE: | ||
| kmem_free(common_ctx, sizeof (ctr_ctx_t)); | ||
| break; | ||
| case CCM_MODE: | ||
| if (((ccm_ctx_t *)ctx)->ccm_pt_buf != NULL) | ||
| vmem_free(((ccm_ctx_t *)ctx)->ccm_pt_buf, | ||
| ((ccm_ctx_t *)ctx)->ccm_data_len); | ||
| kmem_free(ctx, sizeof (ccm_ctx_t)); | ||
| break; | ||
| case GCM_MODE: | ||
| case GMAC_MODE: | ||
| if (((gcm_ctx_t *)ctx)->gcm_pt_buf != NULL) | ||
| vmem_free(((gcm_ctx_t *)ctx)->gcm_pt_buf, | ||
| ((gcm_ctx_t *)ctx)->gcm_pt_buf_len); | ||
| kmem_free(ctx, sizeof (gcm_ctx_t)); | ||
| } | ||
| } |
| @@ -0,0 +1,151 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2007 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/impl.h> | ||
| #include <sys/crypto/api.h> | ||
| #include <sys/crypto/spi.h> | ||
| #include <sys/crypto/sched_impl.h> | ||
| /* | ||
| * Crypto contexts manipulation routines | ||
| */ | ||
| /* | ||
| * crypto_create_ctx_template() | ||
| * | ||
| * Arguments: | ||
| * | ||
| * mech: crypto_mechanism_t pointer. | ||
| * mech_type is a valid value previously returned by | ||
| * crypto_mech2id(); | ||
| * When the mech's parameter is not NULL, its definition depends | ||
| * on the standard definition of the mechanism. | ||
| * key: pointer to a crypto_key_t structure. | ||
| * ptmpl: a storage for the opaque crypto_ctx_template_t, allocated and | ||
| * initialized by the software provider this routine is | ||
| * dispatched to. | ||
| * kmflag: KM_SLEEP/KM_NOSLEEP mem. alloc. flag. | ||
| * | ||
| * Description: | ||
| * Redirects the call to the software provider of the specified | ||
| * mechanism. That provider will allocate and pre-compute/pre-expand | ||
| * the context template, reusable by later calls to crypto_xxx_init(). | ||
| * The size and address of that provider context template are stored | ||
| * in an internal structure, kcf_ctx_template_t. The address of that | ||
| * structure is given back to the caller in *ptmpl. | ||
| * | ||
| * Context: | ||
| * Process or interrupt. | ||
| * | ||
| * Returns: | ||
| * CRYPTO_SUCCESS when the context template is successfully created. | ||
| * CRYPTO_HOST_MEMEORY: mem alloc failure | ||
| * CRYPTO_ARGUMENTS_BAD: NULL storage for the ctx template. | ||
| * RYPTO_MECHANISM_INVALID: invalid mechanism 'mech'. | ||
| */ | ||
| int | ||
| crypto_create_ctx_template(crypto_mechanism_t *mech, crypto_key_t *key, | ||
| crypto_ctx_template_t *ptmpl, int kmflag) | ||
| { | ||
| int error; | ||
| kcf_mech_entry_t *me; | ||
| kcf_provider_desc_t *pd; | ||
| kcf_ctx_template_t *ctx_tmpl; | ||
| crypto_mechanism_t prov_mech; | ||
| /* A few args validation */ | ||
| if (ptmpl == NULL) | ||
| return (CRYPTO_ARGUMENTS_BAD); | ||
| if (mech == NULL) | ||
| return (CRYPTO_MECHANISM_INVALID); | ||
| error = kcf_get_sw_prov(mech->cm_type, &pd, &me, B_TRUE); | ||
| if (error != CRYPTO_SUCCESS) | ||
| return (error); | ||
| if ((ctx_tmpl = (kcf_ctx_template_t *)kmem_alloc( | ||
| sizeof (kcf_ctx_template_t), kmflag)) == NULL) { | ||
| KCF_PROV_REFRELE(pd); | ||
| return (CRYPTO_HOST_MEMORY); | ||
| } | ||
| /* Pass a mechtype that the provider understands */ | ||
| prov_mech.cm_type = KCF_TO_PROV_MECHNUM(pd, mech->cm_type); | ||
| prov_mech.cm_param = mech->cm_param; | ||
| prov_mech.cm_param_len = mech->cm_param_len; | ||
| error = KCF_PROV_CREATE_CTX_TEMPLATE(pd, &prov_mech, key, | ||
| &(ctx_tmpl->ct_prov_tmpl), &(ctx_tmpl->ct_size), KCF_RHNDL(kmflag)); | ||
| if (error == CRYPTO_SUCCESS) { | ||
| ctx_tmpl->ct_generation = me->me_gen_swprov; | ||
| *ptmpl = ctx_tmpl; | ||
| } else { | ||
| kmem_free(ctx_tmpl, sizeof (kcf_ctx_template_t)); | ||
| } | ||
| KCF_PROV_REFRELE(pd); | ||
| return (error); | ||
| } | ||
| /* | ||
| * crypto_destroy_ctx_template() | ||
| * | ||
| * Arguments: | ||
| * | ||
| * tmpl: an opaque crypto_ctx_template_t previously created by | ||
| * crypto_create_ctx_template() | ||
| * | ||
| * Description: | ||
| * Frees the inbedded crypto_spi_ctx_template_t, then the | ||
| * kcf_ctx_template_t. | ||
| * | ||
| * Context: | ||
| * Process or interrupt. | ||
| * | ||
| */ | ||
| void | ||
| crypto_destroy_ctx_template(crypto_ctx_template_t tmpl) | ||
| { | ||
| kcf_ctx_template_t *ctx_tmpl = (kcf_ctx_template_t *)tmpl; | ||
| if (ctx_tmpl == NULL) | ||
| return; | ||
| ASSERT(ctx_tmpl->ct_prov_tmpl != NULL); | ||
| bzero(ctx_tmpl->ct_prov_tmpl, ctx_tmpl->ct_size); | ||
| kmem_free(ctx_tmpl->ct_prov_tmpl, ctx_tmpl->ct_size); | ||
| kmem_free(ctx_tmpl, sizeof (kcf_ctx_template_t)); | ||
| } | ||
| #if defined(_KERNEL) && defined(HAVE_SPL) | ||
| EXPORT_SYMBOL(crypto_create_ctx_template); | ||
| EXPORT_SYMBOL(crypto_destroy_ctx_template); | ||
| #endif |
| @@ -0,0 +1,127 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2008 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/api.h> | ||
| #include <sys/crypto/impl.h> | ||
| #include <sys/crypto/sched_impl.h> | ||
| /* | ||
| * All event subscribers are put on a list. kcf_notify_list_lock | ||
| * protects changes to this list. | ||
| * | ||
| * The following locking order is maintained in the code - The | ||
| * global kcf_notify_list_lock followed by the individual lock | ||
| * in a kcf_ntfy_elem structure (kn_lock). | ||
| */ | ||
| kmutex_t ntfy_list_lock; | ||
| kcondvar_t ntfy_list_cv; /* cv the service thread waits on */ | ||
| static kcf_ntfy_elem_t *ntfy_list_head; | ||
| /* | ||
| * crypto_mech2id() | ||
| * | ||
| * Arguments: | ||
| * . mechname: A null-terminated string identifying the mechanism name. | ||
| * | ||
| * Description: | ||
| * Walks the mechanisms tables, looking for an entry that matches the | ||
| * mechname. Once it find it, it builds the 64-bit mech_type and returns | ||
| * it. If there are no hardware or software providers for the mechanism, | ||
| * but there is an unloaded software provider, this routine will attempt | ||
| * to load it. | ||
| * | ||
| * Context: | ||
| * Process and interruption. | ||
| * | ||
| * Returns: | ||
| * The unique mechanism identified by 'mechname', if found. | ||
| * CRYPTO_MECH_INVALID otherwise. | ||
| */ | ||
| crypto_mech_type_t | ||
| crypto_mech2id(char *mechname) | ||
| { | ||
| return (crypto_mech2id_common(mechname, B_TRUE)); | ||
| } | ||
| /* | ||
| * We walk the notification list and do the callbacks. | ||
| */ | ||
| void | ||
| kcf_walk_ntfylist(uint32_t event, void *event_arg) | ||
| { | ||
| kcf_ntfy_elem_t *nep; | ||
| int nelem = 0; | ||
| mutex_enter(&ntfy_list_lock); | ||
| /* | ||
| * Count how many clients are on the notification list. We need | ||
| * this count to ensure that clients which joined the list after we | ||
| * have started this walk, are not wrongly notified. | ||
| */ | ||
| for (nep = ntfy_list_head; nep != NULL; nep = nep->kn_next) | ||
| nelem++; | ||
| for (nep = ntfy_list_head; (nep != NULL && nelem); nep = nep->kn_next) { | ||
| nelem--; | ||
| /* | ||
| * Check if this client is interested in the | ||
| * event. | ||
| */ | ||
| if (!(nep->kn_event_mask & event)) | ||
| continue; | ||
| mutex_enter(&nep->kn_lock); | ||
| nep->kn_state = NTFY_RUNNING; | ||
| mutex_exit(&nep->kn_lock); | ||
| mutex_exit(&ntfy_list_lock); | ||
| /* | ||
| * We invoke the callback routine with no locks held. Another | ||
| * client could have joined the list meanwhile. This is fine | ||
| * as we maintain nelem as stated above. The NULL check in the | ||
| * for loop guards against shrinkage. Also, any callers of | ||
| * crypto_unnotify_events() at this point cv_wait till kn_state | ||
| * changes to NTFY_WAITING. Hence, nep is assured to be valid. | ||
| */ | ||
| (*nep->kn_func)(event, event_arg); | ||
| mutex_enter(&nep->kn_lock); | ||
| nep->kn_state = NTFY_WAITING; | ||
| cv_broadcast(&nep->kn_cv); | ||
| mutex_exit(&nep->kn_lock); | ||
| mutex_enter(&ntfy_list_lock); | ||
| } | ||
| mutex_exit(&ntfy_list_lock); | ||
| } | ||
| #if defined(_KERNEL) && defined(HAVE_SPL) | ||
| EXPORT_SYMBOL(crypto_mech2id); | ||
| #endif |
| @@ -0,0 +1,23 @@ | ||
| --------------------------------------------------------------------------- | ||
| Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. | ||
| LICENSE TERMS | ||
| The free distribution and use of this software is allowed (with or without | ||
| changes) provided that: | ||
| 1. source code distributions include the above copyright notice, this | ||
| list of conditions and the following disclaimer; | ||
| 2. binary distributions include the above copyright notice, this list | ||
| of conditions and the following disclaimer in their documentation; | ||
| 3. the name of the copyright holder is not used to endorse products | ||
| built using this software without specific written permission. | ||
| DISCLAIMER | ||
| This software is provided 'as is' with no explicit or implied warranties | ||
| in respect of its properties, including, but not limited to, correctness | ||
| and/or fitness for purpose. | ||
| --------------------------------------------------------------------------- |
| @@ -0,0 +1 @@ | ||
| PORTIONS OF AES FUNCTIONALITY |
| @@ -0,0 +1,127 @@ | ||
| LICENSE ISSUES | ||
| ============== | ||
| The OpenSSL toolkit stays under a dual license, i.e. both the conditions of | ||
| the OpenSSL License and the original SSLeay license apply to the toolkit. | ||
| See below for the actual license texts. Actually both licenses are BSD-style | ||
| Open Source licenses. In case of any license issues related to OpenSSL | ||
| please contact openssl-core@openssl.org. | ||
| OpenSSL License | ||
| --------------- | ||
| /* ==================================================================== | ||
| * Copyright (c) 1998-2008 The OpenSSL Project. All rights reserved. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * | ||
| * 1. Redistributions of source code must retain the above copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in | ||
| * the documentation and/or other materials provided with the | ||
| * distribution. | ||
| * | ||
| * 3. All advertising materials mentioning features or use of this | ||
| * software must display the following acknowledgment: | ||
| * "This product includes software developed by the OpenSSL Project | ||
| * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" | ||
| * | ||
| * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | ||
| * endorse or promote products derived from this software without | ||
| * prior written permission. For written permission, please contact | ||
| * openssl-core@openssl.org. | ||
| * | ||
| * 5. Products derived from this software may not be called "OpenSSL" | ||
| * nor may "OpenSSL" appear in their names without prior written | ||
| * permission of the OpenSSL Project. | ||
| * | ||
| * 6. Redistributions of any form whatsoever must retain the following | ||
| * acknowledgment: | ||
| * "This product includes software developed by the OpenSSL Project | ||
| * for use in the OpenSSL Toolkit (http://www.openssl.org/)" | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | ||
| * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR | ||
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | ||
| * OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| * ==================================================================== | ||
| * | ||
| * This product includes cryptographic software written by Eric Young | ||
| * (eay@cryptsoft.com). This product includes software written by Tim | ||
| * Hudson (tjh@cryptsoft.com). | ||
| * | ||
| */ | ||
| Original SSLeay License | ||
| ----------------------- | ||
| /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | ||
| * All rights reserved. | ||
| * | ||
| * This package is an SSL implementation written | ||
| * by Eric Young (eay@cryptsoft.com). | ||
| * The implementation was written so as to conform with Netscapes SSL. | ||
| * | ||
| * This library is free for commercial and non-commercial use as long as | ||
| * the following conditions are aheared to. The following conditions | ||
| * apply to all code found in this distribution, be it the RC4, RSA, | ||
| * lhash, DES, etc., code; not just the SSL code. The SSL documentation | ||
| * included with this distribution is covered by the same copyright terms | ||
| * except that the holder is Tim Hudson (tjh@cryptsoft.com). | ||
| * | ||
| * Copyright remains Eric Young's, and as such any Copyright notices in | ||
| * the code are not to be removed. | ||
| * If this package is used in a product, Eric Young should be given attribution | ||
| * as the author of the parts of the library used. | ||
| * This can be in the form of a textual message at program startup or | ||
| * in documentation (online or textual) provided with the package. | ||
| * | ||
| * Redistribution and use in source and binary forms, with or without | ||
| * modification, are permitted provided that the following conditions | ||
| * are met: | ||
| * 1. Redistributions of source code must retain the copyright | ||
| * notice, this list of conditions and the following disclaimer. | ||
| * 2. Redistributions in binary form must reproduce the above copyright | ||
| * notice, this list of conditions and the following disclaimer in the | ||
| * documentation and/or other materials provided with the distribution. | ||
| * 3. All advertising materials mentioning features or use of this software | ||
| * must display the following acknowledgement: | ||
| * "This product includes cryptographic software written by | ||
| * Eric Young (eay@cryptsoft.com)" | ||
| * The word 'cryptographic' can be left out if the rouines from the library | ||
| * being used are not cryptographic related :-). | ||
| * 4. If you include any Windows specific code (or a derivative thereof) from | ||
| * the apps directory (application code) you must include an acknowledgement: | ||
| * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | ||
| * | ||
| * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | ||
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| * SUCH DAMAGE. | ||
| * | ||
| * The licence and distribution terms for any publically available version or | ||
| * derivative of this code cannot be changed. i.e. this code cannot simply be | ||
| * copied and put under another distribution licence | ||
| * [including the GNU Public Licence.] | ||
| */ | ||
| @@ -0,0 +1 @@ | ||
| PORTIONS OF AES FUNCTIONALITY |
| @@ -0,0 +1,165 @@ | ||
| /* | ||
| * --------------------------------------------------------------------------- | ||
| * Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. | ||
| * | ||
| * LICENSE TERMS | ||
| * | ||
| * The free distribution and use of this software is allowed (with or without | ||
| * changes) provided that: | ||
| * | ||
| * 1. source code distributions include the above copyright notice, this | ||
| * list of conditions and the following disclaimer; | ||
| * | ||
| * 2. binary distributions include the above copyright notice, this list | ||
| * of conditions and the following disclaimer in their documentation; | ||
| * | ||
| * 3. the name of the copyright holder is not used to endorse products | ||
| * built using this software without specific written permission. | ||
| * | ||
| * DISCLAIMER | ||
| * | ||
| * This software is provided 'as is' with no explicit or implied warranties | ||
| * in respect of its properties, including, but not limited to, correctness | ||
| * and/or fitness for purpose. | ||
| * --------------------------------------------------------------------------- | ||
| * Issue Date: 20/12/2007 | ||
| * | ||
| * This file contains the code for declaring the tables needed to implement | ||
| * AES. The file aesopt.h is assumed to be included before this header file. | ||
| * If there are no global variables, the definitions here can be used to put | ||
| * the AES tables in a structure so that a pointer can then be added to the | ||
| * AES context to pass them to the AES routines that need them. If this | ||
| * facility is used, the calling program has to ensure that this pointer is | ||
| * managed appropriately. In particular, the value of the t_dec(in, it) item | ||
| * in the table structure must be set to zero in order to ensure that the | ||
| * tables are initialised. In practice the three code sequences in aeskey.c | ||
| * that control the calls to aes_init() and the aes_init() routine itself will | ||
| * have to be changed for a specific implementation. If global variables are | ||
| * available it will generally be preferable to use them with the precomputed | ||
| * FIXED_TABLES option that uses static global tables. | ||
| * | ||
| * The following defines can be used to control the way the tables | ||
| * are defined, initialised and used in embedded environments that | ||
| * require special features for these purposes | ||
| * | ||
| * the 't_dec' construction is used to declare fixed table arrays | ||
| * the 't_set' construction is used to set fixed table values | ||
| * the 't_use' construction is used to access fixed table values | ||
| * | ||
| * 256 byte tables: | ||
| * | ||
| * t_xxx(s, box) => forward S box | ||
| * t_xxx(i, box) => inverse S box | ||
| * | ||
| * 256 32-bit word OR 4 x 256 32-bit word tables: | ||
| * | ||
| * t_xxx(f, n) => forward normal round | ||
| * t_xxx(f, l) => forward last round | ||
| * t_xxx(i, n) => inverse normal round | ||
| * t_xxx(i, l) => inverse last round | ||
| * t_xxx(l, s) => key schedule table | ||
| * t_xxx(i, m) => key schedule table | ||
| * | ||
| * Other variables and tables: | ||
| * | ||
| * t_xxx(r, c) => the rcon table | ||
| */ | ||
| /* | ||
| * OpenSolaris OS modifications | ||
| * | ||
| * 1. Added __cplusplus and _AESTAB_H header guards | ||
| * 2. Added header file sys/types.h | ||
| * 3. Remove code defined for _MSC_VER | ||
| * 4. Changed all variables to "static const" | ||
| * 5. Changed uint_8t and uint_32t to uint8_t and uint32_t | ||
| * 6. Cstyled and hdrchk code | ||
| */ | ||
| #ifndef _AESTAB_H | ||
| #define _AESTAB_H | ||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
| #include <sys/types.h> | ||
| #define t_dec(m, n) t_##m##n | ||
| #define t_set(m, n) t_##m##n | ||
| #define t_use(m, n) t_##m##n | ||
| #if defined(DO_TABLES) && defined(FIXED_TABLES) | ||
| #define d_1(t, n, b, e) static const t n[256] = b(e) | ||
| #define d_4(t, n, b, e, f, g, h) static const t n[4][256] = \ | ||
| {b(e), b(f), b(g), b(h)} | ||
| static const uint32_t t_dec(r, c)[RC_LENGTH] = rc_data(w0); | ||
| #else | ||
| #define d_1(t, n, b, e) static const t n[256] | ||
| #define d_4(t, n, b, e, f, g, h) static const t n[4][256] | ||
| static const uint32_t t_dec(r, c)[RC_LENGTH]; | ||
| #endif | ||
| #if defined(SBX_SET) | ||
| d_1(uint8_t, t_dec(s, box), sb_data, h0); | ||
| #endif | ||
| #if defined(ISB_SET) | ||
| d_1(uint8_t, t_dec(i, box), isb_data, h0); | ||
| #endif | ||
| #if defined(FT1_SET) | ||
| d_1(uint32_t, t_dec(f, n), sb_data, u0); | ||
| #endif | ||
| #if defined(FT4_SET) | ||
| d_4(uint32_t, t_dec(f, n), sb_data, u0, u1, u2, u3); | ||
| #endif | ||
| #if defined(FL1_SET) | ||
| d_1(uint32_t, t_dec(f, l), sb_data, w0); | ||
| #endif | ||
| #if defined(FL4_SET) | ||
| d_4(uint32_t, t_dec(f, l), sb_data, w0, w1, w2, w3); | ||
| #endif | ||
| #if defined(IT1_SET) | ||
| d_1(uint32_t, t_dec(i, n), isb_data, v0); | ||
| #endif | ||
| #if defined(IT4_SET) | ||
| d_4(uint32_t, t_dec(i, n), isb_data, v0, v1, v2, v3); | ||
| #endif | ||
| #if defined(IL1_SET) | ||
| d_1(uint32_t, t_dec(i, l), isb_data, w0); | ||
| #endif | ||
| #if defined(IL4_SET) | ||
| d_4(uint32_t, t_dec(i, l), isb_data, w0, w1, w2, w3); | ||
| #endif | ||
| #if defined(LS1_SET) | ||
| #if defined(FL1_SET) | ||
| #undef LS1_SET | ||
| #else | ||
| d_1(uint32_t, t_dec(l, s), sb_data, w0); | ||
| #endif | ||
| #endif | ||
| #if defined(LS4_SET) | ||
| #if defined(FL4_SET) | ||
| #undef LS4_SET | ||
| #else | ||
| d_4(uint32_t, t_dec(l, s), sb_data, w0, w1, w2, w3); | ||
| #endif | ||
| #endif | ||
| #if defined(IM1_SET) | ||
| d_1(uint32_t, t_dec(i, m), mm_data, v0); | ||
| #endif | ||
| #if defined(IM4_SET) | ||
| d_4(uint32_t, t_dec(i, m), mm_data, v0, v1, v2, v3); | ||
| #endif | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
| #endif /* _AESTAB_H */ |
| @@ -0,0 +1,334 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 (c) 2009 Intel Corporation | ||
| * All Rights Reserved. | ||
| */ | ||
| /* | ||
| * Copyright 2009 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| /* | ||
| * Accelerated GHASH implementation with Intel PCLMULQDQ-NI | ||
| * instructions. This file contains an accelerated | ||
| * Galois Field Multiplication implementation. | ||
| * | ||
| * PCLMULQDQ is used to accelerate the most time-consuming part of GHASH, | ||
| * carry-less multiplication. More information about PCLMULQDQ can be | ||
| * found at: | ||
| * http://software.intel.com/en-us/articles/ | ||
| * carry-less-multiplication-and-its-usage-for-computing-the-gcm-mode/ | ||
| * | ||
| */ | ||
| /* | ||
| * ==================================================================== | ||
| * OpenSolaris OS modifications | ||
| * | ||
| * This source originates as file galois_hash_asm.c from | ||
| * Intel Corporation dated September 21, 2009. | ||
| * | ||
| * This OpenSolaris version has these major changes from the original source: | ||
| * | ||
| * 1. Added OpenSolaris ENTRY_NP/SET_SIZE macros from | ||
| * /usr/include/sys/asm_linkage.h, lint(1B) guards, and a dummy C function | ||
| * definition for lint. | ||
| * | ||
| * 2. Formatted code, added comments, and added #includes and #defines. | ||
| * | ||
| * 3. If bit CR0.TS is set, clear and set the TS bit, after and before | ||
| * calling kpreempt_disable() and kpreempt_enable(). | ||
| * If the TS bit is not set, Save and restore %xmm registers at the beginning | ||
| * and end of function calls (%xmm* registers are not saved and restored by | ||
| * during kernel thread preemption). | ||
| * | ||
| * 4. Removed code to perform hashing. This is already done with C macro | ||
| * GHASH in gcm.c. For better performance, this removed code should be | ||
| * reintegrated in the future to replace the C GHASH macro. | ||
| * | ||
| * 5. Added code to byte swap 16-byte input and output. | ||
| * | ||
| * 6. Folded in comments from the original C source with embedded assembly | ||
| * (SB_w_shift_xor.c) | ||
| * | ||
| * 7. Renamed function and reordered parameters to match OpenSolaris: | ||
| * Intel interface: | ||
| * void galois_hash_asm(unsigned char *hk, unsigned char *s, | ||
| * unsigned char *d, int length) | ||
| * OpenSolaris OS interface: | ||
| * void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res); | ||
| * ==================================================================== | ||
| */ | ||
| #if defined(lint) || defined(__lint) | ||
| #include <sys/types.h> | ||
| /* ARGSUSED */ | ||
| void | ||
| gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res) { | ||
| } | ||
| #else /* lint */ | ||
| #define _ASM | ||
| #include <sys/asm_linkage.h> | ||
| #ifdef _KERNEL | ||
| /* | ||
| * Note: the CLTS macro clobbers P2 (%rsi) under i86xpv. That is, | ||
| * it calls HYPERVISOR_fpu_taskswitch() which modifies %rsi when it | ||
| * uses it to pass P2 to syscall. | ||
| * This also occurs with the STTS macro, but we dont care if | ||
| * P2 (%rsi) is modified just before function exit. | ||
| * The CLTS and STTS macros push and pop P1 (%rdi) already. | ||
| */ | ||
| #ifdef __xpv | ||
| #define PROTECTED_CLTS \ | ||
| push %rsi; \ | ||
| CLTS; \ | ||
| pop %rsi | ||
| #else | ||
| #define PROTECTED_CLTS \ | ||
| CLTS | ||
| #endif /* __xpv */ | ||
| /* | ||
| * If CR0_TS is not set, align stack (with push %rbp) and push | ||
| * %xmm0 - %xmm10 on stack, otherwise clear CR0_TS | ||
| */ | ||
| #define CLEAR_TS_OR_PUSH_XMM_REGISTERS(tmpreg) \ | ||
| push %rbp; \ | ||
| mov %rsp, %rbp; \ | ||
| movq %cr0, tmpreg; \ | ||
| testq $CR0_TS, tmpreg; \ | ||
| jnz 1f; \ | ||
| and $-XMM_ALIGN, %rsp; \ | ||
| sub $[XMM_SIZE * 11], %rsp; \ | ||
| movaps %xmm0, 160(%rsp); \ | ||
| movaps %xmm1, 144(%rsp); \ | ||
| movaps %xmm2, 128(%rsp); \ | ||
| movaps %xmm3, 112(%rsp); \ | ||
| movaps %xmm4, 96(%rsp); \ | ||
| movaps %xmm5, 80(%rsp); \ | ||
| movaps %xmm6, 64(%rsp); \ | ||
| movaps %xmm7, 48(%rsp); \ | ||
| movaps %xmm8, 32(%rsp); \ | ||
| movaps %xmm9, 16(%rsp); \ | ||
| movaps %xmm10, (%rsp); \ | ||
| jmp 2f; \ | ||
| 1: \ | ||
| PROTECTED_CLTS; \ | ||
| 2: | ||
| /* | ||
| * If CR0_TS was not set above, pop %xmm0 - %xmm10 off stack, | ||
| * otherwise set CR0_TS. | ||
| */ | ||
| #define SET_TS_OR_POP_XMM_REGISTERS(tmpreg) \ | ||
| testq $CR0_TS, tmpreg; \ | ||
| jnz 1f; \ | ||
| movaps (%rsp), %xmm10; \ | ||
| movaps 16(%rsp), %xmm9; \ | ||
| movaps 32(%rsp), %xmm8; \ | ||
| movaps 48(%rsp), %xmm7; \ | ||
| movaps 64(%rsp), %xmm6; \ | ||
| movaps 80(%rsp), %xmm5; \ | ||
| movaps 96(%rsp), %xmm4; \ | ||
| movaps 112(%rsp), %xmm3; \ | ||
| movaps 128(%rsp), %xmm2; \ | ||
| movaps 144(%rsp), %xmm1; \ | ||
| movaps 160(%rsp), %xmm0; \ | ||
| jmp 2f; \ | ||
| 1: \ | ||
| STTS(tmpreg); \ | ||
| 2: \ | ||
| mov %rbp, %rsp; \ | ||
| pop %rbp | ||
| #else | ||
| #define PROTECTED_CLTS | ||
| #define CLEAR_TS_OR_PUSH_XMM_REGISTERS(tmpreg) | ||
| #define SET_TS_OR_POP_XMM_REGISTERS(tmpreg) | ||
| #endif /* _KERNEL */ | ||
| /* | ||
| * Use this mask to byte-swap a 16-byte integer with the pshufb instruction | ||
| */ | ||
| // static uint8_t byte_swap16_mask[] = { | ||
| // 15, 14, 13, 12, 11, 10, 9, 8, 7, 6 ,5, 4, 3, 2, 1, 0 }; | ||
| .text | ||
| .align XMM_ALIGN | ||
| .Lbyte_swap16_mask: | ||
| .byte 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 | ||
| /* | ||
| * void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res); | ||
| * | ||
| * Perform a carry-less multiplication (that is, use XOR instead of the | ||
| * multiply operator) on P1 and P2 and place the result in P3. | ||
| * | ||
| * Byte swap the input and the output. | ||
| * | ||
| * Note: x_in, y, and res all point to a block of 20-byte numbers | ||
| * (an array of two 64-bit integers). | ||
| * | ||
| * Note2: For kernel code, caller is responsible for ensuring | ||
| * kpreempt_disable() has been called. This is because %xmm registers are | ||
| * not saved/restored. Clear and set the CR0.TS bit on entry and exit, | ||
| * respectively, if TS is set on entry. Otherwise, if TS is not set, | ||
| * save and restore %xmm registers on the stack. | ||
| * | ||
| * Note3: Original Intel definition: | ||
| * void galois_hash_asm(unsigned char *hk, unsigned char *s, | ||
| * unsigned char *d, int length) | ||
| * | ||
| * Note4: Register/parameter mapping: | ||
| * Intel: | ||
| * Parameter 1: %rcx (copied to %xmm0) hk or x_in | ||
| * Parameter 2: %rdx (copied to %xmm1) s or y | ||
| * Parameter 3: %rdi (result) d or res | ||
| * OpenSolaris: | ||
| * Parameter 1: %rdi (copied to %xmm0) x_in | ||
| * Parameter 2: %rsi (copied to %xmm1) y | ||
| * Parameter 3: %rdx (result) res | ||
| */ | ||
| ENTRY_NP(gcm_mul_pclmulqdq) | ||
| CLEAR_TS_OR_PUSH_XMM_REGISTERS(%r10) | ||
| // | ||
| // Copy Parameters | ||
| // | ||
| movdqu (%rdi), %xmm0 // P1 | ||
| movdqu (%rsi), %xmm1 // P2 | ||
| // | ||
| // Byte swap 16-byte input | ||
| // | ||
| lea .Lbyte_swap16_mask(%rip), %rax | ||
| movaps (%rax), %xmm10 | ||
| pshufb %xmm10, %xmm0 | ||
| pshufb %xmm10, %xmm1 | ||
| // | ||
| // Multiply with the hash key | ||
| // | ||
| movdqu %xmm0, %xmm3 | ||
| pclmulqdq $0, %xmm1, %xmm3 // xmm3 holds a0*b0 | ||
| movdqu %xmm0, %xmm4 | ||
| pclmulqdq $16, %xmm1, %xmm4 // xmm4 holds a0*b1 | ||
| movdqu %xmm0, %xmm5 | ||
| pclmulqdq $1, %xmm1, %xmm5 // xmm5 holds a1*b0 | ||
| movdqu %xmm0, %xmm6 | ||
| pclmulqdq $17, %xmm1, %xmm6 // xmm6 holds a1*b1 | ||
| pxor %xmm5, %xmm4 // xmm4 holds a0*b1 + a1*b0 | ||
| movdqu %xmm4, %xmm5 // move the contents of xmm4 to xmm5 | ||
| psrldq $8, %xmm4 // shift by xmm4 64 bits to the right | ||
| pslldq $8, %xmm5 // shift by xmm5 64 bits to the left | ||
| pxor %xmm5, %xmm3 | ||
| pxor %xmm4, %xmm6 // Register pair <xmm6:xmm3> holds the result | ||
| // of the carry-less multiplication of | ||
| // xmm0 by xmm1. | ||
| // We shift the result of the multiplication by one bit position | ||
| // to the left to cope for the fact that the bits are reversed. | ||
| movdqu %xmm3, %xmm7 | ||
| movdqu %xmm6, %xmm8 | ||
| pslld $1, %xmm3 | ||
| pslld $1, %xmm6 | ||
| psrld $31, %xmm7 | ||
| psrld $31, %xmm8 | ||
| movdqu %xmm7, %xmm9 | ||
| pslldq $4, %xmm8 | ||
| pslldq $4, %xmm7 | ||
| psrldq $12, %xmm9 | ||
| por %xmm7, %xmm3 | ||
| por %xmm8, %xmm6 | ||
| por %xmm9, %xmm6 | ||
| // | ||
| // First phase of the reduction | ||
| // | ||
| // Move xmm3 into xmm7, xmm8, xmm9 in order to perform the shifts | ||
| // independently. | ||
| movdqu %xmm3, %xmm7 | ||
| movdqu %xmm3, %xmm8 | ||
| movdqu %xmm3, %xmm9 | ||
| pslld $31, %xmm7 // packed right shift shifting << 31 | ||
| pslld $30, %xmm8 // packed right shift shifting << 30 | ||
| pslld $25, %xmm9 // packed right shift shifting << 25 | ||
| pxor %xmm8, %xmm7 // xor the shifted versions | ||
| pxor %xmm9, %xmm7 | ||
| movdqu %xmm7, %xmm8 | ||
| pslldq $12, %xmm7 | ||
| psrldq $4, %xmm8 | ||
| pxor %xmm7, %xmm3 // first phase of the reduction complete | ||
| // | ||
| // Second phase of the reduction | ||
| // | ||
| // Make 3 copies of xmm3 in xmm2, xmm4, xmm5 for doing these | ||
| // shift operations. | ||
| movdqu %xmm3, %xmm2 | ||
| movdqu %xmm3, %xmm4 // packed left shifting >> 1 | ||
| movdqu %xmm3, %xmm5 | ||
| psrld $1, %xmm2 | ||
| psrld $2, %xmm4 // packed left shifting >> 2 | ||
| psrld $7, %xmm5 // packed left shifting >> 7 | ||
| pxor %xmm4, %xmm2 // xor the shifted versions | ||
| pxor %xmm5, %xmm2 | ||
| pxor %xmm8, %xmm2 | ||
| pxor %xmm2, %xmm3 | ||
| pxor %xmm3, %xmm6 // the result is in xmm6 | ||
| // | ||
| // Byte swap 16-byte result | ||
| // | ||
| pshufb %xmm10, %xmm6 // %xmm10 has the swap mask | ||
| // | ||
| // Store the result | ||
| // | ||
| movdqu %xmm6, (%rdx) // P3 | ||
| // | ||
| // Cleanup and Return | ||
| // | ||
| SET_TS_OR_POP_XMM_REGISTERS(%r10) | ||
| ret | ||
| SET_SIZE(gcm_mul_pclmulqdq) | ||
| #endif /* lint || __lint */ |
| @@ -0,0 +1,229 @@ | ||
| /* | ||
| * 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://www.opensolaris.org/os/licensing. | ||
| * 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 2009 Sun Microsystems, Inc. All rights reserved. | ||
| * Use is subject to license terms. | ||
| */ | ||
| #include <sys/zfs_context.h> | ||
| #include <modes/modes.h> | ||
| #include <sys/crypto/common.h> | ||
| #include <sys/crypto/impl.h> | ||
| /* | ||
| * Utility routine to copy a buffer to a crypto_data structure. | ||
| */ | ||
| /* | ||
| * Utility routine to apply the command, 'cmd', to the | ||
| * data in the uio structure. | ||
| */ | ||
| int | ||
| crypto_uio_data(crypto_data_t *data, uchar_t *buf, int len, cmd_type_t cmd, | ||
| void *digest_ctx, void (*update)(void)) | ||
| { | ||
| uio_t *uiop = data->cd_uio; | ||
| off_t offset = data->cd_offset; | ||
| size_t length = len; | ||
| uint_t vec_idx; | ||
| size_t cur_len; | ||
| uchar_t *datap; | ||
| ASSERT(data->cd_format == CRYPTO_DATA_UIO); | ||
| if (uiop->uio_segflg != UIO_SYSSPACE) { | ||
| return (CRYPTO_ARGUMENTS_BAD); | ||
| } | ||
| /* | ||
| * Jump to the first iovec containing data to be | ||
| * processed. | ||
| */ | ||
| for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && | ||
| offset >= uiop->uio_iov[vec_idx].iov_len; | ||
| offset -= uiop->uio_iov[vec_idx++].iov_len) | ||
| ; | ||
| if (vec_idx == uiop->uio_iovcnt) { | ||
| /* | ||
| * The caller specified an offset that is larger than | ||
| * the total size of the buffers it provided. | ||
| */ | ||
| return (CRYPTO_DATA_LEN_RANGE); | ||
| } | ||
| while (vec_idx < uiop->uio_iovcnt && length > 0) { | ||
| cur_len = MIN(uiop->uio_iov[vec_idx].iov_len - | ||
| offset, length); | ||
| datap = (uchar_t *)(uiop->uio_iov[vec_idx].iov_base + | ||
| offset); | ||
| switch (cmd) { | ||
| case COPY_FROM_DATA: | ||
| bcopy(datap, buf, cur_len); | ||
| buf += cur_len; | ||
| break; | ||
| case COPY_TO_DATA: | ||
| bcopy(buf, datap, cur_len); | ||
| buf += cur_len; | ||
| break; | ||
| case COMPARE_TO_DATA: | ||
| if (bcmp(datap, buf, cur_len)) | ||
| return (CRYPTO_SIGNATURE_INVALID); | ||
| buf += cur_len; | ||
| break; | ||
| case MD5_DIGEST_DATA: | ||
| case SHA1_DIGEST_DATA: | ||
| case SHA2_DIGEST_DATA: | ||
| case GHASH_DATA: | ||
| return (CRYPTO_ARGUMENTS_BAD); | ||
| } | ||
| length -= cur_len; | ||
| vec_idx++; | ||
| offset = 0; | ||
| } | ||
| if (vec_idx == uiop->uio_iovcnt && length > 0) { | ||
| /* | ||
| * The end of the specified iovec's was reached but | ||
| * the length requested could not be processed. | ||
| */ | ||
| switch (cmd) { | ||
| case COPY_TO_DATA: | ||
| data->cd_length = len; | ||
| return (CRYPTO_BUFFER_TOO_SMALL); | ||
| default: | ||
| return (CRYPTO_DATA_LEN_RANGE); | ||
| } | ||
| } | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| int | ||
| crypto_put_output_data(uchar_t *buf, crypto_data_t *output, int len) | ||
| { | ||
| switch (output->cd_format) { | ||
| case CRYPTO_DATA_RAW: | ||
| if (output->cd_raw.iov_len < len) { | ||
| output->cd_length = len; | ||
| return (CRYPTO_BUFFER_TOO_SMALL); | ||
| } | ||
| bcopy(buf, (uchar_t *)(output->cd_raw.iov_base + | ||
| output->cd_offset), len); | ||
| break; | ||
| case CRYPTO_DATA_UIO: | ||
| return (crypto_uio_data(output, buf, len, | ||
| COPY_TO_DATA, NULL, NULL)); | ||
| default: | ||
| return (CRYPTO_ARGUMENTS_BAD); | ||
| } | ||
| return (CRYPTO_SUCCESS); | ||
| } | ||
| int | ||
| crypto_update_iov(void *ctx, crypto_data_t *input, crypto_data_t *output, | ||
| int (*cipher)(void *, caddr_t, size_t, crypto_data_t *), | ||
| void (*copy_block)(uint8_t *, uint64_t *)) | ||
| { | ||
| common_ctx_t *common_ctx = ctx; | ||
| int rv; | ||
| if (input->cd_miscdata != NULL) { | ||
| copy_block((uint8_t *)input->cd_miscdata, | ||
| &common_ctx->cc_iv[0]); | ||
| } | ||
| if (input->cd_raw.iov_len < input->cd_length) | ||
| return (CRYPTO_ARGUMENTS_BAD); | ||
| rv = (cipher)(ctx, input->cd_raw.iov_base + input->cd_offset, | ||
| input->cd_length, (input == output) ? NULL : output); | ||
| return (rv); | ||
| } | ||
| int | ||
| crypto_update_uio(void *ctx, crypto_data_t *input, crypto_data_t *output, | ||
| int (*cipher)(void *, caddr_t, size_t, crypto_data_t *), | ||
| void (*copy_block)(uint8_t *, uint64_t *)) | ||
| { | ||
| common_ctx_t *common_ctx = ctx; | ||
| uio_t *uiop = input->cd_uio; | ||
| off_t offset = input->cd_offset; | ||
| size_t length = input->cd_length; | ||
| uint_t vec_idx; | ||
| size_t cur_len; | ||
| if (input->cd_miscdata != NULL) { | ||
| copy_block((uint8_t *)input->cd_miscdata, | ||
| &common_ctx->cc_iv[0]); | ||
| } | ||
| if (input->cd_uio->uio_segflg != UIO_SYSSPACE) { | ||
| return (CRYPTO_ARGUMENTS_BAD); | ||
| } | ||
| /* | ||
| * Jump to the first iovec containing data to be | ||
| * processed. | ||
| */ | ||
| for (vec_idx = 0; vec_idx < uiop->uio_iovcnt && | ||
| offset >= uiop->uio_iov[vec_idx].iov_len; | ||
| offset -= uiop->uio_iov[vec_idx++].iov_len) | ||
| ; | ||
| if (vec_idx == uiop->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 process the iovecs. | ||
| */ | ||
| while (vec_idx < uiop->uio_iovcnt && length > 0) { | ||
| cur_len = MIN(uiop->uio_iov[vec_idx].iov_len - | ||
| offset, length); | ||
| (cipher)(ctx, uiop->uio_iov[vec_idx].iov_base + offset, | ||
| cur_len, (input == output) ? NULL : output); | ||
| length -= cur_len; | ||
| vec_idx++; | ||
| offset = 0; | ||
| } | ||
| if (vec_idx == uiop->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); | ||
| } |