mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-25 02:49:32 +03:00
Illumos Crypto Port module added to enable native encryption in zfs
A port of the Illumos Crypto Framework to a Linux kernel module (found in module/icp). This is needed to do the actual encryption work. We cannot use the Linux kernel's built in crypto api because it is only exported to GPL-licensed modules. Having the ICP also means the crypto code can run on any of the other kernels under OpenZFS. I ended up porting over most of the internals of the framework, which means that porting over other API calls (if we need them) should be fairly easy. Specifically, I have ported over the API functions related to encryption, digests, macs, and crypto templates. The ICP is able to use assembly-accelerated encryption on amd64 machines and AES-NI instructions on Intel chips that support it. There are place-holder directories for similar assembly optimizations for other architectures (although they have not been written). Signed-off-by: Tom Caputi <tcaputi@datto.com> Signed-off-by: Tony Hutter <hutter2@llnl.gov> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Issue #4329
This commit is contained in:
parent
be88e733a6
commit
0b04990a5d
1
.gitignore
vendored
1
.gitignore
vendored
@ -21,6 +21,7 @@
|
||||
*.swp
|
||||
.deps
|
||||
.libs
|
||||
.dirstamp
|
||||
.DS_Store
|
||||
modules.order
|
||||
Makefile
|
||||
|
22
config/always-arch.m4
Normal file
22
config/always-arch.m4
Normal file
@ -0,0 +1,22 @@
|
||||
dnl #
|
||||
dnl # Set the target arch for libspl atomic implementation and the icp
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_CONFIG_ALWAYS_ARCH], [
|
||||
AC_MSG_CHECKING(for target asm dir)
|
||||
TARGET_ARCH=`echo ${target_cpu} | sed -e s/i.86/i386/`
|
||||
|
||||
case $TARGET_ARCH in
|
||||
i386|x86_64)
|
||||
TARGET_ASM_DIR=asm-${TARGET_ARCH}
|
||||
;;
|
||||
*)
|
||||
TARGET_ASM_DIR=asm-generic
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST([TARGET_ASM_DIR])
|
||||
AM_CONDITIONAL([TARGET_ASM_X86_64], test $TARGET_ASM_DIR = asm-x86_64)
|
||||
AM_CONDITIONAL([TARGET_ASM_I386], test $TARGET_ASM_DIR = asm-i386)
|
||||
AM_CONDITIONAL([TARGET_ASM_GENERIC], test $TARGET_ASM_DIR = asm-generic)
|
||||
AC_MSG_RESULT([$TARGET_ASM_DIR])
|
||||
])
|
@ -1,19 +0,0 @@
|
||||
dnl #
|
||||
dnl # Set the target arch for libspl atomic implementation
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_CONFIG_USER_ARCH], [
|
||||
AC_MSG_CHECKING(for target asm dir)
|
||||
TARGET_ARCH=`echo ${target_cpu} | sed -e s/i.86/i386/`
|
||||
|
||||
case $TARGET_ARCH in
|
||||
i386|x86_64)
|
||||
TARGET_ASM_DIR=asm-${TARGET_ARCH}
|
||||
;;
|
||||
*)
|
||||
TARGET_ASM_DIR=asm-generic
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_SUBST([TARGET_ASM_DIR])
|
||||
AC_MSG_RESULT([$TARGET_ASM_DIR])
|
||||
])
|
@ -7,7 +7,6 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
|
||||
ZFS_AC_CONFIG_USER_SYSTEMD
|
||||
ZFS_AC_CONFIG_USER_SYSVINIT
|
||||
ZFS_AC_CONFIG_USER_DRACUT
|
||||
ZFS_AC_CONFIG_USER_ARCH
|
||||
ZFS_AC_CONFIG_USER_ZLIB
|
||||
ZFS_AC_CONFIG_USER_LIBUUID
|
||||
ZFS_AC_CONFIG_USER_LIBTIRPC
|
||||
|
@ -64,12 +64,10 @@ AC_DEFUN([ZFS_AC_CONFIG_ALWAYS], [
|
||||
ZFS_AC_CONFIG_ALWAYS_NO_UNUSED_BUT_SET_VARIABLE
|
||||
ZFS_AC_CONFIG_ALWAYS_NO_BOOL_COMPARE
|
||||
ZFS_AC_CONFIG_ALWAYS_TOOLCHAIN_SIMD
|
||||
ZFS_AC_CONFIG_ALWAYS_ARCH
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_CONFIG], [
|
||||
TARGET_ASM_DIR=asm-generic
|
||||
AC_SUBST(TARGET_ASM_DIR)
|
||||
|
||||
ZFS_CONFIG=all
|
||||
AC_ARG_WITH([config],
|
||||
AS_HELP_STRING([--with-config=CONFIG],
|
||||
|
@ -39,7 +39,7 @@ AC_CONFIG_MACRO_DIR([config])
|
||||
AC_CANONICAL_SYSTEM
|
||||
AM_MAINTAINER_MODE
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
AM_INIT_AUTOMAKE
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
AC_CONFIG_HEADERS([zfs_config.h], [
|
||||
(mv zfs_config.h zfs_config.h.tmp &&
|
||||
awk -f ${ac_srcdir}/config/config.awk zfs_config.h.tmp >zfs_config.h &&
|
||||
@ -85,6 +85,7 @@ AC_CONFIG_FILES([
|
||||
lib/libspl/include/util/Makefile
|
||||
lib/libavl/Makefile
|
||||
lib/libefi/Makefile
|
||||
lib/libicp/Makefile
|
||||
lib/libnvpair/Makefile
|
||||
lib/libunicode/Makefile
|
||||
lib/libuutil/Makefile
|
||||
@ -125,12 +126,14 @@ AC_CONFIG_FILES([
|
||||
module/zcommon/Makefile
|
||||
module/zfs/Makefile
|
||||
module/zpios/Makefile
|
||||
module/icp/Makefile
|
||||
include/Makefile
|
||||
include/linux/Makefile
|
||||
include/sys/Makefile
|
||||
include/sys/fs/Makefile
|
||||
include/sys/fm/Makefile
|
||||
include/sys/fm/fs/Makefile
|
||||
include/sys/crypto/Makefile
|
||||
scripts/Makefile
|
||||
scripts/zpios-profile/Makefile
|
||||
scripts/zpios-test/Makefile
|
||||
|
19
copy-builtin
19
copy-builtin
@ -34,27 +34,8 @@ cp --recursive include "$KERNEL_DIR/include/zfs"
|
||||
cp --recursive module "$KERNEL_DIR/fs/zfs"
|
||||
cp zfs_config.h "$KERNEL_DIR/"
|
||||
|
||||
adjust_obj_paths()
|
||||
{
|
||||
local FILE="$1"
|
||||
local LINE OBJPATH
|
||||
|
||||
while IFS='' read -r LINE
|
||||
do
|
||||
OBJPATH="${LINE#\$(MODULE)-objs += }"
|
||||
if [ "$OBJPATH" = "$LINE" ]
|
||||
then
|
||||
echo "$LINE"
|
||||
else
|
||||
echo "\$(MODULE)-objs += ${OBJPATH##*/}"
|
||||
fi
|
||||
done < "$FILE" > "$FILE.new"
|
||||
mv "$FILE.new" "$FILE"
|
||||
}
|
||||
|
||||
for MODULE in "${MODULES[@]}"
|
||||
do
|
||||
adjust_obj_paths "$KERNEL_DIR/fs/zfs/$MODULE/Makefile"
|
||||
sed -i.bak '/obj =/d' "$KERNEL_DIR/fs/zfs/$MODULE/Makefile"
|
||||
sed -i.bak '/src =/d' "$KERNEL_DIR/fs/zfs/$MODULE/Makefile"
|
||||
done
|
||||
|
@ -1,4 +1,4 @@
|
||||
SUBDIRS = fm fs
|
||||
SUBDIRS = fm fs crypto
|
||||
|
||||
COMMON_H = \
|
||||
$(top_srcdir)/include/sys/arc.h \
|
||||
|
20
include/sys/crypto/Makefile.am
Normal file
20
include/sys/crypto/Makefile.am
Normal file
@ -0,0 +1,20 @@
|
||||
COMMON_H = \
|
||||
$(top_srcdir)/include/sys/crypto/api.h \
|
||||
$(top_srcdir)/include/sys/crypto/common.h \
|
||||
$(top_srcdir)/include/sys/crypto/icp.h
|
||||
|
||||
KERNEL_H =
|
||||
|
||||
USER_H =
|
||||
|
||||
EXTRA_DIST = $(COMMON_H) $(KERNEL_H) $(USER_H)
|
||||
|
||||
if CONFIG_USER
|
||||
libzfsdir = $(includedir)/libzfs/sys/crypto
|
||||
libzfs_HEADERS = $(COMMON_H) $(USER_H)
|
||||
endif
|
||||
|
||||
if CONFIG_KERNEL
|
||||
kerneldir = @prefix@/src/zfs-$(VERSION)/include/sys/crypto
|
||||
kernel_HEADERS = $(COMMON_H) $(KERNEL_H)
|
||||
endif
|
425
include/sys/crypto/api.h
Normal file
425
include/sys/crypto/api.h
Normal file
@ -0,0 +1,425 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_API_H
|
||||
#define _SYS_CRYPTO_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
|
||||
typedef long crypto_req_id_t;
|
||||
typedef void *crypto_bc_t;
|
||||
typedef void *crypto_context_t;
|
||||
typedef void *crypto_ctx_template_t;
|
||||
|
||||
typedef uint32_t crypto_call_flag_t;
|
||||
|
||||
/* crypto_call_flag's values */
|
||||
#define CRYPTO_ALWAYS_QUEUE 0x00000001 /* ALWAYS queue the req. */
|
||||
#define CRYPTO_NOTIFY_OPDONE 0x00000002 /* Notify intermediate steps */
|
||||
#define CRYPTO_SKIP_REQID 0x00000004 /* Skip request ID generation */
|
||||
#define CRYPTO_RESTRICTED 0x00000008 /* cannot use restricted prov */
|
||||
|
||||
typedef struct {
|
||||
crypto_call_flag_t cr_flag;
|
||||
void (*cr_callback_func)(void *, int);
|
||||
void *cr_callback_arg;
|
||||
crypto_req_id_t cr_reqid;
|
||||
} crypto_call_req_t;
|
||||
|
||||
/*
|
||||
* Returns the mechanism type corresponding to a mechanism name.
|
||||
*/
|
||||
|
||||
#define CRYPTO_MECH_INVALID ((uint64_t)-1)
|
||||
extern crypto_mech_type_t crypto_mech2id(crypto_mech_name_t name);
|
||||
|
||||
/*
|
||||
* Create and destroy context templates.
|
||||
*/
|
||||
extern int crypto_create_ctx_template(crypto_mechanism_t *mech,
|
||||
crypto_key_t *key, crypto_ctx_template_t *tmpl, int kmflag);
|
||||
extern void crypto_destroy_ctx_template(crypto_ctx_template_t tmpl);
|
||||
|
||||
/*
|
||||
* Single and multi-part digest operations.
|
||||
*/
|
||||
extern int crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
|
||||
crypto_data_t *digest, crypto_call_req_t *cr);
|
||||
extern int crypto_digest_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *, crypto_data_t *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_digest_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_digest_update(crypto_context_t ctx, crypto_data_t *data,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_digest_final(crypto_context_t ctx, crypto_data_t *digest,
|
||||
crypto_call_req_t *cr);
|
||||
|
||||
/*
|
||||
* Single and multi-part MAC operations.
|
||||
*/
|
||||
extern int crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_mac_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
extern int crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_mac_verify_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
extern int crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
|
||||
extern int crypto_mac_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
|
||||
crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_mac_update(crypto_context_t ctx, crypto_data_t *data,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_mac_final(crypto_context_t ctx, crypto_data_t *data,
|
||||
crypto_call_req_t *cr);
|
||||
|
||||
/*
|
||||
* Single and multi-part sign with private key operations.
|
||||
*/
|
||||
extern int crypto_sign(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_data_t *data, crypto_ctx_template_t tmpl,
|
||||
crypto_data_t *signature, crypto_call_req_t *cr);
|
||||
extern int crypto_sign_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
extern int crypto_sign_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
|
||||
extern int crypto_sign_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
|
||||
crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_sign_update(crypto_context_t ctx, crypto_data_t *data,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_sign_final(crypto_context_t ctx, crypto_data_t *signature,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_sign_recover_init_prov(crypto_provider_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_sign_recover(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_sign_recover_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
|
||||
/*
|
||||
* Single and multi-part verify with public key operations.
|
||||
*/
|
||||
extern int crypto_verify(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_data_t *data, crypto_ctx_template_t tmpl, crypto_data_t *signature,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_verify_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
extern int crypto_verify_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
|
||||
extern int crypto_verify_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
|
||||
crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_verify_update(crypto_context_t ctx, crypto_data_t *data,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_verify_final(crypto_context_t ctx, crypto_data_t *signature,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_verify_recover_init_prov(crypto_provider_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_verify_recover(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_data_t *signature, crypto_ctx_template_t tmpl, crypto_data_t *data,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_verify_recover_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_data_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
|
||||
/*
|
||||
* Single and multi-part encryption operations.
|
||||
*/
|
||||
extern int crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_encrypt_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
extern int crypto_encrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp, crypto_call_req_t *cr);
|
||||
extern int crypto_encrypt_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
|
||||
crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_encrypt_update(crypto_context_t ctx,
|
||||
crypto_data_t *plaintext, crypto_data_t *ciphertext,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_encrypt_final(crypto_context_t ctx,
|
||||
crypto_data_t *ciphertext, crypto_call_req_t *cr);
|
||||
|
||||
/*
|
||||
* Single and multi-part decryption operations.
|
||||
*/
|
||||
extern int crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_decrypt_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t, crypto_data_t *, crypto_call_req_t *);
|
||||
extern int crypto_decrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_decrypt_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_ctx_template_t,
|
||||
crypto_context_t *, crypto_call_req_t *);
|
||||
extern int crypto_decrypt_update(crypto_context_t ctx,
|
||||
crypto_data_t *ciphertext, crypto_data_t *plaintext,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_decrypt_final(crypto_context_t ctx, crypto_data_t *plaintext,
|
||||
crypto_call_req_t *cr);
|
||||
|
||||
/*
|
||||
* Single and multi-part encrypt/MAC dual operations.
|
||||
*/
|
||||
extern int crypto_encrypt_mac(crypto_mechanism_t *encr_mech,
|
||||
crypto_mechanism_t *mac_mech, crypto_data_t *pt,
|
||||
crypto_key_t *encr_key, crypto_key_t *mac_key,
|
||||
crypto_ctx_template_t encr_tmpl, crypto_ctx_template_t mac_tmpl,
|
||||
crypto_dual_data_t *ct, crypto_data_t *mac, crypto_call_req_t *cr);
|
||||
extern int crypto_encrypt_mac_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_mechanism_t *, crypto_data_t *,
|
||||
crypto_key_t *, crypto_key_t *, crypto_ctx_template_t,
|
||||
crypto_ctx_template_t, crypto_dual_data_t *, crypto_data_t *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_encrypt_mac_init(crypto_mechanism_t *encr_mech,
|
||||
crypto_mechanism_t *mac_mech, crypto_key_t *encr_key,
|
||||
crypto_key_t *mac_key, crypto_ctx_template_t encr_tmpl,
|
||||
crypto_ctx_template_t mac_tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_encrypt_mac_init_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_mechanism_t *, crypto_key_t *, crypto_key_t *,
|
||||
crypto_ctx_template_t, crypto_ctx_template_t, crypto_context_t *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_encrypt_mac_update(crypto_context_t ctx,
|
||||
crypto_data_t *pt, crypto_dual_data_t *ct, crypto_call_req_t *cr);
|
||||
extern int crypto_encrypt_mac_final(crypto_context_t ctx,
|
||||
crypto_dual_data_t *ct, crypto_data_t *mac, crypto_call_req_t *cr);
|
||||
|
||||
/*
|
||||
* Single and multi-part MAC/decrypt dual operations.
|
||||
*/
|
||||
extern int crypto_mac_decrypt(crypto_mechanism_t *mac_mech,
|
||||
crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
|
||||
crypto_key_t *mac_key, crypto_key_t *decr_key,
|
||||
crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
|
||||
crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
|
||||
extern int crypto_mac_decrypt_prov(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *mac_mech, crypto_mechanism_t *decr_mech,
|
||||
crypto_dual_data_t *ct, crypto_key_t *mac_key, crypto_key_t *decr_key,
|
||||
crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
|
||||
crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
|
||||
extern int crypto_mac_verify_decrypt(crypto_mechanism_t *mac_mech,
|
||||
crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
|
||||
crypto_key_t *mac_key, crypto_key_t *decr_key,
|
||||
crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
|
||||
crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
|
||||
extern int crypto_mac_verify_decrypt_prov(crypto_provider_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *mac_mech,
|
||||
crypto_mechanism_t *decr_mech, crypto_dual_data_t *ct,
|
||||
crypto_key_t *mac_key, crypto_key_t *decr_key,
|
||||
crypto_ctx_template_t mac_tmpl, crypto_ctx_template_t decr_tmpl,
|
||||
crypto_data_t *mac, crypto_data_t *pt, crypto_call_req_t *cr);
|
||||
extern int crypto_mac_decrypt_init(crypto_mechanism_t *mac_mech,
|
||||
crypto_mechanism_t *decr_mech, crypto_key_t *mac_key,
|
||||
crypto_key_t *decr_key, crypto_ctx_template_t mac_tmpl,
|
||||
crypto_ctx_template_t decr_tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_mac_decrypt_init_prov(crypto_provider_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *mac_mech,
|
||||
crypto_mechanism_t *decr_mech, crypto_key_t *mac_key,
|
||||
crypto_key_t *decr_key, crypto_ctx_template_t mac_tmpl,
|
||||
crypto_ctx_template_t decr_tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *cr);
|
||||
extern int crypto_mac_decrypt_update(crypto_context_t ctx,
|
||||
crypto_dual_data_t *ct, crypto_data_t *pt, crypto_call_req_t *cr);
|
||||
extern int crypto_mac_decrypt_final(crypto_context_t ctx, crypto_data_t *mac,
|
||||
crypto_data_t *pt, crypto_call_req_t *cr);
|
||||
|
||||
/* Session Management */
|
||||
extern int crypto_session_open(crypto_provider_t, crypto_session_id_t *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_session_close(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_session_login(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_user_type_t, char *, size_t, crypto_call_req_t *);
|
||||
extern int crypto_session_logout(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_call_req_t *);
|
||||
|
||||
/* Object Management */
|
||||
extern int crypto_object_copy(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_object_id_t, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_id_t *, crypto_call_req_t *);
|
||||
extern int crypto_object_create(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_object_destroy(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_object_id_t, crypto_call_req_t *);
|
||||
extern int crypto_object_get_attribute_value(crypto_provider_t,
|
||||
crypto_session_id_t, crypto_object_id_t, crypto_object_attribute_t *,
|
||||
uint_t, crypto_call_req_t *);
|
||||
extern int crypto_object_get_size(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_object_id_t, size_t *, crypto_call_req_t *);
|
||||
extern int crypto_object_find_final(crypto_provider_t, void *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_object_find_init(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_object_attribute_t *, uint_t, void **, crypto_call_req_t *);
|
||||
extern int crypto_object_find(crypto_provider_t, void *, crypto_object_id_t *,
|
||||
uint_t *, uint_t, crypto_call_req_t *);
|
||||
extern int crypto_object_set_attribute_value(crypto_provider_t,
|
||||
crypto_session_id_t, crypto_object_id_t, crypto_object_attribute_t *,
|
||||
uint_t, crypto_call_req_t *);
|
||||
|
||||
/* Key Management */
|
||||
extern int crypto_key_derive(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
|
||||
uint_t, crypto_object_id_t *, crypto_call_req_t *);
|
||||
extern int crypto_key_generate(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_id_t *, crypto_call_req_t *);
|
||||
extern int crypto_key_generate_pair(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
|
||||
crypto_object_id_t *, crypto_call_req_t *);
|
||||
extern int crypto_key_unwrap(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
|
||||
crypto_call_req_t *);
|
||||
extern int crypto_key_wrap(crypto_provider_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *, uchar_t *,
|
||||
size_t *, crypto_call_req_t *);
|
||||
extern int crypto_key_check_prov(crypto_provider_t, crypto_mechanism_t *mech,
|
||||
crypto_key_t *key);
|
||||
extern int crypto_key_check(crypto_mechanism_t *mech, crypto_key_t *key);
|
||||
|
||||
|
||||
/*
|
||||
* Routines to cancel a single asynchronous request or all asynchronous
|
||||
* requests associated with a particular context.
|
||||
*/
|
||||
extern void crypto_cancel_req(crypto_req_id_t req);
|
||||
extern void crypto_cancel_ctx(crypto_context_t ctx);
|
||||
|
||||
/*
|
||||
* crypto_get_mech_list(9F) allocates and returns the list of currently
|
||||
* supported cryptographic mechanisms.
|
||||
*/
|
||||
extern crypto_mech_name_t *crypto_get_mech_list(uint_t *count, int kmflag);
|
||||
extern void crypto_free_mech_list(crypto_mech_name_t *mech_names,
|
||||
uint_t count);
|
||||
|
||||
extern crypto_provider_t crypto_get_provider(char *, char *, char *);
|
||||
extern int crypto_get_provinfo(crypto_provider_t, crypto_provider_ext_info_t *);
|
||||
extern void crypto_release_provider(crypto_provider_t);
|
||||
|
||||
/*
|
||||
* A kernel consumer can request to be notified when some particular event
|
||||
* occurs. The valid events, callback function type, and functions to
|
||||
* be called to register or unregister for notification are defined below.
|
||||
*/
|
||||
|
||||
#define CRYPTO_EVENT_MECHS_CHANGED 0x00000001
|
||||
#define CRYPTO_EVENT_PROVIDER_REGISTERED 0x00000002
|
||||
#define CRYPTO_EVENT_PROVIDER_UNREGISTERED 0x00000004
|
||||
|
||||
typedef enum {
|
||||
CRYPTO_MECH_ADDED = 1,
|
||||
CRYPTO_MECH_REMOVED
|
||||
} crypto_event_change_t;
|
||||
|
||||
/* The event_arg argument structure for CRYPTO_EVENT_PROVIDERS_CHANGE event */
|
||||
typedef struct crypto_notify_event_change {
|
||||
crypto_mech_name_t ec_mech_name;
|
||||
crypto_provider_type_t ec_provider_type;
|
||||
crypto_event_change_t ec_change;
|
||||
} crypto_notify_event_change_t;
|
||||
|
||||
typedef void *crypto_notify_handle_t;
|
||||
typedef void (*crypto_notify_callback_t)(uint32_t event_mask, void *event_arg);
|
||||
|
||||
extern crypto_notify_handle_t crypto_notify_events(
|
||||
crypto_notify_callback_t nf, uint32_t event_mask);
|
||||
extern void crypto_unnotify_events(crypto_notify_handle_t);
|
||||
|
||||
/*
|
||||
* crypto_bufcall(9F) group of routines.
|
||||
*/
|
||||
extern crypto_bc_t crypto_bufcall_alloc(void);
|
||||
extern int crypto_bufcall_free(crypto_bc_t bc);
|
||||
extern int crypto_bufcall(crypto_bc_t bc, void (*func)(void *arg), void *arg);
|
||||
extern int crypto_unbufcall(crypto_bc_t bc);
|
||||
|
||||
/*
|
||||
* To obtain the list of key size ranges supported by a mechanism.
|
||||
*/
|
||||
|
||||
#define CRYPTO_MECH_USAGE_ENCRYPT 0x00000001
|
||||
#define CRYPTO_MECH_USAGE_DECRYPT 0x00000002
|
||||
#define CRYPTO_MECH_USAGE_MAC 0x00000004
|
||||
|
||||
typedef uint32_t crypto_mech_usage_t;
|
||||
|
||||
typedef struct crypto_mechanism_info {
|
||||
size_t mi_min_key_size;
|
||||
size_t mi_max_key_size;
|
||||
crypto_keysize_unit_t mi_keysize_unit; /* for mi_xxx_key_size */
|
||||
crypto_mech_usage_t mi_usage;
|
||||
} crypto_mechanism_info_t;
|
||||
|
||||
#ifdef _SYSCALL32
|
||||
|
||||
typedef struct crypto_mechanism_info32 {
|
||||
size32_t mi_min_key_size;
|
||||
size32_t mi_max_key_size;
|
||||
crypto_keysize_unit_t mi_keysize_unit; /* for mi_xxx_key_size */
|
||||
crypto_mech_usage_t mi_usage;
|
||||
} crypto_mechanism_info32_t;
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
|
||||
extern int crypto_get_all_mech_info(crypto_mech_type_t,
|
||||
crypto_mechanism_info_t **, uint_t *, int);
|
||||
extern void crypto_free_all_mech_info(crypto_mechanism_info_t *, uint_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_API_H */
|
583
include/sys/crypto/common.h
Normal file
583
include/sys/crypto/common.h
Normal file
@ -0,0 +1,583 @@
|
||||
/*
|
||||
* 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) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_COMMON_H
|
||||
#define _SYS_CRYPTO_COMMON_H
|
||||
|
||||
/*
|
||||
* Header file for the common data structures of the cryptographic framework
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
|
||||
/* Cryptographic Mechanisms */
|
||||
|
||||
#define CRYPTO_MAX_MECH_NAME 32
|
||||
typedef char crypto_mech_name_t[CRYPTO_MAX_MECH_NAME];
|
||||
|
||||
typedef uint64_t crypto_mech_type_t;
|
||||
|
||||
typedef struct crypto_mechanism {
|
||||
crypto_mech_type_t cm_type; /* mechanism type */
|
||||
caddr_t cm_param; /* mech. parameter */
|
||||
size_t cm_param_len; /* mech. parameter len */
|
||||
} crypto_mechanism_t;
|
||||
|
||||
#ifdef _SYSCALL32
|
||||
|
||||
typedef struct crypto_mechanism32 {
|
||||
crypto_mech_type_t cm_type; /* mechanism type */
|
||||
caddr32_t cm_param; /* mech. parameter */
|
||||
size32_t cm_param_len; /* mech. parameter len */
|
||||
} crypto_mechanism32_t;
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
|
||||
/* CK_AES_CTR_PARAMS provides parameters to the CKM_AES_CTR mechanism */
|
||||
typedef struct CK_AES_CTR_PARAMS {
|
||||
ulong_t ulCounterBits;
|
||||
uint8_t cb[16];
|
||||
} CK_AES_CTR_PARAMS;
|
||||
|
||||
/* CK_AES_CCM_PARAMS provides parameters to the CKM_AES_CCM mechanism */
|
||||
typedef struct CK_AES_CCM_PARAMS {
|
||||
ulong_t ulMACSize;
|
||||
ulong_t ulNonceSize;
|
||||
ulong_t ulAuthDataSize;
|
||||
ulong_t ulDataSize; /* used for plaintext or ciphertext */
|
||||
uchar_t *nonce;
|
||||
uchar_t *authData;
|
||||
} CK_AES_CCM_PARAMS;
|
||||
|
||||
/* CK_AES_GCM_PARAMS provides parameters to the CKM_AES_GCM mechanism */
|
||||
typedef struct CK_AES_GCM_PARAMS {
|
||||
uchar_t *pIv;
|
||||
ulong_t ulIvLen;
|
||||
ulong_t ulIvBits;
|
||||
uchar_t *pAAD;
|
||||
ulong_t ulAADLen;
|
||||
ulong_t ulTagBits;
|
||||
} CK_AES_GCM_PARAMS;
|
||||
|
||||
/* CK_AES_GMAC_PARAMS provides parameters to the CKM_AES_GMAC mechanism */
|
||||
typedef struct CK_AES_GMAC_PARAMS {
|
||||
uchar_t *pIv;
|
||||
uchar_t *pAAD;
|
||||
ulong_t ulAADLen;
|
||||
} CK_AES_GMAC_PARAMS;
|
||||
|
||||
/*
|
||||
* CK_ECDH1_DERIVE_PARAMS provides the parameters to the
|
||||
* CKM_ECDH1_KEY_DERIVE mechanism
|
||||
*/
|
||||
typedef struct CK_ECDH1_DERIVE_PARAMS {
|
||||
ulong_t kdf;
|
||||
ulong_t ulSharedDataLen;
|
||||
uchar_t *pSharedData;
|
||||
ulong_t ulPublicDataLen;
|
||||
uchar_t *pPublicData;
|
||||
} CK_ECDH1_DERIVE_PARAMS;
|
||||
|
||||
#ifdef _SYSCALL32
|
||||
|
||||
/* needed for 32-bit applications running on 64-bit kernels */
|
||||
typedef struct CK_AES_CTR_PARAMS32 {
|
||||
uint32_t ulCounterBits;
|
||||
uint8_t cb[16];
|
||||
} CK_AES_CTR_PARAMS32;
|
||||
|
||||
/* needed for 32-bit applications running on 64-bit kernels */
|
||||
typedef struct CK_AES_CCM_PARAMS32 {
|
||||
uint32_t ulMACSize;
|
||||
uint32_t ulNonceSize;
|
||||
uint32_t ulAuthDataSize;
|
||||
uint32_t ulDataSize;
|
||||
caddr32_t nonce;
|
||||
caddr32_t authData;
|
||||
} CK_AES_CCM_PARAMS32;
|
||||
|
||||
/* needed for 32-bit applications running on 64-bit kernels */
|
||||
typedef struct CK_AES_GCM_PARAMS32 {
|
||||
caddr32_t pIv;
|
||||
uint32_t ulIvLen;
|
||||
uint32_t ulIvBits;
|
||||
caddr32_t pAAD;
|
||||
uint32_t ulAADLen;
|
||||
uint32_t ulTagBits;
|
||||
} CK_AES_GCM_PARAMS32;
|
||||
|
||||
/* needed for 32-bit applications running on 64-bit kernels */
|
||||
typedef struct CK_AES_GMAC_PARAMS32 {
|
||||
caddr32_t pIv;
|
||||
caddr32_t pAAD;
|
||||
uint32_t ulAADLen;
|
||||
} CK_AES_GMAC_PARAMS32;
|
||||
|
||||
typedef struct CK_ECDH1_DERIVE_PARAMS32 {
|
||||
uint32_t kdf;
|
||||
uint32_t ulSharedDataLen;
|
||||
caddr32_t pSharedData;
|
||||
uint32_t ulPublicDataLen;
|
||||
caddr32_t pPublicData;
|
||||
} CK_ECDH1_DERIVE_PARAMS32;
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
|
||||
/*
|
||||
* The measurement unit bit flag for a mechanism's minimum or maximum key size.
|
||||
* The unit are mechanism dependent. It can be in bits or in bytes.
|
||||
*/
|
||||
typedef uint32_t crypto_keysize_unit_t;
|
||||
|
||||
/*
|
||||
* The following bit flags are valid in cm_mech_flags field in
|
||||
* the crypto_mech_info_t structure of the SPI.
|
||||
*
|
||||
* Only the first two bit flags are valid in mi_keysize_unit
|
||||
* field in the crypto_mechanism_info_t structure of the API.
|
||||
*/
|
||||
#define CRYPTO_KEYSIZE_UNIT_IN_BITS 0x00000001
|
||||
#define CRYPTO_KEYSIZE_UNIT_IN_BYTES 0x00000002
|
||||
#define CRYPTO_CAN_SHARE_OPSTATE 0x00000004 /* supports sharing */
|
||||
|
||||
|
||||
/* Mechanisms supported out-of-the-box */
|
||||
#define SUN_CKM_MD4 "CKM_MD4"
|
||||
#define SUN_CKM_MD5 "CKM_MD5"
|
||||
#define SUN_CKM_MD5_HMAC "CKM_MD5_HMAC"
|
||||
#define SUN_CKM_MD5_HMAC_GENERAL "CKM_MD5_HMAC_GENERAL"
|
||||
#define SUN_CKM_SHA1 "CKM_SHA_1"
|
||||
#define SUN_CKM_SHA1_HMAC "CKM_SHA_1_HMAC"
|
||||
#define SUN_CKM_SHA1_HMAC_GENERAL "CKM_SHA_1_HMAC_GENERAL"
|
||||
#define SUN_CKM_SHA256 "CKM_SHA256"
|
||||
#define SUN_CKM_SHA256_HMAC "CKM_SHA256_HMAC"
|
||||
#define SUN_CKM_SHA256_HMAC_GENERAL "CKM_SHA256_HMAC_GENERAL"
|
||||
#define SUN_CKM_SHA384 "CKM_SHA384"
|
||||
#define SUN_CKM_SHA384_HMAC "CKM_SHA384_HMAC"
|
||||
#define SUN_CKM_SHA384_HMAC_GENERAL "CKM_SHA384_HMAC_GENERAL"
|
||||
#define SUN_CKM_SHA512 "CKM_SHA512"
|
||||
#define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC"
|
||||
#define SUN_CKM_SHA512_HMAC_GENERAL "CKM_SHA512_HMAC_GENERAL"
|
||||
#define SUN_CKM_SHA512_224 "CKM_SHA512_224"
|
||||
#define SUN_CKM_SHA512_256 "CKM_SHA512_256"
|
||||
#define SUN_CKM_DES_CBC "CKM_DES_CBC"
|
||||
#define SUN_CKM_DES3_CBC "CKM_DES3_CBC"
|
||||
#define SUN_CKM_DES_ECB "CKM_DES_ECB"
|
||||
#define SUN_CKM_DES3_ECB "CKM_DES3_ECB"
|
||||
#define SUN_CKM_BLOWFISH_CBC "CKM_BLOWFISH_CBC"
|
||||
#define SUN_CKM_BLOWFISH_ECB "CKM_BLOWFISH_ECB"
|
||||
#define SUN_CKM_AES_CBC "CKM_AES_CBC"
|
||||
#define SUN_CKM_AES_ECB "CKM_AES_ECB"
|
||||
#define SUN_CKM_AES_CTR "CKM_AES_CTR"
|
||||
#define SUN_CKM_AES_CCM "CKM_AES_CCM"
|
||||
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
|
||||
#define SUN_CKM_AES_GMAC "CKM_AES_GMAC"
|
||||
#define SUN_CKM_AES_CFB128 "CKM_AES_CFB128"
|
||||
#define SUN_CKM_RC4 "CKM_RC4"
|
||||
#define SUN_CKM_RSA_PKCS "CKM_RSA_PKCS"
|
||||
#define SUN_CKM_RSA_X_509 "CKM_RSA_X_509"
|
||||
#define SUN_CKM_MD5_RSA_PKCS "CKM_MD5_RSA_PKCS"
|
||||
#define SUN_CKM_SHA1_RSA_PKCS "CKM_SHA1_RSA_PKCS"
|
||||
#define SUN_CKM_SHA256_RSA_PKCS "CKM_SHA256_RSA_PKCS"
|
||||
#define SUN_CKM_SHA384_RSA_PKCS "CKM_SHA384_RSA_PKCS"
|
||||
#define SUN_CKM_SHA512_RSA_PKCS "CKM_SHA512_RSA_PKCS"
|
||||
#define SUN_CKM_EC_KEY_PAIR_GEN "CKM_EC_KEY_PAIR_GEN"
|
||||
#define SUN_CKM_ECDH1_DERIVE "CKM_ECDH1_DERIVE"
|
||||
#define SUN_CKM_ECDSA_SHA1 "CKM_ECDSA_SHA1"
|
||||
#define SUN_CKM_ECDSA "CKM_ECDSA"
|
||||
|
||||
/* Shared operation context format for CKM_RC4 */
|
||||
typedef struct {
|
||||
#if defined(__amd64)
|
||||
uint32_t i, j;
|
||||
uint32_t arr[256];
|
||||
uint32_t flag;
|
||||
#else
|
||||
uchar_t arr[256];
|
||||
uchar_t i, j;
|
||||
#endif /* __amd64 */
|
||||
uint64_t pad; /* For 64-bit alignment */
|
||||
} arcfour_state_t;
|
||||
|
||||
/* Data arguments of cryptographic operations */
|
||||
|
||||
typedef enum crypto_data_format {
|
||||
CRYPTO_DATA_RAW = 1,
|
||||
CRYPTO_DATA_UIO,
|
||||
} crypto_data_format_t;
|
||||
|
||||
typedef struct crypto_data {
|
||||
crypto_data_format_t cd_format; /* Format identifier */
|
||||
off_t cd_offset; /* Offset from the beginning */
|
||||
size_t cd_length; /* # of bytes in use */
|
||||
caddr_t cd_miscdata; /* ancillary data */
|
||||
union {
|
||||
/* Raw format */
|
||||
iovec_t cdu_raw; /* Pointer and length */
|
||||
|
||||
/* uio scatter-gather format */
|
||||
uio_t *cdu_uio;
|
||||
|
||||
} cdu; /* Crypto Data Union */
|
||||
} crypto_data_t;
|
||||
|
||||
#define cd_raw cdu.cdu_raw
|
||||
#define cd_uio cdu.cdu_uio
|
||||
#define cd_mp cdu.cdu_mp
|
||||
|
||||
typedef struct crypto_dual_data {
|
||||
crypto_data_t dd_data; /* The data */
|
||||
off_t dd_offset2; /* Used by dual operation */
|
||||
size_t dd_len2; /* # of bytes to take */
|
||||
} crypto_dual_data_t;
|
||||
|
||||
#define dd_format dd_data.cd_format
|
||||
#define dd_offset1 dd_data.cd_offset
|
||||
#define dd_len1 dd_data.cd_length
|
||||
#define dd_miscdata dd_data.cd_miscdata
|
||||
#define dd_raw dd_data.cd_raw
|
||||
#define dd_uio dd_data.cd_uio
|
||||
#define dd_mp dd_data.cd_mp
|
||||
|
||||
/* The keys, and their contents */
|
||||
|
||||
typedef enum {
|
||||
CRYPTO_KEY_RAW = 1, /* ck_data is a cleartext key */
|
||||
CRYPTO_KEY_REFERENCE, /* ck_obj_id is an opaque reference */
|
||||
CRYPTO_KEY_ATTR_LIST /* ck_attrs is a list of object attributes */
|
||||
} crypto_key_format_t;
|
||||
|
||||
typedef uint64_t crypto_attr_type_t;
|
||||
|
||||
/* Attribute types to use for passing a RSA public key or a private key. */
|
||||
#define SUN_CKA_MODULUS 0x00000120
|
||||
#define SUN_CKA_MODULUS_BITS 0x00000121
|
||||
#define SUN_CKA_PUBLIC_EXPONENT 0x00000122
|
||||
#define SUN_CKA_PRIVATE_EXPONENT 0x00000123
|
||||
#define SUN_CKA_PRIME_1 0x00000124
|
||||
#define SUN_CKA_PRIME_2 0x00000125
|
||||
#define SUN_CKA_EXPONENT_1 0x00000126
|
||||
#define SUN_CKA_EXPONENT_2 0x00000127
|
||||
#define SUN_CKA_COEFFICIENT 0x00000128
|
||||
#define SUN_CKA_PRIME 0x00000130
|
||||
#define SUN_CKA_SUBPRIME 0x00000131
|
||||
#define SUN_CKA_BASE 0x00000132
|
||||
|
||||
#define CKK_EC 0x00000003
|
||||
#define CKK_GENERIC_SECRET 0x00000010
|
||||
#define CKK_RC4 0x00000012
|
||||
#define CKK_AES 0x0000001F
|
||||
#define CKK_DES 0x00000013
|
||||
#define CKK_DES2 0x00000014
|
||||
#define CKK_DES3 0x00000015
|
||||
|
||||
#define CKO_PUBLIC_KEY 0x00000002
|
||||
#define CKO_PRIVATE_KEY 0x00000003
|
||||
#define CKA_CLASS 0x00000000
|
||||
#define CKA_VALUE 0x00000011
|
||||
#define CKA_KEY_TYPE 0x00000100
|
||||
#define CKA_VALUE_LEN 0x00000161
|
||||
#define CKA_EC_PARAMS 0x00000180
|
||||
#define CKA_EC_POINT 0x00000181
|
||||
|
||||
typedef uint32_t crypto_object_id_t;
|
||||
|
||||
typedef struct crypto_object_attribute {
|
||||
crypto_attr_type_t oa_type; /* attribute type */
|
||||
caddr_t oa_value; /* attribute value */
|
||||
ssize_t oa_value_len; /* length of attribute value */
|
||||
} crypto_object_attribute_t;
|
||||
|
||||
typedef struct crypto_key {
|
||||
crypto_key_format_t ck_format; /* format identifier */
|
||||
union {
|
||||
/* for CRYPTO_KEY_RAW ck_format */
|
||||
struct {
|
||||
uint_t cku_v_length; /* # of bits in ck_data */
|
||||
void *cku_v_data; /* ptr to key value */
|
||||
} cku_key_value;
|
||||
|
||||
/* for CRYPTO_KEY_REFERENCE ck_format */
|
||||
crypto_object_id_t cku_key_id; /* reference to object key */
|
||||
|
||||
/* for CRYPTO_KEY_ATTR_LIST ck_format */
|
||||
struct {
|
||||
uint_t cku_a_count; /* number of attributes */
|
||||
crypto_object_attribute_t *cku_a_oattr;
|
||||
} cku_key_attrs;
|
||||
} cku_data; /* Crypto Key union */
|
||||
} crypto_key_t;
|
||||
|
||||
#ifdef _SYSCALL32
|
||||
|
||||
typedef struct crypto_object_attribute32 {
|
||||
uint64_t oa_type; /* attribute type */
|
||||
caddr32_t oa_value; /* attribute value */
|
||||
ssize32_t oa_value_len; /* length of attribute value */
|
||||
} crypto_object_attribute32_t;
|
||||
|
||||
typedef struct crypto_key32 {
|
||||
crypto_key_format_t ck_format; /* format identifier */
|
||||
union {
|
||||
/* for CRYPTO_KEY_RAW ck_format */
|
||||
struct {
|
||||
uint32_t cku_v_length; /* # of bytes in ck_data */
|
||||
caddr32_t cku_v_data; /* ptr to key value */
|
||||
} cku_key_value;
|
||||
|
||||
/* for CRYPTO_KEY_REFERENCE ck_format */
|
||||
crypto_object_id_t cku_key_id; /* reference to object key */
|
||||
|
||||
/* for CRYPTO_KEY_ATTR_LIST ck_format */
|
||||
struct {
|
||||
uint32_t cku_a_count; /* number of attributes */
|
||||
caddr32_t cku_a_oattr;
|
||||
} cku_key_attrs;
|
||||
} cku_data; /* Crypto Key union */
|
||||
} crypto_key32_t;
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
|
||||
#define ck_data cku_data.cku_key_value.cku_v_data
|
||||
#define ck_length cku_data.cku_key_value.cku_v_length
|
||||
#define ck_obj_id cku_data.cku_key_id
|
||||
#define ck_count cku_data.cku_key_attrs.cku_a_count
|
||||
#define ck_attrs cku_data.cku_key_attrs.cku_a_oattr
|
||||
|
||||
/*
|
||||
* Raw key lengths are expressed in number of bits.
|
||||
* The following macro returns the minimum number of
|
||||
* bytes that can contain the specified number of bits.
|
||||
* Round up without overflowing the integer type.
|
||||
*/
|
||||
#define CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1)
|
||||
#define CRYPTO_BYTES2BITS(n) ((n) << 3)
|
||||
|
||||
/* Providers */
|
||||
|
||||
typedef enum {
|
||||
CRYPTO_HW_PROVIDER = 0,
|
||||
CRYPTO_SW_PROVIDER,
|
||||
CRYPTO_LOGICAL_PROVIDER
|
||||
} crypto_provider_type_t;
|
||||
|
||||
typedef uint32_t crypto_provider_id_t;
|
||||
#define KCF_PROVID_INVALID ((uint32_t)-1)
|
||||
|
||||
typedef struct crypto_provider_entry {
|
||||
crypto_provider_id_t pe_provider_id;
|
||||
uint_t pe_mechanism_count;
|
||||
} crypto_provider_entry_t;
|
||||
|
||||
typedef struct crypto_dev_list_entry {
|
||||
char le_dev_name[MAXNAMELEN];
|
||||
uint_t le_dev_instance;
|
||||
uint_t le_mechanism_count;
|
||||
} crypto_dev_list_entry_t;
|
||||
|
||||
/* User type for authentication ioctls and SPI entry points */
|
||||
|
||||
typedef enum crypto_user_type {
|
||||
CRYPTO_SO = 0,
|
||||
CRYPTO_USER
|
||||
} crypto_user_type_t;
|
||||
|
||||
/* Version for provider management ioctls and SPI entry points */
|
||||
|
||||
typedef struct crypto_version {
|
||||
uchar_t cv_major;
|
||||
uchar_t cv_minor;
|
||||
} crypto_version_t;
|
||||
|
||||
/* session data structure opaque to the consumer */
|
||||
typedef void *crypto_session_t;
|
||||
|
||||
/* provider data structure opaque to the consumer */
|
||||
typedef void *crypto_provider_t;
|
||||
|
||||
/* Limits used by both consumers and providers */
|
||||
#define CRYPTO_EXT_SIZE_LABEL 32
|
||||
#define CRYPTO_EXT_SIZE_MANUF 32
|
||||
#define CRYPTO_EXT_SIZE_MODEL 16
|
||||
#define CRYPTO_EXT_SIZE_SERIAL 16
|
||||
#define CRYPTO_EXT_SIZE_TIME 16
|
||||
|
||||
typedef struct crypto_provider_ext_info {
|
||||
uchar_t ei_label[CRYPTO_EXT_SIZE_LABEL];
|
||||
uchar_t ei_manufacturerID[CRYPTO_EXT_SIZE_MANUF];
|
||||
uchar_t ei_model[CRYPTO_EXT_SIZE_MODEL];
|
||||
uchar_t ei_serial_number[CRYPTO_EXT_SIZE_SERIAL];
|
||||
ulong_t ei_flags;
|
||||
ulong_t ei_max_session_count;
|
||||
ulong_t ei_max_pin_len;
|
||||
ulong_t ei_min_pin_len;
|
||||
ulong_t ei_total_public_memory;
|
||||
ulong_t ei_free_public_memory;
|
||||
ulong_t ei_total_private_memory;
|
||||
ulong_t ei_free_private_memory;
|
||||
crypto_version_t ei_hardware_version;
|
||||
crypto_version_t ei_firmware_version;
|
||||
uchar_t ei_time[CRYPTO_EXT_SIZE_TIME];
|
||||
int ei_hash_max_input_len;
|
||||
int ei_hmac_max_input_len;
|
||||
} crypto_provider_ext_info_t;
|
||||
|
||||
typedef uint_t crypto_session_id_t;
|
||||
|
||||
typedef enum cmd_type {
|
||||
COPY_FROM_DATA,
|
||||
COPY_TO_DATA,
|
||||
COMPARE_TO_DATA,
|
||||
MD5_DIGEST_DATA,
|
||||
SHA1_DIGEST_DATA,
|
||||
SHA2_DIGEST_DATA,
|
||||
GHASH_DATA
|
||||
} cmd_type_t;
|
||||
|
||||
#define CRYPTO_DO_UPDATE 0x01
|
||||
#define CRYPTO_DO_FINAL 0x02
|
||||
#define CRYPTO_DO_MD5 0x04
|
||||
#define CRYPTO_DO_SHA1 0x08
|
||||
#define CRYPTO_DO_SIGN 0x10
|
||||
#define CRYPTO_DO_VERIFY 0x20
|
||||
#define CRYPTO_DO_SHA2 0x40
|
||||
|
||||
#define PROVIDER_OWNS_KEY_SCHEDULE 0x00000001
|
||||
|
||||
/*
|
||||
* Common cryptographic status and error codes.
|
||||
*/
|
||||
#define CRYPTO_SUCCESS 0x00000000
|
||||
#define CRYPTO_CANCEL 0x00000001
|
||||
#define CRYPTO_HOST_MEMORY 0x00000002
|
||||
#define CRYPTO_GENERAL_ERROR 0x00000003
|
||||
#define CRYPTO_FAILED 0x00000004
|
||||
#define CRYPTO_ARGUMENTS_BAD 0x00000005
|
||||
#define CRYPTO_ATTRIBUTE_READ_ONLY 0x00000006
|
||||
#define CRYPTO_ATTRIBUTE_SENSITIVE 0x00000007
|
||||
#define CRYPTO_ATTRIBUTE_TYPE_INVALID 0x00000008
|
||||
#define CRYPTO_ATTRIBUTE_VALUE_INVALID 0x00000009
|
||||
#define CRYPTO_CANCELED 0x0000000A
|
||||
#define CRYPTO_DATA_INVALID 0x0000000B
|
||||
#define CRYPTO_DATA_LEN_RANGE 0x0000000C
|
||||
#define CRYPTO_DEVICE_ERROR 0x0000000D
|
||||
#define CRYPTO_DEVICE_MEMORY 0x0000000E
|
||||
#define CRYPTO_DEVICE_REMOVED 0x0000000F
|
||||
#define CRYPTO_ENCRYPTED_DATA_INVALID 0x00000010
|
||||
#define CRYPTO_ENCRYPTED_DATA_LEN_RANGE 0x00000011
|
||||
#define CRYPTO_KEY_HANDLE_INVALID 0x00000012
|
||||
#define CRYPTO_KEY_SIZE_RANGE 0x00000013
|
||||
#define CRYPTO_KEY_TYPE_INCONSISTENT 0x00000014
|
||||
#define CRYPTO_KEY_NOT_NEEDED 0x00000015
|
||||
#define CRYPTO_KEY_CHANGED 0x00000016
|
||||
#define CRYPTO_KEY_NEEDED 0x00000017
|
||||
#define CRYPTO_KEY_INDIGESTIBLE 0x00000018
|
||||
#define CRYPTO_KEY_FUNCTION_NOT_PERMITTED 0x00000019
|
||||
#define CRYPTO_KEY_NOT_WRAPPABLE 0x0000001A
|
||||
#define CRYPTO_KEY_UNEXTRACTABLE 0x0000001B
|
||||
#define CRYPTO_MECHANISM_INVALID 0x0000001C
|
||||
#define CRYPTO_MECHANISM_PARAM_INVALID 0x0000001D
|
||||
#define CRYPTO_OBJECT_HANDLE_INVALID 0x0000001E
|
||||
#define CRYPTO_OPERATION_IS_ACTIVE 0x0000001F
|
||||
#define CRYPTO_OPERATION_NOT_INITIALIZED 0x00000020
|
||||
#define CRYPTO_PIN_INCORRECT 0x00000021
|
||||
#define CRYPTO_PIN_INVALID 0x00000022
|
||||
#define CRYPTO_PIN_LEN_RANGE 0x00000023
|
||||
#define CRYPTO_PIN_EXPIRED 0x00000024
|
||||
#define CRYPTO_PIN_LOCKED 0x00000025
|
||||
#define CRYPTO_SESSION_CLOSED 0x00000026
|
||||
#define CRYPTO_SESSION_COUNT 0x00000027
|
||||
#define CRYPTO_SESSION_HANDLE_INVALID 0x00000028
|
||||
#define CRYPTO_SESSION_READ_ONLY 0x00000029
|
||||
#define CRYPTO_SESSION_EXISTS 0x0000002A
|
||||
#define CRYPTO_SESSION_READ_ONLY_EXISTS 0x0000002B
|
||||
#define CRYPTO_SESSION_READ_WRITE_SO_EXISTS 0x0000002C
|
||||
#define CRYPTO_SIGNATURE_INVALID 0x0000002D
|
||||
#define CRYPTO_SIGNATURE_LEN_RANGE 0x0000002E
|
||||
#define CRYPTO_TEMPLATE_INCOMPLETE 0x0000002F
|
||||
#define CRYPTO_TEMPLATE_INCONSISTENT 0x00000030
|
||||
#define CRYPTO_UNWRAPPING_KEY_HANDLE_INVALID 0x00000031
|
||||
#define CRYPTO_UNWRAPPING_KEY_SIZE_RANGE 0x00000032
|
||||
#define CRYPTO_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x00000033
|
||||
#define CRYPTO_USER_ALREADY_LOGGED_IN 0x00000034
|
||||
#define CRYPTO_USER_NOT_LOGGED_IN 0x00000035
|
||||
#define CRYPTO_USER_PIN_NOT_INITIALIZED 0x00000036
|
||||
#define CRYPTO_USER_TYPE_INVALID 0x00000037
|
||||
#define CRYPTO_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000038
|
||||
#define CRYPTO_USER_TOO_MANY_TYPES 0x00000039
|
||||
#define CRYPTO_WRAPPED_KEY_INVALID 0x0000003A
|
||||
#define CRYPTO_WRAPPED_KEY_LEN_RANGE 0x0000003B
|
||||
#define CRYPTO_WRAPPING_KEY_HANDLE_INVALID 0x0000003C
|
||||
#define CRYPTO_WRAPPING_KEY_SIZE_RANGE 0x0000003D
|
||||
#define CRYPTO_WRAPPING_KEY_TYPE_INCONSISTENT 0x0000003E
|
||||
#define CRYPTO_RANDOM_SEED_NOT_SUPPORTED 0x0000003F
|
||||
#define CRYPTO_RANDOM_NO_RNG 0x00000040
|
||||
#define CRYPTO_DOMAIN_PARAMS_INVALID 0x00000041
|
||||
#define CRYPTO_BUFFER_TOO_SMALL 0x00000042
|
||||
#define CRYPTO_INFORMATION_SENSITIVE 0x00000043
|
||||
#define CRYPTO_NOT_SUPPORTED 0x00000044
|
||||
|
||||
#define CRYPTO_QUEUED 0x00000045
|
||||
#define CRYPTO_BUFFER_TOO_BIG 0x00000046
|
||||
#define CRYPTO_INVALID_CONTEXT 0x00000047
|
||||
#define CRYPTO_INVALID_MAC 0x00000048
|
||||
#define CRYPTO_MECH_NOT_SUPPORTED 0x00000049
|
||||
#define CRYPTO_INCONSISTENT_ATTRIBUTE 0x0000004A
|
||||
#define CRYPTO_NO_PERMISSION 0x0000004B
|
||||
#define CRYPTO_INVALID_PROVIDER_ID 0x0000004C
|
||||
#define CRYPTO_VERSION_MISMATCH 0x0000004D
|
||||
#define CRYPTO_BUSY 0x0000004E
|
||||
#define CRYPTO_UNKNOWN_PROVIDER 0x0000004F
|
||||
#define CRYPTO_MODVERIFICATION_FAILED 0x00000050
|
||||
#define CRYPTO_OLD_CTX_TEMPLATE 0x00000051
|
||||
#define CRYPTO_WEAK_KEY 0x00000052
|
||||
#define CRYPTO_FIPS140_ERROR 0x00000053
|
||||
/*
|
||||
* Don't forget to update CRYPTO_LAST_ERROR and the error_number_table[]
|
||||
* in kernelUtil.c when new error code is added.
|
||||
*/
|
||||
#define CRYPTO_LAST_ERROR 0x00000053
|
||||
|
||||
/*
|
||||
* Special values that can be used to indicate that information is unavailable
|
||||
* or that there is not practical limit. These values can be used
|
||||
* by fields of the SPI crypto_provider_ext_info(9S) structure.
|
||||
* The value of CRYPTO_UNAVAILABLE_INFO should be the same as
|
||||
* CK_UNAVAILABLE_INFO in the PKCS#11 spec.
|
||||
*/
|
||||
#define CRYPTO_UNAVAILABLE_INFO ((ulong_t)(-1))
|
||||
#define CRYPTO_EFFECTIVELY_INFINITE 0x0
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_COMMON_H */
|
41
include/sys/crypto/icp.h
Normal file
41
include/sys/crypto/icp.h
Normal file
@ -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 */
|
@ -62,6 +62,7 @@
|
||||
#include <vm/seg_kmem.h>
|
||||
#include <sys/zone.h>
|
||||
#include <sys/sdt.h>
|
||||
#include <sys/kstat.h>
|
||||
#include <sys/zfs_debug.h>
|
||||
#include <sys/zfs_delay.h>
|
||||
#include <sys/fm/fs/zfs.h>
|
||||
@ -445,7 +446,9 @@ typedef enum kmem_cbrc {
|
||||
/*
|
||||
* Task queues
|
||||
*/
|
||||
typedef struct taskq taskq_t;
|
||||
|
||||
#define TASKQ_NAMELEN 31
|
||||
|
||||
typedef uintptr_t taskqid_t;
|
||||
typedef void (task_func_t)(void *);
|
||||
|
||||
@ -457,6 +460,25 @@ typedef struct taskq_ent {
|
||||
uintptr_t tqent_flags;
|
||||
} taskq_ent_t;
|
||||
|
||||
typedef struct taskq {
|
||||
char tq_name[TASKQ_NAMELEN + 1];
|
||||
kmutex_t tq_lock;
|
||||
krwlock_t tq_threadlock;
|
||||
kcondvar_t tq_dispatch_cv;
|
||||
kcondvar_t tq_wait_cv;
|
||||
kthread_t **tq_threadlist;
|
||||
int tq_flags;
|
||||
int tq_active;
|
||||
int tq_nthreads;
|
||||
int tq_nalloc;
|
||||
int tq_minalloc;
|
||||
int tq_maxalloc;
|
||||
kcondvar_t tq_maxalloc_cv;
|
||||
int tq_maxalloc_wait;
|
||||
taskq_ent_t *tq_freelist;
|
||||
taskq_ent_t tq_task;
|
||||
} taskq_t;
|
||||
|
||||
#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */
|
||||
|
||||
#define TASKQ_PREPOPULATE 0x0001
|
||||
@ -651,6 +673,8 @@ extern uint64_t physmem;
|
||||
|
||||
extern int highbit64(uint64_t i);
|
||||
extern int lowbit64(uint64_t i);
|
||||
extern int highbit(ulong_t i);
|
||||
extern int lowbit(ulong_t i);
|
||||
extern int random_get_bytes(uint8_t *ptr, size_t len);
|
||||
extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len);
|
||||
|
||||
@ -658,6 +682,8 @@ extern void kernel_init(int);
|
||||
extern void kernel_fini(void);
|
||||
extern void thread_init(void);
|
||||
extern void thread_fini(void);
|
||||
extern void random_init(void);
|
||||
extern void random_fini(void);
|
||||
|
||||
struct spa;
|
||||
extern void nicenum(uint64_t num, char *buf);
|
||||
|
@ -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
|
||||
|
78
lib/libicp/Makefile.am
Normal file
78
lib/libicp/Makefile.am
Normal file
@ -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
|
@ -128,6 +128,28 @@ extern in_port_t ntohs(in_port_t);
|
||||
#define BE_64(x) BSWAP_64(x)
|
||||
#endif
|
||||
|
||||
#ifdef _BIG_ENDIAN
|
||||
static __inline__ uint64_t
|
||||
htonll(uint64_t n) {
|
||||
return (n);
|
||||
}
|
||||
|
||||
static __inline__ uint64_t
|
||||
ntohll(uint64_t n) {
|
||||
return (n);
|
||||
}
|
||||
#else
|
||||
static __inline__ uint64_t
|
||||
htonll(uint64_t n) {
|
||||
return ((((uint64_t)htonl(n)) << 32) + htonl(n >> 32));
|
||||
}
|
||||
|
||||
static __inline__ uint64_t
|
||||
ntohll(uint64_t n) {
|
||||
return ((((uint64_t)ntohl(n)) << 32) + ntohl(n >> 32));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Macros to read unaligned values from a specific byte order to
|
||||
* native byte order
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
#define FREAD 1
|
||||
#define FWRITE 2
|
||||
// #define FAPPEND 8
|
||||
// #define FAPPEND 8
|
||||
|
||||
#define FCREAT O_CREAT
|
||||
#define FTRUNC O_TRUNC
|
||||
|
@ -64,6 +64,7 @@ typedef int major_t;
|
||||
typedef int minor_t;
|
||||
|
||||
typedef ushort_t o_mode_t; /* old file attribute type */
|
||||
typedef short index_t;
|
||||
|
||||
/*
|
||||
* Definitions remaining from previous partial support for 64-bit file
|
||||
|
@ -126,7 +126,8 @@ nodist_libzpool_la_SOURCES = \
|
||||
libzpool_la_LIBADD = \
|
||||
$(top_builddir)/lib/libunicode/libunicode.la \
|
||||
$(top_builddir)/lib/libuutil/libuutil.la \
|
||||
$(top_builddir)/lib/libnvpair/libnvpair.la
|
||||
$(top_builddir)/lib/libnvpair/libnvpair.la \
|
||||
$(top_builddir)/lib/libicp/libicp.la
|
||||
|
||||
libzpool_la_LIBADD += $(ZLIB)
|
||||
libzpool_la_LDFLAGS = -version-info 2:0:0
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/systeminfo.h>
|
||||
#include <zfs_fletcher.h>
|
||||
#include <sys/crypto/icp.h>
|
||||
|
||||
/*
|
||||
* Emulation of kernel services in userland.
|
||||
@ -1113,9 +1114,96 @@ lowbit64(uint64_t i)
|
||||
return (h);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find highest one bit set.
|
||||
* Returns bit number + 1 of highest bit that is set, otherwise returns 0.
|
||||
* High order bit is 31 (or 63 in _LP64 kernel).
|
||||
*/
|
||||
int
|
||||
highbit(ulong_t i)
|
||||
{
|
||||
register int h = 1;
|
||||
|
||||
if (i == 0)
|
||||
return (0);
|
||||
#ifdef _LP64
|
||||
if (i & 0xffffffff00000000ul) {
|
||||
h += 32; i >>= 32;
|
||||
}
|
||||
#endif
|
||||
if (i & 0xffff0000) {
|
||||
h += 16; i >>= 16;
|
||||
}
|
||||
if (i & 0xff00) {
|
||||
h += 8; i >>= 8;
|
||||
}
|
||||
if (i & 0xf0) {
|
||||
h += 4; i >>= 4;
|
||||
}
|
||||
if (i & 0xc) {
|
||||
h += 2; i >>= 2;
|
||||
}
|
||||
if (i & 0x2) {
|
||||
h += 1;
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find lowest one bit set.
|
||||
* Returns bit number + 1 of lowest bit that is set, otherwise returns 0.
|
||||
* Low order bit is 0.
|
||||
*/
|
||||
int
|
||||
lowbit(ulong_t i)
|
||||
{
|
||||
register int h = 1;
|
||||
|
||||
if (i == 0)
|
||||
return (0);
|
||||
|
||||
#ifdef _LP64
|
||||
if (!(i & 0xffffffff)) {
|
||||
h += 32; i >>= 32;
|
||||
}
|
||||
#endif
|
||||
if (!(i & 0xffff)) {
|
||||
h += 16; i >>= 16;
|
||||
}
|
||||
if (!(i & 0xff)) {
|
||||
h += 8; i >>= 8;
|
||||
}
|
||||
if (!(i & 0xf)) {
|
||||
h += 4; i >>= 4;
|
||||
}
|
||||
if (!(i & 0x3)) {
|
||||
h += 2; i >>= 2;
|
||||
}
|
||||
if (!(i & 0x1)) {
|
||||
h += 1;
|
||||
}
|
||||
return (h);
|
||||
}
|
||||
|
||||
static int random_fd = -1, urandom_fd = -1;
|
||||
|
||||
void
|
||||
random_init(void)
|
||||
{
|
||||
VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
|
||||
VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
|
||||
}
|
||||
|
||||
void
|
||||
random_fini(void)
|
||||
{
|
||||
close(random_fd);
|
||||
close(urandom_fd);
|
||||
|
||||
random_fd = -1;
|
||||
urandom_fd = -1;
|
||||
}
|
||||
|
||||
static int
|
||||
random_get_bytes_common(uint8_t *ptr, size_t len, int fd)
|
||||
{
|
||||
@ -1228,12 +1316,13 @@ kernel_init(int mode)
|
||||
(void) snprintf(hw_serial, sizeof (hw_serial), "%ld",
|
||||
(mode & FWRITE) ? get_system_hostid() : 0);
|
||||
|
||||
VERIFY((random_fd = open("/dev/random", O_RDONLY)) != -1);
|
||||
VERIFY((urandom_fd = open("/dev/urandom", O_RDONLY)) != -1);
|
||||
random_init();
|
||||
|
||||
VERIFY0(uname(&hw_utsname));
|
||||
|
||||
thread_init();
|
||||
system_taskq_init();
|
||||
icp_init();
|
||||
|
||||
spa_init(mode);
|
||||
|
||||
@ -1248,14 +1337,11 @@ kernel_fini(void)
|
||||
fletcher_4_fini();
|
||||
spa_fini();
|
||||
|
||||
icp_fini();
|
||||
system_taskq_fini();
|
||||
thread_fini();
|
||||
|
||||
close(random_fd);
|
||||
close(urandom_fd);
|
||||
|
||||
random_fd = -1;
|
||||
urandom_fd = -1;
|
||||
random_fini();
|
||||
}
|
||||
|
||||
uid_t
|
||||
|
@ -34,26 +34,6 @@ int taskq_now;
|
||||
taskq_t *system_taskq;
|
||||
|
||||
#define TASKQ_ACTIVE 0x00010000
|
||||
#define TASKQ_NAMELEN 31
|
||||
|
||||
struct taskq {
|
||||
char tq_name[TASKQ_NAMELEN + 1];
|
||||
kmutex_t tq_lock;
|
||||
krwlock_t tq_threadlock;
|
||||
kcondvar_t tq_dispatch_cv;
|
||||
kcondvar_t tq_wait_cv;
|
||||
kthread_t **tq_threadlist;
|
||||
int tq_flags;
|
||||
int tq_active;
|
||||
int tq_nthreads;
|
||||
int tq_nalloc;
|
||||
int tq_minalloc;
|
||||
int tq_maxalloc;
|
||||
kcondvar_t tq_maxalloc_cv;
|
||||
int tq_maxalloc_wait;
|
||||
taskq_ent_t *tq_freelist;
|
||||
taskq_ent_t tq_task;
|
||||
};
|
||||
|
||||
static taskq_ent_t *
|
||||
task_alloc(taskq_t *tq, int tqflags)
|
||||
|
@ -4,6 +4,7 @@ subdir-m += unicode
|
||||
subdir-m += zcommon
|
||||
subdir-m += zfs
|
||||
subdir-m += zpios
|
||||
subdir-m += icp
|
||||
|
||||
INSTALL_MOD_DIR ?= extra
|
||||
|
||||
@ -12,6 +13,8 @@ ZFS_MODULE_CFLAGS += -include @abs_top_builddir@/zfs_config.h
|
||||
ZFS_MODULE_CFLAGS += -I@abs_top_srcdir@/include -I@SPL@/include -I@SPL@
|
||||
export ZFS_MODULE_CFLAGS
|
||||
|
||||
SUBDIR_TARGETS = icp
|
||||
|
||||
modules:
|
||||
@# Make the exported SPL symbols available to these modules.
|
||||
@# They may be in the root of SPL_OBJ when building against
|
||||
@ -28,6 +31,9 @@ modules:
|
||||
"*** - @SPL_OBJ@/module/@SPL_SYMBOLS@\n"; \
|
||||
exit 1; \
|
||||
fi
|
||||
list='$(SUBDIR_TARGETS)'; for targetdir in $$list; do \
|
||||
$(MAKE) -C $$targetdir; \
|
||||
done
|
||||
$(MAKE) -C @LINUX_OBJ@ SUBDIRS=`pwd` @KERNELMAKE_PARAMS@ CONFIG_ZFS=m $@
|
||||
|
||||
clean:
|
||||
@ -64,8 +70,8 @@ modules_uninstall:
|
||||
|
||||
distdir:
|
||||
list='$(subdir-m)'; for subdir in $$list; do \
|
||||
(find @top_srcdir@/module/$$subdir -name '*.c' -o -name '*.h' |\
|
||||
xargs /bin/cp -t $$distdir/$$subdir); \
|
||||
(cd @top_srcdir@/module && find $$subdir -name '*.c' -o -name '*.h' -o -name '*.S' |\
|
||||
xargs /bin/cp --parents -t $$distdir); \
|
||||
done
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
|
82
module/icp/Makefile.in
Normal file
82
module/icp/Makefile.in
Normal file
@ -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)
|
1618
module/icp/algs/aes/aes_impl.c
Normal file
1618
module/icp/algs/aes/aes_impl.c
Normal file
File diff suppressed because it is too large
Load Diff
135
module/icp/algs/aes/aes_modes.c
Normal file
135
module/icp/algs/aes/aes_modes.c
Normal file
@ -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);
|
||||
}
|
305
module/icp/algs/modes/cbc.c
Normal file
305
module/icp/algs/modes/cbc.c
Normal file
@ -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);
|
||||
}
|
920
module/icp/algs/modes/ccm.c
Normal file
920
module/icp/algs/modes/ccm.c
Normal file
@ -0,0 +1,920 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#if defined(__i386) || defined(__amd64)
|
||||
#include <sys/byteorder.h>
|
||||
#define UNALIGNED_POINTERS_PERMITTED
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Encrypt multiple blocks of data in CCM mode. Decrypt for CCM mode
|
||||
* is done in another function.
|
||||
*/
|
||||
int
|
||||
ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,
|
||||
crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(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;
|
||||
uint64_t counter;
|
||||
uint8_t *mac_buf;
|
||||
|
||||
if (length + ctx->ccm_remainder_len < block_size) {
|
||||
/* accumulate bytes here and return */
|
||||
bcopy(datap,
|
||||
(uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,
|
||||
length);
|
||||
ctx->ccm_remainder_len += length;
|
||||
ctx->ccm_copy_to = datap;
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
lastp = (uint8_t *)ctx->ccm_cb;
|
||||
if (out != NULL)
|
||||
crypto_init_ptrs(out, &iov_or_mp, &offset);
|
||||
|
||||
mac_buf = (uint8_t *)ctx->ccm_mac_buf;
|
||||
|
||||
do {
|
||||
/* Unprocessed data from last call. */
|
||||
if (ctx->ccm_remainder_len > 0) {
|
||||
need = block_size - ctx->ccm_remainder_len;
|
||||
|
||||
if (need > remainder)
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
|
||||
bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
|
||||
[ctx->ccm_remainder_len], need);
|
||||
|
||||
blockp = (uint8_t *)ctx->ccm_remainder;
|
||||
} else {
|
||||
blockp = datap;
|
||||
}
|
||||
|
||||
/*
|
||||
* do CBC MAC
|
||||
*
|
||||
* XOR the previous cipher block current clear block.
|
||||
* mac_buf always contain previous cipher block.
|
||||
*/
|
||||
xor_block(blockp, mac_buf);
|
||||
encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
|
||||
|
||||
/* ccm_cb is the counter block */
|
||||
encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb,
|
||||
(uint8_t *)ctx->ccm_tmp);
|
||||
|
||||
lastp = (uint8_t *)ctx->ccm_tmp;
|
||||
|
||||
/*
|
||||
* Increment counter. Counter bits are confined
|
||||
* to the bottom 64 bits of the counter block.
|
||||
*/
|
||||
#ifdef _LITTLE_ENDIAN
|
||||
counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask);
|
||||
counter = htonll(counter + 1);
|
||||
#else
|
||||
counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;
|
||||
counter++;
|
||||
#endif /* _LITTLE_ENDIAN */
|
||||
counter &= ctx->ccm_counter_mask;
|
||||
ctx->ccm_cb[1] =
|
||||
(ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
|
||||
|
||||
/*
|
||||
* XOR encrypted counter block with the current clear block.
|
||||
*/
|
||||
xor_block(blockp, lastp);
|
||||
|
||||
ctx->ccm_processed_data_len += block_size;
|
||||
|
||||
if (out == NULL) {
|
||||
if (ctx->ccm_remainder_len > 0) {
|
||||
bcopy(blockp, ctx->ccm_copy_to,
|
||||
ctx->ccm_remainder_len);
|
||||
bcopy(blockp + ctx->ccm_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 */
|
||||
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->ccm_remainder_len != 0) {
|
||||
datap += need;
|
||||
ctx->ccm_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->ccm_remainder, remainder);
|
||||
ctx->ccm_remainder_len = remainder;
|
||||
ctx->ccm_copy_to = datap;
|
||||
goto out;
|
||||
}
|
||||
ctx->ccm_copy_to = NULL;
|
||||
|
||||
} while (remainder > 0);
|
||||
|
||||
out:
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
calculate_ccm_mac(ccm_ctx_t *ctx, uint8_t *ccm_mac,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
|
||||
{
|
||||
uint64_t counter;
|
||||
uint8_t *counterp, *mac_buf;
|
||||
int i;
|
||||
|
||||
mac_buf = (uint8_t *)ctx->ccm_mac_buf;
|
||||
|
||||
/* first counter block start with index 0 */
|
||||
counter = 0;
|
||||
ctx->ccm_cb[1] = (ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
|
||||
|
||||
counterp = (uint8_t *)ctx->ccm_tmp;
|
||||
encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);
|
||||
|
||||
/* calculate XOR of MAC with first counter block */
|
||||
for (i = 0; i < ctx->ccm_mac_len; i++) {
|
||||
ccm_mac[i] = mac_buf[i] ^ counterp[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
ccm_encrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
uint8_t *lastp, *mac_buf, *ccm_mac_p, *macp = NULL;
|
||||
void *iov_or_mp;
|
||||
offset_t offset;
|
||||
uint8_t *out_data_1;
|
||||
uint8_t *out_data_2;
|
||||
size_t out_data_1_len;
|
||||
int i;
|
||||
|
||||
if (out->cd_length < (ctx->ccm_remainder_len + ctx->ccm_mac_len)) {
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* When we get here, the number of bytes of payload processed
|
||||
* plus whatever data remains, if any,
|
||||
* should be the same as the number of bytes that's being
|
||||
* passed in the argument during init time.
|
||||
*/
|
||||
if ((ctx->ccm_processed_data_len + ctx->ccm_remainder_len)
|
||||
!= (ctx->ccm_data_len)) {
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
mac_buf = (uint8_t *)ctx->ccm_mac_buf;
|
||||
|
||||
if (ctx->ccm_remainder_len > 0) {
|
||||
|
||||
/* ccm_mac_input_buf is not used for encryption */
|
||||
macp = (uint8_t *)ctx->ccm_mac_input_buf;
|
||||
bzero(macp, block_size);
|
||||
|
||||
/* copy remainder to temporary buffer */
|
||||
bcopy(ctx->ccm_remainder, macp, ctx->ccm_remainder_len);
|
||||
|
||||
/* calculate the CBC MAC */
|
||||
xor_block(macp, mac_buf);
|
||||
encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
|
||||
|
||||
/* calculate the counter mode */
|
||||
lastp = (uint8_t *)ctx->ccm_tmp;
|
||||
encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, lastp);
|
||||
|
||||
/* XOR with counter block */
|
||||
for (i = 0; i < ctx->ccm_remainder_len; i++) {
|
||||
macp[i] ^= lastp[i];
|
||||
}
|
||||
ctx->ccm_processed_data_len += ctx->ccm_remainder_len;
|
||||
}
|
||||
|
||||
/* Calculate the CCM MAC */
|
||||
ccm_mac_p = (uint8_t *)ctx->ccm_tmp;
|
||||
calculate_ccm_mac(ctx, ccm_mac_p, encrypt_block);
|
||||
|
||||
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->ccm_remainder_len + ctx->ccm_mac_len);
|
||||
|
||||
if (ctx->ccm_remainder_len > 0) {
|
||||
|
||||
/* copy temporary block to where it belongs */
|
||||
if (out_data_2 == NULL) {
|
||||
/* everything will fit in out_data_1 */
|
||||
bcopy(macp, out_data_1, ctx->ccm_remainder_len);
|
||||
bcopy(ccm_mac_p, out_data_1 + ctx->ccm_remainder_len,
|
||||
ctx->ccm_mac_len);
|
||||
} else {
|
||||
|
||||
if (out_data_1_len < ctx->ccm_remainder_len) {
|
||||
|
||||
size_t data_2_len_used;
|
||||
|
||||
bcopy(macp, out_data_1, out_data_1_len);
|
||||
|
||||
data_2_len_used = ctx->ccm_remainder_len
|
||||
- out_data_1_len;
|
||||
|
||||
bcopy((uint8_t *)macp + out_data_1_len,
|
||||
out_data_2, data_2_len_used);
|
||||
bcopy(ccm_mac_p, out_data_2 + data_2_len_used,
|
||||
ctx->ccm_mac_len);
|
||||
} else {
|
||||
bcopy(macp, out_data_1, out_data_1_len);
|
||||
if (out_data_1_len == ctx->ccm_remainder_len) {
|
||||
/* mac will be in out_data_2 */
|
||||
bcopy(ccm_mac_p, out_data_2,
|
||||
ctx->ccm_mac_len);
|
||||
} else {
|
||||
size_t len_not_used = out_data_1_len -
|
||||
ctx->ccm_remainder_len;
|
||||
/*
|
||||
* part of mac in will be in
|
||||
* out_data_1, part of the mac will be
|
||||
* in out_data_2
|
||||
*/
|
||||
bcopy(ccm_mac_p,
|
||||
out_data_1 + ctx->ccm_remainder_len,
|
||||
len_not_used);
|
||||
bcopy(ccm_mac_p + len_not_used,
|
||||
out_data_2,
|
||||
ctx->ccm_mac_len - len_not_used);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* copy block to where it belongs */
|
||||
bcopy(ccm_mac_p, out_data_1, out_data_1_len);
|
||||
if (out_data_2 != NULL) {
|
||||
bcopy(ccm_mac_p + out_data_1_len, out_data_2,
|
||||
block_size - out_data_1_len);
|
||||
}
|
||||
}
|
||||
out->cd_offset += ctx->ccm_remainder_len + ctx->ccm_mac_len;
|
||||
ctx->ccm_remainder_len = 0;
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will only deal with decrypting the last block of the input that
|
||||
* might not be a multiple of block length.
|
||||
*/
|
||||
void
|
||||
ccm_decrypt_incomplete_block(ccm_ctx_t *ctx,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *))
|
||||
{
|
||||
uint8_t *datap, *outp, *counterp;
|
||||
int i;
|
||||
|
||||
datap = (uint8_t *)ctx->ccm_remainder;
|
||||
outp = &((ctx->ccm_pt_buf)[ctx->ccm_processed_data_len]);
|
||||
|
||||
counterp = (uint8_t *)ctx->ccm_tmp;
|
||||
encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, counterp);
|
||||
|
||||
/* XOR with counter block */
|
||||
for (i = 0; i < ctx->ccm_remainder_len; i++) {
|
||||
outp[i] = datap[i] ^ counterp[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This will decrypt the cipher text. However, the plaintext won't be
|
||||
* returned to the caller. It will be returned when decrypt_final() is
|
||||
* called if the MAC matches
|
||||
*/
|
||||
/* ARGSUSED */
|
||||
int
|
||||
ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *ctx, char *data, size_t length,
|
||||
crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(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 *cbp;
|
||||
uint64_t counter;
|
||||
size_t pt_len, total_decrypted_len, mac_len, pm_len, pd_len;
|
||||
uint8_t *resultp;
|
||||
|
||||
|
||||
pm_len = ctx->ccm_processed_mac_len;
|
||||
|
||||
if (pm_len > 0) {
|
||||
uint8_t *tmp;
|
||||
/*
|
||||
* all ciphertext has been processed, just waiting for
|
||||
* part of the value of the mac
|
||||
*/
|
||||
if ((pm_len + length) > ctx->ccm_mac_len) {
|
||||
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
|
||||
}
|
||||
tmp = (uint8_t *)ctx->ccm_mac_input_buf;
|
||||
|
||||
bcopy(datap, tmp + pm_len, length);
|
||||
|
||||
ctx->ccm_processed_mac_len += length;
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we decrypt the given data, what total amount of data would
|
||||
* have been decrypted?
|
||||
*/
|
||||
pd_len = ctx->ccm_processed_data_len;
|
||||
total_decrypted_len = pd_len + length + ctx->ccm_remainder_len;
|
||||
|
||||
if (total_decrypted_len >
|
||||
(ctx->ccm_data_len + ctx->ccm_mac_len)) {
|
||||
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
pt_len = ctx->ccm_data_len;
|
||||
|
||||
if (total_decrypted_len > pt_len) {
|
||||
/*
|
||||
* part of the input will be the MAC, need to isolate that
|
||||
* to be dealt with later. The left-over data in
|
||||
* ccm_remainder_len from last time will not be part of the
|
||||
* MAC. Otherwise, it would have already been taken out
|
||||
* when this call is made last time.
|
||||
*/
|
||||
size_t pt_part = pt_len - pd_len - ctx->ccm_remainder_len;
|
||||
|
||||
mac_len = length - pt_part;
|
||||
|
||||
ctx->ccm_processed_mac_len = mac_len;
|
||||
bcopy(data + pt_part, ctx->ccm_mac_input_buf, mac_len);
|
||||
|
||||
if (pt_part + ctx->ccm_remainder_len < block_size) {
|
||||
/*
|
||||
* since this is last of the ciphertext, will
|
||||
* just decrypt with it here
|
||||
*/
|
||||
bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
|
||||
[ctx->ccm_remainder_len], pt_part);
|
||||
ctx->ccm_remainder_len += pt_part;
|
||||
ccm_decrypt_incomplete_block(ctx, encrypt_block);
|
||||
ctx->ccm_processed_data_len += ctx->ccm_remainder_len;
|
||||
ctx->ccm_remainder_len = 0;
|
||||
return (CRYPTO_SUCCESS);
|
||||
} else {
|
||||
/* let rest of the code handle this */
|
||||
length = pt_part;
|
||||
}
|
||||
} else if (length + ctx->ccm_remainder_len < block_size) {
|
||||
/* accumulate bytes here and return */
|
||||
bcopy(datap,
|
||||
(uint8_t *)ctx->ccm_remainder + ctx->ccm_remainder_len,
|
||||
length);
|
||||
ctx->ccm_remainder_len += length;
|
||||
ctx->ccm_copy_to = datap;
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
do {
|
||||
/* Unprocessed data from last call. */
|
||||
if (ctx->ccm_remainder_len > 0) {
|
||||
need = block_size - ctx->ccm_remainder_len;
|
||||
|
||||
if (need > remainder)
|
||||
return (CRYPTO_ENCRYPTED_DATA_LEN_RANGE);
|
||||
|
||||
bcopy(datap, &((uint8_t *)ctx->ccm_remainder)
|
||||
[ctx->ccm_remainder_len], need);
|
||||
|
||||
blockp = (uint8_t *)ctx->ccm_remainder;
|
||||
} else {
|
||||
blockp = datap;
|
||||
}
|
||||
|
||||
/* Calculate the counter mode, ccm_cb is the counter block */
|
||||
cbp = (uint8_t *)ctx->ccm_tmp;
|
||||
encrypt_block(ctx->ccm_keysched, (uint8_t *)ctx->ccm_cb, cbp);
|
||||
|
||||
/*
|
||||
* Increment counter.
|
||||
* Counter bits are confined to the bottom 64 bits
|
||||
*/
|
||||
#ifdef _LITTLE_ENDIAN
|
||||
counter = ntohll(ctx->ccm_cb[1] & ctx->ccm_counter_mask);
|
||||
counter = htonll(counter + 1);
|
||||
#else
|
||||
counter = ctx->ccm_cb[1] & ctx->ccm_counter_mask;
|
||||
counter++;
|
||||
#endif /* _LITTLE_ENDIAN */
|
||||
counter &= ctx->ccm_counter_mask;
|
||||
ctx->ccm_cb[1] =
|
||||
(ctx->ccm_cb[1] & ~(ctx->ccm_counter_mask)) | counter;
|
||||
|
||||
/* XOR with the ciphertext */
|
||||
xor_block(blockp, cbp);
|
||||
|
||||
/* Copy the plaintext to the "holding buffer" */
|
||||
resultp = (uint8_t *)ctx->ccm_pt_buf +
|
||||
ctx->ccm_processed_data_len;
|
||||
copy_block(cbp, resultp);
|
||||
|
||||
ctx->ccm_processed_data_len += block_size;
|
||||
|
||||
ctx->ccm_lastp = blockp;
|
||||
|
||||
/* Update pointer to next block of data to be processed. */
|
||||
if (ctx->ccm_remainder_len != 0) {
|
||||
datap += need;
|
||||
ctx->ccm_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->ccm_remainder, remainder);
|
||||
ctx->ccm_remainder_len = remainder;
|
||||
ctx->ccm_copy_to = datap;
|
||||
if (ctx->ccm_processed_mac_len > 0) {
|
||||
/*
|
||||
* not expecting anymore ciphertext, just
|
||||
* compute plaintext for the remaining input
|
||||
*/
|
||||
ccm_decrypt_incomplete_block(ctx,
|
||||
encrypt_block);
|
||||
ctx->ccm_processed_data_len += remainder;
|
||||
ctx->ccm_remainder_len = 0;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
ctx->ccm_copy_to = NULL;
|
||||
|
||||
} while (remainder > 0);
|
||||
|
||||
out:
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
ccm_decrypt_final(ccm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
size_t mac_remain, pt_len;
|
||||
uint8_t *pt, *mac_buf, *macp, *ccm_mac_p;
|
||||
int rv;
|
||||
|
||||
pt_len = ctx->ccm_data_len;
|
||||
|
||||
/* Make sure output buffer can fit all of the plaintext */
|
||||
if (out->cd_length < pt_len) {
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
pt = ctx->ccm_pt_buf;
|
||||
mac_remain = ctx->ccm_processed_data_len;
|
||||
mac_buf = (uint8_t *)ctx->ccm_mac_buf;
|
||||
|
||||
macp = (uint8_t *)ctx->ccm_tmp;
|
||||
|
||||
while (mac_remain > 0) {
|
||||
|
||||
if (mac_remain < block_size) {
|
||||
bzero(macp, block_size);
|
||||
bcopy(pt, macp, mac_remain);
|
||||
mac_remain = 0;
|
||||
} else {
|
||||
copy_block(pt, macp);
|
||||
mac_remain -= block_size;
|
||||
pt += block_size;
|
||||
}
|
||||
|
||||
/* calculate the CBC MAC */
|
||||
xor_block(macp, mac_buf);
|
||||
encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
|
||||
}
|
||||
|
||||
/* Calculate the CCM MAC */
|
||||
ccm_mac_p = (uint8_t *)ctx->ccm_tmp;
|
||||
calculate_ccm_mac((ccm_ctx_t *)ctx, ccm_mac_p, encrypt_block);
|
||||
|
||||
/* compare the input CCM MAC value with what we calculated */
|
||||
if (bcmp(ctx->ccm_mac_input_buf, ccm_mac_p, ctx->ccm_mac_len)) {
|
||||
/* They don't match */
|
||||
return (CRYPTO_INVALID_MAC);
|
||||
} else {
|
||||
rv = crypto_put_output_data(ctx->ccm_pt_buf, out, pt_len);
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
out->cd_offset += pt_len;
|
||||
}
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
ccm_validate_args(CK_AES_CCM_PARAMS *ccm_param, boolean_t is_encrypt_init)
|
||||
{
|
||||
size_t macSize, nonceSize;
|
||||
uint8_t q;
|
||||
uint64_t maxValue;
|
||||
|
||||
/*
|
||||
* Check the length of the MAC. The only valid
|
||||
* lengths for the MAC are: 4, 6, 8, 10, 12, 14, 16
|
||||
*/
|
||||
macSize = ccm_param->ulMACSize;
|
||||
if ((macSize < 4) || (macSize > 16) || ((macSize % 2) != 0)) {
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
}
|
||||
|
||||
/* Check the nonce length. Valid values are 7, 8, 9, 10, 11, 12, 13 */
|
||||
nonceSize = ccm_param->ulNonceSize;
|
||||
if ((nonceSize < 7) || (nonceSize > 13)) {
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
}
|
||||
|
||||
/* q is the length of the field storing the length, in bytes */
|
||||
q = (uint8_t)((15 - nonceSize) & 0xFF);
|
||||
|
||||
|
||||
/*
|
||||
* If it is decrypt, need to make sure size of ciphertext is at least
|
||||
* bigger than MAC len
|
||||
*/
|
||||
if ((!is_encrypt_init) && (ccm_param->ulDataSize < macSize)) {
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to make sure the length of the payload is within the
|
||||
* range of values allowed by q
|
||||
*/
|
||||
if (q < 8) {
|
||||
maxValue = (1ULL << (q * 8)) - 1;
|
||||
} else {
|
||||
maxValue = ULONG_MAX;
|
||||
}
|
||||
|
||||
if (ccm_param->ulDataSize > maxValue) {
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
}
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Format the first block used in CBC-MAC (B0) and the initial counter
|
||||
* block based on formatting functions and counter generation functions
|
||||
* specified in RFC 3610 and NIST publication 800-38C, appendix A
|
||||
*
|
||||
* b0 is the first block used in CBC-MAC
|
||||
* cb0 is the first counter block
|
||||
*
|
||||
* It's assumed that the arguments b0 and cb0 are preallocated AES blocks
|
||||
*
|
||||
*/
|
||||
static void
|
||||
ccm_format_initial_blocks(uchar_t *nonce, ulong_t nonceSize,
|
||||
ulong_t authDataSize, uint8_t *b0, ccm_ctx_t *aes_ctx)
|
||||
{
|
||||
uint64_t payloadSize;
|
||||
uint8_t t, q, have_adata = 0;
|
||||
size_t limit;
|
||||
int i, j, k;
|
||||
uint64_t mask = 0;
|
||||
uint8_t *cb;
|
||||
|
||||
q = (uint8_t)((15 - nonceSize) & 0xFF);
|
||||
t = (uint8_t)((aes_ctx->ccm_mac_len) & 0xFF);
|
||||
|
||||
/* Construct the first octet of b0 */
|
||||
if (authDataSize > 0) {
|
||||
have_adata = 1;
|
||||
}
|
||||
b0[0] = (have_adata << 6) | (((t - 2) / 2) << 3) | (q - 1);
|
||||
|
||||
/* copy the nonce value into b0 */
|
||||
bcopy(nonce, &(b0[1]), nonceSize);
|
||||
|
||||
/* store the length of the payload into b0 */
|
||||
bzero(&(b0[1+nonceSize]), q);
|
||||
|
||||
payloadSize = aes_ctx->ccm_data_len;
|
||||
limit = 8 < q ? 8 : q;
|
||||
|
||||
for (i = 0, j = 0, k = 15; i < limit; i++, j += 8, k--) {
|
||||
b0[k] = (uint8_t)((payloadSize >> j) & 0xFF);
|
||||
}
|
||||
|
||||
/* format the counter block */
|
||||
|
||||
cb = (uint8_t *)aes_ctx->ccm_cb;
|
||||
|
||||
cb[0] = 0x07 & (q-1); /* first byte */
|
||||
|
||||
/* copy the nonce value into the counter block */
|
||||
bcopy(nonce, &(cb[1]), nonceSize);
|
||||
|
||||
bzero(&(cb[1+nonceSize]), q);
|
||||
|
||||
/* Create the mask for the counter field based on the size of nonce */
|
||||
q <<= 3;
|
||||
while (q-- > 0) {
|
||||
mask |= (1ULL << q);
|
||||
}
|
||||
|
||||
#ifdef _LITTLE_ENDIAN
|
||||
mask = htonll(mask);
|
||||
#endif
|
||||
aes_ctx->ccm_counter_mask = mask;
|
||||
|
||||
/*
|
||||
* During calculation, we start using counter block 1, we will
|
||||
* set it up right here.
|
||||
* We can just set the last byte to have the value 1, because
|
||||
* even with the biggest nonce of 13, the last byte of the
|
||||
* counter block will be used for the counter value.
|
||||
*/
|
||||
cb[15] = 0x01;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode the length of the associated data as
|
||||
* specified in RFC 3610 and NIST publication 800-38C, appendix A
|
||||
*/
|
||||
static void
|
||||
encode_adata_len(ulong_t auth_data_len, uint8_t *encoded, size_t *encoded_len)
|
||||
{
|
||||
#ifdef UNALIGNED_POINTERS_PERMITTED
|
||||
uint32_t *lencoded_ptr;
|
||||
#ifdef _LP64
|
||||
uint64_t *llencoded_ptr;
|
||||
#endif
|
||||
#endif /* UNALIGNED_POINTERS_PERMITTED */
|
||||
|
||||
if (auth_data_len < ((1ULL<<16) - (1ULL<<8))) {
|
||||
/* 0 < a < (2^16-2^8) */
|
||||
*encoded_len = 2;
|
||||
encoded[0] = (auth_data_len & 0xff00) >> 8;
|
||||
encoded[1] = auth_data_len & 0xff;
|
||||
|
||||
} else if ((auth_data_len >= ((1ULL<<16) - (1ULL<<8))) &&
|
||||
(auth_data_len < (1ULL << 31))) {
|
||||
/* (2^16-2^8) <= a < 2^32 */
|
||||
*encoded_len = 6;
|
||||
encoded[0] = 0xff;
|
||||
encoded[1] = 0xfe;
|
||||
#ifdef UNALIGNED_POINTERS_PERMITTED
|
||||
lencoded_ptr = (uint32_t *)&encoded[2];
|
||||
*lencoded_ptr = htonl(auth_data_len);
|
||||
#else
|
||||
encoded[2] = (auth_data_len & 0xff000000) >> 24;
|
||||
encoded[3] = (auth_data_len & 0xff0000) >> 16;
|
||||
encoded[4] = (auth_data_len & 0xff00) >> 8;
|
||||
encoded[5] = auth_data_len & 0xff;
|
||||
#endif /* UNALIGNED_POINTERS_PERMITTED */
|
||||
|
||||
#ifdef _LP64
|
||||
} else {
|
||||
/* 2^32 <= a < 2^64 */
|
||||
*encoded_len = 10;
|
||||
encoded[0] = 0xff;
|
||||
encoded[1] = 0xff;
|
||||
#ifdef UNALIGNED_POINTERS_PERMITTED
|
||||
llencoded_ptr = (uint64_t *)&encoded[2];
|
||||
*llencoded_ptr = htonl(auth_data_len);
|
||||
#else
|
||||
encoded[2] = (auth_data_len & 0xff00000000000000) >> 56;
|
||||
encoded[3] = (auth_data_len & 0xff000000000000) >> 48;
|
||||
encoded[4] = (auth_data_len & 0xff0000000000) >> 40;
|
||||
encoded[5] = (auth_data_len & 0xff00000000) >> 32;
|
||||
encoded[6] = (auth_data_len & 0xff000000) >> 24;
|
||||
encoded[7] = (auth_data_len & 0xff0000) >> 16;
|
||||
encoded[8] = (auth_data_len & 0xff00) >> 8;
|
||||
encoded[9] = auth_data_len & 0xff;
|
||||
#endif /* UNALIGNED_POINTERS_PERMITTED */
|
||||
#endif /* _LP64 */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function should be call at encrypt or decrypt init time
|
||||
* for AES CCM mode.
|
||||
*/
|
||||
int
|
||||
ccm_init(ccm_ctx_t *ctx, unsigned char *nonce, size_t nonce_len,
|
||||
unsigned char *auth_data, size_t auth_data_len, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
uint8_t *mac_buf, *datap, *ivp, *authp;
|
||||
size_t remainder, processed;
|
||||
uint8_t encoded_a[10]; /* max encoded auth data length is 10 octets */
|
||||
size_t encoded_a_len = 0;
|
||||
|
||||
mac_buf = (uint8_t *)&(ctx->ccm_mac_buf);
|
||||
|
||||
/*
|
||||
* Format the 1st block for CBC-MAC and construct the
|
||||
* 1st counter block.
|
||||
*
|
||||
* aes_ctx->ccm_iv is used for storing the counter block
|
||||
* mac_buf will store b0 at this time.
|
||||
*/
|
||||
ccm_format_initial_blocks(nonce, nonce_len,
|
||||
auth_data_len, mac_buf, ctx);
|
||||
|
||||
/* The IV for CBC MAC for AES CCM mode is always zero */
|
||||
ivp = (uint8_t *)ctx->ccm_tmp;
|
||||
bzero(ivp, block_size);
|
||||
|
||||
xor_block(ivp, mac_buf);
|
||||
|
||||
/* encrypt the nonce */
|
||||
encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
|
||||
|
||||
/* take care of the associated data, if any */
|
||||
if (auth_data_len == 0) {
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
encode_adata_len(auth_data_len, encoded_a, &encoded_a_len);
|
||||
|
||||
remainder = auth_data_len;
|
||||
|
||||
/* 1st block: it contains encoded associated data, and some data */
|
||||
authp = (uint8_t *)ctx->ccm_tmp;
|
||||
bzero(authp, block_size);
|
||||
bcopy(encoded_a, authp, encoded_a_len);
|
||||
processed = block_size - encoded_a_len;
|
||||
if (processed > auth_data_len) {
|
||||
/* in case auth_data is very small */
|
||||
processed = auth_data_len;
|
||||
}
|
||||
bcopy(auth_data, authp+encoded_a_len, processed);
|
||||
/* xor with previous buffer */
|
||||
xor_block(authp, mac_buf);
|
||||
encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
|
||||
remainder -= processed;
|
||||
if (remainder == 0) {
|
||||
/* a small amount of associated data, it's all done now */
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
do {
|
||||
if (remainder < block_size) {
|
||||
/*
|
||||
* There's not a block full of data, pad rest of
|
||||
* buffer with zero
|
||||
*/
|
||||
bzero(authp, block_size);
|
||||
bcopy(&(auth_data[processed]), authp, remainder);
|
||||
datap = (uint8_t *)authp;
|
||||
remainder = 0;
|
||||
} else {
|
||||
datap = (uint8_t *)(&(auth_data[processed]));
|
||||
processed += block_size;
|
||||
remainder -= block_size;
|
||||
}
|
||||
|
||||
xor_block(datap, mac_buf);
|
||||
encrypt_block(ctx->ccm_keysched, mac_buf, mac_buf);
|
||||
|
||||
} while (remainder > 0);
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
ccm_init_ctx(ccm_ctx_t *ccm_ctx, char *param, int kmflag,
|
||||
boolean_t is_encrypt_init, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
int rv;
|
||||
CK_AES_CCM_PARAMS *ccm_param;
|
||||
|
||||
if (param != NULL) {
|
||||
ccm_param = (CK_AES_CCM_PARAMS *)param;
|
||||
|
||||
if ((rv = ccm_validate_args(ccm_param,
|
||||
is_encrypt_init)) != 0) {
|
||||
return (rv);
|
||||
}
|
||||
|
||||
ccm_ctx->ccm_mac_len = ccm_param->ulMACSize;
|
||||
if (is_encrypt_init) {
|
||||
ccm_ctx->ccm_data_len = ccm_param->ulDataSize;
|
||||
} else {
|
||||
ccm_ctx->ccm_data_len =
|
||||
ccm_param->ulDataSize - ccm_ctx->ccm_mac_len;
|
||||
ccm_ctx->ccm_processed_mac_len = 0;
|
||||
}
|
||||
ccm_ctx->ccm_processed_data_len = 0;
|
||||
|
||||
ccm_ctx->ccm_flags |= CCM_MODE;
|
||||
} else {
|
||||
rv = CRYPTO_MECHANISM_PARAM_INVALID;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ccm_init(ccm_ctx, ccm_param->nonce, ccm_param->ulNonceSize,
|
||||
ccm_param->authData, ccm_param->ulAuthDataSize, block_size,
|
||||
encrypt_block, xor_block) != 0) {
|
||||
rv = CRYPTO_MECHANISM_PARAM_INVALID;
|
||||
goto out;
|
||||
}
|
||||
if (!is_encrypt_init) {
|
||||
/* allocate buffer for storing decrypted plaintext */
|
||||
ccm_ctx->ccm_pt_buf = vmem_alloc(ccm_ctx->ccm_data_len,
|
||||
kmflag);
|
||||
if (ccm_ctx->ccm_pt_buf == NULL) {
|
||||
rv = CRYPTO_HOST_MEMORY;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return (rv);
|
||||
}
|
||||
|
||||
void *
|
||||
ccm_alloc_ctx(int kmflag)
|
||||
{
|
||||
ccm_ctx_t *ccm_ctx;
|
||||
|
||||
if ((ccm_ctx = kmem_zalloc(sizeof (ccm_ctx_t), kmflag)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
ccm_ctx->ccm_flags = CCM_MODE;
|
||||
return (ccm_ctx);
|
||||
}
|
238
module/icp/algs/modes/ctr.c
Normal file
238
module/icp/algs/modes/ctr.c
Normal file
@ -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);
|
||||
}
|
143
module/icp/algs/modes/ecb.c
Normal file
143
module/icp/algs/modes/ecb.c
Normal file
@ -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);
|
||||
}
|
748
module/icp/algs/modes/gcm.c
Normal file
748
module/icp/algs/modes/gcm.c
Normal file
@ -0,0 +1,748 @@
|
||||
/*
|
||||
* 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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <modes/modes.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/byteorder.h>
|
||||
|
||||
#ifdef __amd64
|
||||
|
||||
#ifdef _KERNEL
|
||||
/* Workaround for no XMM kernel thread save/restore */
|
||||
#define KPREEMPT_DISABLE kpreempt_disable()
|
||||
#define KPREEMPT_ENABLE kpreempt_enable()
|
||||
|
||||
#else
|
||||
#define KPREEMPT_DISABLE
|
||||
#define KPREEMPT_ENABLE
|
||||
#endif /* _KERNEL */
|
||||
|
||||
extern void gcm_mul_pclmulqdq(uint64_t *x_in, uint64_t *y, uint64_t *res);
|
||||
static int intel_pclmulqdq_instruction_present(void);
|
||||
#endif /* __amd64 */
|
||||
|
||||
struct aes_block {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* gcm_mul()
|
||||
* Perform a carry-less multiplication (that is, use XOR instead of the
|
||||
* multiply operator) on *x_in and *y and place the result in *res.
|
||||
*
|
||||
* Byte swap the input (*x_in and *y) and the output (*res).
|
||||
*
|
||||
* Note: x_in, y, and res all point to 16-byte numbers (an array of two
|
||||
* 64-bit integers).
|
||||
*/
|
||||
void
|
||||
gcm_mul(uint64_t *x_in, uint64_t *y, uint64_t *res)
|
||||
{
|
||||
#ifdef __amd64
|
||||
if (intel_pclmulqdq_instruction_present()) {
|
||||
KPREEMPT_DISABLE;
|
||||
gcm_mul_pclmulqdq(x_in, y, res);
|
||||
KPREEMPT_ENABLE;
|
||||
} else
|
||||
#endif /* __amd64 */
|
||||
{
|
||||
static const uint64_t R = 0xe100000000000000ULL;
|
||||
struct aes_block z = {0, 0};
|
||||
struct aes_block v;
|
||||
uint64_t x;
|
||||
int i, j;
|
||||
|
||||
v.a = ntohll(y[0]);
|
||||
v.b = ntohll(y[1]);
|
||||
|
||||
for (j = 0; j < 2; j++) {
|
||||
x = ntohll(x_in[j]);
|
||||
for (i = 0; i < 64; i++, x <<= 1) {
|
||||
if (x & 0x8000000000000000ULL) {
|
||||
z.a ^= v.a;
|
||||
z.b ^= v.b;
|
||||
}
|
||||
if (v.b & 1ULL) {
|
||||
v.b = (v.a << 63)|(v.b >> 1);
|
||||
v.a = (v.a >> 1) ^ R;
|
||||
} else {
|
||||
v.b = (v.a << 63)|(v.b >> 1);
|
||||
v.a = v.a >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
res[0] = htonll(z.a);
|
||||
res[1] = htonll(z.b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define GHASH(c, d, t) \
|
||||
xor_block((uint8_t *)(d), (uint8_t *)(c)->gcm_ghash); \
|
||||
gcm_mul((uint64_t *)(void *)(c)->gcm_ghash, (c)->gcm_H, \
|
||||
(uint64_t *)(void *)(t));
|
||||
|
||||
|
||||
/*
|
||||
* Encrypt multiple blocks of data in GCM mode. Decrypt for GCM mode
|
||||
* is done in another function.
|
||||
*/
|
||||
int
|
||||
gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
|
||||
crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(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;
|
||||
uint64_t counter;
|
||||
uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
|
||||
|
||||
if (length + ctx->gcm_remainder_len < block_size) {
|
||||
/* accumulate bytes here and return */
|
||||
bcopy(datap,
|
||||
(uint8_t *)ctx->gcm_remainder + ctx->gcm_remainder_len,
|
||||
length);
|
||||
ctx->gcm_remainder_len += length;
|
||||
ctx->gcm_copy_to = datap;
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
lastp = (uint8_t *)ctx->gcm_cb;
|
||||
if (out != NULL)
|
||||
crypto_init_ptrs(out, &iov_or_mp, &offset);
|
||||
|
||||
do {
|
||||
/* Unprocessed data from last call. */
|
||||
if (ctx->gcm_remainder_len > 0) {
|
||||
need = block_size - ctx->gcm_remainder_len;
|
||||
|
||||
if (need > remainder)
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
|
||||
bcopy(datap, &((uint8_t *)ctx->gcm_remainder)
|
||||
[ctx->gcm_remainder_len], need);
|
||||
|
||||
blockp = (uint8_t *)ctx->gcm_remainder;
|
||||
} else {
|
||||
blockp = datap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment counter. Counter bits are confined
|
||||
* to the bottom 32 bits of the counter block.
|
||||
*/
|
||||
counter = ntohll(ctx->gcm_cb[1] & counter_mask);
|
||||
counter = htonll(counter + 1);
|
||||
counter &= counter_mask;
|
||||
ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
|
||||
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
|
||||
(uint8_t *)ctx->gcm_tmp);
|
||||
xor_block(blockp, (uint8_t *)ctx->gcm_tmp);
|
||||
|
||||
lastp = (uint8_t *)ctx->gcm_tmp;
|
||||
|
||||
ctx->gcm_processed_data_len += block_size;
|
||||
|
||||
if (out == NULL) {
|
||||
if (ctx->gcm_remainder_len > 0) {
|
||||
bcopy(blockp, ctx->gcm_copy_to,
|
||||
ctx->gcm_remainder_len);
|
||||
bcopy(blockp + ctx->gcm_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 */
|
||||
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;
|
||||
}
|
||||
|
||||
/* add ciphertext to the hash */
|
||||
GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
|
||||
|
||||
/* Update pointer to next block of data to be processed. */
|
||||
if (ctx->gcm_remainder_len != 0) {
|
||||
datap += need;
|
||||
ctx->gcm_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->gcm_remainder, remainder);
|
||||
ctx->gcm_remainder_len = remainder;
|
||||
ctx->gcm_copy_to = datap;
|
||||
goto out;
|
||||
}
|
||||
ctx->gcm_copy_to = NULL;
|
||||
|
||||
} while (remainder > 0);
|
||||
out:
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
gcm_encrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
|
||||
uint8_t *ghash, *macp = NULL;
|
||||
int i, rv;
|
||||
|
||||
if (out->cd_length <
|
||||
(ctx->gcm_remainder_len + ctx->gcm_tag_len)) {
|
||||
return (CRYPTO_DATA_LEN_RANGE);
|
||||
}
|
||||
|
||||
ghash = (uint8_t *)ctx->gcm_ghash;
|
||||
|
||||
if (ctx->gcm_remainder_len > 0) {
|
||||
uint64_t counter;
|
||||
uint8_t *tmpp = (uint8_t *)ctx->gcm_tmp;
|
||||
|
||||
/*
|
||||
* Here is where we deal with data that is not a
|
||||
* multiple of the block size.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Increment counter.
|
||||
*/
|
||||
counter = ntohll(ctx->gcm_cb[1] & counter_mask);
|
||||
counter = htonll(counter + 1);
|
||||
counter &= counter_mask;
|
||||
ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
|
||||
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb,
|
||||
(uint8_t *)ctx->gcm_tmp);
|
||||
|
||||
macp = (uint8_t *)ctx->gcm_remainder;
|
||||
bzero(macp + ctx->gcm_remainder_len,
|
||||
block_size - ctx->gcm_remainder_len);
|
||||
|
||||
/* XOR with counter block */
|
||||
for (i = 0; i < ctx->gcm_remainder_len; i++) {
|
||||
macp[i] ^= tmpp[i];
|
||||
}
|
||||
|
||||
/* add ciphertext to the hash */
|
||||
GHASH(ctx, macp, ghash);
|
||||
|
||||
ctx->gcm_processed_data_len += ctx->gcm_remainder_len;
|
||||
}
|
||||
|
||||
ctx->gcm_len_a_len_c[1] =
|
||||
htonll(CRYPTO_BYTES2BITS(ctx->gcm_processed_data_len));
|
||||
GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
|
||||
(uint8_t *)ctx->gcm_J0);
|
||||
xor_block((uint8_t *)ctx->gcm_J0, ghash);
|
||||
|
||||
if (ctx->gcm_remainder_len > 0) {
|
||||
rv = crypto_put_output_data(macp, out, ctx->gcm_remainder_len);
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
}
|
||||
out->cd_offset += ctx->gcm_remainder_len;
|
||||
ctx->gcm_remainder_len = 0;
|
||||
rv = crypto_put_output_data(ghash, out, ctx->gcm_tag_len);
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
out->cd_offset += ctx->gcm_tag_len;
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This will only deal with decrypting the last block of the input that
|
||||
* might not be a multiple of block length.
|
||||
*/
|
||||
static void
|
||||
gcm_decrypt_incomplete_block(gcm_ctx_t *ctx, size_t block_size, size_t index,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
uint8_t *datap, *outp, *counterp;
|
||||
uint64_t counter;
|
||||
uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Increment counter.
|
||||
* Counter bits are confined to the bottom 32 bits
|
||||
*/
|
||||
counter = ntohll(ctx->gcm_cb[1] & counter_mask);
|
||||
counter = htonll(counter + 1);
|
||||
counter &= counter_mask;
|
||||
ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
|
||||
|
||||
datap = (uint8_t *)ctx->gcm_remainder;
|
||||
outp = &((ctx->gcm_pt_buf)[index]);
|
||||
counterp = (uint8_t *)ctx->gcm_tmp;
|
||||
|
||||
/* authentication tag */
|
||||
bzero((uint8_t *)ctx->gcm_tmp, block_size);
|
||||
bcopy(datap, (uint8_t *)ctx->gcm_tmp, ctx->gcm_remainder_len);
|
||||
|
||||
/* add ciphertext to the hash */
|
||||
GHASH(ctx, ctx->gcm_tmp, ctx->gcm_ghash);
|
||||
|
||||
/* decrypt remaining ciphertext */
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, counterp);
|
||||
|
||||
/* XOR with counter block */
|
||||
for (i = 0; i < ctx->gcm_remainder_len; i++) {
|
||||
outp[i] = datap[i] ^ counterp[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *ctx, char *data, size_t length,
|
||||
crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
size_t new_len;
|
||||
uint8_t *new;
|
||||
|
||||
/*
|
||||
* Copy contiguous ciphertext input blocks to plaintext buffer.
|
||||
* Ciphertext will be decrypted in the final.
|
||||
*/
|
||||
if (length > 0) {
|
||||
new_len = ctx->gcm_pt_buf_len + length;
|
||||
new = vmem_alloc(new_len, ctx->gcm_kmflag);
|
||||
bcopy(ctx->gcm_pt_buf, new, ctx->gcm_pt_buf_len);
|
||||
vmem_free(ctx->gcm_pt_buf, ctx->gcm_pt_buf_len);
|
||||
if (new == NULL)
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
|
||||
ctx->gcm_pt_buf = new;
|
||||
ctx->gcm_pt_buf_len = new_len;
|
||||
bcopy(data, &ctx->gcm_pt_buf[ctx->gcm_processed_data_len],
|
||||
length);
|
||||
ctx->gcm_processed_data_len += length;
|
||||
}
|
||||
|
||||
ctx->gcm_remainder_len = 0;
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
gcm_decrypt_final(gcm_ctx_t *ctx, crypto_data_t *out, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
size_t pt_len;
|
||||
size_t remainder;
|
||||
uint8_t *ghash;
|
||||
uint8_t *blockp;
|
||||
uint8_t *cbp;
|
||||
uint64_t counter;
|
||||
uint64_t counter_mask = ntohll(0x00000000ffffffffULL);
|
||||
int processed = 0, rv;
|
||||
|
||||
ASSERT(ctx->gcm_processed_data_len == ctx->gcm_pt_buf_len);
|
||||
|
||||
pt_len = ctx->gcm_processed_data_len - ctx->gcm_tag_len;
|
||||
ghash = (uint8_t *)ctx->gcm_ghash;
|
||||
blockp = ctx->gcm_pt_buf;
|
||||
remainder = pt_len;
|
||||
while (remainder > 0) {
|
||||
/* Incomplete last block */
|
||||
if (remainder < block_size) {
|
||||
bcopy(blockp, ctx->gcm_remainder, remainder);
|
||||
ctx->gcm_remainder_len = remainder;
|
||||
/*
|
||||
* not expecting anymore ciphertext, just
|
||||
* compute plaintext for the remaining input
|
||||
*/
|
||||
gcm_decrypt_incomplete_block(ctx, block_size,
|
||||
processed, encrypt_block, xor_block);
|
||||
ctx->gcm_remainder_len = 0;
|
||||
goto out;
|
||||
}
|
||||
/* add ciphertext to the hash */
|
||||
GHASH(ctx, blockp, ghash);
|
||||
|
||||
/*
|
||||
* Increment counter.
|
||||
* Counter bits are confined to the bottom 32 bits
|
||||
*/
|
||||
counter = ntohll(ctx->gcm_cb[1] & counter_mask);
|
||||
counter = htonll(counter + 1);
|
||||
counter &= counter_mask;
|
||||
ctx->gcm_cb[1] = (ctx->gcm_cb[1] & ~counter_mask) | counter;
|
||||
|
||||
cbp = (uint8_t *)ctx->gcm_tmp;
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_cb, cbp);
|
||||
|
||||
/* XOR with ciphertext */
|
||||
xor_block(cbp, blockp);
|
||||
|
||||
processed += block_size;
|
||||
blockp += block_size;
|
||||
remainder -= block_size;
|
||||
}
|
||||
out:
|
||||
ctx->gcm_len_a_len_c[1] = htonll(CRYPTO_BYTES2BITS(pt_len));
|
||||
GHASH(ctx, ctx->gcm_len_a_len_c, ghash);
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_J0,
|
||||
(uint8_t *)ctx->gcm_J0);
|
||||
xor_block((uint8_t *)ctx->gcm_J0, ghash);
|
||||
|
||||
/* compare the input authentication tag with what we calculated */
|
||||
if (bcmp(&ctx->gcm_pt_buf[pt_len], ghash, ctx->gcm_tag_len)) {
|
||||
/* They don't match */
|
||||
return (CRYPTO_INVALID_MAC);
|
||||
} else {
|
||||
rv = crypto_put_output_data(ctx->gcm_pt_buf, out, pt_len);
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
out->cd_offset += pt_len;
|
||||
}
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
gcm_validate_args(CK_AES_GCM_PARAMS *gcm_param)
|
||||
{
|
||||
size_t tag_len;
|
||||
|
||||
/*
|
||||
* Check the length of the authentication tag (in bits).
|
||||
*/
|
||||
tag_len = gcm_param->ulTagBits;
|
||||
switch (tag_len) {
|
||||
case 32:
|
||||
case 64:
|
||||
case 96:
|
||||
case 104:
|
||||
case 112:
|
||||
case 120:
|
||||
case 128:
|
||||
break;
|
||||
default:
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
}
|
||||
|
||||
if (gcm_param->ulIvLen == 0)
|
||||
return (CRYPTO_MECHANISM_PARAM_INVALID);
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
gcm_format_initial_blocks(uchar_t *iv, ulong_t iv_len,
|
||||
gcm_ctx_t *ctx, size_t block_size,
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
uint8_t *cb;
|
||||
ulong_t remainder = iv_len;
|
||||
ulong_t processed = 0;
|
||||
uint8_t *datap, *ghash;
|
||||
uint64_t len_a_len_c[2];
|
||||
|
||||
ghash = (uint8_t *)ctx->gcm_ghash;
|
||||
cb = (uint8_t *)ctx->gcm_cb;
|
||||
if (iv_len == 12) {
|
||||
bcopy(iv, cb, 12);
|
||||
cb[12] = 0;
|
||||
cb[13] = 0;
|
||||
cb[14] = 0;
|
||||
cb[15] = 1;
|
||||
/* J0 will be used again in the final */
|
||||
copy_block(cb, (uint8_t *)ctx->gcm_J0);
|
||||
} else {
|
||||
/* GHASH the IV */
|
||||
do {
|
||||
if (remainder < block_size) {
|
||||
bzero(cb, block_size);
|
||||
bcopy(&(iv[processed]), cb, remainder);
|
||||
datap = (uint8_t *)cb;
|
||||
remainder = 0;
|
||||
} else {
|
||||
datap = (uint8_t *)(&(iv[processed]));
|
||||
processed += block_size;
|
||||
remainder -= block_size;
|
||||
}
|
||||
GHASH(ctx, datap, ghash);
|
||||
} while (remainder > 0);
|
||||
|
||||
len_a_len_c[0] = 0;
|
||||
len_a_len_c[1] = htonll(CRYPTO_BYTES2BITS(iv_len));
|
||||
GHASH(ctx, len_a_len_c, ctx->gcm_J0);
|
||||
|
||||
/* J0 will be used again in the final */
|
||||
copy_block((uint8_t *)ctx->gcm_J0, (uint8_t *)cb);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function is called at encrypt or decrypt init time
|
||||
* for AES GCM mode.
|
||||
*/
|
||||
int
|
||||
gcm_init(gcm_ctx_t *ctx, unsigned char *iv, size_t iv_len,
|
||||
unsigned char *auth_data, size_t auth_data_len, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
uint8_t *ghash, *datap, *authp;
|
||||
size_t remainder, processed;
|
||||
|
||||
/* encrypt zero block to get subkey H */
|
||||
bzero(ctx->gcm_H, sizeof (ctx->gcm_H));
|
||||
encrypt_block(ctx->gcm_keysched, (uint8_t *)ctx->gcm_H,
|
||||
(uint8_t *)ctx->gcm_H);
|
||||
|
||||
gcm_format_initial_blocks(iv, iv_len, ctx, block_size,
|
||||
copy_block, xor_block);
|
||||
|
||||
authp = (uint8_t *)ctx->gcm_tmp;
|
||||
ghash = (uint8_t *)ctx->gcm_ghash;
|
||||
bzero(authp, block_size);
|
||||
bzero(ghash, block_size);
|
||||
|
||||
processed = 0;
|
||||
remainder = auth_data_len;
|
||||
do {
|
||||
if (remainder < block_size) {
|
||||
/*
|
||||
* There's not a block full of data, pad rest of
|
||||
* buffer with zero
|
||||
*/
|
||||
bzero(authp, block_size);
|
||||
bcopy(&(auth_data[processed]), authp, remainder);
|
||||
datap = (uint8_t *)authp;
|
||||
remainder = 0;
|
||||
} else {
|
||||
datap = (uint8_t *)(&(auth_data[processed]));
|
||||
processed += block_size;
|
||||
remainder -= block_size;
|
||||
}
|
||||
|
||||
/* add auth data to the hash */
|
||||
GHASH(ctx, datap, ghash);
|
||||
|
||||
} while (remainder > 0);
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
int
|
||||
gcm_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
int rv;
|
||||
CK_AES_GCM_PARAMS *gcm_param;
|
||||
|
||||
if (param != NULL) {
|
||||
gcm_param = (CK_AES_GCM_PARAMS *)(void *)param;
|
||||
|
||||
if ((rv = gcm_validate_args(gcm_param)) != 0) {
|
||||
return (rv);
|
||||
}
|
||||
|
||||
gcm_ctx->gcm_tag_len = gcm_param->ulTagBits;
|
||||
gcm_ctx->gcm_tag_len >>= 3;
|
||||
gcm_ctx->gcm_processed_data_len = 0;
|
||||
|
||||
/* these values are in bits */
|
||||
gcm_ctx->gcm_len_a_len_c[0]
|
||||
= htonll(CRYPTO_BYTES2BITS(gcm_param->ulAADLen));
|
||||
|
||||
rv = CRYPTO_SUCCESS;
|
||||
gcm_ctx->gcm_flags |= GCM_MODE;
|
||||
} else {
|
||||
rv = CRYPTO_MECHANISM_PARAM_INVALID;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gcm_init(gcm_ctx, gcm_param->pIv, gcm_param->ulIvLen,
|
||||
gcm_param->pAAD, gcm_param->ulAADLen, block_size,
|
||||
encrypt_block, copy_block, xor_block) != 0) {
|
||||
rv = CRYPTO_MECHANISM_PARAM_INVALID;
|
||||
}
|
||||
out:
|
||||
return (rv);
|
||||
}
|
||||
|
||||
int
|
||||
gmac_init_ctx(gcm_ctx_t *gcm_ctx, char *param, size_t block_size,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *))
|
||||
{
|
||||
int rv;
|
||||
CK_AES_GMAC_PARAMS *gmac_param;
|
||||
|
||||
if (param != NULL) {
|
||||
gmac_param = (CK_AES_GMAC_PARAMS *)(void *)param;
|
||||
|
||||
gcm_ctx->gcm_tag_len = CRYPTO_BITS2BYTES(AES_GMAC_TAG_BITS);
|
||||
gcm_ctx->gcm_processed_data_len = 0;
|
||||
|
||||
/* these values are in bits */
|
||||
gcm_ctx->gcm_len_a_len_c[0]
|
||||
= htonll(CRYPTO_BYTES2BITS(gmac_param->ulAADLen));
|
||||
|
||||
rv = CRYPTO_SUCCESS;
|
||||
gcm_ctx->gcm_flags |= GMAC_MODE;
|
||||
} else {
|
||||
rv = CRYPTO_MECHANISM_PARAM_INVALID;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (gcm_init(gcm_ctx, gmac_param->pIv, AES_GMAC_IV_LEN,
|
||||
gmac_param->pAAD, gmac_param->ulAADLen, block_size,
|
||||
encrypt_block, copy_block, xor_block) != 0) {
|
||||
rv = CRYPTO_MECHANISM_PARAM_INVALID;
|
||||
}
|
||||
out:
|
||||
return (rv);
|
||||
}
|
||||
|
||||
void *
|
||||
gcm_alloc_ctx(int kmflag)
|
||||
{
|
||||
gcm_ctx_t *gcm_ctx;
|
||||
|
||||
if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
gcm_ctx->gcm_flags = GCM_MODE;
|
||||
return (gcm_ctx);
|
||||
}
|
||||
|
||||
void *
|
||||
gmac_alloc_ctx(int kmflag)
|
||||
{
|
||||
gcm_ctx_t *gcm_ctx;
|
||||
|
||||
if ((gcm_ctx = kmem_zalloc(sizeof (gcm_ctx_t), kmflag)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
gcm_ctx->gcm_flags = GMAC_MODE;
|
||||
return (gcm_ctx);
|
||||
}
|
||||
|
||||
void
|
||||
gcm_set_kmflag(gcm_ctx_t *ctx, int kmflag)
|
||||
{
|
||||
ctx->gcm_kmflag = kmflag;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __amd64
|
||||
|
||||
#define INTEL_PCLMULQDQ_FLAG (1 << 1)
|
||||
|
||||
/*
|
||||
* Return 1 if executing on Intel with PCLMULQDQ instructions,
|
||||
* otherwise 0 (i.e., Intel without PCLMULQDQ or AMD64).
|
||||
* Cache the result, as the CPU can't change.
|
||||
*
|
||||
* Note: the userland version uses getisax(). The kernel version uses
|
||||
* is_x86_featureset().
|
||||
*/
|
||||
static int
|
||||
intel_pclmulqdq_instruction_present(void)
|
||||
{
|
||||
static int cached_result = -1;
|
||||
unsigned eax, ebx, ecx, edx;
|
||||
unsigned func, subfunc;
|
||||
|
||||
if (cached_result == -1) { /* first time */
|
||||
/* check for an intel cpu */
|
||||
func = 0;
|
||||
subfunc = 0;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"cpuid"
|
||||
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
|
||||
: "a"(func), "c"(subfunc));
|
||||
|
||||
if (memcmp((char *) (&ebx), "Genu", 4) == 0 &&
|
||||
memcmp((char *) (&edx), "ineI", 4) == 0 &&
|
||||
memcmp((char *) (&ecx), "ntel", 4) == 0) {
|
||||
|
||||
func = 1;
|
||||
subfunc = 0;
|
||||
|
||||
/* check for aes-ni instruction set */
|
||||
__asm__ __volatile__(
|
||||
"cpuid"
|
||||
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx)
|
||||
: "a"(func), "c"(subfunc));
|
||||
|
||||
cached_result = !!(ecx & INTEL_PCLMULQDQ_FLAG);
|
||||
} else {
|
||||
cached_result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return (cached_result);
|
||||
}
|
||||
|
||||
#endif /* __amd64 */
|
159
module/icp/algs/modes/modes.c
Normal file
159
module/icp/algs/modes/modes.c
Normal file
@ -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));
|
||||
}
|
||||
}
|
663
module/icp/algs/sha1/sha1.c
Normal file
663
module/icp/algs/sha1/sha1.c
Normal file
@ -0,0 +1,663 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The basic framework for this code came from the reference
|
||||
* implementation for MD5. That implementation is Copyright (C)
|
||||
* 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
|
||||
*
|
||||
* License to copy and use this software is granted provided that it
|
||||
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
* Algorithm" in all material mentioning or referencing this software
|
||||
* or this function.
|
||||
*
|
||||
* License is also granted to make and use derivative works provided
|
||||
* that such works are identified as "derived from the RSA Data
|
||||
* Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
* mentioning or referencing the derived work.
|
||||
*
|
||||
* RSA Data Security, Inc. makes no representations concerning either
|
||||
* the merchantability of this software or the suitability of this
|
||||
* software for any particular purpose. It is provided "as is"
|
||||
* without express or implied warranty of any kind.
|
||||
*
|
||||
* These notices must be retained in any copies of any part of this
|
||||
* documentation and/or software.
|
||||
*
|
||||
* NOTE: Cleaned-up and optimized, version of SHA1, based on the FIPS 180-1
|
||||
* standard, available at http://www.itl.nist.gov/fipspubs/fip180-1.htm
|
||||
* Not as fast as one would like -- further optimizations are encouraged
|
||||
* and appreciated.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sha1/sha1.h>
|
||||
#include <sha1/sha1_consts.h>
|
||||
|
||||
#ifdef _LITTLE_ENDIAN
|
||||
#include <sys/byteorder.h>
|
||||
#define HAVE_HTONL
|
||||
#endif
|
||||
|
||||
#define _RESTRICT_KYWD
|
||||
|
||||
static void Encode(uint8_t *, const uint32_t *, size_t);
|
||||
|
||||
#if defined(__amd64)
|
||||
|
||||
#define SHA1_TRANSFORM(ctx, in) sha1_block_data_order((ctx), (in), 1)
|
||||
#define SHA1_TRANSFORM_BLOCKS(ctx, in, num) sha1_block_data_order((ctx), \
|
||||
(in), (num))
|
||||
|
||||
void sha1_block_data_order(SHA1_CTX *ctx, const void *inpp, size_t num_blocks);
|
||||
|
||||
#else
|
||||
|
||||
#define SHA1_TRANSFORM(ctx, in) SHA1Transform((ctx), (in))
|
||||
|
||||
static void SHA1Transform(SHA1_CTX *, const uint8_t *);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static uint8_t PADDING[64] = { 0x80, /* all zeros */ };
|
||||
|
||||
/*
|
||||
* F, G, and H are the basic SHA1 functions.
|
||||
*/
|
||||
#define F(b, c, d) (((b) & (c)) | ((~b) & (d)))
|
||||
#define G(b, c, d) ((b) ^ (c) ^ (d))
|
||||
#define H(b, c, d) (((b) & (c)) | (((b)|(c)) & (d)))
|
||||
|
||||
/*
|
||||
* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && defined(_LP64)
|
||||
static __inline__ uint64_t
|
||||
ROTATE_LEFT(uint64_t value, uint32_t n)
|
||||
{
|
||||
uint32_t t32;
|
||||
|
||||
t32 = (uint32_t)value;
|
||||
return ((t32 << n) | (t32 >> (32 - n)));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define ROTATE_LEFT(x, n) \
|
||||
(((x) << (n)) | ((x) >> ((sizeof (x) * NBBY)-(n))))
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* SHA1Init()
|
||||
*
|
||||
* purpose: initializes the sha1 context and begins and sha1 digest operation
|
||||
* input: SHA1_CTX * : the context to initializes.
|
||||
* output: void
|
||||
*/
|
||||
|
||||
void
|
||||
SHA1Init(SHA1_CTX *ctx)
|
||||
{
|
||||
ctx->count[0] = ctx->count[1] = 0;
|
||||
|
||||
/*
|
||||
* load magic initialization constants. Tell lint
|
||||
* that these constants are unsigned by using U.
|
||||
*/
|
||||
|
||||
ctx->state[0] = 0x67452301U;
|
||||
ctx->state[1] = 0xefcdab89U;
|
||||
ctx->state[2] = 0x98badcfeU;
|
||||
ctx->state[3] = 0x10325476U;
|
||||
ctx->state[4] = 0xc3d2e1f0U;
|
||||
}
|
||||
|
||||
void
|
||||
SHA1Update(SHA1_CTX *ctx, const void *inptr, size_t input_len)
|
||||
{
|
||||
uint32_t i, buf_index, buf_len;
|
||||
const uint8_t *input = inptr;
|
||||
#if defined(__amd64)
|
||||
uint32_t block_count;
|
||||
#endif /* __amd64 */
|
||||
|
||||
/* check for noop */
|
||||
if (input_len == 0)
|
||||
return;
|
||||
|
||||
/* compute number of bytes mod 64 */
|
||||
buf_index = (ctx->count[1] >> 3) & 0x3F;
|
||||
|
||||
/* update number of bits */
|
||||
if ((ctx->count[1] += (input_len << 3)) < (input_len << 3))
|
||||
ctx->count[0]++;
|
||||
|
||||
ctx->count[0] += (input_len >> 29);
|
||||
|
||||
buf_len = 64 - buf_index;
|
||||
|
||||
/* transform as many times as possible */
|
||||
i = 0;
|
||||
if (input_len >= buf_len) {
|
||||
|
||||
/*
|
||||
* general optimization:
|
||||
*
|
||||
* only do initial bcopy() and SHA1Transform() if
|
||||
* buf_index != 0. if buf_index == 0, we're just
|
||||
* wasting our time doing the bcopy() since there
|
||||
* wasn't any data left over from a previous call to
|
||||
* SHA1Update().
|
||||
*/
|
||||
|
||||
if (buf_index) {
|
||||
bcopy(input, &ctx->buf_un.buf8[buf_index], buf_len);
|
||||
SHA1_TRANSFORM(ctx, ctx->buf_un.buf8);
|
||||
i = buf_len;
|
||||
}
|
||||
|
||||
#if !defined(__amd64)
|
||||
for (; i + 63 < input_len; i += 64)
|
||||
SHA1_TRANSFORM(ctx, &input[i]);
|
||||
#else
|
||||
block_count = (input_len - i) >> 6;
|
||||
if (block_count > 0) {
|
||||
SHA1_TRANSFORM_BLOCKS(ctx, &input[i], block_count);
|
||||
i += block_count << 6;
|
||||
}
|
||||
#endif /* !__amd64 */
|
||||
|
||||
/*
|
||||
* general optimization:
|
||||
*
|
||||
* if i and input_len are the same, return now instead
|
||||
* of calling bcopy(), since the bcopy() in this case
|
||||
* will be an expensive nop.
|
||||
*/
|
||||
|
||||
if (input_len == i)
|
||||
return;
|
||||
|
||||
buf_index = 0;
|
||||
}
|
||||
|
||||
/* buffer remaining input */
|
||||
bcopy(&input[i], &ctx->buf_un.buf8[buf_index], input_len - i);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Final()
|
||||
*
|
||||
* purpose: ends an sha1 digest operation, finalizing the message digest and
|
||||
* zeroing the context.
|
||||
* input: uchar_t * : A buffer to store the digest.
|
||||
* : The function actually uses void* because many
|
||||
* : callers pass things other than uchar_t here.
|
||||
* SHA1_CTX * : the context to finalize, save, and zero
|
||||
* output: void
|
||||
*/
|
||||
|
||||
void
|
||||
SHA1Final(void *digest, SHA1_CTX *ctx)
|
||||
{
|
||||
uint8_t bitcount_be[sizeof (ctx->count)];
|
||||
uint32_t index = (ctx->count[1] >> 3) & 0x3f;
|
||||
|
||||
/* store bit count, big endian */
|
||||
Encode(bitcount_be, ctx->count, sizeof (bitcount_be));
|
||||
|
||||
/* pad out to 56 mod 64 */
|
||||
SHA1Update(ctx, PADDING, ((index < 56) ? 56 : 120) - index);
|
||||
|
||||
/* append length (before padding) */
|
||||
SHA1Update(ctx, bitcount_be, sizeof (bitcount_be));
|
||||
|
||||
/* store state in digest */
|
||||
Encode(digest, ctx->state, sizeof (ctx->state));
|
||||
|
||||
/* zeroize sensitive information */
|
||||
bzero(ctx, sizeof (*ctx));
|
||||
}
|
||||
|
||||
|
||||
#if !defined(__amd64)
|
||||
|
||||
typedef uint32_t sha1word;
|
||||
|
||||
/*
|
||||
* sparc optimization:
|
||||
*
|
||||
* on the sparc, we can load big endian 32-bit data easily. note that
|
||||
* special care must be taken to ensure the address is 32-bit aligned.
|
||||
* in the interest of speed, we don't check to make sure, since
|
||||
* careful programming can guarantee this for us.
|
||||
*/
|
||||
|
||||
#if defined(_BIG_ENDIAN)
|
||||
#define LOAD_BIG_32(addr) (*(uint32_t *)(addr))
|
||||
|
||||
#elif defined(HAVE_HTONL)
|
||||
#define LOAD_BIG_32(addr) htonl(*((uint32_t *)(addr)))
|
||||
|
||||
#else
|
||||
/* little endian -- will work on big endian, but slowly */
|
||||
#define LOAD_BIG_32(addr) \
|
||||
(((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
|
||||
#endif /* _BIG_ENDIAN */
|
||||
|
||||
/*
|
||||
* SHA1Transform()
|
||||
*/
|
||||
#if defined(W_ARRAY)
|
||||
#define W(n) w[n]
|
||||
#else /* !defined(W_ARRAY) */
|
||||
#define W(n) w_ ## n
|
||||
#endif /* !defined(W_ARRAY) */
|
||||
|
||||
void /* CSTYLED */
|
||||
SHA1Transform(SHA1_CTX *ctx, const uint8_t blk[64])
|
||||
{
|
||||
/* CSTYLED */
|
||||
sha1word a = ctx->state[0];
|
||||
sha1word b = ctx->state[1];
|
||||
sha1word c = ctx->state[2];
|
||||
sha1word d = ctx->state[3];
|
||||
sha1word e = ctx->state[4];
|
||||
|
||||
#if defined(W_ARRAY)
|
||||
sha1word w[16];
|
||||
#else /* !defined(W_ARRAY) */
|
||||
sha1word w_0, w_1, w_2, w_3, w_4, w_5, w_6, w_7;
|
||||
sha1word w_8, w_9, w_10, w_11, w_12, w_13, w_14, w_15;
|
||||
#endif /* !defined(W_ARRAY) */
|
||||
|
||||
W(0) = LOAD_BIG_32((void *)(blk + 0));
|
||||
W(1) = LOAD_BIG_32((void *)(blk + 4));
|
||||
W(2) = LOAD_BIG_32((void *)(blk + 8));
|
||||
W(3) = LOAD_BIG_32((void *)(blk + 12));
|
||||
W(4) = LOAD_BIG_32((void *)(blk + 16));
|
||||
W(5) = LOAD_BIG_32((void *)(blk + 20));
|
||||
W(6) = LOAD_BIG_32((void *)(blk + 24));
|
||||
W(7) = LOAD_BIG_32((void *)(blk + 28));
|
||||
W(8) = LOAD_BIG_32((void *)(blk + 32));
|
||||
W(9) = LOAD_BIG_32((void *)(blk + 36));
|
||||
W(10) = LOAD_BIG_32((void *)(blk + 40));
|
||||
W(11) = LOAD_BIG_32((void *)(blk + 44));
|
||||
W(12) = LOAD_BIG_32((void *)(blk + 48));
|
||||
W(13) = LOAD_BIG_32((void *)(blk + 52));
|
||||
W(14) = LOAD_BIG_32((void *)(blk + 56));
|
||||
W(15) = LOAD_BIG_32((void *)(blk + 60));
|
||||
|
||||
/*
|
||||
* general optimization:
|
||||
*
|
||||
* even though this approach is described in the standard as
|
||||
* being slower algorithmically, it is 30-40% faster than the
|
||||
* "faster" version under SPARC, because this version has more
|
||||
* of the constraints specified at compile-time and uses fewer
|
||||
* variables (and therefore has better register utilization)
|
||||
* than its "speedier" brother. (i've tried both, trust me)
|
||||
*
|
||||
* for either method given in the spec, there is an "assignment"
|
||||
* phase where the following takes place:
|
||||
*
|
||||
* tmp = (main_computation);
|
||||
* e = d; d = c; c = rotate_left(b, 30); b = a; a = tmp;
|
||||
*
|
||||
* we can make the algorithm go faster by not doing this work,
|
||||
* but just pretending that `d' is now `e', etc. this works
|
||||
* really well and obviates the need for a temporary variable.
|
||||
* however, we still explicitly perform the rotate action,
|
||||
* since it is cheaper on SPARC to do it once than to have to
|
||||
* do it over and over again.
|
||||
*/
|
||||
|
||||
/* round 1 */
|
||||
e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(0) + SHA1_CONST(0); /* 0 */
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(1) + SHA1_CONST(0); /* 1 */
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(2) + SHA1_CONST(0); /* 2 */
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(3) + SHA1_CONST(0); /* 3 */
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(4) + SHA1_CONST(0); /* 4 */
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(5) + SHA1_CONST(0); /* 5 */
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(6) + SHA1_CONST(0); /* 6 */
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(7) + SHA1_CONST(0); /* 7 */
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(8) + SHA1_CONST(0); /* 8 */
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(9) + SHA1_CONST(0); /* 9 */
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(10) + SHA1_CONST(0); /* 10 */
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(11) + SHA1_CONST(0); /* 11 */
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(12) + SHA1_CONST(0); /* 12 */
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(13) + SHA1_CONST(0); /* 13 */
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(14) + SHA1_CONST(0); /* 14 */
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
e = ROTATE_LEFT(a, 5) + F(b, c, d) + e + W(15) + SHA1_CONST(0); /* 15 */
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1); /* 16 */
|
||||
d = ROTATE_LEFT(e, 5) + F(a, b, c) + d + W(0) + SHA1_CONST(0);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1); /* 17 */
|
||||
c = ROTATE_LEFT(d, 5) + F(e, a, b) + c + W(1) + SHA1_CONST(0);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1); /* 18 */
|
||||
b = ROTATE_LEFT(c, 5) + F(d, e, a) + b + W(2) + SHA1_CONST(0);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1); /* 19 */
|
||||
a = ROTATE_LEFT(b, 5) + F(c, d, e) + a + W(3) + SHA1_CONST(0);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
/* round 2 */
|
||||
W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1); /* 20 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(4) + SHA1_CONST(1);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1); /* 21 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(5) + SHA1_CONST(1);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1); /* 22 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(6) + SHA1_CONST(1);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1); /* 23 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(7) + SHA1_CONST(1);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1); /* 24 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(8) + SHA1_CONST(1);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1); /* 25 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(9) + SHA1_CONST(1);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1); /* 26 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(10) + SHA1_CONST(1);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1); /* 27 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(11) + SHA1_CONST(1);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1); /* 28 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(12) + SHA1_CONST(1);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 29 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(13) + SHA1_CONST(1);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1); /* 30 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(14) + SHA1_CONST(1);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1); /* 31 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(15) + SHA1_CONST(1);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1); /* 32 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(0) + SHA1_CONST(1);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1); /* 33 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(1) + SHA1_CONST(1);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1); /* 34 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(2) + SHA1_CONST(1);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1); /* 35 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(3) + SHA1_CONST(1);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1); /* 36 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(4) + SHA1_CONST(1);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1); /* 37 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(5) + SHA1_CONST(1);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1); /* 38 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(6) + SHA1_CONST(1);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1); /* 39 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(7) + SHA1_CONST(1);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
/* round 3 */
|
||||
W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1); /* 40 */
|
||||
e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(8) + SHA1_CONST(2);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1); /* 41 */
|
||||
d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(9) + SHA1_CONST(2);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1); /* 42 */
|
||||
c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(10) + SHA1_CONST(2);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1); /* 43 */
|
||||
b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(11) + SHA1_CONST(2);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1); /* 44 */
|
||||
a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(12) + SHA1_CONST(2);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 45 */
|
||||
e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(13) + SHA1_CONST(2);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1); /* 46 */
|
||||
d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(14) + SHA1_CONST(2);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1); /* 47 */
|
||||
c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(15) + SHA1_CONST(2);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1); /* 48 */
|
||||
b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(0) + SHA1_CONST(2);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1); /* 49 */
|
||||
a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(1) + SHA1_CONST(2);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1); /* 50 */
|
||||
e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(2) + SHA1_CONST(2);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1); /* 51 */
|
||||
d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(3) + SHA1_CONST(2);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1); /* 52 */
|
||||
c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(4) + SHA1_CONST(2);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1); /* 53 */
|
||||
b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(5) + SHA1_CONST(2);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1); /* 54 */
|
||||
a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(6) + SHA1_CONST(2);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1); /* 55 */
|
||||
e = ROTATE_LEFT(a, 5) + H(b, c, d) + e + W(7) + SHA1_CONST(2);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1); /* 56 */
|
||||
d = ROTATE_LEFT(e, 5) + H(a, b, c) + d + W(8) + SHA1_CONST(2);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1); /* 57 */
|
||||
c = ROTATE_LEFT(d, 5) + H(e, a, b) + c + W(9) + SHA1_CONST(2);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1); /* 58 */
|
||||
b = ROTATE_LEFT(c, 5) + H(d, e, a) + b + W(10) + SHA1_CONST(2);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1); /* 59 */
|
||||
a = ROTATE_LEFT(b, 5) + H(c, d, e) + a + W(11) + SHA1_CONST(2);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
/* round 4 */
|
||||
W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1); /* 60 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(12) + SHA1_CONST(3);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 61 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(13) + SHA1_CONST(3);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1); /* 62 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(14) + SHA1_CONST(3);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1); /* 63 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(15) + SHA1_CONST(3);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(0) = ROTATE_LEFT((W(13) ^ W(8) ^ W(2) ^ W(0)), 1); /* 64 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(0) + SHA1_CONST(3);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(1) = ROTATE_LEFT((W(14) ^ W(9) ^ W(3) ^ W(1)), 1); /* 65 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(1) + SHA1_CONST(3);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(2) = ROTATE_LEFT((W(15) ^ W(10) ^ W(4) ^ W(2)), 1); /* 66 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(2) + SHA1_CONST(3);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(3) = ROTATE_LEFT((W(0) ^ W(11) ^ W(5) ^ W(3)), 1); /* 67 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(3) + SHA1_CONST(3);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(4) = ROTATE_LEFT((W(1) ^ W(12) ^ W(6) ^ W(4)), 1); /* 68 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(4) + SHA1_CONST(3);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(5) = ROTATE_LEFT((W(2) ^ W(13) ^ W(7) ^ W(5)), 1); /* 69 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(5) + SHA1_CONST(3);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(6) = ROTATE_LEFT((W(3) ^ W(14) ^ W(8) ^ W(6)), 1); /* 70 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(6) + SHA1_CONST(3);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(7) = ROTATE_LEFT((W(4) ^ W(15) ^ W(9) ^ W(7)), 1); /* 71 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(7) + SHA1_CONST(3);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(8) = ROTATE_LEFT((W(5) ^ W(0) ^ W(10) ^ W(8)), 1); /* 72 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(8) + SHA1_CONST(3);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(9) = ROTATE_LEFT((W(6) ^ W(1) ^ W(11) ^ W(9)), 1); /* 73 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(9) + SHA1_CONST(3);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(10) = ROTATE_LEFT((W(7) ^ W(2) ^ W(12) ^ W(10)), 1); /* 74 */
|
||||
a = ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(10) + SHA1_CONST(3);
|
||||
c = ROTATE_LEFT(c, 30);
|
||||
|
||||
W(11) = ROTATE_LEFT((W(8) ^ W(3) ^ W(13) ^ W(11)), 1); /* 75 */
|
||||
e = ROTATE_LEFT(a, 5) + G(b, c, d) + e + W(11) + SHA1_CONST(3);
|
||||
b = ROTATE_LEFT(b, 30);
|
||||
|
||||
W(12) = ROTATE_LEFT((W(9) ^ W(4) ^ W(14) ^ W(12)), 1); /* 76 */
|
||||
d = ROTATE_LEFT(e, 5) + G(a, b, c) + d + W(12) + SHA1_CONST(3);
|
||||
a = ROTATE_LEFT(a, 30);
|
||||
|
||||
W(13) = ROTATE_LEFT((W(10) ^ W(5) ^ W(15) ^ W(13)), 1); /* 77 */
|
||||
c = ROTATE_LEFT(d, 5) + G(e, a, b) + c + W(13) + SHA1_CONST(3);
|
||||
e = ROTATE_LEFT(e, 30);
|
||||
|
||||
W(14) = ROTATE_LEFT((W(11) ^ W(6) ^ W(0) ^ W(14)), 1); /* 78 */
|
||||
b = ROTATE_LEFT(c, 5) + G(d, e, a) + b + W(14) + SHA1_CONST(3);
|
||||
d = ROTATE_LEFT(d, 30);
|
||||
|
||||
W(15) = ROTATE_LEFT((W(12) ^ W(7) ^ W(1) ^ W(15)), 1); /* 79 */
|
||||
|
||||
ctx->state[0] += ROTATE_LEFT(b, 5) + G(c, d, e) + a + W(15) +
|
||||
SHA1_CONST(3);
|
||||
ctx->state[1] += b;
|
||||
ctx->state[2] += ROTATE_LEFT(c, 30);
|
||||
ctx->state[3] += d;
|
||||
ctx->state[4] += e;
|
||||
|
||||
/* zeroize sensitive information */
|
||||
W(0) = W(1) = W(2) = W(3) = W(4) = W(5) = W(6) = W(7) = W(8) = 0;
|
||||
W(9) = W(10) = W(11) = W(12) = W(13) = W(14) = W(15) = 0;
|
||||
}
|
||||
#endif /* !__amd64 */
|
||||
|
||||
|
||||
/*
|
||||
* Encode()
|
||||
*
|
||||
* purpose: to convert a list of numbers from little endian to big endian
|
||||
* input: uint8_t * : place to store the converted big endian numbers
|
||||
* uint32_t * : place to get numbers to convert from
|
||||
* size_t : the length of the input in bytes
|
||||
* output: void
|
||||
*/
|
||||
|
||||
static void
|
||||
Encode(uint8_t *_RESTRICT_KYWD output, const uint32_t *_RESTRICT_KYWD input,
|
||||
size_t len)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (input[i] >> 24) & 0xff;
|
||||
output[j + 1] = (input[i] >> 16) & 0xff;
|
||||
output[j + 2] = (input[i] >> 8) & 0xff;
|
||||
output[j + 3] = input[i] & 0xff;
|
||||
}
|
||||
}
|
495
module/icp/algs/sha2/sha2.c
Normal file
495
module/icp/algs/sha2/sha2.c
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
/*
|
||||
* Copyright 2013 Saso Kiselkov. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The basic framework for this code came from the reference
|
||||
* implementation for MD5. That implementation is Copyright (C)
|
||||
* 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
|
||||
*
|
||||
* License to copy and use this software is granted provided that it
|
||||
* is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
* Algorithm" in all material mentioning or referencing this software
|
||||
* or this function.
|
||||
*
|
||||
* License is also granted to make and use derivative works provided
|
||||
* that such works are identified as "derived from the RSA Data
|
||||
* Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
* mentioning or referencing the derived work.
|
||||
*
|
||||
* RSA Data Security, Inc. makes no representations concerning either
|
||||
* the merchantability of this software or the suitability of this
|
||||
* software for any particular purpose. It is provided "as is"
|
||||
* without express or implied warranty of any kind.
|
||||
*
|
||||
* These notices must be retained in any copies of any part of this
|
||||
* documentation and/or software.
|
||||
*
|
||||
* NOTE: Cleaned-up and optimized, version of SHA2, based on the FIPS 180-2
|
||||
* standard, available at
|
||||
* http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf
|
||||
* Not as fast as one would like -- further optimizations are encouraged
|
||||
* and appreciated.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#define _SHA2_IMPL
|
||||
#include <sha2/sha2.h>
|
||||
#include <sha2/sha2_consts.h>
|
||||
|
||||
#define _RESTRICT_KYWD
|
||||
|
||||
#ifdef _LITTLE_ENDIAN
|
||||
#include <sys/byteorder.h>
|
||||
#define HAVE_HTONL
|
||||
#endif
|
||||
|
||||
static void Encode(uint8_t *, uint32_t *, size_t);
|
||||
|
||||
#if defined(__amd64)
|
||||
#define SHA256Transform(ctx, in) SHA256TransformBlocks((ctx), (in), 1)
|
||||
void SHA256TransformBlocks(SHA2_CTX *ctx, const void *in, size_t num);
|
||||
#else
|
||||
static void SHA256Transform(SHA2_CTX *, const uint8_t *);
|
||||
#endif /* __amd64 */
|
||||
|
||||
static uint8_t PADDING[128] = { 0x80, /* all zeros */ };
|
||||
|
||||
/* Ch and Maj are the basic SHA2 functions. */
|
||||
#define Ch(b, c, d) (((b) & (c)) ^ ((~b) & (d)))
|
||||
#define Maj(b, c, d) (((b) & (c)) ^ ((b) & (d)) ^ ((c) & (d)))
|
||||
|
||||
/* Rotates x right n bits. */
|
||||
#define ROTR(x, n) \
|
||||
(((x) >> (n)) | ((x) << ((sizeof (x) * NBBY)-(n))))
|
||||
|
||||
/* Shift x right n bits */
|
||||
#define SHR(x, n) ((x) >> (n))
|
||||
|
||||
/* SHA256 Functions */
|
||||
#define BIGSIGMA0_256(x) (ROTR((x), 2) ^ ROTR((x), 13) ^ ROTR((x), 22))
|
||||
#define BIGSIGMA1_256(x) (ROTR((x), 6) ^ ROTR((x), 11) ^ ROTR((x), 25))
|
||||
#define SIGMA0_256(x) (ROTR((x), 7) ^ ROTR((x), 18) ^ SHR((x), 3))
|
||||
#define SIGMA1_256(x) (ROTR((x), 17) ^ ROTR((x), 19) ^ SHR((x), 10))
|
||||
|
||||
#define SHA256ROUND(a, b, c, d, e, f, g, h, i, w) \
|
||||
T1 = h + BIGSIGMA1_256(e) + Ch(e, f, g) + SHA256_CONST(i) + w; \
|
||||
d += T1; \
|
||||
T2 = BIGSIGMA0_256(a) + Maj(a, b, c); \
|
||||
h = T1 + T2
|
||||
|
||||
/*
|
||||
* sparc optimization:
|
||||
*
|
||||
* on the sparc, we can load big endian 32-bit data easily. note that
|
||||
* special care must be taken to ensure the address is 32-bit aligned.
|
||||
* in the interest of speed, we don't check to make sure, since
|
||||
* careful programming can guarantee this for us.
|
||||
*/
|
||||
|
||||
#if defined(_BIG_ENDIAN)
|
||||
#define LOAD_BIG_32(addr) (*(uint32_t *)(addr))
|
||||
#define LOAD_BIG_64(addr) (*(uint64_t *)(addr))
|
||||
|
||||
#elif defined(HAVE_HTONL)
|
||||
#define LOAD_BIG_32(addr) htonl(*((uint32_t *)(addr)))
|
||||
#define LOAD_BIG_64(addr) htonll(*((uint64_t *)(addr)))
|
||||
|
||||
#else
|
||||
/* little endian -- will work on big endian, but slowly */
|
||||
#define LOAD_BIG_32(addr) \
|
||||
(((addr)[0] << 24) | ((addr)[1] << 16) | ((addr)[2] << 8) | (addr)[3])
|
||||
#define LOAD_BIG_64(addr) \
|
||||
(((uint64_t)(addr)[0] << 56) | ((uint64_t)(addr)[1] << 48) | \
|
||||
((uint64_t)(addr)[2] << 40) | ((uint64_t)(addr)[3] << 32) | \
|
||||
((uint64_t)(addr)[4] << 24) | ((uint64_t)(addr)[5] << 16) | \
|
||||
((uint64_t)(addr)[6] << 8) | (uint64_t)(addr)[7])
|
||||
#endif /* _BIG_ENDIAN */
|
||||
|
||||
|
||||
#if !defined(__amd64)
|
||||
/* SHA256 Transform */
|
||||
|
||||
static void
|
||||
SHA256Transform(SHA2_CTX *ctx, const uint8_t *blk)
|
||||
{
|
||||
uint32_t a = ctx->state.s32[0];
|
||||
uint32_t b = ctx->state.s32[1];
|
||||
uint32_t c = ctx->state.s32[2];
|
||||
uint32_t d = ctx->state.s32[3];
|
||||
uint32_t e = ctx->state.s32[4];
|
||||
uint32_t f = ctx->state.s32[5];
|
||||
uint32_t g = ctx->state.s32[6];
|
||||
uint32_t h = ctx->state.s32[7];
|
||||
|
||||
uint32_t w0, w1, w2, w3, w4, w5, w6, w7;
|
||||
uint32_t w8, w9, w10, w11, w12, w13, w14, w15;
|
||||
uint32_t T1, T2;
|
||||
|
||||
if ((uintptr_t)blk & 0x3) { /* not 4-byte aligned? */
|
||||
bcopy(blk, ctx->buf_un.buf32, sizeof (ctx->buf_un.buf32));
|
||||
blk = (uint8_t *)ctx->buf_un.buf32;
|
||||
}
|
||||
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w0 = LOAD_BIG_32(blk + 4 * 0);
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 0, w0);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w1 = LOAD_BIG_32(blk + 4 * 1);
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 1, w1);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w2 = LOAD_BIG_32(blk + 4 * 2);
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 2, w2);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w3 = LOAD_BIG_32(blk + 4 * 3);
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 3, w3);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w4 = LOAD_BIG_32(blk + 4 * 4);
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 4, w4);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w5 = LOAD_BIG_32(blk + 4 * 5);
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 5, w5);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w6 = LOAD_BIG_32(blk + 4 * 6);
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 6, w6);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w7 = LOAD_BIG_32(blk + 4 * 7);
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 7, w7);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w8 = LOAD_BIG_32(blk + 4 * 8);
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 8, w8);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w9 = LOAD_BIG_32(blk + 4 * 9);
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 9, w9);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w10 = LOAD_BIG_32(blk + 4 * 10);
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 10, w10);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w11 = LOAD_BIG_32(blk + 4 * 11);
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 11, w11);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w12 = LOAD_BIG_32(blk + 4 * 12);
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 12, w12);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w13 = LOAD_BIG_32(blk + 4 * 13);
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 13, w13);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w14 = LOAD_BIG_32(blk + 4 * 14);
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 14, w14);
|
||||
/* LINTED E_BAD_PTR_CAST_ALIGN */
|
||||
w15 = LOAD_BIG_32(blk + 4 * 15);
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 15, w15);
|
||||
|
||||
w0 = SIGMA1_256(w14) + w9 + SIGMA0_256(w1) + w0;
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 16, w0);
|
||||
w1 = SIGMA1_256(w15) + w10 + SIGMA0_256(w2) + w1;
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 17, w1);
|
||||
w2 = SIGMA1_256(w0) + w11 + SIGMA0_256(w3) + w2;
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 18, w2);
|
||||
w3 = SIGMA1_256(w1) + w12 + SIGMA0_256(w4) + w3;
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 19, w3);
|
||||
w4 = SIGMA1_256(w2) + w13 + SIGMA0_256(w5) + w4;
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 20, w4);
|
||||
w5 = SIGMA1_256(w3) + w14 + SIGMA0_256(w6) + w5;
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 21, w5);
|
||||
w6 = SIGMA1_256(w4) + w15 + SIGMA0_256(w7) + w6;
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 22, w6);
|
||||
w7 = SIGMA1_256(w5) + w0 + SIGMA0_256(w8) + w7;
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 23, w7);
|
||||
w8 = SIGMA1_256(w6) + w1 + SIGMA0_256(w9) + w8;
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 24, w8);
|
||||
w9 = SIGMA1_256(w7) + w2 + SIGMA0_256(w10) + w9;
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 25, w9);
|
||||
w10 = SIGMA1_256(w8) + w3 + SIGMA0_256(w11) + w10;
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 26, w10);
|
||||
w11 = SIGMA1_256(w9) + w4 + SIGMA0_256(w12) + w11;
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 27, w11);
|
||||
w12 = SIGMA1_256(w10) + w5 + SIGMA0_256(w13) + w12;
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 28, w12);
|
||||
w13 = SIGMA1_256(w11) + w6 + SIGMA0_256(w14) + w13;
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 29, w13);
|
||||
w14 = SIGMA1_256(w12) + w7 + SIGMA0_256(w15) + w14;
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 30, w14);
|
||||
w15 = SIGMA1_256(w13) + w8 + SIGMA0_256(w0) + w15;
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 31, w15);
|
||||
|
||||
w0 = SIGMA1_256(w14) + w9 + SIGMA0_256(w1) + w0;
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 32, w0);
|
||||
w1 = SIGMA1_256(w15) + w10 + SIGMA0_256(w2) + w1;
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 33, w1);
|
||||
w2 = SIGMA1_256(w0) + w11 + SIGMA0_256(w3) + w2;
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 34, w2);
|
||||
w3 = SIGMA1_256(w1) + w12 + SIGMA0_256(w4) + w3;
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 35, w3);
|
||||
w4 = SIGMA1_256(w2) + w13 + SIGMA0_256(w5) + w4;
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 36, w4);
|
||||
w5 = SIGMA1_256(w3) + w14 + SIGMA0_256(w6) + w5;
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 37, w5);
|
||||
w6 = SIGMA1_256(w4) + w15 + SIGMA0_256(w7) + w6;
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 38, w6);
|
||||
w7 = SIGMA1_256(w5) + w0 + SIGMA0_256(w8) + w7;
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 39, w7);
|
||||
w8 = SIGMA1_256(w6) + w1 + SIGMA0_256(w9) + w8;
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 40, w8);
|
||||
w9 = SIGMA1_256(w7) + w2 + SIGMA0_256(w10) + w9;
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 41, w9);
|
||||
w10 = SIGMA1_256(w8) + w3 + SIGMA0_256(w11) + w10;
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 42, w10);
|
||||
w11 = SIGMA1_256(w9) + w4 + SIGMA0_256(w12) + w11;
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 43, w11);
|
||||
w12 = SIGMA1_256(w10) + w5 + SIGMA0_256(w13) + w12;
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 44, w12);
|
||||
w13 = SIGMA1_256(w11) + w6 + SIGMA0_256(w14) + w13;
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 45, w13);
|
||||
w14 = SIGMA1_256(w12) + w7 + SIGMA0_256(w15) + w14;
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 46, w14);
|
||||
w15 = SIGMA1_256(w13) + w8 + SIGMA0_256(w0) + w15;
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 47, w15);
|
||||
|
||||
w0 = SIGMA1_256(w14) + w9 + SIGMA0_256(w1) + w0;
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 48, w0);
|
||||
w1 = SIGMA1_256(w15) + w10 + SIGMA0_256(w2) + w1;
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 49, w1);
|
||||
w2 = SIGMA1_256(w0) + w11 + SIGMA0_256(w3) + w2;
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 50, w2);
|
||||
w3 = SIGMA1_256(w1) + w12 + SIGMA0_256(w4) + w3;
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 51, w3);
|
||||
w4 = SIGMA1_256(w2) + w13 + SIGMA0_256(w5) + w4;
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 52, w4);
|
||||
w5 = SIGMA1_256(w3) + w14 + SIGMA0_256(w6) + w5;
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 53, w5);
|
||||
w6 = SIGMA1_256(w4) + w15 + SIGMA0_256(w7) + w6;
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 54, w6);
|
||||
w7 = SIGMA1_256(w5) + w0 + SIGMA0_256(w8) + w7;
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 55, w7);
|
||||
w8 = SIGMA1_256(w6) + w1 + SIGMA0_256(w9) + w8;
|
||||
SHA256ROUND(a, b, c, d, e, f, g, h, 56, w8);
|
||||
w9 = SIGMA1_256(w7) + w2 + SIGMA0_256(w10) + w9;
|
||||
SHA256ROUND(h, a, b, c, d, e, f, g, 57, w9);
|
||||
w10 = SIGMA1_256(w8) + w3 + SIGMA0_256(w11) + w10;
|
||||
SHA256ROUND(g, h, a, b, c, d, e, f, 58, w10);
|
||||
w11 = SIGMA1_256(w9) + w4 + SIGMA0_256(w12) + w11;
|
||||
SHA256ROUND(f, g, h, a, b, c, d, e, 59, w11);
|
||||
w12 = SIGMA1_256(w10) + w5 + SIGMA0_256(w13) + w12;
|
||||
SHA256ROUND(e, f, g, h, a, b, c, d, 60, w12);
|
||||
w13 = SIGMA1_256(w11) + w6 + SIGMA0_256(w14) + w13;
|
||||
SHA256ROUND(d, e, f, g, h, a, b, c, 61, w13);
|
||||
w14 = SIGMA1_256(w12) + w7 + SIGMA0_256(w15) + w14;
|
||||
SHA256ROUND(c, d, e, f, g, h, a, b, 62, w14);
|
||||
w15 = SIGMA1_256(w13) + w8 + SIGMA0_256(w0) + w15;
|
||||
SHA256ROUND(b, c, d, e, f, g, h, a, 63, w15);
|
||||
|
||||
ctx->state.s32[0] += a;
|
||||
ctx->state.s32[1] += b;
|
||||
ctx->state.s32[2] += c;
|
||||
ctx->state.s32[3] += d;
|
||||
ctx->state.s32[4] += e;
|
||||
ctx->state.s32[5] += f;
|
||||
ctx->state.s32[6] += g;
|
||||
ctx->state.s32[7] += h;
|
||||
}
|
||||
#endif /* !__amd64 */
|
||||
|
||||
|
||||
/*
|
||||
* Encode()
|
||||
*
|
||||
* purpose: to convert a list of numbers from little endian to big endian
|
||||
* input: uint8_t * : place to store the converted big endian numbers
|
||||
* uint32_t * : place to get numbers to convert from
|
||||
* size_t : the length of the input in bytes
|
||||
* output: void
|
||||
*/
|
||||
|
||||
static void
|
||||
Encode(uint8_t *_RESTRICT_KYWD output, uint32_t *_RESTRICT_KYWD input,
|
||||
size_t len)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (input[i] >> 24) & 0xff;
|
||||
output[j + 1] = (input[i] >> 16) & 0xff;
|
||||
output[j + 2] = (input[i] >> 8) & 0xff;
|
||||
output[j + 3] = input[i] & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SHA2Init(uint64_t mech, SHA2_CTX *ctx)
|
||||
{
|
||||
|
||||
switch (mech) {
|
||||
case SHA256_MECH_INFO_TYPE:
|
||||
case SHA256_HMAC_MECH_INFO_TYPE:
|
||||
case SHA256_HMAC_GEN_MECH_INFO_TYPE:
|
||||
ctx->state.s32[0] = 0x6a09e667U;
|
||||
ctx->state.s32[1] = 0xbb67ae85U;
|
||||
ctx->state.s32[2] = 0x3c6ef372U;
|
||||
ctx->state.s32[3] = 0xa54ff53aU;
|
||||
ctx->state.s32[4] = 0x510e527fU;
|
||||
ctx->state.s32[5] = 0x9b05688cU;
|
||||
ctx->state.s32[6] = 0x1f83d9abU;
|
||||
ctx->state.s32[7] = 0x5be0cd19U;
|
||||
break;
|
||||
default:
|
||||
cmn_err(CE_PANIC,
|
||||
"sha2_init: failed to find a supported algorithm: 0x%x",
|
||||
(uint32_t)mech);
|
||||
}
|
||||
|
||||
ctx->algotype = (uint32_t)mech;
|
||||
ctx->count.c64[0] = ctx->count.c64[1] = 0;
|
||||
}
|
||||
|
||||
void
|
||||
SHA256Init(SHA256_CTX *ctx)
|
||||
{
|
||||
SHA2Init(SHA256, ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA2Update()
|
||||
*
|
||||
* purpose: continues an sha2 digest operation, using the message block
|
||||
* to update the context.
|
||||
* input: SHA2_CTX * : the context to update
|
||||
* void * : the message block
|
||||
* size_t : the length of the message block, in bytes
|
||||
* output: void
|
||||
*/
|
||||
|
||||
void
|
||||
SHA2Update(SHA2_CTX *ctx, const void *inptr, size_t input_len)
|
||||
{
|
||||
uint32_t i, buf_index, buf_len, buf_limit;
|
||||
const uint8_t *input = inptr;
|
||||
uint32_t algotype = ctx->algotype;
|
||||
#if defined(__amd64)
|
||||
uint32_t block_count;
|
||||
#endif /* !__amd64 */
|
||||
|
||||
|
||||
/* check for noop */
|
||||
if (input_len == 0)
|
||||
return;
|
||||
|
||||
if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
|
||||
buf_limit = 64;
|
||||
|
||||
/* compute number of bytes mod 64 */
|
||||
buf_index = (ctx->count.c32[1] >> 3) & 0x3F;
|
||||
|
||||
/* update number of bits */
|
||||
if ((ctx->count.c32[1] += (input_len << 3)) < (input_len << 3))
|
||||
ctx->count.c32[0]++;
|
||||
|
||||
ctx->count.c32[0] += (input_len >> 29);
|
||||
|
||||
} else {
|
||||
buf_limit = 128;
|
||||
|
||||
/* compute number of bytes mod 128 */
|
||||
buf_index = (ctx->count.c64[1] >> 3) & 0x7F;
|
||||
|
||||
/* update number of bits */
|
||||
if ((ctx->count.c64[1] += (input_len << 3)) < (input_len << 3))
|
||||
ctx->count.c64[0]++;
|
||||
|
||||
ctx->count.c64[0] += (input_len >> 29);
|
||||
}
|
||||
|
||||
buf_len = buf_limit - buf_index;
|
||||
|
||||
/* transform as many times as possible */
|
||||
i = 0;
|
||||
if (input_len >= buf_len) {
|
||||
|
||||
/*
|
||||
* general optimization:
|
||||
*
|
||||
* only do initial bcopy() and SHA2Transform() if
|
||||
* buf_index != 0. if buf_index == 0, we're just
|
||||
* wasting our time doing the bcopy() since there
|
||||
* wasn't any data left over from a previous call to
|
||||
* SHA2Update().
|
||||
*/
|
||||
if (buf_index) {
|
||||
bcopy(input, &ctx->buf_un.buf8[buf_index], buf_len);
|
||||
if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE)
|
||||
SHA256Transform(ctx, ctx->buf_un.buf8);
|
||||
|
||||
i = buf_len;
|
||||
}
|
||||
|
||||
#if !defined(__amd64)
|
||||
if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
|
||||
for (; i + buf_limit - 1 < input_len; i += buf_limit) {
|
||||
SHA256Transform(ctx, &input[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
|
||||
block_count = (input_len - i) >> 6;
|
||||
if (block_count > 0) {
|
||||
SHA256TransformBlocks(ctx, &input[i],
|
||||
block_count);
|
||||
i += block_count << 6;
|
||||
}
|
||||
}
|
||||
#endif /* !__amd64 */
|
||||
|
||||
/*
|
||||
* general optimization:
|
||||
*
|
||||
* if i and input_len are the same, return now instead
|
||||
* of calling bcopy(), since the bcopy() in this case
|
||||
* will be an expensive noop.
|
||||
*/
|
||||
|
||||
if (input_len == i)
|
||||
return;
|
||||
|
||||
buf_index = 0;
|
||||
}
|
||||
|
||||
/* buffer remaining input */
|
||||
bcopy(&input[i], &ctx->buf_un.buf8[buf_index], input_len - i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SHA2Final()
|
||||
*
|
||||
* purpose: ends an sha2 digest operation, finalizing the message digest and
|
||||
* zeroing the context.
|
||||
* input: uchar_t * : a buffer to store the digest
|
||||
* : The function actually uses void* because many
|
||||
* : callers pass things other than uchar_t here.
|
||||
* SHA2_CTX * : the context to finalize, save, and zero
|
||||
* output: void
|
||||
*/
|
||||
|
||||
void
|
||||
SHA2Final(void *digest, SHA2_CTX *ctx)
|
||||
{
|
||||
uint8_t bitcount_be[sizeof (ctx->count.c32)];
|
||||
uint32_t index;
|
||||
uint32_t algotype = ctx->algotype;
|
||||
|
||||
if (algotype <= SHA256_HMAC_GEN_MECH_INFO_TYPE) {
|
||||
index = (ctx->count.c32[1] >> 3) & 0x3f;
|
||||
Encode(bitcount_be, ctx->count.c32, sizeof (bitcount_be));
|
||||
SHA2Update(ctx, PADDING, ((index < 56) ? 56 : 120) - index);
|
||||
SHA2Update(ctx, bitcount_be, sizeof (bitcount_be));
|
||||
Encode(digest, ctx->state.s32, sizeof (ctx->state.s32));
|
||||
}
|
||||
|
||||
/* zeroize sensitive information */
|
||||
bzero(ctx, sizeof (*ctx));
|
||||
}
|
935
module/icp/api/kcf_cipher.c
Normal file
935
module/icp/api/kcf_cipher.c
Normal file
@ -0,0 +1,935 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f)
|
||||
#define CRYPTO_CIPHER_OFFSET(f) offsetof(crypto_cipher_ops_t, f)
|
||||
|
||||
/*
|
||||
* Encryption and decryption routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following are the possible returned values common to all the routines
|
||||
* below. The applicability of some of these return values depends on the
|
||||
* presence of the arguments.
|
||||
*
|
||||
* CRYPTO_SUCCESS: The operation completed successfully.
|
||||
* CRYPTO_QUEUED: A request was submitted successfully. The callback
|
||||
* routine will be called when the operation is done.
|
||||
* CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
|
||||
* CRYPTO_INVALID_MECH for problems with the 'mech'.
|
||||
* CRYPTO_INVALID_DATA for bogus 'data'
|
||||
* CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
|
||||
* CRYPTO_INVALID_CONTEXT: Not a valid context.
|
||||
* CRYPTO_BUSY: Cannot process the request now. Schedule a
|
||||
* crypto_bufcall(), or try later.
|
||||
* CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
|
||||
* capable of a function or a mechanism.
|
||||
* CRYPTO_INVALID_KEY: bogus 'key' argument.
|
||||
* CRYPTO_INVALID_PLAINTEXT: bogus 'plaintext' argument.
|
||||
* CRYPTO_INVALID_CIPHERTEXT: bogus 'ciphertext' argument.
|
||||
*/
|
||||
|
||||
/*
|
||||
* crypto_cipher_init_prov()
|
||||
*
|
||||
* Arguments:
|
||||
*
|
||||
* pd: provider descriptor
|
||||
* sid: session id
|
||||
* 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.
|
||||
* tmpl: a crypto_ctx_template_t, opaque template of a context of an
|
||||
* encryption or decryption with the 'mech' using 'key'.
|
||||
* 'tmpl' is created by a previous call to
|
||||
* crypto_create_ctx_template().
|
||||
* ctxp: Pointer to a crypto_context_t.
|
||||
* func: CRYPTO_FG_ENCRYPT or CRYPTO_FG_DECRYPT.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* This is a common function invoked internally by both
|
||||
* crypto_encrypt_init() and crypto_decrypt_init().
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* initialization of an encryption or a decryption operation.
|
||||
* When possible and applicable, will internally use the pre-expanded key
|
||||
* schedule from the context template, tmpl.
|
||||
* When complete and successful, 'ctxp' will contain a crypto_context_t
|
||||
* valid for later calls to encrypt_update() and encrypt_final(), or
|
||||
* decrypt_update() and decrypt_final().
|
||||
* The caller should hold a reference on the specified provider
|
||||
* descriptor before calling this function.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
static int
|
||||
crypto_cipher_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_spi_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq, crypto_func_group_t func)
|
||||
{
|
||||
int error;
|
||||
crypto_ctx_t *ctx;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
if (func == CRYPTO_FG_ENCRYPT) {
|
||||
error = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_ENCRYPT);
|
||||
} else {
|
||||
error = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_DECRYPT);
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Allocate and initialize the canonical context */
|
||||
if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
|
||||
|
||||
if (func == CRYPTO_FG_ENCRYPT)
|
||||
error = KCF_PROV_ENCRYPT_INIT(real_provider, ctx,
|
||||
&lmech, key, tmpl, KCF_SWFP_RHNDL(crq));
|
||||
else {
|
||||
ASSERT(func == CRYPTO_FG_DECRYPT);
|
||||
|
||||
error = KCF_PROV_DECRYPT_INIT(real_provider, ctx,
|
||||
&lmech, key, tmpl, KCF_SWFP_RHNDL(crq));
|
||||
}
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Check if context sharing is possible */
|
||||
if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
key->ck_format == CRYPTO_KEY_RAW &&
|
||||
KCF_CAN_SHARE_OPSTATE(pd, mech->cm_type)) {
|
||||
kcf_context_t *tctxp = (kcf_context_t *)ctx;
|
||||
kcf_provider_desc_t *tpd = NULL;
|
||||
crypto_mech_info_t *sinfo;
|
||||
|
||||
if ((kcf_get_sw_prov(mech->cm_type, &tpd, &tctxp->kc_mech,
|
||||
B_FALSE) == CRYPTO_SUCCESS)) {
|
||||
int tlen;
|
||||
|
||||
sinfo = &(KCF_TO_PROV_MECHINFO(tpd, mech->cm_type));
|
||||
/*
|
||||
* key->ck_length from the consumer is always in bits.
|
||||
* We convert it to be in the same unit registered by
|
||||
* the provider in order to do a comparison.
|
||||
*/
|
||||
if (sinfo->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)
|
||||
tlen = key->ck_length >> 3;
|
||||
else
|
||||
tlen = key->ck_length;
|
||||
/*
|
||||
* Check if the software provider can support context
|
||||
* sharing and support this key length.
|
||||
*/
|
||||
if ((sinfo->cm_mech_flags & CRYPTO_CAN_SHARE_OPSTATE) &&
|
||||
(tlen >= sinfo->cm_min_key_length) &&
|
||||
(tlen <= sinfo->cm_max_key_length)) {
|
||||
ctx->cc_flags = CRYPTO_INIT_OPSTATE;
|
||||
tctxp->kc_sw_prov_desc = tpd;
|
||||
} else
|
||||
KCF_PROV_REFRELE(tpd);
|
||||
}
|
||||
}
|
||||
|
||||
if (func == CRYPTO_FG_ENCRYPT) {
|
||||
KCF_WRAP_ENCRYPT_OPS_PARAMS(¶ms, KCF_OP_INIT, sid,
|
||||
mech, key, NULL, NULL, tmpl);
|
||||
} else {
|
||||
ASSERT(func == CRYPTO_FG_DECRYPT);
|
||||
KCF_WRAP_DECRYPT_OPS_PARAMS(¶ms, KCF_OP_INIT, sid,
|
||||
mech, key, NULL, NULL, tmpl);
|
||||
}
|
||||
|
||||
error = kcf_submit_request(real_provider, ctx, crq, ¶ms,
|
||||
B_FALSE);
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
done:
|
||||
if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
|
||||
*ctxp = (crypto_context_t)ctx;
|
||||
else {
|
||||
/* Release the hold done in kcf_new_ctx(). */
|
||||
KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_cipher_init_prov(), but relies on the scheduler to pick
|
||||
* an appropriate provider. See crypto_cipher_init_prov() comments for more
|
||||
* details.
|
||||
*/
|
||||
static int
|
||||
crypto_cipher_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq, crypto_func_group_t func)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *me;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_ctx_template_t *ctx_tmpl;
|
||||
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
|
||||
list, func, CHECK_RESTRICT(crq), 0)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* For SW providers, check the validity of the context template
|
||||
* It is very rare that the generation number mis-matches, so
|
||||
* is acceptable to fail here, and let the consumer recover by
|
||||
* freeing this tmpl and create a new one for the key and new SW
|
||||
* provider
|
||||
*/
|
||||
if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
|
||||
((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
|
||||
if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (CRYPTO_OLD_CTX_TEMPLATE);
|
||||
} else {
|
||||
spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
error = crypto_cipher_init_prov(pd, pd->pd_sid, mech, key,
|
||||
spi_ctx_tmpl, ctxp, crq, func);
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_encrypt_prov()
|
||||
*
|
||||
* Arguments:
|
||||
* pd: provider descriptor
|
||||
* sid: session id
|
||||
* 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.
|
||||
* plaintext: The message to be encrypted
|
||||
* ciphertext: Storage for the encrypted message. The length needed
|
||||
* depends on the mechanism, and the plaintext's size.
|
||||
* tmpl: a crypto_ctx_template_t, opaque template of a context of an
|
||||
* encryption with the 'mech' using 'key'. 'tmpl' is created by
|
||||
* a previous call to crypto_create_ctx_template().
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* single-part encryption of 'plaintext' with the mechanism 'mech', using
|
||||
* the key 'key'.
|
||||
* When complete and successful, 'ciphertext' will contain the encrypted
|
||||
* message.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_encrypt_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_data_t *plaintext, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
int error;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
error = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_ENCRYPT_ATOMIC);
|
||||
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
return (error);
|
||||
}
|
||||
|
||||
KCF_WRAP_ENCRYPT_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, key,
|
||||
plaintext, ciphertext, tmpl);
|
||||
|
||||
error = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_encrypt_prov(), but relies on the scheduler to pick
|
||||
* a provider. See crypto_encrypt_prov() for more details.
|
||||
*/
|
||||
int
|
||||
crypto_encrypt(crypto_mechanism_t *mech, crypto_data_t *plaintext,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *ciphertext,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *me;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_ctx_template_t *ctx_tmpl;
|
||||
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
|
||||
list, CRYPTO_FG_ENCRYPT_ATOMIC, CHECK_RESTRICT(crq),
|
||||
plaintext->cd_length)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* For SW providers, check the validity of the context template
|
||||
* It is very rare that the generation number mis-matches, so
|
||||
* is acceptable to fail here, and let the consumer recover by
|
||||
* freeing this tmpl and create a new one for the key and new SW
|
||||
* provider
|
||||
*/
|
||||
if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
|
||||
((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
|
||||
if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (CRYPTO_OLD_CTX_TEMPLATE);
|
||||
} else {
|
||||
spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
|
||||
|
||||
error = KCF_PROV_ENCRYPT_ATOMIC(pd, pd->pd_sid, &lmech, key,
|
||||
plaintext, ciphertext, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_ENCRYPT_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, pd->pd_sid,
|
||||
mech, key, plaintext, ciphertext, spi_ctx_tmpl);
|
||||
error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_encrypt_init_prov()
|
||||
*
|
||||
* Calls crypto_cipher_init_prov() to initialize an encryption operation.
|
||||
*/
|
||||
int
|
||||
crypto_encrypt_init_prov(crypto_provider_t pd, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
return (crypto_cipher_init_prov(pd, sid, mech, key, tmpl, ctxp, crq,
|
||||
CRYPTO_FG_ENCRYPT));
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_encrypt_init()
|
||||
*
|
||||
* Calls crypto_cipher_init() to initialize an encryption operation
|
||||
*/
|
||||
int
|
||||
crypto_encrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
return (crypto_cipher_init(mech, key, tmpl, ctxp, crq,
|
||||
CRYPTO_FG_ENCRYPT));
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_encrypt_update()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by encrypt_init().
|
||||
* plaintext: The message part to be encrypted
|
||||
* ciphertext: Storage for the encrypted message part.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* part of an encryption operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_encrypt_update(crypto_context_t context, crypto_data_t *plaintext,
|
||||
crypto_data_t *ciphertext, crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_ENCRYPT_UPDATE(pd, ctx, plaintext,
|
||||
ciphertext, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Check if we should use a software provider for small jobs */
|
||||
if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && cr == NULL) {
|
||||
if (plaintext->cd_length < kcf_ctx->kc_mech->me_threshold &&
|
||||
kcf_ctx->kc_sw_prov_desc != NULL &&
|
||||
KCF_IS_PROV_USABLE(kcf_ctx->kc_sw_prov_desc)) {
|
||||
pd = kcf_ctx->kc_sw_prov_desc;
|
||||
}
|
||||
}
|
||||
|
||||
KCF_WRAP_ENCRYPT_OPS_PARAMS(¶ms, KCF_OP_UPDATE,
|
||||
ctx->cc_session, NULL, NULL, plaintext, ciphertext, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_encrypt_final()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by encrypt_init().
|
||||
* ciphertext: Storage for the last part of encrypted message
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* final part of an encryption operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_encrypt_final(crypto_context_t context, crypto_data_t *ciphertext,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_ENCRYPT_FINAL(pd, ctx, ciphertext, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_ENCRYPT_OPS_PARAMS(¶ms, KCF_OP_FINAL,
|
||||
ctx->cc_session, NULL, NULL, NULL, ciphertext, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_decrypt_prov()
|
||||
*
|
||||
* Arguments:
|
||||
* pd: provider descriptor
|
||||
* sid: session id
|
||||
* 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.
|
||||
* ciphertext: The message to be encrypted
|
||||
* plaintext: Storage for the encrypted message. The length needed
|
||||
* depends on the mechanism, and the plaintext's size.
|
||||
* tmpl: a crypto_ctx_template_t, opaque template of a context of an
|
||||
* encryption with the 'mech' using 'key'. 'tmpl' is created by
|
||||
* a previous call to crypto_create_ctx_template().
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* single-part decryption of 'ciphertext' with the mechanism 'mech', using
|
||||
* the key 'key'.
|
||||
* When complete and successful, 'plaintext' will contain the decrypted
|
||||
* message.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_decrypt_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_data_t *ciphertext, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
int rv;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
rv = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_DECRYPT_ATOMIC);
|
||||
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
KCF_WRAP_DECRYPT_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, key,
|
||||
ciphertext, plaintext, tmpl);
|
||||
|
||||
rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_decrypt_prov(), but relies on the KCF scheduler to
|
||||
* choose a provider. See crypto_decrypt_prov() comments for more
|
||||
* information.
|
||||
*/
|
||||
int
|
||||
crypto_decrypt(crypto_mechanism_t *mech, crypto_data_t *ciphertext,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *plaintext,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *me;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_ctx_template_t *ctx_tmpl;
|
||||
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
|
||||
list, CRYPTO_FG_DECRYPT_ATOMIC, CHECK_RESTRICT(crq),
|
||||
ciphertext->cd_length)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* For SW providers, check the validity of the context template
|
||||
* It is very rare that the generation number mis-matches, so
|
||||
* is acceptable to fail here, and let the consumer recover by
|
||||
* freeing this tmpl and create a new one for the key and new SW
|
||||
* provider
|
||||
*/
|
||||
if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
|
||||
((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
|
||||
if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (CRYPTO_OLD_CTX_TEMPLATE);
|
||||
} else {
|
||||
spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
|
||||
|
||||
error = KCF_PROV_DECRYPT_ATOMIC(pd, pd->pd_sid, &lmech, key,
|
||||
ciphertext, plaintext, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DECRYPT_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, pd->pd_sid,
|
||||
mech, key, ciphertext, plaintext, spi_ctx_tmpl);
|
||||
error = kcf_submit_request(pd, NULL, crq, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_decrypt_init_prov()
|
||||
*
|
||||
* Calls crypto_cipher_init_prov() to initialize a decryption operation
|
||||
*/
|
||||
int
|
||||
crypto_decrypt_init_prov(crypto_provider_t pd, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
return (crypto_cipher_init_prov(pd, sid, mech, key, tmpl, ctxp, crq,
|
||||
CRYPTO_FG_DECRYPT));
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_decrypt_init()
|
||||
*
|
||||
* Calls crypto_cipher_init() to initialize a decryption operation
|
||||
*/
|
||||
int
|
||||
crypto_decrypt_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
return (crypto_cipher_init(mech, key, tmpl, ctxp, crq,
|
||||
CRYPTO_FG_DECRYPT));
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_decrypt_update()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by decrypt_init().
|
||||
* ciphertext: The message part to be decrypted
|
||||
* plaintext: Storage for the decrypted message part.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* part of an decryption operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_decrypt_update(crypto_context_t context, crypto_data_t *ciphertext,
|
||||
crypto_data_t *plaintext, crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DECRYPT_UPDATE(pd, ctx, ciphertext,
|
||||
plaintext, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Check if we should use a software provider for small jobs */
|
||||
if ((ctx->cc_flags & CRYPTO_USE_OPSTATE) && cr == NULL) {
|
||||
if (ciphertext->cd_length < kcf_ctx->kc_mech->me_threshold &&
|
||||
kcf_ctx->kc_sw_prov_desc != NULL &&
|
||||
KCF_IS_PROV_USABLE(kcf_ctx->kc_sw_prov_desc)) {
|
||||
pd = kcf_ctx->kc_sw_prov_desc;
|
||||
}
|
||||
}
|
||||
|
||||
KCF_WRAP_DECRYPT_OPS_PARAMS(¶ms, KCF_OP_UPDATE,
|
||||
ctx->cc_session, NULL, NULL, ciphertext, plaintext, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_decrypt_final()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by decrypt_init().
|
||||
* plaintext: Storage for the last part of the decrypted message
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* final part of a decryption operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_decrypt_final(crypto_context_t context, crypto_data_t *plaintext,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DECRYPT_FINAL(pd, ctx, plaintext,
|
||||
NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DECRYPT_OPS_PARAMS(¶ms, KCF_OP_FINAL,
|
||||
ctx->cc_session, NULL, NULL, NULL, plaintext, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* See comments for crypto_encrypt_update().
|
||||
*/
|
||||
int
|
||||
crypto_encrypt_single(crypto_context_t context, crypto_data_t *plaintext,
|
||||
crypto_data_t *ciphertext, crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_ENCRYPT(pd, ctx, plaintext,
|
||||
ciphertext, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_ENCRYPT_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid,
|
||||
NULL, NULL, plaintext, ciphertext, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* See comments for crypto_decrypt_update().
|
||||
*/
|
||||
int
|
||||
crypto_decrypt_single(crypto_context_t context, crypto_data_t *ciphertext,
|
||||
crypto_data_t *plaintext, crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DECRYPT(pd, ctx, ciphertext,
|
||||
plaintext, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DECRYPT_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid,
|
||||
NULL, NULL, ciphertext, plaintext, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||
EXPORT_SYMBOL(crypto_cipher_init_prov);
|
||||
EXPORT_SYMBOL(crypto_cipher_init);
|
||||
EXPORT_SYMBOL(crypto_encrypt_prov);
|
||||
EXPORT_SYMBOL(crypto_encrypt);
|
||||
EXPORT_SYMBOL(crypto_encrypt_init_prov);
|
||||
EXPORT_SYMBOL(crypto_encrypt_init);
|
||||
EXPORT_SYMBOL(crypto_encrypt_update);
|
||||
EXPORT_SYMBOL(crypto_encrypt_final);
|
||||
EXPORT_SYMBOL(crypto_decrypt_prov);
|
||||
EXPORT_SYMBOL(crypto_decrypt);
|
||||
EXPORT_SYMBOL(crypto_decrypt_init_prov);
|
||||
EXPORT_SYMBOL(crypto_decrypt_init);
|
||||
EXPORT_SYMBOL(crypto_decrypt_update);
|
||||
EXPORT_SYMBOL(crypto_decrypt_final);
|
||||
EXPORT_SYMBOL(crypto_encrypt_single);
|
||||
EXPORT_SYMBOL(crypto_decrypt_single);
|
||||
#endif
|
151
module/icp/api/kcf_ctxops.c
Normal file
151
module/icp/api/kcf_ctxops.c
Normal file
@ -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
|
494
module/icp/api/kcf_digest.c
Normal file
494
module/icp/api/kcf_digest.c
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f)
|
||||
#define CRYPTO_DIGEST_OFFSET(f) offsetof(crypto_digest_ops_t, f)
|
||||
|
||||
/*
|
||||
* Message digest routines
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following are the possible returned values common to all the routines
|
||||
* below. The applicability of some of these return values depends on the
|
||||
* presence of the arguments.
|
||||
*
|
||||
* CRYPTO_SUCCESS: The operation completed successfully.
|
||||
* CRYPTO_QUEUED: A request was submitted successfully. The callback
|
||||
* routine will be called when the operation is done.
|
||||
* CRYPTO_MECHANISM_INVALID or CRYPTO_INVALID_MECH_PARAM
|
||||
* for problems with the 'mech'.
|
||||
* CRYPTO_INVALID_DATA for bogus 'data'
|
||||
* CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
|
||||
* CRYPTO_INVALID_CONTEXT: Not a valid context.
|
||||
* CRYPTO_BUSY: Cannot process the request now. Schedule a
|
||||
* crypto_bufcall(), or try later.
|
||||
* CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED:
|
||||
* No provider is capable of a function or a mechanism.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* crypto_digest_prov()
|
||||
*
|
||||
* Arguments:
|
||||
* pd: pointer to the descriptor of the provider to use for this
|
||||
* operation.
|
||||
* sid: provider session id.
|
||||
* 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.
|
||||
* data: The message to be digested.
|
||||
* digest: Storage for the digest. The length needed depends on the
|
||||
* mechanism.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* digesting operation of 'data' on the specified
|
||||
* provider with the specified session.
|
||||
* When complete and successful, 'digest' will contain the digest value.
|
||||
* The caller should hold a reference on the specified provider
|
||||
* descriptor before calling this function.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_digest_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_data_t *data, crypto_data_t *digest,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
int rv;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
rv = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq),
|
||||
pd, &real_provider, CRYPTO_FG_DIGEST_ATOMIC);
|
||||
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
}
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, NULL,
|
||||
data, digest);
|
||||
|
||||
/* no crypto context to carry between multiple parts. */
|
||||
rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Same as crypto_digest_prov(), but relies on the KCF scheduler to
|
||||
* choose a provider. See crypto_digest_prov() comments for more information.
|
||||
*/
|
||||
int
|
||||
crypto_digest(crypto_mechanism_t *mech, crypto_data_t *data,
|
||||
crypto_data_t *digest, crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_req_params_t params;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* The pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error, list,
|
||||
CRYPTO_FG_DIGEST_ATOMIC, CHECK_RESTRICT(crq),
|
||||
data->cd_length)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
|
||||
error = KCF_PROV_DIGEST_ATOMIC(pd, pd->pd_sid, &lmech, data,
|
||||
digest, KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
|
||||
(data->cd_length > pd->pd_hash_limit)) {
|
||||
error = CRYPTO_BUFFER_TOO_BIG;
|
||||
} else {
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_ATOMIC,
|
||||
pd->pd_sid, mech, NULL, data, digest);
|
||||
|
||||
/* no crypto context to carry between multiple parts. */
|
||||
error = kcf_submit_request(pd, NULL, crq, ¶ms,
|
||||
B_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_digest_init_prov()
|
||||
*
|
||||
* pd: pointer to the descriptor of the provider to use for this
|
||||
* operation.
|
||||
* sid: provider session id.
|
||||
* 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.
|
||||
* ctxp: Pointer to a crypto_context_t.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* initialization of a message digest operation on the specified
|
||||
* provider with the specified session.
|
||||
* When complete and successful, 'ctxp' will contain a crypto_context_t
|
||||
* valid for later calls to digest_update() and digest_final().
|
||||
* The caller should hold a reference on the specified provider
|
||||
* descriptor before calling this function.
|
||||
*/
|
||||
int
|
||||
crypto_digest_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_context_t *ctxp, crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
crypto_ctx_t *ctx;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
error = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_DIGEST);
|
||||
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Allocate and initialize the canonical context */
|
||||
if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
|
||||
error = KCF_PROV_DIGEST_INIT(real_provider, ctx, &lmech,
|
||||
KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_INIT, sid,
|
||||
mech, NULL, NULL, NULL);
|
||||
error = kcf_submit_request(real_provider, ctx, crq, ¶ms,
|
||||
B_FALSE);
|
||||
}
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
if ((error == CRYPTO_SUCCESS) || (error == CRYPTO_QUEUED))
|
||||
*ctxp = (crypto_context_t)ctx;
|
||||
else {
|
||||
/* Release the hold done in kcf_new_ctx(). */
|
||||
KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_digest_init_prov(), but relies on the KCF scheduler
|
||||
* to choose a provider. See crypto_digest_init_prov() comments for
|
||||
* more information.
|
||||
*/
|
||||
int
|
||||
crypto_digest_init(crypto_mechanism_t *mech, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* The pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, NULL, &error,
|
||||
list, CRYPTO_FG_DIGEST, CHECK_RESTRICT(crq), 0)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
|
||||
/*
|
||||
* The hardware provider has limited digest support.
|
||||
* So, we fallback early here to using a software provider.
|
||||
*
|
||||
* XXX - need to enhance to do the fallback later in
|
||||
* crypto_digest_update() if the size of accumulated input data
|
||||
* exceeds the maximum size digestable by hardware provider.
|
||||
*/
|
||||
error = CRYPTO_BUFFER_TOO_BIG;
|
||||
} else {
|
||||
error = crypto_digest_init_prov(pd, pd->pd_sid,
|
||||
mech, ctxp, crq);
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_digest_update()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by digest_init().
|
||||
* data: The part of message to be digested.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* part of a message digest operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_digest_update(crypto_context_t context, crypto_data_t *data,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DIGEST_UPDATE(pd, ctx, data, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_UPDATE,
|
||||
ctx->cc_session, NULL, NULL, data, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_digest_final()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by digest_init().
|
||||
* digest: The storage for the digest.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* final part of a message digest operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_digest_final(crypto_context_t context, crypto_data_t *digest,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DIGEST_FINAL(pd, ctx, digest, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_FINAL,
|
||||
ctx->cc_session, NULL, NULL, NULL, digest);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a digest update on the specified key. Note that there is
|
||||
* no k-API crypto_digest_key() equivalent of this function.
|
||||
*/
|
||||
int
|
||||
crypto_digest_key_prov(crypto_context_t context, crypto_key_t *key,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DIGEST_KEY(pd, ctx, key, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_DIGEST_KEY,
|
||||
ctx->cc_session, NULL, key, NULL, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* See comments for crypto_digest_update() and crypto_digest_final().
|
||||
*/
|
||||
int
|
||||
crypto_digest_single(crypto_context_t context, crypto_data_t *data,
|
||||
crypto_data_t *digest, crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_DIGEST(pd, ctx, data, digest, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_DIGEST_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid,
|
||||
NULL, NULL, data, digest);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||
EXPORT_SYMBOL(crypto_digest_prov);
|
||||
EXPORT_SYMBOL(crypto_digest);
|
||||
EXPORT_SYMBOL(crypto_digest_init_prov);
|
||||
EXPORT_SYMBOL(crypto_digest_init);
|
||||
EXPORT_SYMBOL(crypto_digest_update);
|
||||
EXPORT_SYMBOL(crypto_digest_final);
|
||||
EXPORT_SYMBOL(crypto_digest_key_prov);
|
||||
EXPORT_SYMBOL(crypto_digest_single);
|
||||
#endif
|
648
module/icp/api/kcf_mac.c
Normal file
648
module/icp/api/kcf_mac.c
Normal file
@ -0,0 +1,648 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
#define CRYPTO_OPS_OFFSET(f) offsetof(crypto_ops_t, co_##f)
|
||||
#define CRYPTO_MAC_OFFSET(f) offsetof(crypto_mac_ops_t, f)
|
||||
|
||||
/*
|
||||
* Message authentication codes routines.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following are the possible returned values common to all the routines
|
||||
* below. The applicability of some of these return values depends on the
|
||||
* presence of the arguments.
|
||||
*
|
||||
* CRYPTO_SUCCESS: The operation completed successfully.
|
||||
* CRYPTO_QUEUED: A request was submitted successfully. The callback
|
||||
* routine will be called when the operation is done.
|
||||
* CRYPTO_INVALID_MECH_NUMBER, CRYPTO_INVALID_MECH_PARAM, or
|
||||
* CRYPTO_INVALID_MECH for problems with the 'mech'.
|
||||
* CRYPTO_INVALID_DATA for bogus 'data'
|
||||
* CRYPTO_HOST_MEMORY for failure to allocate memory to handle this work.
|
||||
* CRYPTO_INVALID_CONTEXT: Not a valid context.
|
||||
* CRYPTO_BUSY: Cannot process the request now. Schedule a
|
||||
* crypto_bufcall(), or try later.
|
||||
* CRYPTO_NOT_SUPPORTED and CRYPTO_MECH_NOT_SUPPORTED: No provider is
|
||||
* capable of a function or a mechanism.
|
||||
* CRYPTO_INVALID_KEY: bogus 'key' argument.
|
||||
* CRYPTO_INVALID_MAC: bogus 'mac' argument.
|
||||
*/
|
||||
|
||||
/*
|
||||
* crypto_mac_prov()
|
||||
*
|
||||
* 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.
|
||||
* data: The message to compute the MAC for.
|
||||
* mac: Storage for the MAC. The length needed depends on the mechanism.
|
||||
* tmpl: a crypto_ctx_template_t, opaque template of a context of a
|
||||
* MAC with the 'mech' using 'key'. 'tmpl' is created by
|
||||
* a previous call to crypto_create_ctx_template().
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* single-part message authentication of 'data' with the mechanism
|
||||
* 'mech', using * the key 'key', on the specified provider with
|
||||
* the specified session id.
|
||||
* When complete and successful, 'mac' will contain the message
|
||||
* authentication code.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'crq'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_mac_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
|
||||
{
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
int rv;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
rv = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_MAC_ATOMIC);
|
||||
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_ATOMIC, sid, mech, key,
|
||||
data, mac, tmpl);
|
||||
rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_mac_prov(), but relies on the KCF scheduler to choose
|
||||
* a provider. See crypto_mac() comments for more information.
|
||||
*/
|
||||
int
|
||||
crypto_mac(crypto_mechanism_t *mech, crypto_data_t *data,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *me;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_ctx_template_t *ctx_tmpl;
|
||||
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* The pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
|
||||
list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
|
||||
data->cd_length)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* For SW providers, check the validity of the context template
|
||||
* It is very rare that the generation number mis-matches, so
|
||||
* is acceptable to fail here, and let the consumer recover by
|
||||
* freeing this tmpl and create a new one for the key and new SW
|
||||
* provider
|
||||
*/
|
||||
if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
|
||||
((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
|
||||
if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (CRYPTO_OLD_CTX_TEMPLATE);
|
||||
} else {
|
||||
spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
|
||||
|
||||
error = KCF_PROV_MAC_ATOMIC(pd, pd->pd_sid, &lmech, key, data,
|
||||
mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
|
||||
(data->cd_length > pd->pd_hash_limit)) {
|
||||
/*
|
||||
* XXX - We need a check to see if this is indeed
|
||||
* a HMAC. So far, all kernel clients use
|
||||
* this interface only for HMAC. So, this is fine
|
||||
* for now.
|
||||
*/
|
||||
error = CRYPTO_BUFFER_TOO_BIG;
|
||||
} else {
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_ATOMIC,
|
||||
pd->pd_sid, mech, key, data, mac, spi_ctx_tmpl);
|
||||
|
||||
error = kcf_submit_request(pd, NULL, crq, ¶ms,
|
||||
KCF_ISDUALREQ(crq));
|
||||
}
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Single part operation to compute the MAC corresponding to the specified
|
||||
* 'data' and to verify that it matches the MAC specified by 'mac'.
|
||||
* The other arguments are the same as the function crypto_mac_prov().
|
||||
*/
|
||||
int
|
||||
crypto_mac_verify_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_data_t *data, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_data_t *mac, crypto_call_req_t *crq)
|
||||
{
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
int rv;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
rv = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_MAC_ATOMIC);
|
||||
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_MAC_VERIFY_ATOMIC, sid, mech,
|
||||
key, data, mac, tmpl);
|
||||
rv = kcf_submit_request(real_provider, NULL, crq, ¶ms, B_FALSE);
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_mac_verify_prov(), but relies on the KCF scheduler to choose
|
||||
* a provider. See crypto_mac_verify_prov() comments for more information.
|
||||
*/
|
||||
int
|
||||
crypto_mac_verify(crypto_mechanism_t *mech, crypto_data_t *data,
|
||||
crypto_key_t *key, crypto_ctx_template_t tmpl, crypto_data_t *mac,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *me;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_ctx_template_t *ctx_tmpl;
|
||||
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* The pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
|
||||
list, CRYPTO_FG_MAC_ATOMIC, CHECK_RESTRICT(crq),
|
||||
data->cd_length)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* For SW providers, check the validity of the context template
|
||||
* It is very rare that the generation number mis-matches, so
|
||||
* is acceptable to fail here, and let the consumer recover by
|
||||
* freeing this tmpl and create a new one for the key and new SW
|
||||
* provider
|
||||
*/
|
||||
if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
|
||||
((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
|
||||
if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (CRYPTO_OLD_CTX_TEMPLATE);
|
||||
} else {
|
||||
spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, pd, &lmech);
|
||||
|
||||
error = KCF_PROV_MAC_VERIFY_ATOMIC(pd, pd->pd_sid, &lmech, key,
|
||||
data, mac, spi_ctx_tmpl, KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(pd->pd_flags & CRYPTO_HASH_NO_UPDATE) &&
|
||||
(data->cd_length > pd->pd_hash_limit)) {
|
||||
/* see comments in crypto_mac() */
|
||||
error = CRYPTO_BUFFER_TOO_BIG;
|
||||
} else {
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms,
|
||||
KCF_OP_MAC_VERIFY_ATOMIC, pd->pd_sid, mech,
|
||||
key, data, mac, spi_ctx_tmpl);
|
||||
|
||||
error = kcf_submit_request(pd, NULL, crq, ¶ms,
|
||||
KCF_ISDUALREQ(crq));
|
||||
}
|
||||
}
|
||||
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_mac_init_prov()
|
||||
*
|
||||
* Arguments:
|
||||
* pd: pointer to the descriptor of the provider to use for this
|
||||
* operation.
|
||||
* sid: provider session id.
|
||||
* 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.
|
||||
* tmpl: a crypto_ctx_template_t, opaque template of a context of a
|
||||
* MAC with the 'mech' using 'key'. 'tmpl' is created by
|
||||
* a previous call to crypto_create_ctx_template().
|
||||
* ctxp: Pointer to a crypto_context_t.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs the
|
||||
* initialization of a MAC operation on the specified provider with
|
||||
* the specified session.
|
||||
* When possible and applicable, will internally use the pre-computed MAC
|
||||
* context from the context template, tmpl.
|
||||
* When complete and successful, 'ctxp' will contain a crypto_context_t
|
||||
* valid for later calls to mac_update() and mac_final().
|
||||
* The caller should hold a reference on the specified provider
|
||||
* descriptor before calling this function.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_mac_init_prov(crypto_provider_t provider, crypto_session_id_t sid,
|
||||
crypto_mechanism_t *mech, crypto_key_t *key, crypto_spi_ctx_template_t tmpl,
|
||||
crypto_context_t *ctxp, crypto_call_req_t *crq)
|
||||
{
|
||||
int rv;
|
||||
crypto_ctx_t *ctx;
|
||||
kcf_req_params_t params;
|
||||
kcf_provider_desc_t *pd = provider;
|
||||
kcf_provider_desc_t *real_provider = pd;
|
||||
|
||||
ASSERT(KCF_PROV_REFHELD(pd));
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
rv = kcf_get_hardware_provider(mech->cm_type,
|
||||
CRYPTO_MECH_INVALID, CHECK_RESTRICT(crq), pd,
|
||||
&real_provider, CRYPTO_FG_MAC);
|
||||
|
||||
if (rv != CRYPTO_SUCCESS)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* Allocate and initialize the canonical context */
|
||||
if ((ctx = kcf_new_ctx(crq, real_provider, sid)) == NULL) {
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
}
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(crq, pd)) {
|
||||
crypto_mechanism_t lmech;
|
||||
|
||||
lmech = *mech;
|
||||
KCF_SET_PROVIDER_MECHNUM(mech->cm_type, real_provider, &lmech);
|
||||
rv = KCF_PROV_MAC_INIT(real_provider, ctx, &lmech, key, tmpl,
|
||||
KCF_SWFP_RHNDL(crq));
|
||||
KCF_PROV_INCRSTATS(pd, rv);
|
||||
} else {
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_INIT, sid, mech, key,
|
||||
NULL, NULL, tmpl);
|
||||
rv = kcf_submit_request(real_provider, ctx, crq, ¶ms,
|
||||
B_FALSE);
|
||||
}
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)
|
||||
KCF_PROV_REFRELE(real_provider);
|
||||
|
||||
if ((rv == CRYPTO_SUCCESS) || (rv == CRYPTO_QUEUED))
|
||||
*ctxp = (crypto_context_t)ctx;
|
||||
else {
|
||||
/* Release the hold done in kcf_new_ctx(). */
|
||||
KCF_CONTEXT_REFRELE((kcf_context_t *)ctx->cc_framework_private);
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same as crypto_mac_init_prov(), but relies on the KCF scheduler to
|
||||
* choose a provider. See crypto_mac_init_prov() comments for more
|
||||
* information.
|
||||
*/
|
||||
int
|
||||
crypto_mac_init(crypto_mechanism_t *mech, crypto_key_t *key,
|
||||
crypto_ctx_template_t tmpl, crypto_context_t *ctxp,
|
||||
crypto_call_req_t *crq)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *me;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_ctx_template_t *ctx_tmpl;
|
||||
crypto_spi_ctx_template_t spi_ctx_tmpl = NULL;
|
||||
kcf_prov_tried_t *list = NULL;
|
||||
|
||||
retry:
|
||||
/* The pd is returned held */
|
||||
if ((pd = kcf_get_mech_provider(mech->cm_type, &me, &error,
|
||||
list, CRYPTO_FG_MAC, CHECK_RESTRICT(crq), 0)) == NULL) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* For SW providers, check the validity of the context template
|
||||
* It is very rare that the generation number mis-matches, so
|
||||
* is acceptable to fail here, and let the consumer recover by
|
||||
* freeing this tmpl and create a new one for the key and new SW
|
||||
* provider
|
||||
*/
|
||||
|
||||
if ((pd->pd_prov_type == CRYPTO_SW_PROVIDER) &&
|
||||
((ctx_tmpl = (kcf_ctx_template_t *)tmpl) != NULL)) {
|
||||
if (ctx_tmpl->ct_generation != me->me_gen_swprov) {
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (CRYPTO_OLD_CTX_TEMPLATE);
|
||||
} else {
|
||||
spi_ctx_tmpl = ctx_tmpl->ct_prov_tmpl;
|
||||
}
|
||||
}
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(pd->pd_flags & CRYPTO_HASH_NO_UPDATE)) {
|
||||
/*
|
||||
* The hardware provider has limited HMAC support.
|
||||
* So, we fallback early here to using a software provider.
|
||||
*
|
||||
* XXX - need to enhance to do the fallback later in
|
||||
* crypto_mac_update() if the size of accumulated input data
|
||||
* exceeds the maximum size digestable by hardware provider.
|
||||
*/
|
||||
error = CRYPTO_BUFFER_TOO_BIG;
|
||||
} else {
|
||||
error = crypto_mac_init_prov(pd, pd->pd_sid, mech, key,
|
||||
spi_ctx_tmpl, ctxp, crq);
|
||||
}
|
||||
if (error != CRYPTO_SUCCESS && error != CRYPTO_QUEUED &&
|
||||
IS_RECOVERABLE(error)) {
|
||||
/* Add pd to the linked list of providers tried. */
|
||||
if (kcf_insert_triedlist(&list, pd, KCF_KMFLAG(crq)) != NULL)
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (list != NULL)
|
||||
kcf_free_triedlist(list);
|
||||
|
||||
KCF_PROV_REFRELE(pd);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_mac_update()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by mac_init().
|
||||
* data: The message part to be MAC'ed
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* part of a MAC operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_mac_update(crypto_context_t context, crypto_data_t *data,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_req_params_t params;
|
||||
int rv;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
rv = KCF_PROV_MAC_UPDATE(pd, ctx, data, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, rv);
|
||||
} else {
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_UPDATE,
|
||||
ctx->cc_session, NULL, NULL, data, NULL, NULL);
|
||||
rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* crypto_mac_final()
|
||||
*
|
||||
* Arguments:
|
||||
* context: A crypto_context_t initialized by mac_init().
|
||||
* mac: Storage for the message authentication code.
|
||||
* cr: crypto_call_req_t calling conditions and call back info.
|
||||
*
|
||||
* Description:
|
||||
* Asynchronously submits a request for, or synchronously performs a
|
||||
* part of a message authentication operation.
|
||||
*
|
||||
* Context:
|
||||
* Process or interrupt, according to the semantics dictated by the 'cr'.
|
||||
*
|
||||
* Returns:
|
||||
* See comment in the beginning of the file.
|
||||
*/
|
||||
int
|
||||
crypto_mac_final(crypto_context_t context, crypto_data_t *mac,
|
||||
crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
kcf_req_params_t params;
|
||||
int rv;
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
ASSERT(pd->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
rv = KCF_PROV_MAC_FINAL(pd, ctx, mac, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, rv);
|
||||
} else {
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_FINAL,
|
||||
ctx->cc_session, NULL, NULL, NULL, mac, NULL);
|
||||
rv = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* See comments for crypto_mac_update() and crypto_mac_final().
|
||||
*/
|
||||
int
|
||||
crypto_mac_single(crypto_context_t context, crypto_data_t *data,
|
||||
crypto_data_t *mac, crypto_call_req_t *cr)
|
||||
{
|
||||
crypto_ctx_t *ctx = (crypto_ctx_t *)context;
|
||||
kcf_context_t *kcf_ctx;
|
||||
kcf_provider_desc_t *pd;
|
||||
int error;
|
||||
kcf_req_params_t params;
|
||||
|
||||
|
||||
if ((ctx == NULL) ||
|
||||
((kcf_ctx = (kcf_context_t *)ctx->cc_framework_private) == NULL) ||
|
||||
((pd = kcf_ctx->kc_prov_desc) == NULL)) {
|
||||
return (CRYPTO_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
|
||||
/* The fast path for SW providers. */
|
||||
if (CHECK_FASTPATH(cr, pd)) {
|
||||
error = KCF_PROV_MAC(pd, ctx, data, mac, NULL);
|
||||
KCF_PROV_INCRSTATS(pd, error);
|
||||
} else {
|
||||
KCF_WRAP_MAC_OPS_PARAMS(¶ms, KCF_OP_SINGLE, pd->pd_sid,
|
||||
NULL, NULL, data, mac, NULL);
|
||||
error = kcf_submit_request(pd, ctx, cr, ¶ms, B_FALSE);
|
||||
}
|
||||
|
||||
/* Release the hold done in kcf_new_ctx() during init step. */
|
||||
KCF_CONTEXT_COND_RELEASE(error, kcf_ctx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||
EXPORT_SYMBOL(crypto_mac_prov);
|
||||
EXPORT_SYMBOL(crypto_mac);
|
||||
EXPORT_SYMBOL(crypto_mac_verify_prov);
|
||||
EXPORT_SYMBOL(crypto_mac_verify);
|
||||
EXPORT_SYMBOL(crypto_mac_init_prov);
|
||||
EXPORT_SYMBOL(crypto_mac_init);
|
||||
EXPORT_SYMBOL(crypto_mac_update);
|
||||
EXPORT_SYMBOL(crypto_mac_final);
|
||||
EXPORT_SYMBOL(crypto_mac_single);
|
||||
#endif
|
127
module/icp/api/kcf_miscapi.c
Normal file
127
module/icp/api/kcf_miscapi.c
Normal file
@ -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
|
23
module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
Normal file
23
module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.gladman
Normal file
@ -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
|
127
module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
Normal file
127
module/icp/asm-x86_64/aes/THIRDPARTYLICENSE.openssl
Normal file
@ -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
|
900
module/icp/asm-x86_64/aes/aes_amd64.S
Normal file
900
module/icp/asm-x86_64/aes/aes_amd64.S
Normal file
@ -0,0 +1,900 @@
|
||||
/*
|
||||
* ---------------------------------------------------------------------------
|
||||
* 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 20/12/2007
|
||||
*
|
||||
* I am grateful to Dag Arne Osvik for many discussions of the techniques that
|
||||
* can be used to optimise AES assembler code on AMD64/EM64T architectures.
|
||||
* Some of the techniques used in this implementation are the result of
|
||||
* suggestions made by him for which I am most grateful.
|
||||
*
|
||||
* An AES implementation for AMD64 processors using the YASM assembler. This
|
||||
* implementation provides only encryption, decryption and hence requires key
|
||||
* scheduling support in C. It uses 8k bytes of tables but its encryption and
|
||||
* decryption performance is very close to that obtained using large tables.
|
||||
* It can use either MS Windows or Gnu/Linux/OpenSolaris OS calling conventions,
|
||||
* which are as follows:
|
||||
* ms windows gnu/linux/opensolaris os
|
||||
*
|
||||
* in_blk rcx rdi
|
||||
* out_blk rdx rsi
|
||||
* context (cx) r8 rdx
|
||||
*
|
||||
* preserved rsi - + rbx, rbp, rsp, r12, r13, r14 & r15
|
||||
* registers rdi - on both
|
||||
*
|
||||
* destroyed - rsi + rax, rcx, rdx, r8, r9, r10 & r11
|
||||
* registers - rdi on both
|
||||
*
|
||||
* The convention used here is that for gnu/linux/opensolaris os.
|
||||
*
|
||||
* This code provides the standard AES block size (128 bits, 16 bytes) and the
|
||||
* three standard AES key sizes (128, 192 and 256 bits). It has the same call
|
||||
* interface as my C implementation. It uses the Microsoft C AMD64 calling
|
||||
* conventions in which the three parameters are placed in rcx, rdx and r8
|
||||
* respectively. The rbx, rsi, rdi, rbp and r12..r15 registers are preserved.
|
||||
*
|
||||
* OpenSolaris Note:
|
||||
* Modified to use GNU/Linux/Solaris calling conventions.
|
||||
* That is parameters are placed in rdi, rsi, rdx, and rcx, respectively.
|
||||
*
|
||||
* AES_RETURN aes_encrypt(const unsigned char in_blk[],
|
||||
* unsigned char out_blk[], const aes_encrypt_ctx cx[1])/
|
||||
*
|
||||
* AES_RETURN aes_decrypt(const unsigned char in_blk[],
|
||||
* unsigned char out_blk[], const aes_decrypt_ctx cx[1])/
|
||||
*
|
||||
* AES_RETURN aes_encrypt_key<NNN>(const unsigned char key[],
|
||||
* const aes_encrypt_ctx cx[1])/
|
||||
*
|
||||
* AES_RETURN aes_decrypt_key<NNN>(const unsigned char key[],
|
||||
* const aes_decrypt_ctx cx[1])/
|
||||
*
|
||||
* AES_RETURN aes_encrypt_key(const unsigned char key[],
|
||||
* unsigned int len, const aes_decrypt_ctx cx[1])/
|
||||
*
|
||||
* AES_RETURN aes_decrypt_key(const unsigned char key[],
|
||||
* unsigned int len, const aes_decrypt_ctx cx[1])/
|
||||
*
|
||||
* where <NNN> is 128, 102 or 256. In the last two calls the length can be in
|
||||
* either bits or bytes.
|
||||
*
|
||||
* Comment in/out the following lines to obtain the desired subroutines. These
|
||||
* selections MUST match those in the C header file aesopt.h
|
||||
*/
|
||||
#define AES_REV_DKS /* define if key decryption schedule is reversed */
|
||||
|
||||
#define LAST_ROUND_TABLES /* define for the faster version using extra tables */
|
||||
|
||||
/*
|
||||
* The encryption key schedule has the following in memory layout where N is the
|
||||
* number of rounds (10, 12 or 14):
|
||||
*
|
||||
* lo: | input key (round 0) | / each round is four 32-bit words
|
||||
* | encryption round 1 |
|
||||
* | encryption round 2 |
|
||||
* ....
|
||||
* | encryption round N-1 |
|
||||
* hi: | encryption round N |
|
||||
*
|
||||
* The decryption key schedule is normally set up so that it has the same
|
||||
* layout as above by actually reversing the order of the encryption key
|
||||
* schedule in memory (this happens when AES_REV_DKS is set):
|
||||
*
|
||||
* lo: | decryption round 0 | = | encryption round N |
|
||||
* | decryption round 1 | = INV_MIX_COL[ | encryption round N-1 | ]
|
||||
* | decryption round 2 | = INV_MIX_COL[ | encryption round N-2 | ]
|
||||
* .... ....
|
||||
* | decryption round N-1 | = INV_MIX_COL[ | encryption round 1 | ]
|
||||
* hi: | decryption round N | = | input key (round 0) |
|
||||
*
|
||||
* with rounds except the first and last modified using inv_mix_column()
|
||||
* But if AES_REV_DKS is NOT set the order of keys is left as it is for
|
||||
* encryption so that it has to be accessed in reverse when used for
|
||||
* decryption (although the inverse mix column modifications are done)
|
||||
*
|
||||
* lo: | decryption round 0 | = | input key (round 0) |
|
||||
* | decryption round 1 | = INV_MIX_COL[ | encryption round 1 | ]
|
||||
* | decryption round 2 | = INV_MIX_COL[ | encryption round 2 | ]
|
||||
* .... ....
|
||||
* | decryption round N-1 | = INV_MIX_COL[ | encryption round N-1 | ]
|
||||
* hi: | decryption round N | = | encryption round N |
|
||||
*
|
||||
* This layout is faster when the assembler key scheduling provided here
|
||||
* is used.
|
||||
*
|
||||
* End of user defines
|
||||
*/
|
||||
|
||||
/*
|
||||
* ---------------------------------------------------------------------------
|
||||
* OpenSolaris OS modifications
|
||||
*
|
||||
* This source originates from Brian Gladman file aes_amd64.asm
|
||||
* in http://fp.gladman.plus.com/AES/aes-src-04-03-08.zip
|
||||
* with these changes:
|
||||
*
|
||||
* 1. Removed MS Windows-specific code within DLL_EXPORT, _SEH_, and
|
||||
* !__GNUC__ ifdefs. Also removed ENCRYPTION, DECRYPTION,
|
||||
* AES_128, AES_192, AES_256, AES_VAR ifdefs.
|
||||
*
|
||||
* 2. Translate yasm/nasm %define and .macro definitions to cpp(1) #define
|
||||
*
|
||||
* 3. Translate yasm/nasm %ifdef/%ifndef to cpp(1) #ifdef
|
||||
*
|
||||
* 4. Translate Intel/yasm/nasm syntax to ATT/OpenSolaris as(1) syntax
|
||||
* (operands reversed, literals prefixed with "$", registers prefixed with "%",
|
||||
* and "[register+offset]", addressing changed to "offset(register)",
|
||||
* parenthesis in constant expressions "()" changed to square brackets "[]",
|
||||
* "." removed from local (numeric) labels, and other changes.
|
||||
* Examples:
|
||||
* Intel/yasm/nasm Syntax ATT/OpenSolaris Syntax
|
||||
* mov rax,(4*20h) mov $[4*0x20],%rax
|
||||
* mov rax,[ebx+20h] mov 0x20(%ebx),%rax
|
||||
* lea rax,[ebx+ecx] lea (%ebx,%ecx),%rax
|
||||
* sub rax,[ebx+ecx*4-20h] sub -0x20(%ebx,%ecx,4),%rax
|
||||
*
|
||||
* 5. Added OpenSolaris ENTRY_NP/SET_SIZE macros from
|
||||
* /usr/include/sys/asm_linkage.h, lint(1B) guards, and dummy C function
|
||||
* definitions for lint.
|
||||
*
|
||||
* 6. Renamed functions and reordered parameters to match OpenSolaris:
|
||||
* Original Gladman interface:
|
||||
* int aes_encrypt(const unsigned char *in,
|
||||
* unsigned char *out, const aes_encrypt_ctx cx[1])/
|
||||
* int aes_decrypt(const unsigned char *in,
|
||||
* unsigned char *out, const aes_encrypt_ctx cx[1])/
|
||||
* Note: aes_encrypt_ctx contains ks, a 60 element array of uint32_t,
|
||||
* and a union type, inf., containing inf.l, a uint32_t and
|
||||
* inf.b, a 4-element array of uint32_t. Only b[0] in the array (aka "l") is
|
||||
* used and contains the key schedule length * 16 where key schedule length is
|
||||
* 10, 12, or 14 bytes.
|
||||
*
|
||||
* OpenSolaris OS interface:
|
||||
* void aes_encrypt_amd64(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4])/
|
||||
* void aes_decrypt_amd64(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4])/
|
||||
* typedef union {uint64_t ks64[(MAX_AES_NR + 1) * 4]/
|
||||
* uint32_t ks32[(MAX_AES_NR + 1) * 4]/ } aes_ks_t/
|
||||
* Note: ks is the AES key schedule, Nr is number of rounds, pt is plain text,
|
||||
* ct is crypto text, and MAX_AES_NR is 14.
|
||||
* For the x86 64-bit architecture, OpenSolaris OS uses ks32 instead of ks64.
|
||||
*/
|
||||
|
||||
#if defined(lint) || defined(__lint)
|
||||
|
||||
#include <sys/types.h>
|
||||
/* ARGSUSED */
|
||||
void
|
||||
aes_encrypt_amd64(const uint32_t rk[], int Nr, const uint32_t pt[4],
|
||||
uint32_t ct[4]) {
|
||||
}
|
||||
/* ARGSUSED */
|
||||
void
|
||||
aes_decrypt_amd64(const uint32_t rk[], int Nr, const uint32_t ct[4],
|
||||
uint32_t pt[4]) {
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define _ASM
|
||||
#include <sys/asm_linkage.h>
|
||||
|
||||
#define KS_LENGTH 60
|
||||
|
||||
#define raxd eax
|
||||
#define rdxd edx
|
||||
#define rcxd ecx
|
||||
#define rbxd ebx
|
||||
#define rsid esi
|
||||
#define rdid edi
|
||||
|
||||
#define raxb al
|
||||
#define rdxb dl
|
||||
#define rcxb cl
|
||||
#define rbxb bl
|
||||
#define rsib sil
|
||||
#define rdib dil
|
||||
|
||||
// finite field multiplies by {02}, {04} and {08}
|
||||
|
||||
#define f2(x) [[x<<1]^[[[x>>7]&1]*0x11b]]
|
||||
#define f4(x) [[x<<2]^[[[x>>6]&1]*0x11b]^[[[x>>6]&2]*0x11b]]
|
||||
#define f8(x) [[x<<3]^[[[x>>5]&1]*0x11b]^[[[x>>5]&2]*0x11b]^[[[x>>5]&4]*0x11b]]
|
||||
|
||||
// finite field multiplies required in table generation
|
||||
|
||||
#define f3(x) [[f2(x)] ^ [x]]
|
||||
#define f9(x) [[f8(x)] ^ [x]]
|
||||
#define fb(x) [[f8(x)] ^ [f2(x)] ^ [x]]
|
||||
#define fd(x) [[f8(x)] ^ [f4(x)] ^ [x]]
|
||||
#define fe(x) [[f8(x)] ^ [f4(x)] ^ [f2(x)]]
|
||||
|
||||
// macros for expanding S-box data
|
||||
|
||||
#define u8(x) [f2(x)], [x], [x], [f3(x)], [f2(x)], [x], [x], [f3(x)]
|
||||
#define v8(x) [fe(x)], [f9(x)], [fd(x)], [fb(x)], [fe(x)], [f9(x)], [fd(x)], [x]
|
||||
#define w8(x) [x], 0, 0, 0, [x], 0, 0, 0
|
||||
|
||||
#define enc_vals(x) \
|
||||
.byte x(0x63),x(0x7c),x(0x77),x(0x7b),x(0xf2),x(0x6b),x(0x6f),x(0xc5); \
|
||||
.byte x(0x30),x(0x01),x(0x67),x(0x2b),x(0xfe),x(0xd7),x(0xab),x(0x76); \
|
||||
.byte x(0xca),x(0x82),x(0xc9),x(0x7d),x(0xfa),x(0x59),x(0x47),x(0xf0); \
|
||||
.byte x(0xad),x(0xd4),x(0xa2),x(0xaf),x(0x9c),x(0xa4),x(0x72),x(0xc0); \
|
||||
.byte x(0xb7),x(0xfd),x(0x93),x(0x26),x(0x36),x(0x3f),x(0xf7),x(0xcc); \
|
||||
.byte x(0x34),x(0xa5),x(0xe5),x(0xf1),x(0x71),x(0xd8),x(0x31),x(0x15); \
|
||||
.byte x(0x04),x(0xc7),x(0x23),x(0xc3),x(0x18),x(0x96),x(0x05),x(0x9a); \
|
||||
.byte x(0x07),x(0x12),x(0x80),x(0xe2),x(0xeb),x(0x27),x(0xb2),x(0x75); \
|
||||
.byte x(0x09),x(0x83),x(0x2c),x(0x1a),x(0x1b),x(0x6e),x(0x5a),x(0xa0); \
|
||||
.byte x(0x52),x(0x3b),x(0xd6),x(0xb3),x(0x29),x(0xe3),x(0x2f),x(0x84); \
|
||||
.byte x(0x53),x(0xd1),x(0x00),x(0xed),x(0x20),x(0xfc),x(0xb1),x(0x5b); \
|
||||
.byte x(0x6a),x(0xcb),x(0xbe),x(0x39),x(0x4a),x(0x4c),x(0x58),x(0xcf); \
|
||||
.byte x(0xd0),x(0xef),x(0xaa),x(0xfb),x(0x43),x(0x4d),x(0x33),x(0x85); \
|
||||
.byte x(0x45),x(0xf9),x(0x02),x(0x7f),x(0x50),x(0x3c),x(0x9f),x(0xa8); \
|
||||
.byte x(0x51),x(0xa3),x(0x40),x(0x8f),x(0x92),x(0x9d),x(0x38),x(0xf5); \
|
||||
.byte x(0xbc),x(0xb6),x(0xda),x(0x21),x(0x10),x(0xff),x(0xf3),x(0xd2); \
|
||||
.byte x(0xcd),x(0x0c),x(0x13),x(0xec),x(0x5f),x(0x97),x(0x44),x(0x17); \
|
||||
.byte x(0xc4),x(0xa7),x(0x7e),x(0x3d),x(0x64),x(0x5d),x(0x19),x(0x73); \
|
||||
.byte x(0x60),x(0x81),x(0x4f),x(0xdc),x(0x22),x(0x2a),x(0x90),x(0x88); \
|
||||
.byte x(0x46),x(0xee),x(0xb8),x(0x14),x(0xde),x(0x5e),x(0x0b),x(0xdb); \
|
||||
.byte x(0xe0),x(0x32),x(0x3a),x(0x0a),x(0x49),x(0x06),x(0x24),x(0x5c); \
|
||||
.byte x(0xc2),x(0xd3),x(0xac),x(0x62),x(0x91),x(0x95),x(0xe4),x(0x79); \
|
||||
.byte x(0xe7),x(0xc8),x(0x37),x(0x6d),x(0x8d),x(0xd5),x(0x4e),x(0xa9); \
|
||||
.byte x(0x6c),x(0x56),x(0xf4),x(0xea),x(0x65),x(0x7a),x(0xae),x(0x08); \
|
||||
.byte x(0xba),x(0x78),x(0x25),x(0x2e),x(0x1c),x(0xa6),x(0xb4),x(0xc6); \
|
||||
.byte x(0xe8),x(0xdd),x(0x74),x(0x1f),x(0x4b),x(0xbd),x(0x8b),x(0x8a); \
|
||||
.byte x(0x70),x(0x3e),x(0xb5),x(0x66),x(0x48),x(0x03),x(0xf6),x(0x0e); \
|
||||
.byte x(0x61),x(0x35),x(0x57),x(0xb9),x(0x86),x(0xc1),x(0x1d),x(0x9e); \
|
||||
.byte x(0xe1),x(0xf8),x(0x98),x(0x11),x(0x69),x(0xd9),x(0x8e),x(0x94); \
|
||||
.byte x(0x9b),x(0x1e),x(0x87),x(0xe9),x(0xce),x(0x55),x(0x28),x(0xdf); \
|
||||
.byte x(0x8c),x(0xa1),x(0x89),x(0x0d),x(0xbf),x(0xe6),x(0x42),x(0x68); \
|
||||
.byte x(0x41),x(0x99),x(0x2d),x(0x0f),x(0xb0),x(0x54),x(0xbb),x(0x16)
|
||||
|
||||
#define dec_vals(x) \
|
||||
.byte x(0x52),x(0x09),x(0x6a),x(0xd5),x(0x30),x(0x36),x(0xa5),x(0x38); \
|
||||
.byte x(0xbf),x(0x40),x(0xa3),x(0x9e),x(0x81),x(0xf3),x(0xd7),x(0xfb); \
|
||||
.byte x(0x7c),x(0xe3),x(0x39),x(0x82),x(0x9b),x(0x2f),x(0xff),x(0x87); \
|
||||
.byte x(0x34),x(0x8e),x(0x43),x(0x44),x(0xc4),x(0xde),x(0xe9),x(0xcb); \
|
||||
.byte x(0x54),x(0x7b),x(0x94),x(0x32),x(0xa6),x(0xc2),x(0x23),x(0x3d); \
|
||||
.byte x(0xee),x(0x4c),x(0x95),x(0x0b),x(0x42),x(0xfa),x(0xc3),x(0x4e); \
|
||||
.byte x(0x08),x(0x2e),x(0xa1),x(0x66),x(0x28),x(0xd9),x(0x24),x(0xb2); \
|
||||
.byte x(0x76),x(0x5b),x(0xa2),x(0x49),x(0x6d),x(0x8b),x(0xd1),x(0x25); \
|
||||
.byte x(0x72),x(0xf8),x(0xf6),x(0x64),x(0x86),x(0x68),x(0x98),x(0x16); \
|
||||
.byte x(0xd4),x(0xa4),x(0x5c),x(0xcc),x(0x5d),x(0x65),x(0xb6),x(0x92); \
|
||||
.byte x(0x6c),x(0x70),x(0x48),x(0x50),x(0xfd),x(0xed),x(0xb9),x(0xda); \
|
||||
.byte x(0x5e),x(0x15),x(0x46),x(0x57),x(0xa7),x(0x8d),x(0x9d),x(0x84); \
|
||||
.byte x(0x90),x(0xd8),x(0xab),x(0x00),x(0x8c),x(0xbc),x(0xd3),x(0x0a); \
|
||||
.byte x(0xf7),x(0xe4),x(0x58),x(0x05),x(0xb8),x(0xb3),x(0x45),x(0x06); \
|
||||
.byte x(0xd0),x(0x2c),x(0x1e),x(0x8f),x(0xca),x(0x3f),x(0x0f),x(0x02); \
|
||||
.byte x(0xc1),x(0xaf),x(0xbd),x(0x03),x(0x01),x(0x13),x(0x8a),x(0x6b); \
|
||||
.byte x(0x3a),x(0x91),x(0x11),x(0x41),x(0x4f),x(0x67),x(0xdc),x(0xea); \
|
||||
.byte x(0x97),x(0xf2),x(0xcf),x(0xce),x(0xf0),x(0xb4),x(0xe6),x(0x73); \
|
||||
.byte x(0x96),x(0xac),x(0x74),x(0x22),x(0xe7),x(0xad),x(0x35),x(0x85); \
|
||||
.byte x(0xe2),x(0xf9),x(0x37),x(0xe8),x(0x1c),x(0x75),x(0xdf),x(0x6e); \
|
||||
.byte x(0x47),x(0xf1),x(0x1a),x(0x71),x(0x1d),x(0x29),x(0xc5),x(0x89); \
|
||||
.byte x(0x6f),x(0xb7),x(0x62),x(0x0e),x(0xaa),x(0x18),x(0xbe),x(0x1b); \
|
||||
.byte x(0xfc),x(0x56),x(0x3e),x(0x4b),x(0xc6),x(0xd2),x(0x79),x(0x20); \
|
||||
.byte x(0x9a),x(0xdb),x(0xc0),x(0xfe),x(0x78),x(0xcd),x(0x5a),x(0xf4); \
|
||||
.byte x(0x1f),x(0xdd),x(0xa8),x(0x33),x(0x88),x(0x07),x(0xc7),x(0x31); \
|
||||
.byte x(0xb1),x(0x12),x(0x10),x(0x59),x(0x27),x(0x80),x(0xec),x(0x5f); \
|
||||
.byte x(0x60),x(0x51),x(0x7f),x(0xa9),x(0x19),x(0xb5),x(0x4a),x(0x0d); \
|
||||
.byte x(0x2d),x(0xe5),x(0x7a),x(0x9f),x(0x93),x(0xc9),x(0x9c),x(0xef); \
|
||||
.byte x(0xa0),x(0xe0),x(0x3b),x(0x4d),x(0xae),x(0x2a),x(0xf5),x(0xb0); \
|
||||
.byte x(0xc8),x(0xeb),x(0xbb),x(0x3c),x(0x83),x(0x53),x(0x99),x(0x61); \
|
||||
.byte x(0x17),x(0x2b),x(0x04),x(0x7e),x(0xba),x(0x77),x(0xd6),x(0x26); \
|
||||
.byte x(0xe1),x(0x69),x(0x14),x(0x63),x(0x55),x(0x21),x(0x0c),x(0x7d)
|
||||
|
||||
#define tptr %rbp /* table pointer */
|
||||
#define kptr %r8 /* key schedule pointer */
|
||||
#define fofs 128 /* adjust offset in key schedule to keep |disp| < 128 */
|
||||
#define fk_ref(x, y) -16*x+fofs+4*y(kptr)
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define rofs 128
|
||||
#define ik_ref(x, y) -16*x+rofs+4*y(kptr)
|
||||
|
||||
#else
|
||||
#define rofs -128
|
||||
#define ik_ref(x, y) 16*x+rofs+4*y(kptr)
|
||||
#endif /* AES_REV_DKS */
|
||||
|
||||
#define tab_0(x) (tptr,x,8)
|
||||
#define tab_1(x) 3(tptr,x,8)
|
||||
#define tab_2(x) 2(tptr,x,8)
|
||||
#define tab_3(x) 1(tptr,x,8)
|
||||
#define tab_f(x) 1(tptr,x,8)
|
||||
#define tab_i(x) 7(tptr,x,8)
|
||||
|
||||
#define ff_rnd(p1, p2, p3, p4, round) /* normal forward round */ \
|
||||
mov fk_ref(round,0), p1; \
|
||||
mov fk_ref(round,1), p2; \
|
||||
mov fk_ref(round,2), p3; \
|
||||
mov fk_ref(round,3), p4; \
|
||||
\
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
shr $16, %eax; \
|
||||
xor tab_0(%rsi), p1; \
|
||||
xor tab_1(%rdi), p4; \
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
xor tab_2(%rsi), p3; \
|
||||
xor tab_3(%rdi), p2; \
|
||||
\
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
shr $16, %ebx; \
|
||||
xor tab_0(%rsi), p2; \
|
||||
xor tab_1(%rdi), p1; \
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
xor tab_2(%rsi), p4; \
|
||||
xor tab_3(%rdi), p3; \
|
||||
\
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
shr $16, %ecx; \
|
||||
xor tab_0(%rsi), p3; \
|
||||
xor tab_1(%rdi), p2; \
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
xor tab_2(%rsi), p1; \
|
||||
xor tab_3(%rdi), p4; \
|
||||
\
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
shr $16, %edx; \
|
||||
xor tab_0(%rsi), p4; \
|
||||
xor tab_1(%rdi), p3; \
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
xor tab_2(%rsi), p2; \
|
||||
xor tab_3(%rdi), p1; \
|
||||
\
|
||||
mov p1, %eax; \
|
||||
mov p2, %ebx; \
|
||||
mov p3, %ecx; \
|
||||
mov p4, %edx
|
||||
|
||||
#ifdef LAST_ROUND_TABLES
|
||||
|
||||
#define fl_rnd(p1, p2, p3, p4, round) /* last forward round */ \
|
||||
add $2048, tptr; \
|
||||
mov fk_ref(round,0), p1; \
|
||||
mov fk_ref(round,1), p2; \
|
||||
mov fk_ref(round,2), p3; \
|
||||
mov fk_ref(round,3), p4; \
|
||||
\
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
shr $16, %eax; \
|
||||
xor tab_0(%rsi), p1; \
|
||||
xor tab_1(%rdi), p4; \
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
xor tab_2(%rsi), p3; \
|
||||
xor tab_3(%rdi), p2; \
|
||||
\
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
shr $16, %ebx; \
|
||||
xor tab_0(%rsi), p2; \
|
||||
xor tab_1(%rdi), p1; \
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
xor tab_2(%rsi), p4; \
|
||||
xor tab_3(%rdi), p3; \
|
||||
\
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
shr $16, %ecx; \
|
||||
xor tab_0(%rsi), p3; \
|
||||
xor tab_1(%rdi), p2; \
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
xor tab_2(%rsi), p1; \
|
||||
xor tab_3(%rdi), p4; \
|
||||
\
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
shr $16, %edx; \
|
||||
xor tab_0(%rsi), p4; \
|
||||
xor tab_1(%rdi), p3; \
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
xor tab_2(%rsi), p2; \
|
||||
xor tab_3(%rdi), p1
|
||||
|
||||
#else
|
||||
|
||||
#define fl_rnd(p1, p2, p3, p4, round) /* last forward round */ \
|
||||
mov fk_ref(round,0), p1; \
|
||||
mov fk_ref(round,1), p2; \
|
||||
mov fk_ref(round,2), p3; \
|
||||
mov fk_ref(round,3), p4; \
|
||||
\
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
shr $16, %eax; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
xor %esi, p1; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p4; \
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p3; \
|
||||
xor %edi, p2; \
|
||||
\
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
shr $16, %ebx; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
xor %esi, p2; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p1; \
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p4; \
|
||||
xor %edi, p3; \
|
||||
\
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
shr $16, %ecx; \
|
||||
xor %esi, p3; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p2; \
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p1; \
|
||||
xor %edi, p4; \
|
||||
\
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
shr $16, %edx; \
|
||||
xor %esi, p4; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p3; \
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
movzx tab_f(%rsi), %esi; \
|
||||
movzx tab_f(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p2; \
|
||||
xor %edi, p1
|
||||
|
||||
#endif /* LAST_ROUND_TABLES */
|
||||
|
||||
#define ii_rnd(p1, p2, p3, p4, round) /* normal inverse round */ \
|
||||
mov ik_ref(round,0), p1; \
|
||||
mov ik_ref(round,1), p2; \
|
||||
mov ik_ref(round,2), p3; \
|
||||
mov ik_ref(round,3), p4; \
|
||||
\
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
shr $16, %eax; \
|
||||
xor tab_0(%rsi), p1; \
|
||||
xor tab_1(%rdi), p2; \
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
xor tab_2(%rsi), p3; \
|
||||
xor tab_3(%rdi), p4; \
|
||||
\
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
shr $16, %ebx; \
|
||||
xor tab_0(%rsi), p2; \
|
||||
xor tab_1(%rdi), p3; \
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
xor tab_2(%rsi), p4; \
|
||||
xor tab_3(%rdi), p1; \
|
||||
\
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
shr $16, %ecx; \
|
||||
xor tab_0(%rsi), p3; \
|
||||
xor tab_1(%rdi), p4; \
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
xor tab_2(%rsi), p1; \
|
||||
xor tab_3(%rdi), p2; \
|
||||
\
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
shr $16, %edx; \
|
||||
xor tab_0(%rsi), p4; \
|
||||
xor tab_1(%rdi), p1; \
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
xor tab_2(%rsi), p2; \
|
||||
xor tab_3(%rdi), p3; \
|
||||
\
|
||||
mov p1, %eax; \
|
||||
mov p2, %ebx; \
|
||||
mov p3, %ecx; \
|
||||
mov p4, %edx
|
||||
|
||||
#ifdef LAST_ROUND_TABLES
|
||||
|
||||
#define il_rnd(p1, p2, p3, p4, round) /* last inverse round */ \
|
||||
add $2048, tptr; \
|
||||
mov ik_ref(round,0), p1; \
|
||||
mov ik_ref(round,1), p2; \
|
||||
mov ik_ref(round,2), p3; \
|
||||
mov ik_ref(round,3), p4; \
|
||||
\
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
shr $16, %eax; \
|
||||
xor tab_0(%rsi), p1; \
|
||||
xor tab_1(%rdi), p2; \
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
xor tab_2(%rsi), p3; \
|
||||
xor tab_3(%rdi), p4; \
|
||||
\
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
shr $16, %ebx; \
|
||||
xor tab_0(%rsi), p2; \
|
||||
xor tab_1(%rdi), p3; \
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
xor tab_2(%rsi), p4; \
|
||||
xor tab_3(%rdi), p1; \
|
||||
\
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
shr $16, %ecx; \
|
||||
xor tab_0(%rsi), p3; \
|
||||
xor tab_1(%rdi), p4; \
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
xor tab_2(%rsi), p1; \
|
||||
xor tab_3(%rdi), p2; \
|
||||
\
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
shr $16, %edx; \
|
||||
xor tab_0(%rsi), p4; \
|
||||
xor tab_1(%rdi), p1; \
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
xor tab_2(%rsi), p2; \
|
||||
xor tab_3(%rdi), p3
|
||||
|
||||
#else
|
||||
|
||||
#define il_rnd(p1, p2, p3, p4, round) /* last inverse round */ \
|
||||
mov ik_ref(round,0), p1; \
|
||||
mov ik_ref(round,1), p2; \
|
||||
mov ik_ref(round,2), p3; \
|
||||
mov ik_ref(round,3), p4; \
|
||||
\
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
shr $16, %eax; \
|
||||
xor %esi, p1; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p2; \
|
||||
movzx %al, %esi; \
|
||||
movzx %ah, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p3; \
|
||||
xor %edi, p4; \
|
||||
\
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
shr $16, %ebx; \
|
||||
xor %esi, p2; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p3; \
|
||||
movzx %bl, %esi; \
|
||||
movzx %bh, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p4; \
|
||||
xor %edi, p1; \
|
||||
\
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
shr $16, %ecx; \
|
||||
xor %esi, p3; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p4; \
|
||||
movzx %cl, %esi; \
|
||||
movzx %ch, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p1; \
|
||||
xor %edi, p2; \
|
||||
\
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
shr $16, %edx; \
|
||||
xor %esi, p4; \
|
||||
rol $8, %edi; \
|
||||
xor %edi, p1; \
|
||||
movzx %dl, %esi; \
|
||||
movzx %dh, %edi; \
|
||||
movzx tab_i(%rsi), %esi; \
|
||||
movzx tab_i(%rdi), %edi; \
|
||||
rol $16, %esi; \
|
||||
rol $24, %edi; \
|
||||
xor %esi, p2; \
|
||||
xor %edi, p3
|
||||
|
||||
#endif /* LAST_ROUND_TABLES */
|
||||
|
||||
/*
|
||||
* OpenSolaris OS:
|
||||
* void aes_encrypt_amd64(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4])/
|
||||
*
|
||||
* Original interface:
|
||||
* int aes_encrypt(const unsigned char *in,
|
||||
* unsigned char *out, const aes_encrypt_ctx cx[1])/
|
||||
*/
|
||||
.align 64
|
||||
enc_tab:
|
||||
enc_vals(u8)
|
||||
#ifdef LAST_ROUND_TABLES
|
||||
// Last Round Tables:
|
||||
enc_vals(w8)
|
||||
#endif
|
||||
|
||||
|
||||
ENTRY_NP(aes_encrypt_amd64)
|
||||
#ifdef GLADMAN_INTERFACE
|
||||
// Original interface
|
||||
sub $[4*8], %rsp // gnu/linux/opensolaris binary interface
|
||||
mov %rsi, (%rsp) // output pointer (P2)
|
||||
mov %rdx, %r8 // context (P3)
|
||||
|
||||
mov %rbx, 1*8(%rsp) // P1: input pointer in rdi
|
||||
mov %rbp, 2*8(%rsp) // P2: output pointer in (rsp)
|
||||
mov %r12, 3*8(%rsp) // P3: context in r8
|
||||
movzx 4*KS_LENGTH(kptr), %esi // Get byte key length * 16
|
||||
|
||||
#else
|
||||
// OpenSolaris OS interface
|
||||
sub $[4*8], %rsp // Make room on stack to save registers
|
||||
mov %rcx, (%rsp) // Save output pointer (P4) on stack
|
||||
mov %rdi, %r8 // context (P1)
|
||||
mov %rdx, %rdi // P3: save input pointer
|
||||
shl $4, %esi // P2: esi byte key length * 16
|
||||
|
||||
mov %rbx, 1*8(%rsp) // Save registers
|
||||
mov %rbp, 2*8(%rsp)
|
||||
mov %r12, 3*8(%rsp)
|
||||
// P1: context in r8
|
||||
// P2: byte key length * 16 in esi
|
||||
// P3: input pointer in rdi
|
||||
// P4: output pointer in (rsp)
|
||||
#endif /* GLADMAN_INTERFACE */
|
||||
|
||||
lea enc_tab(%rip), tptr
|
||||
sub $fofs, kptr
|
||||
|
||||
// Load input block into registers
|
||||
mov (%rdi), %eax
|
||||
mov 1*4(%rdi), %ebx
|
||||
mov 2*4(%rdi), %ecx
|
||||
mov 3*4(%rdi), %edx
|
||||
|
||||
xor fofs(kptr), %eax
|
||||
xor fofs+4(kptr), %ebx
|
||||
xor fofs+8(kptr), %ecx
|
||||
xor fofs+12(kptr), %edx
|
||||
|
||||
lea (kptr,%rsi), kptr
|
||||
// Jump based on byte key length * 16:
|
||||
cmp $[10*16], %esi
|
||||
je 3f
|
||||
cmp $[12*16], %esi
|
||||
je 2f
|
||||
cmp $[14*16], %esi
|
||||
je 1f
|
||||
mov $-1, %rax // error
|
||||
jmp 4f
|
||||
|
||||
// Perform normal forward rounds
|
||||
1: ff_rnd(%r9d, %r10d, %r11d, %r12d, 13)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 12)
|
||||
2: ff_rnd(%r9d, %r10d, %r11d, %r12d, 11)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 10)
|
||||
3: ff_rnd(%r9d, %r10d, %r11d, %r12d, 9)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 8)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 7)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 6)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 5)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 4)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 3)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 2)
|
||||
ff_rnd(%r9d, %r10d, %r11d, %r12d, 1)
|
||||
fl_rnd(%r9d, %r10d, %r11d, %r12d, 0)
|
||||
|
||||
// Copy results
|
||||
mov (%rsp), %rbx
|
||||
mov %r9d, (%rbx)
|
||||
mov %r10d, 4(%rbx)
|
||||
mov %r11d, 8(%rbx)
|
||||
mov %r12d, 12(%rbx)
|
||||
xor %rax, %rax
|
||||
4: // Restore registers
|
||||
mov 1*8(%rsp), %rbx
|
||||
mov 2*8(%rsp), %rbp
|
||||
mov 3*8(%rsp), %r12
|
||||
add $[4*8], %rsp
|
||||
ret
|
||||
|
||||
SET_SIZE(aes_encrypt_amd64)
|
||||
|
||||
/*
|
||||
* OpenSolaris OS:
|
||||
* void aes_decrypt_amd64(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4])/
|
||||
*
|
||||
* Original interface:
|
||||
* int aes_decrypt(const unsigned char *in,
|
||||
* unsigned char *out, const aes_encrypt_ctx cx[1])/
|
||||
*/
|
||||
.align 64
|
||||
dec_tab:
|
||||
dec_vals(v8)
|
||||
#ifdef LAST_ROUND_TABLES
|
||||
// Last Round Tables:
|
||||
dec_vals(w8)
|
||||
#endif
|
||||
|
||||
|
||||
ENTRY_NP(aes_decrypt_amd64)
|
||||
#ifdef GLADMAN_INTERFACE
|
||||
// Original interface
|
||||
sub $[4*8], %rsp // gnu/linux/opensolaris binary interface
|
||||
mov %rsi, (%rsp) // output pointer (P2)
|
||||
mov %rdx, %r8 // context (P3)
|
||||
|
||||
mov %rbx, 1*8(%rsp) // P1: input pointer in rdi
|
||||
mov %rbp, 2*8(%rsp) // P2: output pointer in (rsp)
|
||||
mov %r12, 3*8(%rsp) // P3: context in r8
|
||||
movzx 4*KS_LENGTH(kptr), %esi // Get byte key length * 16
|
||||
|
||||
#else
|
||||
// OpenSolaris OS interface
|
||||
sub $[4*8], %rsp // Make room on stack to save registers
|
||||
mov %rcx, (%rsp) // Save output pointer (P4) on stack
|
||||
mov %rdi, %r8 // context (P1)
|
||||
mov %rdx, %rdi // P3: save input pointer
|
||||
shl $4, %esi // P2: esi byte key length * 16
|
||||
|
||||
mov %rbx, 1*8(%rsp) // Save registers
|
||||
mov %rbp, 2*8(%rsp)
|
||||
mov %r12, 3*8(%rsp)
|
||||
// P1: context in r8
|
||||
// P2: byte key length * 16 in esi
|
||||
// P3: input pointer in rdi
|
||||
// P4: output pointer in (rsp)
|
||||
#endif /* GLADMAN_INTERFACE */
|
||||
|
||||
lea dec_tab(%rip), tptr
|
||||
sub $rofs, kptr
|
||||
|
||||
// Load input block into registers
|
||||
mov (%rdi), %eax
|
||||
mov 1*4(%rdi), %ebx
|
||||
mov 2*4(%rdi), %ecx
|
||||
mov 3*4(%rdi), %edx
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
mov kptr, %rdi
|
||||
lea (kptr,%rsi), kptr
|
||||
#else
|
||||
lea (kptr,%rsi), %rdi
|
||||
#endif
|
||||
|
||||
xor rofs(%rdi), %eax
|
||||
xor rofs+4(%rdi), %ebx
|
||||
xor rofs+8(%rdi), %ecx
|
||||
xor rofs+12(%rdi), %edx
|
||||
|
||||
// Jump based on byte key length * 16:
|
||||
cmp $[10*16], %esi
|
||||
je 3f
|
||||
cmp $[12*16], %esi
|
||||
je 2f
|
||||
cmp $[14*16], %esi
|
||||
je 1f
|
||||
mov $-1, %rax // error
|
||||
jmp 4f
|
||||
|
||||
// Perform normal inverse rounds
|
||||
1: ii_rnd(%r9d, %r10d, %r11d, %r12d, 13)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 12)
|
||||
2: ii_rnd(%r9d, %r10d, %r11d, %r12d, 11)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 10)
|
||||
3: ii_rnd(%r9d, %r10d, %r11d, %r12d, 9)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 8)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 7)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 6)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 5)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 4)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 3)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 2)
|
||||
ii_rnd(%r9d, %r10d, %r11d, %r12d, 1)
|
||||
il_rnd(%r9d, %r10d, %r11d, %r12d, 0)
|
||||
|
||||
// Copy results
|
||||
mov (%rsp), %rbx
|
||||
mov %r9d, (%rbx)
|
||||
mov %r10d, 4(%rbx)
|
||||
mov %r11d, 8(%rbx)
|
||||
mov %r12d, 12(%rbx)
|
||||
xor %rax, %rax
|
||||
4: // Restore registers
|
||||
mov 1*8(%rsp), %rbx
|
||||
mov 2*8(%rsp), %rbp
|
||||
mov 3*8(%rsp), %r12
|
||||
add $[4*8], %rsp
|
||||
ret
|
||||
|
||||
SET_SIZE(aes_decrypt_amd64)
|
||||
#endif /* lint || __lint */
|
851
module/icp/asm-x86_64/aes/aes_intel.S
Normal file
851
module/icp/asm-x86_64/aes/aes_intel.S
Normal file
@ -0,0 +1,851 @@
|
||||
/*
|
||||
* ====================================================================
|
||||
* Written by Intel Corporation for the OpenSSL project to add support
|
||||
* for Intel AES-NI instructions. Rights for redistribution and usage
|
||||
* in source and binary forms are granted according to the OpenSSL
|
||||
* license.
|
||||
*
|
||||
* Author: Huang Ying <ying.huang at intel dot com>
|
||||
* Vinodh Gopal <vinodh.gopal at intel dot com>
|
||||
* Kahraman Akdemir
|
||||
*
|
||||
* Intel AES-NI is a new set of Single Instruction Multiple Data (SIMD)
|
||||
* instructions that are going to be introduced in the next generation
|
||||
* of Intel processor, as of 2009. These instructions enable fast and
|
||||
* secure data encryption and decryption, using the Advanced Encryption
|
||||
* Standard (AES), defined by FIPS Publication number 197. The
|
||||
* architecture introduces six instructions that offer full hardware
|
||||
* support for AES. Four of them support high performance data
|
||||
* encryption and decryption, and the other two instructions support
|
||||
* the AES key expansion procedure.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================================
|
||||
* 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.
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* ====================================================================
|
||||
* OpenSolaris OS modifications
|
||||
*
|
||||
* This source originates as files aes-intel.S and eng_aesni_asm.pl, in
|
||||
* patches sent sent Dec. 9, 2008 and Dec. 24, 2008, respectively, by
|
||||
* Huang Ying of Intel to the openssl-dev mailing list under the subject
|
||||
* of "Add support to Intel AES-NI instruction set for x86_64 platform".
|
||||
*
|
||||
* 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 dummy C function
|
||||
* definitions 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. Renamed functions, reordered parameters, and changed return value
|
||||
* to match OpenSolaris:
|
||||
*
|
||||
* OpenSSL interface:
|
||||
* int intel_AES_set_encrypt_key(const unsigned char *userKey,
|
||||
* const int bits, AES_KEY *key);
|
||||
* int intel_AES_set_decrypt_key(const unsigned char *userKey,
|
||||
* const int bits, AES_KEY *key);
|
||||
* Return values for above are non-zero on error, 0 on success.
|
||||
*
|
||||
* void intel_AES_encrypt(const unsigned char *in, unsigned char *out,
|
||||
* const AES_KEY *key);
|
||||
* void intel_AES_decrypt(const unsigned char *in, unsigned char *out,
|
||||
* const AES_KEY *key);
|
||||
* typedef struct aes_key_st {
|
||||
* unsigned int rd_key[4 *(AES_MAXNR + 1)];
|
||||
* int rounds;
|
||||
* unsigned int pad[3];
|
||||
* } AES_KEY;
|
||||
* Note: AES_LONG is undefined (that is, Intel uses 32-bit key schedules
|
||||
* (ks32) instead of 64-bit (ks64).
|
||||
* Number of rounds (aka round count) is at offset 240 of AES_KEY.
|
||||
*
|
||||
* OpenSolaris OS interface (#ifdefs removed for readability):
|
||||
* int rijndael_key_setup_dec_intel(uint32_t rk[],
|
||||
* const uint32_t cipherKey[], uint64_t keyBits);
|
||||
* int rijndael_key_setup_enc_intel(uint32_t rk[],
|
||||
* const uint32_t cipherKey[], uint64_t keyBits);
|
||||
* Return values for above are 0 on error, number of rounds on success.
|
||||
*
|
||||
* void aes_encrypt_intel(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4]);
|
||||
* void aes_decrypt_intel(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4]);
|
||||
* typedef union {uint64_t ks64[(MAX_AES_NR + 1) * 4];
|
||||
* uint32_t ks32[(MAX_AES_NR + 1) * 4]; } aes_ks_t;
|
||||
*
|
||||
* typedef union {
|
||||
* uint32_t ks32[((MAX_AES_NR) + 1) * (MAX_AES_NB)];
|
||||
* } aes_ks_t;
|
||||
* typedef struct aes_key {
|
||||
* aes_ks_t encr_ks, decr_ks;
|
||||
* long double align128;
|
||||
* int flags, nr, type;
|
||||
* } aes_key_t;
|
||||
*
|
||||
* Note: ks is the AES key schedule, Nr is number of rounds, pt is plain text,
|
||||
* ct is crypto text, and MAX_AES_NR is 14.
|
||||
* For the x86 64-bit architecture, OpenSolaris OS uses ks32 instead of ks64.
|
||||
*
|
||||
* Note2: aes_ks_t must be aligned on a 0 mod 128 byte boundary.
|
||||
*
|
||||
* ====================================================================
|
||||
*/
|
||||
|
||||
#if defined(lint) || defined(__lint)
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
/* ARGSUSED */
|
||||
void
|
||||
aes_encrypt_intel(const uint32_t rk[], int Nr, const uint32_t pt[4],
|
||||
uint32_t ct[4]) {
|
||||
}
|
||||
/* ARGSUSED */
|
||||
void
|
||||
aes_decrypt_intel(const uint32_t rk[], int Nr, const uint32_t ct[4],
|
||||
uint32_t pt[4]) {
|
||||
}
|
||||
/* ARGSUSED */
|
||||
int
|
||||
rijndael_key_setup_enc_intel(uint32_t rk[], const uint32_t cipherKey[],
|
||||
uint64_t keyBits) {
|
||||
return (0);
|
||||
}
|
||||
/* ARGSUSED */
|
||||
int
|
||||
rijndael_key_setup_dec_intel(uint32_t rk[], const uint32_t cipherKey[],
|
||||
uint64_t keyBits) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
#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 */
|
||||
|
||||
#define CLEAR_TS_OR_PUSH_XMM0_XMM1(tmpreg) \
|
||||
push %rbp; \
|
||||
mov %rsp, %rbp; \
|
||||
movq %cr0, tmpreg; \
|
||||
testq $CR0_TS, tmpreg; \
|
||||
jnz 1f; \
|
||||
and $-XMM_ALIGN, %rsp; \
|
||||
sub $[XMM_SIZE * 2], %rsp; \
|
||||
movaps %xmm0, 16(%rsp); \
|
||||
movaps %xmm1, (%rsp); \
|
||||
jmp 2f; \
|
||||
1: \
|
||||
PROTECTED_CLTS; \
|
||||
2:
|
||||
|
||||
/*
|
||||
* If CR0_TS was not set above, pop %xmm0 and %xmm1 off stack,
|
||||
* otherwise set CR0_TS.
|
||||
*/
|
||||
#define SET_TS_OR_POP_XMM0_XMM1(tmpreg) \
|
||||
testq $CR0_TS, tmpreg; \
|
||||
jnz 1f; \
|
||||
movaps (%rsp), %xmm1; \
|
||||
movaps 16(%rsp), %xmm0; \
|
||||
jmp 2f; \
|
||||
1: \
|
||||
STTS(tmpreg); \
|
||||
2: \
|
||||
mov %rbp, %rsp; \
|
||||
pop %rbp
|
||||
|
||||
/*
|
||||
* If CR0_TS is not set, align stack (with push %rbp) and push
|
||||
* %xmm0 - %xmm6 on stack, otherwise clear CR0_TS
|
||||
*/
|
||||
#define CLEAR_TS_OR_PUSH_XMM0_TO_XMM6(tmpreg) \
|
||||
push %rbp; \
|
||||
mov %rsp, %rbp; \
|
||||
movq %cr0, tmpreg; \
|
||||
testq $CR0_TS, tmpreg; \
|
||||
jnz 1f; \
|
||||
and $-XMM_ALIGN, %rsp; \
|
||||
sub $[XMM_SIZE * 7], %rsp; \
|
||||
movaps %xmm0, 96(%rsp); \
|
||||
movaps %xmm1, 80(%rsp); \
|
||||
movaps %xmm2, 64(%rsp); \
|
||||
movaps %xmm3, 48(%rsp); \
|
||||
movaps %xmm4, 32(%rsp); \
|
||||
movaps %xmm5, 16(%rsp); \
|
||||
movaps %xmm6, (%rsp); \
|
||||
jmp 2f; \
|
||||
1: \
|
||||
PROTECTED_CLTS; \
|
||||
2:
|
||||
|
||||
|
||||
/*
|
||||
* If CR0_TS was not set above, pop %xmm0 - %xmm6 off stack,
|
||||
* otherwise set CR0_TS.
|
||||
*/
|
||||
#define SET_TS_OR_POP_XMM0_TO_XMM6(tmpreg) \
|
||||
testq $CR0_TS, tmpreg; \
|
||||
jnz 1f; \
|
||||
movaps (%rsp), %xmm6; \
|
||||
movaps 16(%rsp), %xmm5; \
|
||||
movaps 32(%rsp), %xmm4; \
|
||||
movaps 48(%rsp), %xmm3; \
|
||||
movaps 64(%rsp), %xmm2; \
|
||||
movaps 80(%rsp), %xmm1; \
|
||||
movaps 96(%rsp), %xmm0; \
|
||||
jmp 2f; \
|
||||
1: \
|
||||
STTS(tmpreg); \
|
||||
2: \
|
||||
mov %rbp, %rsp; \
|
||||
pop %rbp
|
||||
|
||||
|
||||
#else
|
||||
#define PROTECTED_CLTS
|
||||
#define CLEAR_TS_OR_PUSH_XMM0_XMM1(tmpreg)
|
||||
#define SET_TS_OR_POP_XMM0_XMM1(tmpreg)
|
||||
#define CLEAR_TS_OR_PUSH_XMM0_TO_XMM6(tmpreg)
|
||||
#define SET_TS_OR_POP_XMM0_TO_XMM6(tmpreg)
|
||||
#endif /* _KERNEL */
|
||||
|
||||
|
||||
/*
|
||||
* _key_expansion_128(), * _key_expansion_192a(), _key_expansion_192b(),
|
||||
* _key_expansion_256a(), _key_expansion_256b()
|
||||
*
|
||||
* Helper functions called by rijndael_key_setup_inc_intel().
|
||||
* Also used indirectly by rijndael_key_setup_dec_intel().
|
||||
*
|
||||
* Input:
|
||||
* %xmm0 User-provided cipher key
|
||||
* %xmm1 Round constant
|
||||
* Output:
|
||||
* (%rcx) AES key
|
||||
*/
|
||||
|
||||
.align 16
|
||||
_key_expansion_128:
|
||||
_key_expansion_256a:
|
||||
pshufd $0b11111111, %xmm1, %xmm1
|
||||
shufps $0b00010000, %xmm0, %xmm4
|
||||
pxor %xmm4, %xmm0
|
||||
shufps $0b10001100, %xmm0, %xmm4
|
||||
pxor %xmm4, %xmm0
|
||||
pxor %xmm1, %xmm0
|
||||
movaps %xmm0, (%rcx)
|
||||
add $0x10, %rcx
|
||||
ret
|
||||
SET_SIZE(_key_expansion_128)
|
||||
SET_SIZE(_key_expansion_256a)
|
||||
|
||||
.align 16
|
||||
_key_expansion_192a:
|
||||
pshufd $0b01010101, %xmm1, %xmm1
|
||||
shufps $0b00010000, %xmm0, %xmm4
|
||||
pxor %xmm4, %xmm0
|
||||
shufps $0b10001100, %xmm0, %xmm4
|
||||
pxor %xmm4, %xmm0
|
||||
pxor %xmm1, %xmm0
|
||||
|
||||
movaps %xmm2, %xmm5
|
||||
movaps %xmm2, %xmm6
|
||||
pslldq $4, %xmm5
|
||||
pshufd $0b11111111, %xmm0, %xmm3
|
||||
pxor %xmm3, %xmm2
|
||||
pxor %xmm5, %xmm2
|
||||
|
||||
movaps %xmm0, %xmm1
|
||||
shufps $0b01000100, %xmm0, %xmm6
|
||||
movaps %xmm6, (%rcx)
|
||||
shufps $0b01001110, %xmm2, %xmm1
|
||||
movaps %xmm1, 0x10(%rcx)
|
||||
add $0x20, %rcx
|
||||
ret
|
||||
SET_SIZE(_key_expansion_192a)
|
||||
|
||||
.align 16
|
||||
_key_expansion_192b:
|
||||
pshufd $0b01010101, %xmm1, %xmm1
|
||||
shufps $0b00010000, %xmm0, %xmm4
|
||||
pxor %xmm4, %xmm0
|
||||
shufps $0b10001100, %xmm0, %xmm4
|
||||
pxor %xmm4, %xmm0
|
||||
pxor %xmm1, %xmm0
|
||||
|
||||
movaps %xmm2, %xmm5
|
||||
pslldq $4, %xmm5
|
||||
pshufd $0b11111111, %xmm0, %xmm3
|
||||
pxor %xmm3, %xmm2
|
||||
pxor %xmm5, %xmm2
|
||||
|
||||
movaps %xmm0, (%rcx)
|
||||
add $0x10, %rcx
|
||||
ret
|
||||
SET_SIZE(_key_expansion_192b)
|
||||
|
||||
.align 16
|
||||
_key_expansion_256b:
|
||||
pshufd $0b10101010, %xmm1, %xmm1
|
||||
shufps $0b00010000, %xmm2, %xmm4
|
||||
pxor %xmm4, %xmm2
|
||||
shufps $0b10001100, %xmm2, %xmm4
|
||||
pxor %xmm4, %xmm2
|
||||
pxor %xmm1, %xmm2
|
||||
movaps %xmm2, (%rcx)
|
||||
add $0x10, %rcx
|
||||
ret
|
||||
SET_SIZE(_key_expansion_256b)
|
||||
|
||||
|
||||
/*
|
||||
* rijndael_key_setup_enc_intel()
|
||||
* Expand the cipher key into the encryption key schedule.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* OpenSolaris interface:
|
||||
* int rijndael_key_setup_enc_intel(uint32_t rk[], const uint32_t cipherKey[],
|
||||
* uint64_t keyBits);
|
||||
* Return value is 0 on error, number of rounds on success.
|
||||
*
|
||||
* Original Intel OpenSSL interface:
|
||||
* int intel_AES_set_encrypt_key(const unsigned char *userKey,
|
||||
* const int bits, AES_KEY *key);
|
||||
* Return value is non-zero on error, 0 on success.
|
||||
*/
|
||||
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
#define rijndael_key_setup_enc_intel intel_AES_set_encrypt_key
|
||||
#define rijndael_key_setup_dec_intel intel_AES_set_decrypt_key
|
||||
|
||||
#define USERCIPHERKEY rdi /* P1, 64 bits */
|
||||
#define KEYSIZE32 esi /* P2, 32 bits */
|
||||
#define KEYSIZE64 rsi /* P2, 64 bits */
|
||||
#define AESKEY rdx /* P3, 64 bits */
|
||||
|
||||
#else /* OpenSolaris Interface */
|
||||
#define AESKEY rdi /* P1, 64 bits */
|
||||
#define USERCIPHERKEY rsi /* P2, 64 bits */
|
||||
#define KEYSIZE32 edx /* P3, 32 bits */
|
||||
#define KEYSIZE64 rdx /* P3, 64 bits */
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
#define ROUNDS32 KEYSIZE32 /* temp */
|
||||
#define ROUNDS64 KEYSIZE64 /* temp */
|
||||
#define ENDAESKEY USERCIPHERKEY /* temp */
|
||||
|
||||
ENTRY_NP(rijndael_key_setup_enc_intel)
|
||||
rijndael_key_setup_enc_intel_local:
|
||||
CLEAR_TS_OR_PUSH_XMM0_TO_XMM6(%r10)
|
||||
|
||||
// NULL pointer sanity check
|
||||
test %USERCIPHERKEY, %USERCIPHERKEY
|
||||
jz .Lenc_key_invalid_param
|
||||
test %AESKEY, %AESKEY
|
||||
jz .Lenc_key_invalid_param
|
||||
|
||||
movups (%USERCIPHERKEY), %xmm0 // user key (first 16 bytes)
|
||||
movaps %xmm0, (%AESKEY)
|
||||
lea 0x10(%AESKEY), %rcx // key addr
|
||||
pxor %xmm4, %xmm4 // xmm4 is assumed 0 in _key_expansion_x
|
||||
|
||||
cmp $256, %KEYSIZE32
|
||||
jnz .Lenc_key192
|
||||
|
||||
// AES 256: 14 rounds in encryption key schedule
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
mov $14, %ROUNDS32
|
||||
movl %ROUNDS32, 240(%AESKEY) // key.rounds = 14
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
movups 0x10(%USERCIPHERKEY), %xmm2 // other user key (2nd 16 bytes)
|
||||
movaps %xmm2, (%rcx)
|
||||
add $0x10, %rcx
|
||||
|
||||
aeskeygenassist $0x1, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
aeskeygenassist $0x1, %xmm0, %xmm1
|
||||
call _key_expansion_256b
|
||||
aeskeygenassist $0x2, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
aeskeygenassist $0x2, %xmm0, %xmm1
|
||||
call _key_expansion_256b
|
||||
aeskeygenassist $0x4, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
aeskeygenassist $0x4, %xmm0, %xmm1
|
||||
call _key_expansion_256b
|
||||
aeskeygenassist $0x8, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
aeskeygenassist $0x8, %xmm0, %xmm1
|
||||
call _key_expansion_256b
|
||||
aeskeygenassist $0x10, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
aeskeygenassist $0x10, %xmm0, %xmm1
|
||||
call _key_expansion_256b
|
||||
aeskeygenassist $0x20, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
aeskeygenassist $0x20, %xmm0, %xmm1
|
||||
call _key_expansion_256b
|
||||
aeskeygenassist $0x40, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_256a
|
||||
|
||||
SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
xor %rax, %rax // return 0 (OK)
|
||||
#else /* Open Solaris Interface */
|
||||
mov $14, %rax // return # rounds = 14
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 4
|
||||
.Lenc_key192:
|
||||
cmp $192, %KEYSIZE32
|
||||
jnz .Lenc_key128
|
||||
|
||||
// AES 192: 12 rounds in encryption key schedule
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
mov $12, %ROUNDS32
|
||||
movl %ROUNDS32, 240(%AESKEY) // key.rounds = 12
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
movq 0x10(%USERCIPHERKEY), %xmm2 // other user key
|
||||
aeskeygenassist $0x1, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192a
|
||||
aeskeygenassist $0x2, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192b
|
||||
aeskeygenassist $0x4, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192a
|
||||
aeskeygenassist $0x8, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192b
|
||||
aeskeygenassist $0x10, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192a
|
||||
aeskeygenassist $0x20, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192b
|
||||
aeskeygenassist $0x40, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192a
|
||||
aeskeygenassist $0x80, %xmm2, %xmm1 // expand the key
|
||||
call _key_expansion_192b
|
||||
|
||||
SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
xor %rax, %rax // return 0 (OK)
|
||||
#else /* OpenSolaris Interface */
|
||||
mov $12, %rax // return # rounds = 12
|
||||
#endif
|
||||
ret
|
||||
|
||||
.align 4
|
||||
.Lenc_key128:
|
||||
cmp $128, %KEYSIZE32
|
||||
jnz .Lenc_key_invalid_key_bits
|
||||
|
||||
// AES 128: 10 rounds in encryption key schedule
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
mov $10, %ROUNDS32
|
||||
movl %ROUNDS32, 240(%AESKEY) // key.rounds = 10
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
aeskeygenassist $0x1, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x2, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x4, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x8, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x10, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x20, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x40, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x80, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x1b, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
aeskeygenassist $0x36, %xmm0, %xmm1 // expand the key
|
||||
call _key_expansion_128
|
||||
|
||||
SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
xor %rax, %rax // return 0 (OK)
|
||||
#else /* OpenSolaris Interface */
|
||||
mov $10, %rax // return # rounds = 10
|
||||
#endif
|
||||
ret
|
||||
|
||||
.Lenc_key_invalid_param:
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
|
||||
mov $-1, %rax // user key or AES key pointer is NULL
|
||||
ret
|
||||
#else
|
||||
/* FALLTHROUGH */
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
.Lenc_key_invalid_key_bits:
|
||||
SET_TS_OR_POP_XMM0_TO_XMM6(%r10)
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
mov $-2, %rax // keysize is invalid
|
||||
#else /* Open Solaris Interface */
|
||||
xor %rax, %rax // a key pointer is NULL or invalid keysize
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
ret
|
||||
SET_SIZE(rijndael_key_setup_enc_intel)
|
||||
|
||||
|
||||
/*
|
||||
* rijndael_key_setup_dec_intel()
|
||||
* Expand the cipher key into the decryption key schedule.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* OpenSolaris interface:
|
||||
* int rijndael_key_setup_dec_intel(uint32_t rk[], const uint32_t cipherKey[],
|
||||
* uint64_t keyBits);
|
||||
* Return value is 0 on error, number of rounds on success.
|
||||
* P1->P2, P2->P3, P3->P1
|
||||
*
|
||||
* Original Intel OpenSSL interface:
|
||||
* int intel_AES_set_decrypt_key(const unsigned char *userKey,
|
||||
* const int bits, AES_KEY *key);
|
||||
* Return value is non-zero on error, 0 on success.
|
||||
*/
|
||||
ENTRY_NP(rijndael_key_setup_dec_intel)
|
||||
// Generate round keys used for encryption
|
||||
call rijndael_key_setup_enc_intel_local
|
||||
test %rax, %rax
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
jnz .Ldec_key_exit // Failed if returned non-0
|
||||
#else /* OpenSolaris Interface */
|
||||
jz .Ldec_key_exit // Failed if returned 0
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
CLEAR_TS_OR_PUSH_XMM0_XMM1(%r10)
|
||||
|
||||
/*
|
||||
* Convert round keys used for encryption
|
||||
* to a form usable for decryption
|
||||
*/
|
||||
#ifndef OPENSSL_INTERFACE /* OpenSolaris Interface */
|
||||
mov %rax, %ROUNDS64 // set # rounds (10, 12, or 14)
|
||||
// (already set for OpenSSL)
|
||||
#endif
|
||||
|
||||
lea 0x10(%AESKEY), %rcx // key addr
|
||||
shl $4, %ROUNDS32
|
||||
add %AESKEY, %ROUNDS64
|
||||
mov %ROUNDS64, %ENDAESKEY
|
||||
|
||||
.align 4
|
||||
.Ldec_key_reorder_loop:
|
||||
movaps (%AESKEY), %xmm0
|
||||
movaps (%ROUNDS64), %xmm1
|
||||
movaps %xmm0, (%ROUNDS64)
|
||||
movaps %xmm1, (%AESKEY)
|
||||
lea 0x10(%AESKEY), %AESKEY
|
||||
lea -0x10(%ROUNDS64), %ROUNDS64
|
||||
cmp %AESKEY, %ROUNDS64
|
||||
ja .Ldec_key_reorder_loop
|
||||
|
||||
.align 4
|
||||
.Ldec_key_inv_loop:
|
||||
movaps (%rcx), %xmm0
|
||||
// Convert an encryption round key to a form usable for decryption
|
||||
// with the "AES Inverse Mix Columns" instruction
|
||||
aesimc %xmm0, %xmm1
|
||||
movaps %xmm1, (%rcx)
|
||||
lea 0x10(%rcx), %rcx
|
||||
cmp %ENDAESKEY, %rcx
|
||||
jnz .Ldec_key_inv_loop
|
||||
|
||||
SET_TS_OR_POP_XMM0_XMM1(%r10)
|
||||
|
||||
.Ldec_key_exit:
|
||||
// OpenSolaris: rax = # rounds (10, 12, or 14) or 0 for error
|
||||
// OpenSSL: rax = 0 for OK, or non-zero for error
|
||||
ret
|
||||
SET_SIZE(rijndael_key_setup_dec_intel)
|
||||
|
||||
|
||||
/*
|
||||
* aes_encrypt_intel()
|
||||
* Encrypt a single block (in and out can overlap).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Temporary register usage:
|
||||
* %xmm0 State
|
||||
* %xmm1 Key
|
||||
*
|
||||
* Original OpenSolaris Interface:
|
||||
* void aes_encrypt_intel(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4])
|
||||
*
|
||||
* Original Intel OpenSSL Interface:
|
||||
* void intel_AES_encrypt(const unsigned char *in, unsigned char *out,
|
||||
* const AES_KEY *key)
|
||||
*/
|
||||
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
#define aes_encrypt_intel intel_AES_encrypt
|
||||
#define aes_decrypt_intel intel_AES_decrypt
|
||||
|
||||
#define INP rdi /* P1, 64 bits */
|
||||
#define OUTP rsi /* P2, 64 bits */
|
||||
#define KEYP rdx /* P3, 64 bits */
|
||||
|
||||
/* No NROUNDS parameter--offset 240 from KEYP saved in %ecx: */
|
||||
#define NROUNDS32 ecx /* temporary, 32 bits */
|
||||
#define NROUNDS cl /* temporary, 8 bits */
|
||||
|
||||
#else /* OpenSolaris Interface */
|
||||
#define KEYP rdi /* P1, 64 bits */
|
||||
#define NROUNDS esi /* P2, 32 bits */
|
||||
#define INP rdx /* P3, 64 bits */
|
||||
#define OUTP rcx /* P4, 64 bits */
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
#define STATE xmm0 /* temporary, 128 bits */
|
||||
#define KEY xmm1 /* temporary, 128 bits */
|
||||
|
||||
ENTRY_NP(aes_encrypt_intel)
|
||||
CLEAR_TS_OR_PUSH_XMM0_XMM1(%r10)
|
||||
|
||||
movups (%INP), %STATE // input
|
||||
movaps (%KEYP), %KEY // key
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
mov 240(%KEYP), %NROUNDS32 // round count
|
||||
#else /* OpenSolaris Interface */
|
||||
/* Round count is already present as P2 in %rsi/%esi */
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
pxor %KEY, %STATE // round 0
|
||||
lea 0x30(%KEYP), %KEYP
|
||||
cmp $12, %NROUNDS
|
||||
jb .Lenc128
|
||||
lea 0x20(%KEYP), %KEYP
|
||||
je .Lenc192
|
||||
|
||||
// AES 256
|
||||
lea 0x20(%KEYP), %KEYP
|
||||
movaps -0x60(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps -0x50(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
|
||||
.align 4
|
||||
.Lenc192:
|
||||
// AES 192 and 256
|
||||
movaps -0x40(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps -0x30(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
|
||||
.align 4
|
||||
.Lenc128:
|
||||
// AES 128, 192, and 256
|
||||
movaps -0x20(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps -0x10(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps (%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x10(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x20(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x30(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x40(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x50(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x60(%KEYP), %KEY
|
||||
aesenc %KEY, %STATE
|
||||
movaps 0x70(%KEYP), %KEY
|
||||
aesenclast %KEY, %STATE // last round
|
||||
movups %STATE, (%OUTP) // output
|
||||
|
||||
SET_TS_OR_POP_XMM0_XMM1(%r10)
|
||||
ret
|
||||
SET_SIZE(aes_encrypt_intel)
|
||||
|
||||
|
||||
/*
|
||||
* aes_decrypt_intel()
|
||||
* Decrypt a single block (in and out can overlap).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Temporary register usage:
|
||||
* %xmm0 State
|
||||
* %xmm1 Key
|
||||
*
|
||||
* Original OpenSolaris Interface:
|
||||
* void aes_decrypt_intel(const aes_ks_t *ks, int Nr,
|
||||
* const uint32_t pt[4], uint32_t ct[4])/
|
||||
*
|
||||
* Original Intel OpenSSL Interface:
|
||||
* void intel_AES_decrypt(const unsigned char *in, unsigned char *out,
|
||||
* const AES_KEY *key);
|
||||
*/
|
||||
ENTRY_NP(aes_decrypt_intel)
|
||||
CLEAR_TS_OR_PUSH_XMM0_XMM1(%r10)
|
||||
|
||||
movups (%INP), %STATE // input
|
||||
movaps (%KEYP), %KEY // key
|
||||
#ifdef OPENSSL_INTERFACE
|
||||
mov 240(%KEYP), %NROUNDS32 // round count
|
||||
#else /* OpenSolaris Interface */
|
||||
/* Round count is already present as P2 in %rsi/%esi */
|
||||
#endif /* OPENSSL_INTERFACE */
|
||||
|
||||
pxor %KEY, %STATE // round 0
|
||||
lea 0x30(%KEYP), %KEYP
|
||||
cmp $12, %NROUNDS
|
||||
jb .Ldec128
|
||||
lea 0x20(%KEYP), %KEYP
|
||||
je .Ldec192
|
||||
|
||||
// AES 256
|
||||
lea 0x20(%KEYP), %KEYP
|
||||
movaps -0x60(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps -0x50(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
|
||||
.align 4
|
||||
.Ldec192:
|
||||
// AES 192 and 256
|
||||
movaps -0x40(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps -0x30(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
|
||||
.align 4
|
||||
.Ldec128:
|
||||
// AES 128, 192, and 256
|
||||
movaps -0x20(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps -0x10(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps (%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x10(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x20(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x30(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x40(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x50(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x60(%KEYP), %KEY
|
||||
aesdec %KEY, %STATE
|
||||
movaps 0x70(%KEYP), %KEY
|
||||
aesdeclast %KEY, %STATE // last round
|
||||
movups %STATE, (%OUTP) // output
|
||||
|
||||
SET_TS_OR_POP_XMM0_XMM1(%r10)
|
||||
ret
|
||||
SET_SIZE(aes_decrypt_intel)
|
||||
|
||||
#endif /* lint || __lint */
|
580
module/icp/asm-x86_64/aes/aeskey.c
Normal file
580
module/icp/asm-x86_64/aes/aeskey.c
Normal file
@ -0,0 +1,580 @@
|
||||
/*
|
||||
* ---------------------------------------------------------------------------
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <aes/aes_impl.h>
|
||||
#include "aesopt.h"
|
||||
#include "aestab.h"
|
||||
#include "aestab2.h"
|
||||
|
||||
/*
|
||||
* Initialise the key schedule from the user supplied key. The key
|
||||
* length can be specified in bytes, with legal values of 16, 24
|
||||
* and 32, or in bits, with legal values of 128, 192 and 256. These
|
||||
* values correspond with Nk values of 4, 6 and 8 respectively.
|
||||
*
|
||||
* The following macros implement a single cycle in the key
|
||||
* schedule generation process. The number of cycles needed
|
||||
* for each cx->n_col and nk value is:
|
||||
*
|
||||
* nk = 4 5 6 7 8
|
||||
* ------------------------------
|
||||
* cx->n_col = 4 10 9 8 7 7
|
||||
* cx->n_col = 5 14 11 10 9 9
|
||||
* cx->n_col = 6 19 15 12 11 11
|
||||
* cx->n_col = 7 21 19 16 13 14
|
||||
* cx->n_col = 8 29 23 19 17 14
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenSolaris changes
|
||||
* 1. Added header files aes_impl.h and aestab2.h
|
||||
* 2. Changed uint_8t and uint_32t to uint8_t and uint32_t
|
||||
* 3. Remove code under ifdef USE_VIA_ACE_IF_PRESENT (always undefined)
|
||||
* 4. Removed always-defined ifdefs FUNCS_IN_C, ENC_KEYING_IN_C,
|
||||
* AES_128, AES_192, AES_256, AES_VAR defines
|
||||
* 5. Changed aes_encrypt_key* aes_decrypt_key* functions to "static void"
|
||||
* 6. Changed N_COLS to MAX_AES_NB
|
||||
* 7. Replaced functions aes_encrypt_key and aes_decrypt_key with
|
||||
* OpenSolaris-compatible functions rijndael_key_setup_enc_amd64 and
|
||||
* rijndael_key_setup_dec_amd64
|
||||
* 8. cstyled code and removed lint warnings
|
||||
*/
|
||||
|
||||
#if defined(REDUCE_CODE_SIZE)
|
||||
#define ls_box ls_sub
|
||||
uint32_t ls_sub(const uint32_t t, const uint32_t n);
|
||||
#define inv_mcol im_sub
|
||||
uint32_t im_sub(const uint32_t x);
|
||||
#ifdef ENC_KS_UNROLL
|
||||
#undef ENC_KS_UNROLL
|
||||
#endif
|
||||
#ifdef DEC_KS_UNROLL
|
||||
#undef DEC_KS_UNROLL
|
||||
#endif
|
||||
#endif /* REDUCE_CODE_SIZE */
|
||||
|
||||
|
||||
#define ke4(k, i) \
|
||||
{ k[4 * (i) + 4] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[4 * (i) + 5] = ss[1] ^= ss[0]; \
|
||||
k[4 * (i) + 6] = ss[2] ^= ss[1]; \
|
||||
k[4 * (i) + 7] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
static void
|
||||
aes_encrypt_key128(const unsigned char *key, uint32_t rk[])
|
||||
{
|
||||
uint32_t ss[4];
|
||||
|
||||
rk[0] = ss[0] = word_in(key, 0);
|
||||
rk[1] = ss[1] = word_in(key, 1);
|
||||
rk[2] = ss[2] = word_in(key, 2);
|
||||
rk[3] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke4(rk, 0); ke4(rk, 1);
|
||||
ke4(rk, 2); ke4(rk, 3);
|
||||
ke4(rk, 4); ke4(rk, 5);
|
||||
ke4(rk, 6); ke4(rk, 7);
|
||||
ke4(rk, 8);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < 9; ++i)
|
||||
ke4(rk, i);
|
||||
}
|
||||
#endif /* ENC_KS_UNROLL */
|
||||
ke4(rk, 9);
|
||||
}
|
||||
|
||||
|
||||
#define kef6(k, i) \
|
||||
{ k[6 * (i) + 6] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[6 * (i) + 7] = ss[1] ^= ss[0]; \
|
||||
k[6 * (i) + 8] = ss[2] ^= ss[1]; \
|
||||
k[6 * (i) + 9] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke6(k, i) \
|
||||
{ kef6(k, i); \
|
||||
k[6 * (i) + 10] = ss[4] ^= ss[3]; \
|
||||
k[6 * (i) + 11] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
static void
|
||||
aes_encrypt_key192(const unsigned char *key, uint32_t rk[])
|
||||
{
|
||||
uint32_t ss[6];
|
||||
|
||||
rk[0] = ss[0] = word_in(key, 0);
|
||||
rk[1] = ss[1] = word_in(key, 1);
|
||||
rk[2] = ss[2] = word_in(key, 2);
|
||||
rk[3] = ss[3] = word_in(key, 3);
|
||||
rk[4] = ss[4] = word_in(key, 4);
|
||||
rk[5] = ss[5] = word_in(key, 5);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke6(rk, 0); ke6(rk, 1);
|
||||
ke6(rk, 2); ke6(rk, 3);
|
||||
ke6(rk, 4); ke6(rk, 5);
|
||||
ke6(rk, 6);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < 7; ++i)
|
||||
ke6(rk, i);
|
||||
}
|
||||
#endif /* ENC_KS_UNROLL */
|
||||
kef6(rk, 7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define kef8(k, i) \
|
||||
{ k[8 * (i) + 8] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[8 * (i) + 9] = ss[1] ^= ss[0]; \
|
||||
k[8 * (i) + 10] = ss[2] ^= ss[1]; \
|
||||
k[8 * (i) + 11] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define ke8(k, i) \
|
||||
{ kef8(k, i); \
|
||||
k[8 * (i) + 12] = ss[4] ^= ls_box(ss[3], 0); \
|
||||
k[8 * (i) + 13] = ss[5] ^= ss[4]; \
|
||||
k[8 * (i) + 14] = ss[6] ^= ss[5]; \
|
||||
k[8 * (i) + 15] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
static void
|
||||
aes_encrypt_key256(const unsigned char *key, uint32_t rk[])
|
||||
{
|
||||
uint32_t ss[8];
|
||||
|
||||
rk[0] = ss[0] = word_in(key, 0);
|
||||
rk[1] = ss[1] = word_in(key, 1);
|
||||
rk[2] = ss[2] = word_in(key, 2);
|
||||
rk[3] = ss[3] = word_in(key, 3);
|
||||
rk[4] = ss[4] = word_in(key, 4);
|
||||
rk[5] = ss[5] = word_in(key, 5);
|
||||
rk[6] = ss[6] = word_in(key, 6);
|
||||
rk[7] = ss[7] = word_in(key, 7);
|
||||
|
||||
#ifdef ENC_KS_UNROLL
|
||||
ke8(rk, 0); ke8(rk, 1);
|
||||
ke8(rk, 2); ke8(rk, 3);
|
||||
ke8(rk, 4); ke8(rk, 5);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < 6; ++i)
|
||||
ke8(rk, i);
|
||||
}
|
||||
#endif /* ENC_KS_UNROLL */
|
||||
kef8(rk, 6);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Expand the cipher key into the encryption key schedule.
|
||||
*
|
||||
* Return the number of rounds for the given cipher key size.
|
||||
* The size of the key schedule depends on the number of rounds
|
||||
* (which can be computed from the size of the key), i.e. 4 * (Nr + 1).
|
||||
*
|
||||
* Parameters:
|
||||
* rk AES key schedule 32-bit array to be initialized
|
||||
* cipherKey User key
|
||||
* keyBits AES key size (128, 192, or 256 bits)
|
||||
*/
|
||||
int
|
||||
rijndael_key_setup_enc_amd64(uint32_t rk[], const uint32_t cipherKey[],
|
||||
int keyBits)
|
||||
{
|
||||
switch (keyBits) {
|
||||
case 128:
|
||||
aes_encrypt_key128((unsigned char *)&cipherKey[0], rk);
|
||||
return (10);
|
||||
case 192:
|
||||
aes_encrypt_key192((unsigned char *)&cipherKey[0], rk);
|
||||
return (12);
|
||||
case 256:
|
||||
aes_encrypt_key256((unsigned char *)&cipherKey[0], rk);
|
||||
return (14);
|
||||
default: /* should never get here */
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/* this is used to store the decryption round keys */
|
||||
/* in forward or reverse order */
|
||||
|
||||
#ifdef AES_REV_DKS
|
||||
#define v(n, i) ((n) - (i) + 2 * ((i) & 3))
|
||||
#else
|
||||
#define v(n, i) (i)
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES
|
||||
#define ff(x) (x)
|
||||
#else
|
||||
#define ff(x) inv_mcol(x)
|
||||
#if defined(dec_imvars)
|
||||
#define d_vars dec_imvars
|
||||
#endif
|
||||
#endif /* FUNCS_IN_C & DEC_KEYING_IN_C */
|
||||
|
||||
|
||||
#define k4e(k, i) \
|
||||
{ k[v(40, (4 * (i)) + 4)] = ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[1] ^= ss[0]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[2] ^= ss[1]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#if 1
|
||||
|
||||
#define kdf4(k, i) \
|
||||
{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \
|
||||
ss[1] = ss[1] ^ ss[3]; \
|
||||
ss[2] = ss[2] ^ ss[3]; \
|
||||
ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
ss[4] ^= k[v(40, (4 * (i)))]; k[v(40, (4 * (i)) + 4)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40, (4 * (i)) + 1)]; k[v(40, (4 * (i)) + 5)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40, (4 * (i)) + 2)]; k[v(40, (4 * (i)) + 6)] = ff(ss[4]); \
|
||||
ss[4] ^= k[v(40, (4 * (i)) + 3)]; k[v(40, (4 * (i)) + 7)] = ff(ss[4]); \
|
||||
}
|
||||
|
||||
#define kd4(k, i) \
|
||||
{ ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k, i) \
|
||||
{ ss[4] = ls_box(ss[(i + 3) % 4], 3) ^ t_use(r, c)[i]; \
|
||||
ss[i % 4] ^= ss[4]; \
|
||||
k[v(40, (4 * (i)) + 4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[1] ^ ss[3]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[0]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[1]; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define kdf4(k, i) \
|
||||
{ ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(40, (4 * (i)) + 4)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(40, (4 * (i)) + 5)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(40, (4 * (i)) + 6)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(40, (4 * (i)) + 7)] = ff(ss[3]); \
|
||||
}
|
||||
|
||||
#define kd4(k, i) \
|
||||
{ ss[4] = ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
ss[0] ^= ss[4]; \
|
||||
ss[4] = ff(ss[4]); \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[4] ^= k[v(40, (4 * (i)))]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(40, (4 * (i)) + 5)] = ss[4] ^= k[v(40, (4 * (i)) + 1)]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(40, (4 * (i)) + 6)] = ss[4] ^= k[v(40, (4 * (i)) + 2)]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(40, (4 * (i)) + 7)] = ss[4] ^= k[v(40, (4 * (i)) + 3)]; \
|
||||
}
|
||||
|
||||
#define kdl4(k, i) \
|
||||
{ ss[0] ^= ls_box(ss[3], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(40, (4 * (i)) + 4)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(40, (4 * (i)) + 5)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(40, (4 * (i)) + 6)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(40, (4 * (i)) + 7)] = ss[3]; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
aes_decrypt_key128(const unsigned char *key, uint32_t rk[])
|
||||
{
|
||||
uint32_t ss[5];
|
||||
#if defined(d_vars)
|
||||
d_vars;
|
||||
#endif
|
||||
rk[v(40, (0))] = ss[0] = word_in(key, 0);
|
||||
rk[v(40, (1))] = ss[1] = word_in(key, 1);
|
||||
rk[v(40, (2))] = ss[2] = word_in(key, 2);
|
||||
rk[v(40, (3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
kdf4(rk, 0); kd4(rk, 1);
|
||||
kd4(rk, 2); kd4(rk, 3);
|
||||
kd4(rk, 4); kd4(rk, 5);
|
||||
kd4(rk, 6); kd4(rk, 7);
|
||||
kd4(rk, 8); kdl4(rk, 9);
|
||||
#else
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < 10; ++i)
|
||||
k4e(rk, i);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for (i = MAX_AES_NB; i < 10 * MAX_AES_NB; ++i)
|
||||
rk[i] = inv_mcol(rk[i]);
|
||||
#endif
|
||||
}
|
||||
#endif /* DEC_KS_UNROLL */
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define k6ef(k, i) \
|
||||
{ k[v(48, (6 * (i)) + 6)] = ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(48, (6 * (i)) + 7)] = ss[1] ^= ss[0]; \
|
||||
k[v(48, (6 * (i)) + 8)] = ss[2] ^= ss[1]; \
|
||||
k[v(48, (6 * (i)) + 9)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k6e(k, i) \
|
||||
{ k6ef(k, i); \
|
||||
k[v(48, (6 * (i)) + 10)] = ss[4] ^= ss[3]; \
|
||||
k[v(48, (6 * (i)) + 11)] = ss[5] ^= ss[4]; \
|
||||
}
|
||||
|
||||
#define kdf6(k, i) \
|
||||
{ ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(48, (6 * (i)) + 6)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(48, (6 * (i)) + 7)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(48, (6 * (i)) + 8)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(48, (6 * (i)) + 9)] = ff(ss[3]); \
|
||||
ss[4] ^= ss[3]; k[v(48, (6 * (i)) + 10)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(48, (6 * (i)) + 11)] = ff(ss[5]); \
|
||||
}
|
||||
|
||||
#define kd6(k, i) \
|
||||
{ ss[6] = ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
ss[0] ^= ss[6]; ss[6] = ff(ss[6]); \
|
||||
k[v(48, (6 * (i)) + 6)] = ss[6] ^= k[v(48, (6 * (i)))]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(48, (6 * (i)) + 7)] = ss[6] ^= k[v(48, (6 * (i)) + 1)]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(48, (6 * (i)) + 8)] = ss[6] ^= k[v(48, (6 * (i)) + 2)]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(48, (6 * (i)) + 9)] = ss[6] ^= k[v(48, (6 * (i)) + 3)]; \
|
||||
ss[4] ^= ss[3]; \
|
||||
k[v(48, (6 * (i)) + 10)] = ss[6] ^= k[v(48, (6 * (i)) + 4)]; \
|
||||
ss[5] ^= ss[4]; \
|
||||
k[v(48, (6 * (i)) + 11)] = ss[6] ^= k[v(48, (6 * (i)) + 5)]; \
|
||||
}
|
||||
|
||||
#define kdl6(k, i) \
|
||||
{ ss[0] ^= ls_box(ss[5], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(48, (6 * (i)) + 6)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(48, (6 * (i)) + 7)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(48, (6 * (i)) + 8)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(48, (6 * (i)) + 9)] = ss[3]; \
|
||||
}
|
||||
|
||||
static void
|
||||
aes_decrypt_key192(const unsigned char *key, uint32_t rk[])
|
||||
{
|
||||
uint32_t ss[7];
|
||||
#if defined(d_vars)
|
||||
d_vars;
|
||||
#endif
|
||||
rk[v(48, (0))] = ss[0] = word_in(key, 0);
|
||||
rk[v(48, (1))] = ss[1] = word_in(key, 1);
|
||||
rk[v(48, (2))] = ss[2] = word_in(key, 2);
|
||||
rk[v(48, (3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
ss[4] = word_in(key, 4);
|
||||
rk[v(48, (4))] = ff(ss[4]);
|
||||
ss[5] = word_in(key, 5);
|
||||
rk[v(48, (5))] = ff(ss[5]);
|
||||
kdf6(rk, 0); kd6(rk, 1);
|
||||
kd6(rk, 2); kd6(rk, 3);
|
||||
kd6(rk, 4); kd6(rk, 5);
|
||||
kd6(rk, 6); kdl6(rk, 7);
|
||||
#else
|
||||
rk[v(48, (4))] = ss[4] = word_in(key, 4);
|
||||
rk[v(48, (5))] = ss[5] = word_in(key, 5);
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < 7; ++i)
|
||||
k6e(rk, i);
|
||||
k6ef(rk, 7);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for (i = MAX_AES_NB; i < 12 * MAX_AES_NB; ++i)
|
||||
rk[i] = inv_mcol(rk[i]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define k8ef(k, i) \
|
||||
{ k[v(56, (8 * (i)) + 8)] = ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(56, (8 * (i)) + 9)] = ss[1] ^= ss[0]; \
|
||||
k[v(56, (8 * (i)) + 10)] = ss[2] ^= ss[1]; \
|
||||
k[v(56, (8 * (i)) + 11)] = ss[3] ^= ss[2]; \
|
||||
}
|
||||
|
||||
#define k8e(k, i) \
|
||||
{ k8ef(k, i); \
|
||||
k[v(56, (8 * (i)) + 12)] = ss[4] ^= ls_box(ss[3], 0); \
|
||||
k[v(56, (8 * (i)) + 13)] = ss[5] ^= ss[4]; \
|
||||
k[v(56, (8 * (i)) + 14)] = ss[6] ^= ss[5]; \
|
||||
k[v(56, (8 * (i)) + 15)] = ss[7] ^= ss[6]; \
|
||||
}
|
||||
|
||||
#define kdf8(k, i) \
|
||||
{ ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(56, (8 * (i)) + 8)] = ff(ss[0]); \
|
||||
ss[1] ^= ss[0]; k[v(56, (8 * (i)) + 9)] = ff(ss[1]); \
|
||||
ss[2] ^= ss[1]; k[v(56, (8 * (i)) + 10)] = ff(ss[2]); \
|
||||
ss[3] ^= ss[2]; k[v(56, (8 * (i)) + 11)] = ff(ss[3]); \
|
||||
ss[4] ^= ls_box(ss[3], 0); k[v(56, (8 * (i)) + 12)] = ff(ss[4]); \
|
||||
ss[5] ^= ss[4]; k[v(56, (8 * (i)) + 13)] = ff(ss[5]); \
|
||||
ss[6] ^= ss[5]; k[v(56, (8 * (i)) + 14)] = ff(ss[6]); \
|
||||
ss[7] ^= ss[6]; k[v(56, (8 * (i)) + 15)] = ff(ss[7]); \
|
||||
}
|
||||
|
||||
#define kd8(k, i) \
|
||||
{ ss[8] = ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
ss[0] ^= ss[8]; \
|
||||
ss[8] = ff(ss[8]); \
|
||||
k[v(56, (8 * (i)) + 8)] = ss[8] ^= k[v(56, (8 * (i)))]; \
|
||||
ss[1] ^= ss[0]; \
|
||||
k[v(56, (8 * (i)) + 9)] = ss[8] ^= k[v(56, (8 * (i)) + 1)]; \
|
||||
ss[2] ^= ss[1]; \
|
||||
k[v(56, (8 * (i)) + 10)] = ss[8] ^= k[v(56, (8 * (i)) + 2)]; \
|
||||
ss[3] ^= ss[2]; \
|
||||
k[v(56, (8 * (i)) + 11)] = ss[8] ^= k[v(56, (8 * (i)) + 3)]; \
|
||||
ss[8] = ls_box(ss[3], 0); \
|
||||
ss[4] ^= ss[8]; \
|
||||
ss[8] = ff(ss[8]); \
|
||||
k[v(56, (8 * (i)) + 12)] = ss[8] ^= k[v(56, (8 * (i)) + 4)]; \
|
||||
ss[5] ^= ss[4]; \
|
||||
k[v(56, (8 * (i)) + 13)] = ss[8] ^= k[v(56, (8 * (i)) + 5)]; \
|
||||
ss[6] ^= ss[5]; \
|
||||
k[v(56, (8 * (i)) + 14)] = ss[8] ^= k[v(56, (8 * (i)) + 6)]; \
|
||||
ss[7] ^= ss[6]; \
|
||||
k[v(56, (8 * (i)) + 15)] = ss[8] ^= k[v(56, (8 * (i)) + 7)]; \
|
||||
}
|
||||
|
||||
#define kdl8(k, i) \
|
||||
{ ss[0] ^= ls_box(ss[7], 3) ^ t_use(r, c)[i]; \
|
||||
k[v(56, (8 * (i)) + 8)] = ss[0]; \
|
||||
ss[1] ^= ss[0]; k[v(56, (8 * (i)) + 9)] = ss[1]; \
|
||||
ss[2] ^= ss[1]; k[v(56, (8 * (i)) + 10)] = ss[2]; \
|
||||
ss[3] ^= ss[2]; k[v(56, (8 * (i)) + 11)] = ss[3]; \
|
||||
}
|
||||
|
||||
static void
|
||||
aes_decrypt_key256(const unsigned char *key, uint32_t rk[])
|
||||
{
|
||||
uint32_t ss[9];
|
||||
#if defined(d_vars)
|
||||
d_vars;
|
||||
#endif
|
||||
rk[v(56, (0))] = ss[0] = word_in(key, 0);
|
||||
rk[v(56, (1))] = ss[1] = word_in(key, 1);
|
||||
rk[v(56, (2))] = ss[2] = word_in(key, 2);
|
||||
rk[v(56, (3))] = ss[3] = word_in(key, 3);
|
||||
|
||||
#ifdef DEC_KS_UNROLL
|
||||
ss[4] = word_in(key, 4);
|
||||
rk[v(56, (4))] = ff(ss[4]);
|
||||
ss[5] = word_in(key, 5);
|
||||
rk[v(56, (5))] = ff(ss[5]);
|
||||
ss[6] = word_in(key, 6);
|
||||
rk[v(56, (6))] = ff(ss[6]);
|
||||
ss[7] = word_in(key, 7);
|
||||
rk[v(56, (7))] = ff(ss[7]);
|
||||
kdf8(rk, 0); kd8(rk, 1);
|
||||
kd8(rk, 2); kd8(rk, 3);
|
||||
kd8(rk, 4); kd8(rk, 5);
|
||||
kdl8(rk, 6);
|
||||
#else
|
||||
rk[v(56, (4))] = ss[4] = word_in(key, 4);
|
||||
rk[v(56, (5))] = ss[5] = word_in(key, 5);
|
||||
rk[v(56, (6))] = ss[6] = word_in(key, 6);
|
||||
rk[v(56, (7))] = ss[7] = word_in(key, 7);
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < 6; ++i)
|
||||
k8e(rk, i);
|
||||
k8ef(rk, 6);
|
||||
#if !(DEC_ROUND == NO_TABLES)
|
||||
for (i = MAX_AES_NB; i < 14 * MAX_AES_NB; ++i)
|
||||
rk[i] = inv_mcol(rk[i]);
|
||||
#endif
|
||||
}
|
||||
#endif /* DEC_KS_UNROLL */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Expand the cipher key into the decryption key schedule.
|
||||
*
|
||||
* Return the number of rounds for the given cipher key size.
|
||||
* The size of the key schedule depends on the number of rounds
|
||||
* (which can be computed from the size of the key), i.e. 4 * (Nr + 1).
|
||||
*
|
||||
* Parameters:
|
||||
* rk AES key schedule 32-bit array to be initialized
|
||||
* cipherKey User key
|
||||
* keyBits AES key size (128, 192, or 256 bits)
|
||||
*/
|
||||
int
|
||||
rijndael_key_setup_dec_amd64(uint32_t rk[], const uint32_t cipherKey[],
|
||||
int keyBits)
|
||||
{
|
||||
switch (keyBits) {
|
||||
case 128:
|
||||
aes_decrypt_key128((unsigned char *)&cipherKey[0], rk);
|
||||
return (10);
|
||||
case 192:
|
||||
aes_decrypt_key192((unsigned char *)&cipherKey[0], rk);
|
||||
return (12);
|
||||
case 256:
|
||||
aes_decrypt_key256((unsigned char *)&cipherKey[0], rk);
|
||||
return (14);
|
||||
default: /* should never get here */
|
||||
break;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
770
module/icp/asm-x86_64/aes/aesopt.h
Normal file
770
module/icp/asm-x86_64/aes/aesopt.h
Normal file
@ -0,0 +1,770 @@
|
||||
/*
|
||||
* ---------------------------------------------------------------------------
|
||||
* 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 compilation options for AES (Rijndael) and code
|
||||
* that is common across encryption, key scheduling and table generation.
|
||||
*
|
||||
* OPERATION
|
||||
*
|
||||
* These source code files implement the AES algorithm Rijndael designed by
|
||||
* Joan Daemen and Vincent Rijmen. This version is designed for the standard
|
||||
* block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24
|
||||
* and 32 bytes).
|
||||
*
|
||||
* This version is designed for flexibility and speed using operations on
|
||||
* 32-bit words rather than operations on bytes. It can be compiled with
|
||||
* either big or little endian internal byte order but is faster when the
|
||||
* native byte order for the processor is used.
|
||||
*
|
||||
* THE CIPHER INTERFACE
|
||||
*
|
||||
* The cipher interface is implemented as an array of bytes in which lower
|
||||
* AES bit sequence indexes map to higher numeric significance within bytes.
|
||||
*/
|
||||
|
||||
/*
|
||||
* OpenSolaris changes
|
||||
* 1. Added __cplusplus and _AESTAB_H header guards
|
||||
* 2. Added header files sys/types.h and aes_impl.h
|
||||
* 3. Added defines for AES_ENCRYPT, AES_DECRYPT, AES_REV_DKS, and ASM_AMD64_C
|
||||
* 4. Moved defines for IS_BIG_ENDIAN, IS_LITTLE_ENDIAN, PLATFORM_BYTE_ORDER
|
||||
* from brg_endian.h
|
||||
* 5. Undefined VIA_ACE_POSSIBLE and ASSUME_VIA_ACE_PRESENT
|
||||
* 6. Changed uint_8t and uint_32t to uint8_t and uint32_t
|
||||
* 7. Defined aes_sw32 as htonl() for byte swapping
|
||||
* 8. Cstyled and hdrchk code
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _AESOPT_H
|
||||
#define _AESOPT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <aes/aes_impl.h>
|
||||
|
||||
/* SUPPORT FEATURES */
|
||||
#define AES_ENCRYPT /* if support for encryption is needed */
|
||||
#define AES_DECRYPT /* if support for decryption is needed */
|
||||
|
||||
/* PLATFORM-SPECIFIC FEATURES */
|
||||
#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */
|
||||
#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */
|
||||
#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#define AES_REV_DKS /* define to reverse decryption key schedule */
|
||||
|
||||
|
||||
/*
|
||||
* CONFIGURATION - THE USE OF DEFINES
|
||||
* Later in this section there are a number of defines that control the
|
||||
* operation of the code. In each section, the purpose of each define is
|
||||
* explained so that the relevant form can be included or excluded by
|
||||
* setting either 1's or 0's respectively on the branches of the related
|
||||
* #if clauses. The following local defines should not be changed.
|
||||
*/
|
||||
|
||||
#define ENCRYPTION_IN_C 1
|
||||
#define DECRYPTION_IN_C 2
|
||||
#define ENC_KEYING_IN_C 4
|
||||
#define DEC_KEYING_IN_C 8
|
||||
|
||||
#define NO_TABLES 0
|
||||
#define ONE_TABLE 1
|
||||
#define FOUR_TABLES 4
|
||||
#define NONE 0
|
||||
#define PARTIAL 1
|
||||
#define FULL 2
|
||||
|
||||
/* --- START OF USER CONFIGURED OPTIONS --- */
|
||||
|
||||
/*
|
||||
* 1. BYTE ORDER WITHIN 32 BIT WORDS
|
||||
*
|
||||
* The fundamental data processing units in Rijndael are 8-bit bytes. The
|
||||
* input, output and key input are all enumerated arrays of bytes in which
|
||||
* bytes are numbered starting at zero and increasing to one less than the
|
||||
* number of bytes in the array in question. This enumeration is only used
|
||||
* for naming bytes and does not imply any adjacency or order relationship
|
||||
* from one byte to another. When these inputs and outputs are considered
|
||||
* as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to
|
||||
* byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte.
|
||||
* In this implementation bits are numbered from 0 to 7 starting at the
|
||||
* numerically least significant end of each byte. Bit n represents 2^n.
|
||||
*
|
||||
* However, Rijndael can be implemented more efficiently using 32-bit
|
||||
* words by packing bytes into words so that bytes 4*n to 4*n+3 are placed
|
||||
* into word[n]. While in principle these bytes can be assembled into words
|
||||
* in any positions, this implementation only supports the two formats in
|
||||
* which bytes in adjacent positions within words also have adjacent byte
|
||||
* numbers. This order is called big-endian if the lowest numbered bytes
|
||||
* in words have the highest numeric significance and little-endian if the
|
||||
* opposite applies.
|
||||
*
|
||||
* This code can work in either order irrespective of the order used by the
|
||||
* machine on which it runs. Normally the internal byte order will be set
|
||||
* to the order of the processor on which the code is to be run but this
|
||||
* define can be used to reverse this in special situations
|
||||
*
|
||||
* WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set.
|
||||
* This define will hence be redefined later (in section 4) if necessary
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#elif 0
|
||||
#define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||
#elif 0
|
||||
#define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN
|
||||
#else
|
||||
#error The algorithm byte order is not defined
|
||||
#endif
|
||||
|
||||
/* 2. VIA ACE SUPPORT */
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__) || \
|
||||
defined(_WIN32) && defined(_M_IX86) && \
|
||||
!(defined(_WIN64) || defined(_WIN32_WCE) || \
|
||||
defined(_MSC_VER) && (_MSC_VER <= 800))
|
||||
#define VIA_ACE_POSSIBLE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Define this option if support for the VIA ACE is required. This uses
|
||||
* inline assembler instructions and is only implemented for the Microsoft,
|
||||
* Intel and GCC compilers. If VIA ACE is known to be present, then defining
|
||||
* ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption
|
||||
* code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if
|
||||
* it is detected (both present and enabled) but the normal AES code will
|
||||
* also be present.
|
||||
*
|
||||
* When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte
|
||||
* aligned; other input/output buffers do not need to be 16 byte aligned
|
||||
* but there are very large performance gains if this can be arranged.
|
||||
* VIA ACE also requires the decryption key schedule to be in reverse
|
||||
* order (which later checks below ensure).
|
||||
*/
|
||||
|
||||
/* VIA ACE is not used here for OpenSolaris: */
|
||||
#undef VIA_ACE_POSSIBLE
|
||||
#undef ASSUME_VIA_ACE_PRESENT
|
||||
|
||||
#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(USE_VIA_ACE_IF_PRESENT)
|
||||
#define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if 0 && defined(VIA_ACE_POSSIBLE) && !defined(ASSUME_VIA_ACE_PRESENT)
|
||||
#define ASSUME_VIA_ACE_PRESENT
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 3. ASSEMBLER SUPPORT
|
||||
*
|
||||
* This define (which can be on the command line) enables the use of the
|
||||
* assembler code routines for encryption, decryption and key scheduling
|
||||
* as follows:
|
||||
*
|
||||
* ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for
|
||||
* encryption and decryption and but with key scheduling in C
|
||||
* ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
* encryption, decryption and key scheduling
|
||||
* ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for
|
||||
* encryption and decryption and but with key scheduling in C
|
||||
* ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for
|
||||
* encryption and decryption and but with key scheduling in C
|
||||
*
|
||||
* Change one 'if 0' below to 'if 1' to select the version or define
|
||||
* as a compilation option.
|
||||
*/
|
||||
|
||||
#if 0 && !defined(ASM_X86_V1C)
|
||||
#define ASM_X86_V1C
|
||||
#elif 0 && !defined(ASM_X86_V2)
|
||||
#define ASM_X86_V2
|
||||
#elif 0 && !defined(ASM_X86_V2C)
|
||||
#define ASM_X86_V2C
|
||||
#elif 1 && !defined(ASM_AMD64_C)
|
||||
#define ASM_AMD64_C
|
||||
#endif
|
||||
|
||||
#if (defined(ASM_X86_V1C) || defined(ASM_X86_V2) || defined(ASM_X86_V2C)) && \
|
||||
!defined(_M_IX86) || defined(ASM_AMD64_C) && !defined(_M_X64) && \
|
||||
!defined(__amd64)
|
||||
#error Assembler code is only available for x86 and AMD64 systems
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4. FAST INPUT/OUTPUT OPERATIONS.
|
||||
*
|
||||
* On some machines it is possible to improve speed by transferring the
|
||||
* bytes in the input and output arrays to and from the internal 32-bit
|
||||
* variables by addressing these arrays as if they are arrays of 32-bit
|
||||
* words. On some machines this will always be possible but there may
|
||||
* be a large performance penalty if the byte arrays are not aligned on
|
||||
* the normal word boundaries. On other machines this technique will
|
||||
* lead to memory access errors when such 32-bit word accesses are not
|
||||
* properly aligned. The option SAFE_IO avoids such problems but will
|
||||
* often be slower on those machines that support misaligned access
|
||||
* (especially so if care is taken to align the input and output byte
|
||||
* arrays on 32-bit word boundaries). If SAFE_IO is not defined it is
|
||||
* assumed that access to byte arrays as if they are arrays of 32-bit
|
||||
* words will not cause problems when such accesses are misaligned.
|
||||
*/
|
||||
#if 1 && !defined(_MSC_VER)
|
||||
#define SAFE_IO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 5. LOOP UNROLLING
|
||||
*
|
||||
* The code for encryption and decryption cycles through a number of rounds
|
||||
* that can be implemented either in a loop or by expanding the code into a
|
||||
* long sequence of instructions, the latter producing a larger program but
|
||||
* one that will often be much faster. The latter is called loop unrolling.
|
||||
* There are also potential speed advantages in expanding two iterations in
|
||||
* a loop with half the number of iterations, which is called partial loop
|
||||
* unrolling. The following options allow partial or full loop unrolling
|
||||
* to be set independently for encryption and decryption
|
||||
*/
|
||||
#if 1
|
||||
#define ENC_UNROLL FULL
|
||||
#elif 0
|
||||
#define ENC_UNROLL PARTIAL
|
||||
#else
|
||||
#define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define DEC_UNROLL FULL
|
||||
#elif 0
|
||||
#define DEC_UNROLL PARTIAL
|
||||
#else
|
||||
#define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define ENC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
#define DEC_KS_UNROLL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 6. FAST FINITE FIELD OPERATIONS
|
||||
*
|
||||
* If this section is included, tables are used to provide faster finite
|
||||
* field arithmetic. This has no effect if FIXED_TABLES is defined.
|
||||
*/
|
||||
#if 1
|
||||
#define FF_TABLES
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 7. INTERNAL STATE VARIABLE FORMAT
|
||||
*
|
||||
* The internal state of Rijndael is stored in a number of local 32-bit
|
||||
* word variables which can be defined either as an array or as individual
|
||||
* names variables. Include this section if you want to store these local
|
||||
* variables in arrays. Otherwise individual local variables will be used.
|
||||
*/
|
||||
#if 1
|
||||
#define ARRAYS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 8. FIXED OR DYNAMIC TABLES
|
||||
*
|
||||
* When this section is included the tables used by the code are compiled
|
||||
* statically into the binary file. Otherwise the subroutine aes_init()
|
||||
* must be called to compute them before the code is first used.
|
||||
*/
|
||||
#if 1 && !(defined(_MSC_VER) && (_MSC_VER <= 800))
|
||||
#define FIXED_TABLES
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES
|
||||
*
|
||||
* In some systems it is better to mask longer values to extract bytes
|
||||
* rather than using a cast. This option allows this choice.
|
||||
*/
|
||||
#if 0
|
||||
#define to_byte(x) ((uint8_t)(x))
|
||||
#else
|
||||
#define to_byte(x) ((x) & 0xff)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 10. TABLE ALIGNMENT
|
||||
*
|
||||
* On some systems speed will be improved by aligning the AES large lookup
|
||||
* tables on particular boundaries. This define should be set to a power of
|
||||
* two giving the desired alignment. It can be left undefined if alignment
|
||||
* is not needed. This option is specific to the Micrsoft VC++ compiler -
|
||||
* it seems to sometimes cause trouble for the VC++ version 6 compiler.
|
||||
*/
|
||||
|
||||
#if 1 && defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
#define TABLE_ALIGN 32
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 11. REDUCE CODE AND TABLE SIZE
|
||||
*
|
||||
* This replaces some expanded macros with function calls if AES_ASM_V2 or
|
||||
* AES_ASM_V2C are defined
|
||||
*/
|
||||
|
||||
#if 1 && (defined(ASM_X86_V2) || defined(ASM_X86_V2C))
|
||||
#define REDUCE_CODE_SIZE
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 12. TABLE OPTIONS
|
||||
*
|
||||
* This cipher proceeds by repeating in a number of cycles known as rounds
|
||||
* which are implemented by a round function which is optionally be speeded
|
||||
* up using tables. The basic tables are 256 32-bit words, with either
|
||||
* one or four tables being required for each round function depending on
|
||||
* how much speed is required. Encryption and decryption round functions
|
||||
* are different and the last encryption and decryption round functions are
|
||||
* different again making four different round functions in all.
|
||||
*
|
||||
* This means that:
|
||||
* 1. Normal encryption and decryption rounds can each use either 0, 1
|
||||
* or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
* 2. The last encryption and decryption rounds can also use either 0, 1
|
||||
* or 4 tables and table spaces of 0, 1024 or 4096 bytes each.
|
||||
*
|
||||
* Include or exclude the appropriate definitions below to set the number
|
||||
* of tables used by this implementation.
|
||||
*/
|
||||
|
||||
#if 1 /* set tables for the normal encryption round */
|
||||
#define ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last encryption round */
|
||||
#define LAST_ENC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define LAST_ENC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define LAST_ENC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the normal decryption round */
|
||||
#define DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
#if 1 /* set tables for the last decryption round */
|
||||
#define LAST_DEC_ROUND FOUR_TABLES
|
||||
#elif 0
|
||||
#define LAST_DEC_ROUND ONE_TABLE
|
||||
#else
|
||||
#define LAST_DEC_ROUND NO_TABLES
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The decryption key schedule can be speeded up with tables in the same
|
||||
* way that the round functions can. Include or exclude the following
|
||||
* defines to set this requirement.
|
||||
*/
|
||||
#if 1
|
||||
#define KEY_SCHED FOUR_TABLES
|
||||
#elif 0
|
||||
#define KEY_SCHED ONE_TABLE
|
||||
#else
|
||||
#define KEY_SCHED NO_TABLES
|
||||
#endif
|
||||
|
||||
/* ---- END OF USER CONFIGURED OPTIONS ---- */
|
||||
|
||||
/* VIA ACE support is only available for VC++ and GCC */
|
||||
|
||||
#if !defined(_MSC_VER) && !defined(__GNUC__)
|
||||
#if defined(ASSUME_VIA_ACE_PRESENT)
|
||||
#undef ASSUME_VIA_ACE_PRESENT
|
||||
#endif
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT)
|
||||
#undef USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ASSUME_VIA_ACE_PRESENT) && !defined(USE_VIA_ACE_IF_PRESENT)
|
||||
#define USE_VIA_ACE_IF_PRESENT
|
||||
#endif
|
||||
|
||||
#if defined(USE_VIA_ACE_IF_PRESENT) && !defined(AES_REV_DKS)
|
||||
#define AES_REV_DKS
|
||||
#endif
|
||||
|
||||
/* Assembler support requires the use of platform byte order */
|
||||
|
||||
#if (defined(ASM_X86_V1C) || defined(ASM_X86_V2C) || defined(ASM_AMD64_C)) && \
|
||||
(ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER)
|
||||
#undef ALGORITHM_BYTE_ORDER
|
||||
#define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In this implementation the columns of the state array are each held in
|
||||
* 32-bit words. The state array can be held in various ways: in an array
|
||||
* of words, in a number of individual word variables or in a number of
|
||||
* processor registers. The following define maps a variable name x and
|
||||
* a column number c to the way the state array variable is to be held.
|
||||
* The first define below maps the state into an array x[c] whereas the
|
||||
* second form maps the state into a number of individual variables x0,
|
||||
* x1, etc. Another form could map individual state columns to machine
|
||||
* register names.
|
||||
*/
|
||||
|
||||
#if defined(ARRAYS)
|
||||
#define s(x, c) x[c]
|
||||
#else
|
||||
#define s(x, c) x##c
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This implementation provides subroutines for encryption, decryption
|
||||
* and for setting the three key lengths (separately) for encryption
|
||||
* and decryption. Since not all functions are needed, masks are set
|
||||
* up here to determine which will be implemented in C
|
||||
*/
|
||||
|
||||
#if !defined(AES_ENCRYPT)
|
||||
#define EFUNCS_IN_C 0
|
||||
#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || \
|
||||
defined(ASM_X86_V2C) || defined(ASM_AMD64_C)
|
||||
#define EFUNCS_IN_C ENC_KEYING_IN_C
|
||||
#elif !defined(ASM_X86_V2)
|
||||
#define EFUNCS_IN_C (ENCRYPTION_IN_C | ENC_KEYING_IN_C)
|
||||
#else
|
||||
#define EFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#if !defined(AES_DECRYPT)
|
||||
#define DFUNCS_IN_C 0
|
||||
#elif defined(ASSUME_VIA_ACE_PRESENT) || defined(ASM_X86_V1C) || \
|
||||
defined(ASM_X86_V2C) || defined(ASM_AMD64_C)
|
||||
#define DFUNCS_IN_C DEC_KEYING_IN_C
|
||||
#elif !defined(ASM_X86_V2)
|
||||
#define DFUNCS_IN_C (DECRYPTION_IN_C | DEC_KEYING_IN_C)
|
||||
#else
|
||||
#define DFUNCS_IN_C 0
|
||||
#endif
|
||||
|
||||
#define FUNCS_IN_C (EFUNCS_IN_C | DFUNCS_IN_C)
|
||||
|
||||
/* END OF CONFIGURATION OPTIONS */
|
||||
|
||||
/* Disable or report errors on some combinations of options */
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES
|
||||
#undef LAST_ENC_ROUND
|
||||
#define LAST_ENC_ROUND NO_TABLES
|
||||
#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES
|
||||
#undef LAST_ENC_ROUND
|
||||
#define LAST_ENC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE
|
||||
#undef ENC_UNROLL
|
||||
#define ENC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES
|
||||
#undef LAST_DEC_ROUND
|
||||
#define LAST_DEC_ROUND NO_TABLES
|
||||
#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES
|
||||
#undef LAST_DEC_ROUND
|
||||
#define LAST_DEC_ROUND ONE_TABLE
|
||||
#endif
|
||||
|
||||
#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE
|
||||
#undef DEC_UNROLL
|
||||
#define DEC_UNROLL NONE
|
||||
#endif
|
||||
|
||||
#if (ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
#define aes_sw32 htonl
|
||||
#elif defined(bswap32)
|
||||
#define aes_sw32 bswap32
|
||||
#elif defined(bswap_32)
|
||||
#define aes_sw32 bswap_32
|
||||
#else
|
||||
#define brot(x, n) (((uint32_t)(x) << (n)) | ((uint32_t)(x) >> (32 - (n))))
|
||||
#define aes_sw32(x) ((brot((x), 8) & 0x00ff00ff) | (brot((x), 24) & 0xff00ff00))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* upr(x, n): rotates bytes within words by n positions, moving bytes to
|
||||
* higher index positions with wrap around into low positions
|
||||
* ups(x, n): moves bytes by n positions to higher index positions in
|
||||
* words but without wrap around
|
||||
* bval(x, n): extracts a byte from a word
|
||||
*
|
||||
* WARNING: The definitions given here are intended only for use with
|
||||
* unsigned variables and with shift counts that are compile
|
||||
* time constants
|
||||
*/
|
||||
|
||||
#if (ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN)
|
||||
#define upr(x, n) (((uint32_t)(x) << (8 * (n))) | \
|
||||
((uint32_t)(x) >> (32 - 8 * (n))))
|
||||
#define ups(x, n) ((uint32_t)(x) << (8 * (n)))
|
||||
#define bval(x, n) to_byte((x) >> (8 * (n)))
|
||||
#define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | \
|
||||
((uint32_t)(b1) << 8) | (b0))
|
||||
#endif
|
||||
|
||||
#if (ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN)
|
||||
#define upr(x, n) (((uint32_t)(x) >> (8 * (n))) | \
|
||||
((uint32_t)(x) << (32 - 8 * (n))))
|
||||
#define ups(x, n) ((uint32_t)(x) >> (8 * (n)))
|
||||
#define bval(x, n) to_byte((x) >> (24 - 8 * (n)))
|
||||
#define bytes2word(b0, b1, b2, b3) \
|
||||
(((uint32_t)(b0) << 24) | ((uint32_t)(b1) << 16) | \
|
||||
((uint32_t)(b2) << 8) | (b3))
|
||||
#endif
|
||||
|
||||
#if defined(SAFE_IO)
|
||||
#define word_in(x, c) bytes2word(((const uint8_t *)(x) + 4 * c)[0], \
|
||||
((const uint8_t *)(x) + 4 * c)[1], \
|
||||
((const uint8_t *)(x) + 4 * c)[2], \
|
||||
((const uint8_t *)(x) + 4 * c)[3])
|
||||
#define word_out(x, c, v) { ((uint8_t *)(x) + 4 * c)[0] = bval(v, 0); \
|
||||
((uint8_t *)(x) + 4 * c)[1] = bval(v, 1); \
|
||||
((uint8_t *)(x) + 4 * c)[2] = bval(v, 2); \
|
||||
((uint8_t *)(x) + 4 * c)[3] = bval(v, 3); }
|
||||
#elif (ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER)
|
||||
#define word_in(x, c) (*((uint32_t *)(x) + (c)))
|
||||
#define word_out(x, c, v) (*((uint32_t *)(x) + (c)) = (v))
|
||||
#else
|
||||
#define word_in(x, c) aes_sw32(*((uint32_t *)(x) + (c)))
|
||||
#define word_out(x, c, v) (*((uint32_t *)(x) + (c)) = aes_sw32(v))
|
||||
#endif
|
||||
|
||||
/* the finite field modular polynomial and elements */
|
||||
|
||||
#define WPOLY 0x011b
|
||||
#define BPOLY 0x1b
|
||||
|
||||
/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */
|
||||
|
||||
#define m1 0x80808080
|
||||
#define m2 0x7f7f7f7f
|
||||
#define gf_mulx(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY))
|
||||
|
||||
/*
|
||||
* The following defines provide alternative definitions of gf_mulx that might
|
||||
* give improved performance if a fast 32-bit multiply is not available. Note
|
||||
* that a temporary variable u needs to be defined where gf_mulx is used.
|
||||
*
|
||||
* #define gf_mulx(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ \
|
||||
* ((u >> 3) | (u >> 6))
|
||||
* #define m4 (0x01010101 * BPOLY)
|
||||
* #define gf_mulx(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) \
|
||||
* & m4)
|
||||
*/
|
||||
|
||||
/* Work out which tables are needed for the different options */
|
||||
|
||||
#if defined(ASM_X86_V1C)
|
||||
#if defined(ENC_ROUND)
|
||||
#undef ENC_ROUND
|
||||
#endif
|
||||
#define ENC_ROUND FOUR_TABLES
|
||||
#if defined(LAST_ENC_ROUND)
|
||||
#undef LAST_ENC_ROUND
|
||||
#endif
|
||||
#define LAST_ENC_ROUND FOUR_TABLES
|
||||
#if defined(DEC_ROUND)
|
||||
#undef DEC_ROUND
|
||||
#endif
|
||||
#define DEC_ROUND FOUR_TABLES
|
||||
#if defined(LAST_DEC_ROUND)
|
||||
#undef LAST_DEC_ROUND
|
||||
#endif
|
||||
#define LAST_DEC_ROUND FOUR_TABLES
|
||||
#if defined(KEY_SCHED)
|
||||
#undef KEY_SCHED
|
||||
#define KEY_SCHED FOUR_TABLES
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & ENCRYPTION_IN_C) || defined(ASM_X86_V1C)
|
||||
#if ENC_ROUND == ONE_TABLE
|
||||
#define FT1_SET
|
||||
#elif ENC_ROUND == FOUR_TABLES
|
||||
#define FT4_SET
|
||||
#else
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#if LAST_ENC_ROUND == ONE_TABLE
|
||||
#define FL1_SET
|
||||
#elif LAST_ENC_ROUND == FOUR_TABLES
|
||||
#define FL4_SET
|
||||
#elif !defined(SBX_SET)
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if (FUNCS_IN_C & DECRYPTION_IN_C) || defined(ASM_X86_V1C)
|
||||
#if DEC_ROUND == ONE_TABLE
|
||||
#define IT1_SET
|
||||
#elif DEC_ROUND == FOUR_TABLES
|
||||
#define IT4_SET
|
||||
#else
|
||||
#define ISB_SET
|
||||
#endif
|
||||
#if LAST_DEC_ROUND == ONE_TABLE
|
||||
#define IL1_SET
|
||||
#elif LAST_DEC_ROUND == FOUR_TABLES
|
||||
#define IL4_SET
|
||||
#elif !defined(ISB_SET)
|
||||
#define ISB_SET
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || \
|
||||
defined(ASM_X86_V2C)))
|
||||
#if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C))
|
||||
#if KEY_SCHED == ONE_TABLE
|
||||
#if !defined(FL1_SET) && !defined(FL4_SET)
|
||||
#define LS1_SET
|
||||
#endif
|
||||
#elif KEY_SCHED == FOUR_TABLES
|
||||
#if !defined(FL4_SET)
|
||||
#define LS4_SET
|
||||
#endif
|
||||
#elif !defined(SBX_SET)
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
#if (FUNCS_IN_C & DEC_KEYING_IN_C)
|
||||
#if KEY_SCHED == ONE_TABLE
|
||||
#define IM1_SET
|
||||
#elif KEY_SCHED == FOUR_TABLES
|
||||
#define IM4_SET
|
||||
#elif !defined(SBX_SET)
|
||||
#define SBX_SET
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* generic definitions of Rijndael macros that use tables */
|
||||
|
||||
#define no_table(x, box, vf, rf, c) bytes2word(\
|
||||
box[bval(vf(x, 0, c), rf(0, c))], \
|
||||
box[bval(vf(x, 1, c), rf(1, c))], \
|
||||
box[bval(vf(x, 2, c), rf(2, c))], \
|
||||
box[bval(vf(x, 3, c), rf(3, c))])
|
||||
|
||||
#define one_table(x, op, tab, vf, rf, c) \
|
||||
(tab[bval(vf(x, 0, c), rf(0, c))] \
|
||||
^ op(tab[bval(vf(x, 1, c), rf(1, c))], 1) \
|
||||
^ op(tab[bval(vf(x, 2, c), rf(2, c))], 2) \
|
||||
^ op(tab[bval(vf(x, 3, c), rf(3, c))], 3))
|
||||
|
||||
#define four_tables(x, tab, vf, rf, c) \
|
||||
(tab[0][bval(vf(x, 0, c), rf(0, c))] \
|
||||
^ tab[1][bval(vf(x, 1, c), rf(1, c))] \
|
||||
^ tab[2][bval(vf(x, 2, c), rf(2, c))] \
|
||||
^ tab[3][bval(vf(x, 3, c), rf(3, c))])
|
||||
|
||||
#define vf1(x, r, c) (x)
|
||||
#define rf1(r, c) (r)
|
||||
#define rf2(r, c) ((8+r-c)&3)
|
||||
|
||||
/*
|
||||
* Perform forward and inverse column mix operation on four bytes in long word
|
||||
* x in parallel. NOTE: x must be a simple variable, NOT an expression in
|
||||
* these macros.
|
||||
*/
|
||||
|
||||
#if !(defined(REDUCE_CODE_SIZE) && (defined(ASM_X86_V2) || \
|
||||
defined(ASM_X86_V2C)))
|
||||
|
||||
#if defined(FM4_SET) /* not currently used */
|
||||
#define fwd_mcol(x) four_tables(x, t_use(f, m), vf1, rf1, 0)
|
||||
#elif defined(FM1_SET) /* not currently used */
|
||||
#define fwd_mcol(x) one_table(x, upr, t_use(f, m), vf1, rf1, 0)
|
||||
#else
|
||||
#define dec_fmvars uint32_t g2
|
||||
#define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ \
|
||||
upr((x), 2) ^ upr((x), 1))
|
||||
#endif
|
||||
|
||||
#if defined(IM4_SET)
|
||||
#define inv_mcol(x) four_tables(x, t_use(i, m), vf1, rf1, 0)
|
||||
#elif defined(IM1_SET)
|
||||
#define inv_mcol(x) one_table(x, upr, t_use(i, m), vf1, rf1, 0)
|
||||
#else
|
||||
#define dec_imvars uint32_t g2, g4, g9
|
||||
#define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = \
|
||||
(x) ^ gf_mulx(g4), g4 ^= g9, \
|
||||
(x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ \
|
||||
upr(g4, 2) ^ upr(g9, 1))
|
||||
#endif
|
||||
|
||||
#if defined(FL4_SET)
|
||||
#define ls_box(x, c) four_tables(x, t_use(f, l), vf1, rf2, c)
|
||||
#elif defined(LS4_SET)
|
||||
#define ls_box(x, c) four_tables(x, t_use(l, s), vf1, rf2, c)
|
||||
#elif defined(FL1_SET)
|
||||
#define ls_box(x, c) one_table(x, upr, t_use(f, l), vf1, rf2, c)
|
||||
#elif defined(LS1_SET)
|
||||
#define ls_box(x, c) one_table(x, upr, t_use(l, s), vf1, rf2, c)
|
||||
#else
|
||||
#define ls_box(x, c) no_table(x, t_use(s, box), vf1, rf2, c)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ASM_X86_V1C) && defined(AES_DECRYPT) && !defined(ISB_SET)
|
||||
#define ISB_SET
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _AESOPT_H */
|
165
module/icp/asm-x86_64/aes/aestab.h
Normal file
165
module/icp/asm-x86_64/aes/aestab.h
Normal file
@ -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 */
|
594
module/icp/asm-x86_64/aes/aestab2.h
Normal file
594
module/icp/asm-x86_64/aes/aestab2.h
Normal file
@ -0,0 +1,594 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AESTAB2_H
|
||||
#define _AESTAB2_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* To create this file for OpenSolaris:
|
||||
* 1. Compile and run tablegen.c, from aes-src-04-03-08.zip,
|
||||
* after defining ASM_AMD64_C
|
||||
* 2. mv aestab2.c aestab2.h
|
||||
* 3. Add __cplusplus and _AESTAB2_H header guards
|
||||
* 3. Add #include <aes_impl.h>
|
||||
* 4. Change "uint_32t" to "uint32_t"
|
||||
* 5. Change all variables to "static const"
|
||||
* 6. Cstyle and hdrchk this file
|
||||
*/
|
||||
|
||||
#include <aes/aes_impl.h>
|
||||
|
||||
static const uint32_t t_rc[RC_LENGTH] =
|
||||
{
|
||||
0x00000001, 0x00000002, 0x00000004, 0x00000008,
|
||||
0x00000010, 0x00000020, 0x00000040, 0x00000080,
|
||||
0x0000001b, 0x00000036
|
||||
};
|
||||
|
||||
static const uint32_t t_ls[4][256] =
|
||||
{
|
||||
{
|
||||
0x00000063, 0x0000007c, 0x00000077, 0x0000007b,
|
||||
0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5,
|
||||
0x00000030, 0x00000001, 0x00000067, 0x0000002b,
|
||||
0x000000fe, 0x000000d7, 0x000000ab, 0x00000076,
|
||||
0x000000ca, 0x00000082, 0x000000c9, 0x0000007d,
|
||||
0x000000fa, 0x00000059, 0x00000047, 0x000000f0,
|
||||
0x000000ad, 0x000000d4, 0x000000a2, 0x000000af,
|
||||
0x0000009c, 0x000000a4, 0x00000072, 0x000000c0,
|
||||
0x000000b7, 0x000000fd, 0x00000093, 0x00000026,
|
||||
0x00000036, 0x0000003f, 0x000000f7, 0x000000cc,
|
||||
0x00000034, 0x000000a5, 0x000000e5, 0x000000f1,
|
||||
0x00000071, 0x000000d8, 0x00000031, 0x00000015,
|
||||
0x00000004, 0x000000c7, 0x00000023, 0x000000c3,
|
||||
0x00000018, 0x00000096, 0x00000005, 0x0000009a,
|
||||
0x00000007, 0x00000012, 0x00000080, 0x000000e2,
|
||||
0x000000eb, 0x00000027, 0x000000b2, 0x00000075,
|
||||
0x00000009, 0x00000083, 0x0000002c, 0x0000001a,
|
||||
0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0,
|
||||
0x00000052, 0x0000003b, 0x000000d6, 0x000000b3,
|
||||
0x00000029, 0x000000e3, 0x0000002f, 0x00000084,
|
||||
0x00000053, 0x000000d1, 0x00000000, 0x000000ed,
|
||||
0x00000020, 0x000000fc, 0x000000b1, 0x0000005b,
|
||||
0x0000006a, 0x000000cb, 0x000000be, 0x00000039,
|
||||
0x0000004a, 0x0000004c, 0x00000058, 0x000000cf,
|
||||
0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb,
|
||||
0x00000043, 0x0000004d, 0x00000033, 0x00000085,
|
||||
0x00000045, 0x000000f9, 0x00000002, 0x0000007f,
|
||||
0x00000050, 0x0000003c, 0x0000009f, 0x000000a8,
|
||||
0x00000051, 0x000000a3, 0x00000040, 0x0000008f,
|
||||
0x00000092, 0x0000009d, 0x00000038, 0x000000f5,
|
||||
0x000000bc, 0x000000b6, 0x000000da, 0x00000021,
|
||||
0x00000010, 0x000000ff, 0x000000f3, 0x000000d2,
|
||||
0x000000cd, 0x0000000c, 0x00000013, 0x000000ec,
|
||||
0x0000005f, 0x00000097, 0x00000044, 0x00000017,
|
||||
0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d,
|
||||
0x00000064, 0x0000005d, 0x00000019, 0x00000073,
|
||||
0x00000060, 0x00000081, 0x0000004f, 0x000000dc,
|
||||
0x00000022, 0x0000002a, 0x00000090, 0x00000088,
|
||||
0x00000046, 0x000000ee, 0x000000b8, 0x00000014,
|
||||
0x000000de, 0x0000005e, 0x0000000b, 0x000000db,
|
||||
0x000000e0, 0x00000032, 0x0000003a, 0x0000000a,
|
||||
0x00000049, 0x00000006, 0x00000024, 0x0000005c,
|
||||
0x000000c2, 0x000000d3, 0x000000ac, 0x00000062,
|
||||
0x00000091, 0x00000095, 0x000000e4, 0x00000079,
|
||||
0x000000e7, 0x000000c8, 0x00000037, 0x0000006d,
|
||||
0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9,
|
||||
0x0000006c, 0x00000056, 0x000000f4, 0x000000ea,
|
||||
0x00000065, 0x0000007a, 0x000000ae, 0x00000008,
|
||||
0x000000ba, 0x00000078, 0x00000025, 0x0000002e,
|
||||
0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6,
|
||||
0x000000e8, 0x000000dd, 0x00000074, 0x0000001f,
|
||||
0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a,
|
||||
0x00000070, 0x0000003e, 0x000000b5, 0x00000066,
|
||||
0x00000048, 0x00000003, 0x000000f6, 0x0000000e,
|
||||
0x00000061, 0x00000035, 0x00000057, 0x000000b9,
|
||||
0x00000086, 0x000000c1, 0x0000001d, 0x0000009e,
|
||||
0x000000e1, 0x000000f8, 0x00000098, 0x00000011,
|
||||
0x00000069, 0x000000d9, 0x0000008e, 0x00000094,
|
||||
0x0000009b, 0x0000001e, 0x00000087, 0x000000e9,
|
||||
0x000000ce, 0x00000055, 0x00000028, 0x000000df,
|
||||
0x0000008c, 0x000000a1, 0x00000089, 0x0000000d,
|
||||
0x000000bf, 0x000000e6, 0x00000042, 0x00000068,
|
||||
0x00000041, 0x00000099, 0x0000002d, 0x0000000f,
|
||||
0x000000b0, 0x00000054, 0x000000bb, 0x00000016
|
||||
},
|
||||
{
|
||||
0x00006300, 0x00007c00, 0x00007700, 0x00007b00,
|
||||
0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500,
|
||||
0x00003000, 0x00000100, 0x00006700, 0x00002b00,
|
||||
0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600,
|
||||
0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00,
|
||||
0x0000fa00, 0x00005900, 0x00004700, 0x0000f000,
|
||||
0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00,
|
||||
0x00009c00, 0x0000a400, 0x00007200, 0x0000c000,
|
||||
0x0000b700, 0x0000fd00, 0x00009300, 0x00002600,
|
||||
0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00,
|
||||
0x00003400, 0x0000a500, 0x0000e500, 0x0000f100,
|
||||
0x00007100, 0x0000d800, 0x00003100, 0x00001500,
|
||||
0x00000400, 0x0000c700, 0x00002300, 0x0000c300,
|
||||
0x00001800, 0x00009600, 0x00000500, 0x00009a00,
|
||||
0x00000700, 0x00001200, 0x00008000, 0x0000e200,
|
||||
0x0000eb00, 0x00002700, 0x0000b200, 0x00007500,
|
||||
0x00000900, 0x00008300, 0x00002c00, 0x00001a00,
|
||||
0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000,
|
||||
0x00005200, 0x00003b00, 0x0000d600, 0x0000b300,
|
||||
0x00002900, 0x0000e300, 0x00002f00, 0x00008400,
|
||||
0x00005300, 0x0000d100, 0x00000000, 0x0000ed00,
|
||||
0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00,
|
||||
0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900,
|
||||
0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00,
|
||||
0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00,
|
||||
0x00004300, 0x00004d00, 0x00003300, 0x00008500,
|
||||
0x00004500, 0x0000f900, 0x00000200, 0x00007f00,
|
||||
0x00005000, 0x00003c00, 0x00009f00, 0x0000a800,
|
||||
0x00005100, 0x0000a300, 0x00004000, 0x00008f00,
|
||||
0x00009200, 0x00009d00, 0x00003800, 0x0000f500,
|
||||
0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100,
|
||||
0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200,
|
||||
0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00,
|
||||
0x00005f00, 0x00009700, 0x00004400, 0x00001700,
|
||||
0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00,
|
||||
0x00006400, 0x00005d00, 0x00001900, 0x00007300,
|
||||
0x00006000, 0x00008100, 0x00004f00, 0x0000dc00,
|
||||
0x00002200, 0x00002a00, 0x00009000, 0x00008800,
|
||||
0x00004600, 0x0000ee00, 0x0000b800, 0x00001400,
|
||||
0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00,
|
||||
0x0000e000, 0x00003200, 0x00003a00, 0x00000a00,
|
||||
0x00004900, 0x00000600, 0x00002400, 0x00005c00,
|
||||
0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200,
|
||||
0x00009100, 0x00009500, 0x0000e400, 0x00007900,
|
||||
0x0000e700, 0x0000c800, 0x00003700, 0x00006d00,
|
||||
0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900,
|
||||
0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00,
|
||||
0x00006500, 0x00007a00, 0x0000ae00, 0x00000800,
|
||||
0x0000ba00, 0x00007800, 0x00002500, 0x00002e00,
|
||||
0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600,
|
||||
0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00,
|
||||
0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00,
|
||||
0x00007000, 0x00003e00, 0x0000b500, 0x00006600,
|
||||
0x00004800, 0x00000300, 0x0000f600, 0x00000e00,
|
||||
0x00006100, 0x00003500, 0x00005700, 0x0000b900,
|
||||
0x00008600, 0x0000c100, 0x00001d00, 0x00009e00,
|
||||
0x0000e100, 0x0000f800, 0x00009800, 0x00001100,
|
||||
0x00006900, 0x0000d900, 0x00008e00, 0x00009400,
|
||||
0x00009b00, 0x00001e00, 0x00008700, 0x0000e900,
|
||||
0x0000ce00, 0x00005500, 0x00002800, 0x0000df00,
|
||||
0x00008c00, 0x0000a100, 0x00008900, 0x00000d00,
|
||||
0x0000bf00, 0x0000e600, 0x00004200, 0x00006800,
|
||||
0x00004100, 0x00009900, 0x00002d00, 0x00000f00,
|
||||
0x0000b000, 0x00005400, 0x0000bb00, 0x00001600
|
||||
},
|
||||
{
|
||||
0x00630000, 0x007c0000, 0x00770000, 0x007b0000,
|
||||
0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000,
|
||||
0x00300000, 0x00010000, 0x00670000, 0x002b0000,
|
||||
0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000,
|
||||
0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000,
|
||||
0x00fa0000, 0x00590000, 0x00470000, 0x00f00000,
|
||||
0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000,
|
||||
0x009c0000, 0x00a40000, 0x00720000, 0x00c00000,
|
||||
0x00b70000, 0x00fd0000, 0x00930000, 0x00260000,
|
||||
0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000,
|
||||
0x00340000, 0x00a50000, 0x00e50000, 0x00f10000,
|
||||
0x00710000, 0x00d80000, 0x00310000, 0x00150000,
|
||||
0x00040000, 0x00c70000, 0x00230000, 0x00c30000,
|
||||
0x00180000, 0x00960000, 0x00050000, 0x009a0000,
|
||||
0x00070000, 0x00120000, 0x00800000, 0x00e20000,
|
||||
0x00eb0000, 0x00270000, 0x00b20000, 0x00750000,
|
||||
0x00090000, 0x00830000, 0x002c0000, 0x001a0000,
|
||||
0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000,
|
||||
0x00520000, 0x003b0000, 0x00d60000, 0x00b30000,
|
||||
0x00290000, 0x00e30000, 0x002f0000, 0x00840000,
|
||||
0x00530000, 0x00d10000, 0x00000000, 0x00ed0000,
|
||||
0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000,
|
||||
0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000,
|
||||
0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000,
|
||||
0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000,
|
||||
0x00430000, 0x004d0000, 0x00330000, 0x00850000,
|
||||
0x00450000, 0x00f90000, 0x00020000, 0x007f0000,
|
||||
0x00500000, 0x003c0000, 0x009f0000, 0x00a80000,
|
||||
0x00510000, 0x00a30000, 0x00400000, 0x008f0000,
|
||||
0x00920000, 0x009d0000, 0x00380000, 0x00f50000,
|
||||
0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000,
|
||||
0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000,
|
||||
0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000,
|
||||
0x005f0000, 0x00970000, 0x00440000, 0x00170000,
|
||||
0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000,
|
||||
0x00640000, 0x005d0000, 0x00190000, 0x00730000,
|
||||
0x00600000, 0x00810000, 0x004f0000, 0x00dc0000,
|
||||
0x00220000, 0x002a0000, 0x00900000, 0x00880000,
|
||||
0x00460000, 0x00ee0000, 0x00b80000, 0x00140000,
|
||||
0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000,
|
||||
0x00e00000, 0x00320000, 0x003a0000, 0x000a0000,
|
||||
0x00490000, 0x00060000, 0x00240000, 0x005c0000,
|
||||
0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000,
|
||||
0x00910000, 0x00950000, 0x00e40000, 0x00790000,
|
||||
0x00e70000, 0x00c80000, 0x00370000, 0x006d0000,
|
||||
0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000,
|
||||
0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000,
|
||||
0x00650000, 0x007a0000, 0x00ae0000, 0x00080000,
|
||||
0x00ba0000, 0x00780000, 0x00250000, 0x002e0000,
|
||||
0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000,
|
||||
0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000,
|
||||
0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000,
|
||||
0x00700000, 0x003e0000, 0x00b50000, 0x00660000,
|
||||
0x00480000, 0x00030000, 0x00f60000, 0x000e0000,
|
||||
0x00610000, 0x00350000, 0x00570000, 0x00b90000,
|
||||
0x00860000, 0x00c10000, 0x001d0000, 0x009e0000,
|
||||
0x00e10000, 0x00f80000, 0x00980000, 0x00110000,
|
||||
0x00690000, 0x00d90000, 0x008e0000, 0x00940000,
|
||||
0x009b0000, 0x001e0000, 0x00870000, 0x00e90000,
|
||||
0x00ce0000, 0x00550000, 0x00280000, 0x00df0000,
|
||||
0x008c0000, 0x00a10000, 0x00890000, 0x000d0000,
|
||||
0x00bf0000, 0x00e60000, 0x00420000, 0x00680000,
|
||||
0x00410000, 0x00990000, 0x002d0000, 0x000f0000,
|
||||
0x00b00000, 0x00540000, 0x00bb0000, 0x00160000
|
||||
},
|
||||
{
|
||||
0x63000000, 0x7c000000, 0x77000000, 0x7b000000,
|
||||
0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000,
|
||||
0x30000000, 0x01000000, 0x67000000, 0x2b000000,
|
||||
0xfe000000, 0xd7000000, 0xab000000, 0x76000000,
|
||||
0xca000000, 0x82000000, 0xc9000000, 0x7d000000,
|
||||
0xfa000000, 0x59000000, 0x47000000, 0xf0000000,
|
||||
0xad000000, 0xd4000000, 0xa2000000, 0xaf000000,
|
||||
0x9c000000, 0xa4000000, 0x72000000, 0xc0000000,
|
||||
0xb7000000, 0xfd000000, 0x93000000, 0x26000000,
|
||||
0x36000000, 0x3f000000, 0xf7000000, 0xcc000000,
|
||||
0x34000000, 0xa5000000, 0xe5000000, 0xf1000000,
|
||||
0x71000000, 0xd8000000, 0x31000000, 0x15000000,
|
||||
0x04000000, 0xc7000000, 0x23000000, 0xc3000000,
|
||||
0x18000000, 0x96000000, 0x05000000, 0x9a000000,
|
||||
0x07000000, 0x12000000, 0x80000000, 0xe2000000,
|
||||
0xeb000000, 0x27000000, 0xb2000000, 0x75000000,
|
||||
0x09000000, 0x83000000, 0x2c000000, 0x1a000000,
|
||||
0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000,
|
||||
0x52000000, 0x3b000000, 0xd6000000, 0xb3000000,
|
||||
0x29000000, 0xe3000000, 0x2f000000, 0x84000000,
|
||||
0x53000000, 0xd1000000, 0x00000000, 0xed000000,
|
||||
0x20000000, 0xfc000000, 0xb1000000, 0x5b000000,
|
||||
0x6a000000, 0xcb000000, 0xbe000000, 0x39000000,
|
||||
0x4a000000, 0x4c000000, 0x58000000, 0xcf000000,
|
||||
0xd0000000, 0xef000000, 0xaa000000, 0xfb000000,
|
||||
0x43000000, 0x4d000000, 0x33000000, 0x85000000,
|
||||
0x45000000, 0xf9000000, 0x02000000, 0x7f000000,
|
||||
0x50000000, 0x3c000000, 0x9f000000, 0xa8000000,
|
||||
0x51000000, 0xa3000000, 0x40000000, 0x8f000000,
|
||||
0x92000000, 0x9d000000, 0x38000000, 0xf5000000,
|
||||
0xbc000000, 0xb6000000, 0xda000000, 0x21000000,
|
||||
0x10000000, 0xff000000, 0xf3000000, 0xd2000000,
|
||||
0xcd000000, 0x0c000000, 0x13000000, 0xec000000,
|
||||
0x5f000000, 0x97000000, 0x44000000, 0x17000000,
|
||||
0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000,
|
||||
0x64000000, 0x5d000000, 0x19000000, 0x73000000,
|
||||
0x60000000, 0x81000000, 0x4f000000, 0xdc000000,
|
||||
0x22000000, 0x2a000000, 0x90000000, 0x88000000,
|
||||
0x46000000, 0xee000000, 0xb8000000, 0x14000000,
|
||||
0xde000000, 0x5e000000, 0x0b000000, 0xdb000000,
|
||||
0xe0000000, 0x32000000, 0x3a000000, 0x0a000000,
|
||||
0x49000000, 0x06000000, 0x24000000, 0x5c000000,
|
||||
0xc2000000, 0xd3000000, 0xac000000, 0x62000000,
|
||||
0x91000000, 0x95000000, 0xe4000000, 0x79000000,
|
||||
0xe7000000, 0xc8000000, 0x37000000, 0x6d000000,
|
||||
0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000,
|
||||
0x6c000000, 0x56000000, 0xf4000000, 0xea000000,
|
||||
0x65000000, 0x7a000000, 0xae000000, 0x08000000,
|
||||
0xba000000, 0x78000000, 0x25000000, 0x2e000000,
|
||||
0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000,
|
||||
0xe8000000, 0xdd000000, 0x74000000, 0x1f000000,
|
||||
0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000,
|
||||
0x70000000, 0x3e000000, 0xb5000000, 0x66000000,
|
||||
0x48000000, 0x03000000, 0xf6000000, 0x0e000000,
|
||||
0x61000000, 0x35000000, 0x57000000, 0xb9000000,
|
||||
0x86000000, 0xc1000000, 0x1d000000, 0x9e000000,
|
||||
0xe1000000, 0xf8000000, 0x98000000, 0x11000000,
|
||||
0x69000000, 0xd9000000, 0x8e000000, 0x94000000,
|
||||
0x9b000000, 0x1e000000, 0x87000000, 0xe9000000,
|
||||
0xce000000, 0x55000000, 0x28000000, 0xdf000000,
|
||||
0x8c000000, 0xa1000000, 0x89000000, 0x0d000000,
|
||||
0xbf000000, 0xe6000000, 0x42000000, 0x68000000,
|
||||
0x41000000, 0x99000000, 0x2d000000, 0x0f000000,
|
||||
0xb0000000, 0x54000000, 0xbb000000, 0x16000000
|
||||
}
|
||||
};
|
||||
|
||||
static const uint32_t t_im[4][256] =
|
||||
{
|
||||
{
|
||||
0x00000000, 0x0b0d090e, 0x161a121c, 0x1d171b12,
|
||||
0x2c342438, 0x27392d36, 0x3a2e3624, 0x31233f2a,
|
||||
0x58684870, 0x5365417e, 0x4e725a6c, 0x457f5362,
|
||||
0x745c6c48, 0x7f516546, 0x62467e54, 0x694b775a,
|
||||
0xb0d090e0, 0xbbdd99ee, 0xa6ca82fc, 0xadc78bf2,
|
||||
0x9ce4b4d8, 0x97e9bdd6, 0x8afea6c4, 0x81f3afca,
|
||||
0xe8b8d890, 0xe3b5d19e, 0xfea2ca8c, 0xf5afc382,
|
||||
0xc48cfca8, 0xcf81f5a6, 0xd296eeb4, 0xd99be7ba,
|
||||
0x7bbb3bdb, 0x70b632d5, 0x6da129c7, 0x66ac20c9,
|
||||
0x578f1fe3, 0x5c8216ed, 0x41950dff, 0x4a9804f1,
|
||||
0x23d373ab, 0x28de7aa5, 0x35c961b7, 0x3ec468b9,
|
||||
0x0fe75793, 0x04ea5e9d, 0x19fd458f, 0x12f04c81,
|
||||
0xcb6bab3b, 0xc066a235, 0xdd71b927, 0xd67cb029,
|
||||
0xe75f8f03, 0xec52860d, 0xf1459d1f, 0xfa489411,
|
||||
0x9303e34b, 0x980eea45, 0x8519f157, 0x8e14f859,
|
||||
0xbf37c773, 0xb43ace7d, 0xa92dd56f, 0xa220dc61,
|
||||
0xf66d76ad, 0xfd607fa3, 0xe07764b1, 0xeb7a6dbf,
|
||||
0xda595295, 0xd1545b9b, 0xcc434089, 0xc74e4987,
|
||||
0xae053edd, 0xa50837d3, 0xb81f2cc1, 0xb31225cf,
|
||||
0x82311ae5, 0x893c13eb, 0x942b08f9, 0x9f2601f7,
|
||||
0x46bde64d, 0x4db0ef43, 0x50a7f451, 0x5baafd5f,
|
||||
0x6a89c275, 0x6184cb7b, 0x7c93d069, 0x779ed967,
|
||||
0x1ed5ae3d, 0x15d8a733, 0x08cfbc21, 0x03c2b52f,
|
||||
0x32e18a05, 0x39ec830b, 0x24fb9819, 0x2ff69117,
|
||||
0x8dd64d76, 0x86db4478, 0x9bcc5f6a, 0x90c15664,
|
||||
0xa1e2694e, 0xaaef6040, 0xb7f87b52, 0xbcf5725c,
|
||||
0xd5be0506, 0xdeb30c08, 0xc3a4171a, 0xc8a91e14,
|
||||
0xf98a213e, 0xf2872830, 0xef903322, 0xe49d3a2c,
|
||||
0x3d06dd96, 0x360bd498, 0x2b1ccf8a, 0x2011c684,
|
||||
0x1132f9ae, 0x1a3ff0a0, 0x0728ebb2, 0x0c25e2bc,
|
||||
0x656e95e6, 0x6e639ce8, 0x737487fa, 0x78798ef4,
|
||||
0x495ab1de, 0x4257b8d0, 0x5f40a3c2, 0x544daacc,
|
||||
0xf7daec41, 0xfcd7e54f, 0xe1c0fe5d, 0xeacdf753,
|
||||
0xdbeec879, 0xd0e3c177, 0xcdf4da65, 0xc6f9d36b,
|
||||
0xafb2a431, 0xa4bfad3f, 0xb9a8b62d, 0xb2a5bf23,
|
||||
0x83868009, 0x888b8907, 0x959c9215, 0x9e919b1b,
|
||||
0x470a7ca1, 0x4c0775af, 0x51106ebd, 0x5a1d67b3,
|
||||
0x6b3e5899, 0x60335197, 0x7d244a85, 0x7629438b,
|
||||
0x1f6234d1, 0x146f3ddf, 0x097826cd, 0x02752fc3,
|
||||
0x335610e9, 0x385b19e7, 0x254c02f5, 0x2e410bfb,
|
||||
0x8c61d79a, 0x876cde94, 0x9a7bc586, 0x9176cc88,
|
||||
0xa055f3a2, 0xab58faac, 0xb64fe1be, 0xbd42e8b0,
|
||||
0xd4099fea, 0xdf0496e4, 0xc2138df6, 0xc91e84f8,
|
||||
0xf83dbbd2, 0xf330b2dc, 0xee27a9ce, 0xe52aa0c0,
|
||||
0x3cb1477a, 0x37bc4e74, 0x2aab5566, 0x21a65c68,
|
||||
0x10856342, 0x1b886a4c, 0x069f715e, 0x0d927850,
|
||||
0x64d90f0a, 0x6fd40604, 0x72c31d16, 0x79ce1418,
|
||||
0x48ed2b32, 0x43e0223c, 0x5ef7392e, 0x55fa3020,
|
||||
0x01b79aec, 0x0aba93e2, 0x17ad88f0, 0x1ca081fe,
|
||||
0x2d83bed4, 0x268eb7da, 0x3b99acc8, 0x3094a5c6,
|
||||
0x59dfd29c, 0x52d2db92, 0x4fc5c080, 0x44c8c98e,
|
||||
0x75ebf6a4, 0x7ee6ffaa, 0x63f1e4b8, 0x68fcedb6,
|
||||
0xb1670a0c, 0xba6a0302, 0xa77d1810, 0xac70111e,
|
||||
0x9d532e34, 0x965e273a, 0x8b493c28, 0x80443526,
|
||||
0xe90f427c, 0xe2024b72, 0xff155060, 0xf418596e,
|
||||
0xc53b6644, 0xce366f4a, 0xd3217458, 0xd82c7d56,
|
||||
0x7a0ca137, 0x7101a839, 0x6c16b32b, 0x671bba25,
|
||||
0x5638850f, 0x5d358c01, 0x40229713, 0x4b2f9e1d,
|
||||
0x2264e947, 0x2969e049, 0x347efb5b, 0x3f73f255,
|
||||
0x0e50cd7f, 0x055dc471, 0x184adf63, 0x1347d66d,
|
||||
0xcadc31d7, 0xc1d138d9, 0xdcc623cb, 0xd7cb2ac5,
|
||||
0xe6e815ef, 0xede51ce1, 0xf0f207f3, 0xfbff0efd,
|
||||
0x92b479a7, 0x99b970a9, 0x84ae6bbb, 0x8fa362b5,
|
||||
0xbe805d9f, 0xb58d5491, 0xa89a4f83, 0xa397468d
|
||||
},
|
||||
{
|
||||
0x00000000, 0x0d090e0b, 0x1a121c16, 0x171b121d,
|
||||
0x3424382c, 0x392d3627, 0x2e36243a, 0x233f2a31,
|
||||
0x68487058, 0x65417e53, 0x725a6c4e, 0x7f536245,
|
||||
0x5c6c4874, 0x5165467f, 0x467e5462, 0x4b775a69,
|
||||
0xd090e0b0, 0xdd99eebb, 0xca82fca6, 0xc78bf2ad,
|
||||
0xe4b4d89c, 0xe9bdd697, 0xfea6c48a, 0xf3afca81,
|
||||
0xb8d890e8, 0xb5d19ee3, 0xa2ca8cfe, 0xafc382f5,
|
||||
0x8cfca8c4, 0x81f5a6cf, 0x96eeb4d2, 0x9be7bad9,
|
||||
0xbb3bdb7b, 0xb632d570, 0xa129c76d, 0xac20c966,
|
||||
0x8f1fe357, 0x8216ed5c, 0x950dff41, 0x9804f14a,
|
||||
0xd373ab23, 0xde7aa528, 0xc961b735, 0xc468b93e,
|
||||
0xe757930f, 0xea5e9d04, 0xfd458f19, 0xf04c8112,
|
||||
0x6bab3bcb, 0x66a235c0, 0x71b927dd, 0x7cb029d6,
|
||||
0x5f8f03e7, 0x52860dec, 0x459d1ff1, 0x489411fa,
|
||||
0x03e34b93, 0x0eea4598, 0x19f15785, 0x14f8598e,
|
||||
0x37c773bf, 0x3ace7db4, 0x2dd56fa9, 0x20dc61a2,
|
||||
0x6d76adf6, 0x607fa3fd, 0x7764b1e0, 0x7a6dbfeb,
|
||||
0x595295da, 0x545b9bd1, 0x434089cc, 0x4e4987c7,
|
||||
0x053eddae, 0x0837d3a5, 0x1f2cc1b8, 0x1225cfb3,
|
||||
0x311ae582, 0x3c13eb89, 0x2b08f994, 0x2601f79f,
|
||||
0xbde64d46, 0xb0ef434d, 0xa7f45150, 0xaafd5f5b,
|
||||
0x89c2756a, 0x84cb7b61, 0x93d0697c, 0x9ed96777,
|
||||
0xd5ae3d1e, 0xd8a73315, 0xcfbc2108, 0xc2b52f03,
|
||||
0xe18a0532, 0xec830b39, 0xfb981924, 0xf691172f,
|
||||
0xd64d768d, 0xdb447886, 0xcc5f6a9b, 0xc1566490,
|
||||
0xe2694ea1, 0xef6040aa, 0xf87b52b7, 0xf5725cbc,
|
||||
0xbe0506d5, 0xb30c08de, 0xa4171ac3, 0xa91e14c8,
|
||||
0x8a213ef9, 0x872830f2, 0x903322ef, 0x9d3a2ce4,
|
||||
0x06dd963d, 0x0bd49836, 0x1ccf8a2b, 0x11c68420,
|
||||
0x32f9ae11, 0x3ff0a01a, 0x28ebb207, 0x25e2bc0c,
|
||||
0x6e95e665, 0x639ce86e, 0x7487fa73, 0x798ef478,
|
||||
0x5ab1de49, 0x57b8d042, 0x40a3c25f, 0x4daacc54,
|
||||
0xdaec41f7, 0xd7e54ffc, 0xc0fe5de1, 0xcdf753ea,
|
||||
0xeec879db, 0xe3c177d0, 0xf4da65cd, 0xf9d36bc6,
|
||||
0xb2a431af, 0xbfad3fa4, 0xa8b62db9, 0xa5bf23b2,
|
||||
0x86800983, 0x8b890788, 0x9c921595, 0x919b1b9e,
|
||||
0x0a7ca147, 0x0775af4c, 0x106ebd51, 0x1d67b35a,
|
||||
0x3e58996b, 0x33519760, 0x244a857d, 0x29438b76,
|
||||
0x6234d11f, 0x6f3ddf14, 0x7826cd09, 0x752fc302,
|
||||
0x5610e933, 0x5b19e738, 0x4c02f525, 0x410bfb2e,
|
||||
0x61d79a8c, 0x6cde9487, 0x7bc5869a, 0x76cc8891,
|
||||
0x55f3a2a0, 0x58faacab, 0x4fe1beb6, 0x42e8b0bd,
|
||||
0x099fead4, 0x0496e4df, 0x138df6c2, 0x1e84f8c9,
|
||||
0x3dbbd2f8, 0x30b2dcf3, 0x27a9ceee, 0x2aa0c0e5,
|
||||
0xb1477a3c, 0xbc4e7437, 0xab55662a, 0xa65c6821,
|
||||
0x85634210, 0x886a4c1b, 0x9f715e06, 0x9278500d,
|
||||
0xd90f0a64, 0xd406046f, 0xc31d1672, 0xce141879,
|
||||
0xed2b3248, 0xe0223c43, 0xf7392e5e, 0xfa302055,
|
||||
0xb79aec01, 0xba93e20a, 0xad88f017, 0xa081fe1c,
|
||||
0x83bed42d, 0x8eb7da26, 0x99acc83b, 0x94a5c630,
|
||||
0xdfd29c59, 0xd2db9252, 0xc5c0804f, 0xc8c98e44,
|
||||
0xebf6a475, 0xe6ffaa7e, 0xf1e4b863, 0xfcedb668,
|
||||
0x670a0cb1, 0x6a0302ba, 0x7d1810a7, 0x70111eac,
|
||||
0x532e349d, 0x5e273a96, 0x493c288b, 0x44352680,
|
||||
0x0f427ce9, 0x024b72e2, 0x155060ff, 0x18596ef4,
|
||||
0x3b6644c5, 0x366f4ace, 0x217458d3, 0x2c7d56d8,
|
||||
0x0ca1377a, 0x01a83971, 0x16b32b6c, 0x1bba2567,
|
||||
0x38850f56, 0x358c015d, 0x22971340, 0x2f9e1d4b,
|
||||
0x64e94722, 0x69e04929, 0x7efb5b34, 0x73f2553f,
|
||||
0x50cd7f0e, 0x5dc47105, 0x4adf6318, 0x47d66d13,
|
||||
0xdc31d7ca, 0xd138d9c1, 0xc623cbdc, 0xcb2ac5d7,
|
||||
0xe815efe6, 0xe51ce1ed, 0xf207f3f0, 0xff0efdfb,
|
||||
0xb479a792, 0xb970a999, 0xae6bbb84, 0xa362b58f,
|
||||
0x805d9fbe, 0x8d5491b5, 0x9a4f83a8, 0x97468da3
|
||||
},
|
||||
{
|
||||
0x00000000, 0x090e0b0d, 0x121c161a, 0x1b121d17,
|
||||
0x24382c34, 0x2d362739, 0x36243a2e, 0x3f2a3123,
|
||||
0x48705868, 0x417e5365, 0x5a6c4e72, 0x5362457f,
|
||||
0x6c48745c, 0x65467f51, 0x7e546246, 0x775a694b,
|
||||
0x90e0b0d0, 0x99eebbdd, 0x82fca6ca, 0x8bf2adc7,
|
||||
0xb4d89ce4, 0xbdd697e9, 0xa6c48afe, 0xafca81f3,
|
||||
0xd890e8b8, 0xd19ee3b5, 0xca8cfea2, 0xc382f5af,
|
||||
0xfca8c48c, 0xf5a6cf81, 0xeeb4d296, 0xe7bad99b,
|
||||
0x3bdb7bbb, 0x32d570b6, 0x29c76da1, 0x20c966ac,
|
||||
0x1fe3578f, 0x16ed5c82, 0x0dff4195, 0x04f14a98,
|
||||
0x73ab23d3, 0x7aa528de, 0x61b735c9, 0x68b93ec4,
|
||||
0x57930fe7, 0x5e9d04ea, 0x458f19fd, 0x4c8112f0,
|
||||
0xab3bcb6b, 0xa235c066, 0xb927dd71, 0xb029d67c,
|
||||
0x8f03e75f, 0x860dec52, 0x9d1ff145, 0x9411fa48,
|
||||
0xe34b9303, 0xea45980e, 0xf1578519, 0xf8598e14,
|
||||
0xc773bf37, 0xce7db43a, 0xd56fa92d, 0xdc61a220,
|
||||
0x76adf66d, 0x7fa3fd60, 0x64b1e077, 0x6dbfeb7a,
|
||||
0x5295da59, 0x5b9bd154, 0x4089cc43, 0x4987c74e,
|
||||
0x3eddae05, 0x37d3a508, 0x2cc1b81f, 0x25cfb312,
|
||||
0x1ae58231, 0x13eb893c, 0x08f9942b, 0x01f79f26,
|
||||
0xe64d46bd, 0xef434db0, 0xf45150a7, 0xfd5f5baa,
|
||||
0xc2756a89, 0xcb7b6184, 0xd0697c93, 0xd967779e,
|
||||
0xae3d1ed5, 0xa73315d8, 0xbc2108cf, 0xb52f03c2,
|
||||
0x8a0532e1, 0x830b39ec, 0x981924fb, 0x91172ff6,
|
||||
0x4d768dd6, 0x447886db, 0x5f6a9bcc, 0x566490c1,
|
||||
0x694ea1e2, 0x6040aaef, 0x7b52b7f8, 0x725cbcf5,
|
||||
0x0506d5be, 0x0c08deb3, 0x171ac3a4, 0x1e14c8a9,
|
||||
0x213ef98a, 0x2830f287, 0x3322ef90, 0x3a2ce49d,
|
||||
0xdd963d06, 0xd498360b, 0xcf8a2b1c, 0xc6842011,
|
||||
0xf9ae1132, 0xf0a01a3f, 0xebb20728, 0xe2bc0c25,
|
||||
0x95e6656e, 0x9ce86e63, 0x87fa7374, 0x8ef47879,
|
||||
0xb1de495a, 0xb8d04257, 0xa3c25f40, 0xaacc544d,
|
||||
0xec41f7da, 0xe54ffcd7, 0xfe5de1c0, 0xf753eacd,
|
||||
0xc879dbee, 0xc177d0e3, 0xda65cdf4, 0xd36bc6f9,
|
||||
0xa431afb2, 0xad3fa4bf, 0xb62db9a8, 0xbf23b2a5,
|
||||
0x80098386, 0x8907888b, 0x9215959c, 0x9b1b9e91,
|
||||
0x7ca1470a, 0x75af4c07, 0x6ebd5110, 0x67b35a1d,
|
||||
0x58996b3e, 0x51976033, 0x4a857d24, 0x438b7629,
|
||||
0x34d11f62, 0x3ddf146f, 0x26cd0978, 0x2fc30275,
|
||||
0x10e93356, 0x19e7385b, 0x02f5254c, 0x0bfb2e41,
|
||||
0xd79a8c61, 0xde94876c, 0xc5869a7b, 0xcc889176,
|
||||
0xf3a2a055, 0xfaacab58, 0xe1beb64f, 0xe8b0bd42,
|
||||
0x9fead409, 0x96e4df04, 0x8df6c213, 0x84f8c91e,
|
||||
0xbbd2f83d, 0xb2dcf330, 0xa9ceee27, 0xa0c0e52a,
|
||||
0x477a3cb1, 0x4e7437bc, 0x55662aab, 0x5c6821a6,
|
||||
0x63421085, 0x6a4c1b88, 0x715e069f, 0x78500d92,
|
||||
0x0f0a64d9, 0x06046fd4, 0x1d1672c3, 0x141879ce,
|
||||
0x2b3248ed, 0x223c43e0, 0x392e5ef7, 0x302055fa,
|
||||
0x9aec01b7, 0x93e20aba, 0x88f017ad, 0x81fe1ca0,
|
||||
0xbed42d83, 0xb7da268e, 0xacc83b99, 0xa5c63094,
|
||||
0xd29c59df, 0xdb9252d2, 0xc0804fc5, 0xc98e44c8,
|
||||
0xf6a475eb, 0xffaa7ee6, 0xe4b863f1, 0xedb668fc,
|
||||
0x0a0cb167, 0x0302ba6a, 0x1810a77d, 0x111eac70,
|
||||
0x2e349d53, 0x273a965e, 0x3c288b49, 0x35268044,
|
||||
0x427ce90f, 0x4b72e202, 0x5060ff15, 0x596ef418,
|
||||
0x6644c53b, 0x6f4ace36, 0x7458d321, 0x7d56d82c,
|
||||
0xa1377a0c, 0xa8397101, 0xb32b6c16, 0xba25671b,
|
||||
0x850f5638, 0x8c015d35, 0x97134022, 0x9e1d4b2f,
|
||||
0xe9472264, 0xe0492969, 0xfb5b347e, 0xf2553f73,
|
||||
0xcd7f0e50, 0xc471055d, 0xdf63184a, 0xd66d1347,
|
||||
0x31d7cadc, 0x38d9c1d1, 0x23cbdcc6, 0x2ac5d7cb,
|
||||
0x15efe6e8, 0x1ce1ede5, 0x07f3f0f2, 0x0efdfbff,
|
||||
0x79a792b4, 0x70a999b9, 0x6bbb84ae, 0x62b58fa3,
|
||||
0x5d9fbe80, 0x5491b58d, 0x4f83a89a, 0x468da397
|
||||
},
|
||||
{
|
||||
0x00000000, 0x0e0b0d09, 0x1c161a12, 0x121d171b,
|
||||
0x382c3424, 0x3627392d, 0x243a2e36, 0x2a31233f,
|
||||
0x70586848, 0x7e536541, 0x6c4e725a, 0x62457f53,
|
||||
0x48745c6c, 0x467f5165, 0x5462467e, 0x5a694b77,
|
||||
0xe0b0d090, 0xeebbdd99, 0xfca6ca82, 0xf2adc78b,
|
||||
0xd89ce4b4, 0xd697e9bd, 0xc48afea6, 0xca81f3af,
|
||||
0x90e8b8d8, 0x9ee3b5d1, 0x8cfea2ca, 0x82f5afc3,
|
||||
0xa8c48cfc, 0xa6cf81f5, 0xb4d296ee, 0xbad99be7,
|
||||
0xdb7bbb3b, 0xd570b632, 0xc76da129, 0xc966ac20,
|
||||
0xe3578f1f, 0xed5c8216, 0xff41950d, 0xf14a9804,
|
||||
0xab23d373, 0xa528de7a, 0xb735c961, 0xb93ec468,
|
||||
0x930fe757, 0x9d04ea5e, 0x8f19fd45, 0x8112f04c,
|
||||
0x3bcb6bab, 0x35c066a2, 0x27dd71b9, 0x29d67cb0,
|
||||
0x03e75f8f, 0x0dec5286, 0x1ff1459d, 0x11fa4894,
|
||||
0x4b9303e3, 0x45980eea, 0x578519f1, 0x598e14f8,
|
||||
0x73bf37c7, 0x7db43ace, 0x6fa92dd5, 0x61a220dc,
|
||||
0xadf66d76, 0xa3fd607f, 0xb1e07764, 0xbfeb7a6d,
|
||||
0x95da5952, 0x9bd1545b, 0x89cc4340, 0x87c74e49,
|
||||
0xddae053e, 0xd3a50837, 0xc1b81f2c, 0xcfb31225,
|
||||
0xe582311a, 0xeb893c13, 0xf9942b08, 0xf79f2601,
|
||||
0x4d46bde6, 0x434db0ef, 0x5150a7f4, 0x5f5baafd,
|
||||
0x756a89c2, 0x7b6184cb, 0x697c93d0, 0x67779ed9,
|
||||
0x3d1ed5ae, 0x3315d8a7, 0x2108cfbc, 0x2f03c2b5,
|
||||
0x0532e18a, 0x0b39ec83, 0x1924fb98, 0x172ff691,
|
||||
0x768dd64d, 0x7886db44, 0x6a9bcc5f, 0x6490c156,
|
||||
0x4ea1e269, 0x40aaef60, 0x52b7f87b, 0x5cbcf572,
|
||||
0x06d5be05, 0x08deb30c, 0x1ac3a417, 0x14c8a91e,
|
||||
0x3ef98a21, 0x30f28728, 0x22ef9033, 0x2ce49d3a,
|
||||
0x963d06dd, 0x98360bd4, 0x8a2b1ccf, 0x842011c6,
|
||||
0xae1132f9, 0xa01a3ff0, 0xb20728eb, 0xbc0c25e2,
|
||||
0xe6656e95, 0xe86e639c, 0xfa737487, 0xf478798e,
|
||||
0xde495ab1, 0xd04257b8, 0xc25f40a3, 0xcc544daa,
|
||||
0x41f7daec, 0x4ffcd7e5, 0x5de1c0fe, 0x53eacdf7,
|
||||
0x79dbeec8, 0x77d0e3c1, 0x65cdf4da, 0x6bc6f9d3,
|
||||
0x31afb2a4, 0x3fa4bfad, 0x2db9a8b6, 0x23b2a5bf,
|
||||
0x09838680, 0x07888b89, 0x15959c92, 0x1b9e919b,
|
||||
0xa1470a7c, 0xaf4c0775, 0xbd51106e, 0xb35a1d67,
|
||||
0x996b3e58, 0x97603351, 0x857d244a, 0x8b762943,
|
||||
0xd11f6234, 0xdf146f3d, 0xcd097826, 0xc302752f,
|
||||
0xe9335610, 0xe7385b19, 0xf5254c02, 0xfb2e410b,
|
||||
0x9a8c61d7, 0x94876cde, 0x869a7bc5, 0x889176cc,
|
||||
0xa2a055f3, 0xacab58fa, 0xbeb64fe1, 0xb0bd42e8,
|
||||
0xead4099f, 0xe4df0496, 0xf6c2138d, 0xf8c91e84,
|
||||
0xd2f83dbb, 0xdcf330b2, 0xceee27a9, 0xc0e52aa0,
|
||||
0x7a3cb147, 0x7437bc4e, 0x662aab55, 0x6821a65c,
|
||||
0x42108563, 0x4c1b886a, 0x5e069f71, 0x500d9278,
|
||||
0x0a64d90f, 0x046fd406, 0x1672c31d, 0x1879ce14,
|
||||
0x3248ed2b, 0x3c43e022, 0x2e5ef739, 0x2055fa30,
|
||||
0xec01b79a, 0xe20aba93, 0xf017ad88, 0xfe1ca081,
|
||||
0xd42d83be, 0xda268eb7, 0xc83b99ac, 0xc63094a5,
|
||||
0x9c59dfd2, 0x9252d2db, 0x804fc5c0, 0x8e44c8c9,
|
||||
0xa475ebf6, 0xaa7ee6ff, 0xb863f1e4, 0xb668fced,
|
||||
0x0cb1670a, 0x02ba6a03, 0x10a77d18, 0x1eac7011,
|
||||
0x349d532e, 0x3a965e27, 0x288b493c, 0x26804435,
|
||||
0x7ce90f42, 0x72e2024b, 0x60ff1550, 0x6ef41859,
|
||||
0x44c53b66, 0x4ace366f, 0x58d32174, 0x56d82c7d,
|
||||
0x377a0ca1, 0x397101a8, 0x2b6c16b3, 0x25671bba,
|
||||
0x0f563885, 0x015d358c, 0x13402297, 0x1d4b2f9e,
|
||||
0x472264e9, 0x492969e0, 0x5b347efb, 0x553f73f2,
|
||||
0x7f0e50cd, 0x71055dc4, 0x63184adf, 0x6d1347d6,
|
||||
0xd7cadc31, 0xd9c1d138, 0xcbdcc623, 0xc5d7cb2a,
|
||||
0xefe6e815, 0xe1ede51c, 0xf3f0f207, 0xfdfbff0e,
|
||||
0xa792b479, 0xa999b970, 0xbb84ae6b, 0xb58fa362,
|
||||
0x9fbe805d, 0x91b58d54, 0x83a89a4f, 0x8da39746
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _AESTAB2_H */
|
334
module/icp/asm-x86_64/modes/gcm_intel.S
Normal file
334
module/icp/asm-x86_64/modes/gcm_intel.S
Normal file
@ -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 */
|
1346
module/icp/asm-x86_64/sha1/sha1-x86_64.S
Normal file
1346
module/icp/asm-x86_64/sha1/sha1-x86_64.S
Normal file
File diff suppressed because it is too large
Load Diff
2060
module/icp/asm-x86_64/sha2/sha256_impl.S
Normal file
2060
module/icp/asm-x86_64/sha2/sha256_impl.S
Normal file
File diff suppressed because it is too large
Load Diff
1567
module/icp/core/kcf_callprov.c
Normal file
1567
module/icp/core/kcf_callprov.c
Normal file
File diff suppressed because it is too large
Load Diff
775
module/icp/core/kcf_mech_tabs.c
Normal file
775
module/icp/core/kcf_mech_tabs.c
Normal file
@ -0,0 +1,775 @@
|
||||
/*
|
||||
* 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/modhash.h>
|
||||
|
||||
/* Cryptographic mechanisms tables and their access functions */
|
||||
|
||||
/*
|
||||
* Internal numbers assigned to mechanisms are coded as follows:
|
||||
*
|
||||
* +----------------+----------------+
|
||||
* | mech. class | mech. index |
|
||||
* <--- 32-bits --->+<--- 32-bits --->
|
||||
*
|
||||
* the mech_class identifies the table the mechanism belongs to.
|
||||
* mech_index is the index for that mechanism in the table.
|
||||
* A mechanism belongs to exactly 1 table.
|
||||
* The tables are:
|
||||
* . digest_mechs_tab[] for the msg digest mechs.
|
||||
* . cipher_mechs_tab[] for encrypt/decrypt and wrap/unwrap mechs.
|
||||
* . mac_mechs_tab[] for MAC mechs.
|
||||
* . sign_mechs_tab[] for sign & verify mechs.
|
||||
* . keyops_mechs_tab[] for key/key pair generation, and key derivation.
|
||||
* . misc_mechs_tab[] for mechs that don't belong to any of the above.
|
||||
*
|
||||
* There are no holes in the tables.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Locking conventions:
|
||||
* --------------------
|
||||
* A global mutex, kcf_mech_tabs_lock, serializes writes to the
|
||||
* mechanism table via kcf_create_mech_entry().
|
||||
*
|
||||
* A mutex is associated with every entry of the tables.
|
||||
* The mutex is acquired whenever the entry is accessed for
|
||||
* 1) retrieving the mech_id (comparing the mech name)
|
||||
* 2) finding a provider for an xxx_init() or atomic operation.
|
||||
* 3) altering the mechs entry to add or remove a provider.
|
||||
*
|
||||
* In 2), after a provider is chosen, its prov_desc is held and the
|
||||
* entry's mutex must be dropped. The provider's working function (SPI) is
|
||||
* called outside the mech_entry's mutex.
|
||||
*
|
||||
* The number of providers for a particular mechanism is not expected to be
|
||||
* long enough to justify the cost of using rwlocks, so the per-mechanism
|
||||
* entry mutex won't be very *hot*.
|
||||
*
|
||||
* When both kcf_mech_tabs_lock and a mech_entry mutex need to be held,
|
||||
* kcf_mech_tabs_lock must always be acquired first.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Mechanisms tables */
|
||||
|
||||
|
||||
/* RFE 4687834 Will deal with the extensibility of these tables later */
|
||||
|
||||
kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
|
||||
kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
|
||||
kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
|
||||
kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
|
||||
kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
|
||||
kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];
|
||||
|
||||
kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
|
||||
{0, NULL}, /* No class zero */
|
||||
{KCF_MAXDIGEST, kcf_digest_mechs_tab},
|
||||
{KCF_MAXCIPHER, kcf_cipher_mechs_tab},
|
||||
{KCF_MAXMAC, kcf_mac_mechs_tab},
|
||||
{KCF_MAXSIGN, kcf_sign_mechs_tab},
|
||||
{KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
|
||||
{KCF_MAXMISC, kcf_misc_mechs_tab}
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-algorithm internal threasholds for the minimum input size of before
|
||||
* offloading to hardware provider.
|
||||
* Dispatching a crypto operation to a hardware provider entails paying the
|
||||
* cost of an additional context switch. Measurments with Sun Accelerator 4000
|
||||
* shows that 512-byte jobs or smaller are better handled in software.
|
||||
* There is room for refinement here.
|
||||
*
|
||||
*/
|
||||
int kcf_md5_threshold = 512;
|
||||
int kcf_sha1_threshold = 512;
|
||||
int kcf_des_threshold = 512;
|
||||
int kcf_des3_threshold = 512;
|
||||
int kcf_aes_threshold = 512;
|
||||
int kcf_bf_threshold = 512;
|
||||
int kcf_rc4_threshold = 512;
|
||||
|
||||
kmutex_t kcf_mech_tabs_lock;
|
||||
static uint32_t kcf_gen_swprov = 0;
|
||||
|
||||
int kcf_mech_hash_size = 256;
|
||||
mod_hash_t *kcf_mech_hash; /* mech name to id hash */
|
||||
|
||||
static crypto_mech_type_t
|
||||
kcf_mech_hash_find(char *mechname)
|
||||
{
|
||||
mod_hash_val_t hv;
|
||||
crypto_mech_type_t mt;
|
||||
|
||||
mt = CRYPTO_MECH_INVALID;
|
||||
if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
|
||||
mt = *(crypto_mech_type_t *)hv;
|
||||
ASSERT(mt != CRYPTO_MECH_INVALID);
|
||||
}
|
||||
|
||||
return (mt);
|
||||
}
|
||||
|
||||
void
|
||||
kcf_destroy_mech_tabs(void)
|
||||
{
|
||||
if (kcf_mech_hash) mod_hash_destroy_hash(kcf_mech_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* kcf_init_mech_tabs()
|
||||
*
|
||||
* Called by the misc/kcf's _init() routine to initialize the tables
|
||||
* of mech_entry's.
|
||||
*/
|
||||
void
|
||||
kcf_init_mech_tabs(void)
|
||||
{
|
||||
int i, max;
|
||||
kcf_ops_class_t class;
|
||||
kcf_mech_entry_t *me_tab;
|
||||
|
||||
/* Initializes the mutex locks. */
|
||||
|
||||
mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
|
||||
/* Then the pre-defined mechanism entries */
|
||||
|
||||
/* Two digests */
|
||||
(void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;
|
||||
|
||||
(void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;
|
||||
|
||||
/* The symmetric ciphers in various modes */
|
||||
(void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;
|
||||
|
||||
(void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;
|
||||
|
||||
|
||||
/* 4 HMACs */
|
||||
(void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;
|
||||
|
||||
(void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;
|
||||
|
||||
(void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;
|
||||
|
||||
(void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;
|
||||
|
||||
|
||||
/* 1 random number generation pseudo mechanism */
|
||||
(void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
|
||||
kcf_mech_hash = mod_hash_create_strhash_nodtr("kcf mech2id hash",
|
||||
kcf_mech_hash_size, mod_hash_null_valdtor);
|
||||
|
||||
for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
|
||||
max = kcf_mech_tabs_tab[class].met_size;
|
||||
me_tab = kcf_mech_tabs_tab[class].met_tab;
|
||||
for (i = 0; i < max; i++) {
|
||||
mutex_init(&(me_tab[i].me_mutex), NULL,
|
||||
MUTEX_DEFAULT, NULL);
|
||||
if (me_tab[i].me_name[0] != 0) {
|
||||
me_tab[i].me_mechid = KCF_MECHID(class, i);
|
||||
(void) mod_hash_insert(kcf_mech_hash,
|
||||
(mod_hash_key_t)me_tab[i].me_name,
|
||||
(mod_hash_val_t)&(me_tab[i].me_mechid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* kcf_create_mech_entry()
|
||||
*
|
||||
* Arguments:
|
||||
* . The class of mechanism.
|
||||
* . the name of the new mechanism.
|
||||
*
|
||||
* Description:
|
||||
* Creates a new mech_entry for a mechanism not yet known to the
|
||||
* framework.
|
||||
* This routine is called by kcf_add_mech_provider, which is
|
||||
* in turn invoked for each mechanism supported by a provider.
|
||||
* The'class' argument depends on the crypto_func_group_t bitmask
|
||||
* in the registering provider's mech_info struct for this mechanism.
|
||||
* When there is ambiguity in the mapping between the crypto_func_group_t
|
||||
* and a class (dual ops, ...) the KCF_MISC_CLASS should be used.
|
||||
*
|
||||
* Context:
|
||||
* User context only.
|
||||
*
|
||||
* Returns:
|
||||
* KCF_INVALID_MECH_CLASS or KCF_INVALID_MECH_NAME if the class or
|
||||
* the mechname is bogus.
|
||||
* KCF_MECH_TAB_FULL when there is no room left in the mech. tabs.
|
||||
* KCF_SUCCESS otherwise.
|
||||
*/
|
||||
static int
|
||||
kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
|
||||
{
|
||||
crypto_mech_type_t mt;
|
||||
kcf_mech_entry_t *me_tab;
|
||||
int i = 0, size;
|
||||
|
||||
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
|
||||
return (KCF_INVALID_MECH_CLASS);
|
||||
|
||||
if ((mechname == NULL) || (mechname[0] == 0))
|
||||
return (KCF_INVALID_MECH_NAME);
|
||||
/*
|
||||
* First check if the mechanism is already in one of the tables.
|
||||
* The mech_entry could be in another class.
|
||||
*/
|
||||
mutex_enter(&kcf_mech_tabs_lock);
|
||||
mt = kcf_mech_hash_find(mechname);
|
||||
if (mt != CRYPTO_MECH_INVALID) {
|
||||
/* Nothing to do, regardless the suggested class. */
|
||||
mutex_exit(&kcf_mech_tabs_lock);
|
||||
return (KCF_SUCCESS);
|
||||
}
|
||||
/* Now take the next unused mech entry in the class's tab */
|
||||
me_tab = kcf_mech_tabs_tab[class].met_tab;
|
||||
size = kcf_mech_tabs_tab[class].met_size;
|
||||
|
||||
while (i < size) {
|
||||
mutex_enter(&(me_tab[i].me_mutex));
|
||||
if (me_tab[i].me_name[0] == 0) {
|
||||
/* Found an empty spot */
|
||||
(void) strncpy(me_tab[i].me_name, mechname,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
|
||||
me_tab[i].me_mechid = KCF_MECHID(class, i);
|
||||
/*
|
||||
* No a-priori information about the new mechanism, so
|
||||
* the threshold is set to zero.
|
||||
*/
|
||||
me_tab[i].me_threshold = 0;
|
||||
|
||||
mutex_exit(&(me_tab[i].me_mutex));
|
||||
/* Add the new mechanism to the hash table */
|
||||
(void) mod_hash_insert(kcf_mech_hash,
|
||||
(mod_hash_key_t)me_tab[i].me_name,
|
||||
(mod_hash_val_t)&(me_tab[i].me_mechid));
|
||||
break;
|
||||
}
|
||||
mutex_exit(&(me_tab[i].me_mutex));
|
||||
i++;
|
||||
}
|
||||
|
||||
mutex_exit(&kcf_mech_tabs_lock);
|
||||
|
||||
if (i == size) {
|
||||
return (KCF_MECH_TAB_FULL);
|
||||
}
|
||||
|
||||
return (KCF_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* kcf_add_mech_provider()
|
||||
*
|
||||
* Arguments:
|
||||
* . An index in to the provider mechanism array
|
||||
* . A pointer to the provider descriptor
|
||||
* . A storage for the kcf_prov_mech_desc_t the entry was added at.
|
||||
*
|
||||
* Description:
|
||||
* Adds a new provider of a mechanism to the mechanism's mech_entry
|
||||
* chain.
|
||||
*
|
||||
* Context:
|
||||
* User context only.
|
||||
*
|
||||
* Returns
|
||||
* KCF_SUCCESS on success
|
||||
* KCF_MECH_TAB_FULL otherwise.
|
||||
*/
|
||||
int
|
||||
kcf_add_mech_provider(short mech_indx,
|
||||
kcf_provider_desc_t *prov_desc, kcf_prov_mech_desc_t **pmdpp)
|
||||
{
|
||||
int error;
|
||||
kcf_mech_entry_t *mech_entry = NULL;
|
||||
crypto_mech_info_t *mech_info;
|
||||
crypto_mech_type_t kcf_mech_type, mt;
|
||||
kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
|
||||
crypto_func_group_t simple_fg_mask, dual_fg_mask;
|
||||
crypto_mech_info_t *dmi;
|
||||
crypto_mech_info_list_t *mil, *mil2;
|
||||
kcf_mech_entry_t *me;
|
||||
int i;
|
||||
|
||||
ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
mech_info = &prov_desc->pd_mechanisms[mech_indx];
|
||||
|
||||
/*
|
||||
* A mechanism belongs to exactly one mechanism table.
|
||||
* Find the class corresponding to the function group flag of
|
||||
* the mechanism.
|
||||
*/
|
||||
kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
|
||||
if (kcf_mech_type == CRYPTO_MECH_INVALID) {
|
||||
crypto_func_group_t fg = mech_info->cm_func_group_mask;
|
||||
kcf_ops_class_t class;
|
||||
|
||||
if (fg & CRYPTO_FG_DIGEST || fg & CRYPTO_FG_DIGEST_ATOMIC)
|
||||
class = KCF_DIGEST_CLASS;
|
||||
else if (fg & CRYPTO_FG_ENCRYPT || fg & CRYPTO_FG_DECRYPT ||
|
||||
fg & CRYPTO_FG_ENCRYPT_ATOMIC ||
|
||||
fg & CRYPTO_FG_DECRYPT_ATOMIC)
|
||||
class = KCF_CIPHER_CLASS;
|
||||
else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
|
||||
class = KCF_MAC_CLASS;
|
||||
else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
|
||||
fg & CRYPTO_FG_SIGN_ATOMIC ||
|
||||
fg & CRYPTO_FG_VERIFY_ATOMIC ||
|
||||
fg & CRYPTO_FG_SIGN_RECOVER ||
|
||||
fg & CRYPTO_FG_VERIFY_RECOVER)
|
||||
class = KCF_SIGN_CLASS;
|
||||
else if (fg & CRYPTO_FG_GENERATE ||
|
||||
fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
|
||||
fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
|
||||
fg & CRYPTO_FG_DERIVE)
|
||||
class = KCF_KEYOPS_CLASS;
|
||||
else
|
||||
class = KCF_MISC_CLASS;
|
||||
|
||||
/*
|
||||
* Attempt to create a new mech_entry for the specified
|
||||
* mechanism. kcf_create_mech_entry() can handle the case
|
||||
* where such an entry already exists.
|
||||
*/
|
||||
if ((error = kcf_create_mech_entry(class,
|
||||
mech_info->cm_mech_name)) != KCF_SUCCESS) {
|
||||
return (error);
|
||||
}
|
||||
/* get the KCF mech type that was assigned to the mechanism */
|
||||
kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
|
||||
ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
|
||||
}
|
||||
|
||||
error = kcf_get_mech_entry(kcf_mech_type, &mech_entry);
|
||||
ASSERT(error == KCF_SUCCESS);
|
||||
|
||||
/* allocate and initialize new kcf_prov_mech_desc */
|
||||
prov_mech = kmem_zalloc(sizeof (kcf_prov_mech_desc_t), KM_SLEEP);
|
||||
bcopy(mech_info, &prov_mech->pm_mech_info, sizeof (crypto_mech_info_t));
|
||||
prov_mech->pm_prov_desc = prov_desc;
|
||||
prov_desc->pd_mech_indx[KCF_MECH2CLASS(kcf_mech_type)]
|
||||
[KCF_MECH2INDEX(kcf_mech_type)] = mech_indx;
|
||||
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
KCF_PROV_IREFHOLD(prov_desc);
|
||||
|
||||
dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;
|
||||
|
||||
if (dual_fg_mask == ((crypto_func_group_t)0))
|
||||
goto add_entry;
|
||||
|
||||
simple_fg_mask = (mech_info->cm_func_group_mask &
|
||||
CRYPTO_FG_SIMPLEOP_MASK) | CRYPTO_FG_RANDOM;
|
||||
|
||||
for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
|
||||
dmi = &prov_desc->pd_mechanisms[i];
|
||||
|
||||
/* skip self */
|
||||
if (dmi->cm_mech_number == mech_info->cm_mech_number)
|
||||
continue;
|
||||
|
||||
/* skip if not a dual operation mechanism */
|
||||
if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
|
||||
(dmi->cm_func_group_mask & simple_fg_mask))
|
||||
continue;
|
||||
|
||||
mt = kcf_mech_hash_find(dmi->cm_mech_name);
|
||||
if (mt == CRYPTO_MECH_INVALID)
|
||||
continue;
|
||||
|
||||
if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
|
||||
continue;
|
||||
|
||||
mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
|
||||
mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);
|
||||
|
||||
/*
|
||||
* Ignore hard-coded entries in the mech table
|
||||
* if the provider hasn't registered.
|
||||
*/
|
||||
mutex_enter(&me->me_mutex);
|
||||
if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
|
||||
mutex_exit(&me->me_mutex);
|
||||
kmem_free(mil, sizeof (*mil));
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add other dual mechanisms that have registered
|
||||
* with the framework to this mechanism's
|
||||
* cross-reference list.
|
||||
*/
|
||||
mil->ml_mech_info = *dmi; /* struct assignment */
|
||||
mil->ml_kcf_mechid = mt;
|
||||
|
||||
/* add to head of list */
|
||||
mil->ml_next = prov_mech->pm_mi_list;
|
||||
prov_mech->pm_mi_list = mil;
|
||||
|
||||
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
|
||||
prov_mech2 = me->me_hw_prov_chain;
|
||||
else
|
||||
prov_mech2 = me->me_sw_prov;
|
||||
|
||||
if (prov_mech2 == NULL) {
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
mutex_exit(&me->me_mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update all other cross-reference lists by
|
||||
* adding this new mechanism.
|
||||
*/
|
||||
while (prov_mech2 != NULL) {
|
||||
if (prov_mech2->pm_prov_desc == prov_desc) {
|
||||
/* struct assignment */
|
||||
mil2->ml_mech_info = *mech_info;
|
||||
mil2->ml_kcf_mechid = kcf_mech_type;
|
||||
|
||||
/* add to head of list */
|
||||
mil2->ml_next = prov_mech2->pm_mi_list;
|
||||
prov_mech2->pm_mi_list = mil2;
|
||||
break;
|
||||
}
|
||||
prov_mech2 = prov_mech2->pm_next;
|
||||
}
|
||||
if (prov_mech2 == NULL)
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
|
||||
mutex_exit(&me->me_mutex);
|
||||
}
|
||||
|
||||
add_entry:
|
||||
/*
|
||||
* Add new kcf_prov_mech_desc at the front of HW providers
|
||||
* chain.
|
||||
*/
|
||||
switch (prov_desc->pd_prov_type) {
|
||||
|
||||
case CRYPTO_HW_PROVIDER:
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
prov_mech->pm_me = mech_entry;
|
||||
prov_mech->pm_next = mech_entry->me_hw_prov_chain;
|
||||
mech_entry->me_hw_prov_chain = prov_mech;
|
||||
mech_entry->me_num_hwprov++;
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
break;
|
||||
|
||||
case CRYPTO_SW_PROVIDER:
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
if (mech_entry->me_sw_prov != NULL) {
|
||||
/*
|
||||
* There is already a SW provider for this mechanism.
|
||||
* Since we allow only one SW provider per mechanism,
|
||||
* report this condition.
|
||||
*/
|
||||
cmn_err(CE_WARN, "The cryptographic software provider "
|
||||
"\"%s\" will not be used for %s. The provider "
|
||||
"\"%s\" will be used for this mechanism "
|
||||
"instead.", prov_desc->pd_description,
|
||||
mech_info->cm_mech_name,
|
||||
mech_entry->me_sw_prov->pm_prov_desc->
|
||||
pd_description);
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
|
||||
prov_mech = NULL;
|
||||
} else {
|
||||
/*
|
||||
* Set the provider as the software provider for
|
||||
* this mechanism.
|
||||
*/
|
||||
mech_entry->me_sw_prov = prov_mech;
|
||||
|
||||
/* We'll wrap around after 4 billion registrations! */
|
||||
mech_entry->me_gen_swprov = kcf_gen_swprov++;
|
||||
}
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
*pmdpp = prov_mech;
|
||||
|
||||
return (KCF_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* kcf_remove_mech_provider()
|
||||
*
|
||||
* Arguments:
|
||||
* . mech_name: the name of the mechanism.
|
||||
* . prov_desc: The provider descriptor
|
||||
*
|
||||
* Description:
|
||||
* Removes a provider from chain of provider descriptors.
|
||||
* The provider is made unavailable to kernel consumers for the specified
|
||||
* mechanism.
|
||||
*
|
||||
* Context:
|
||||
* User context only.
|
||||
*/
|
||||
void
|
||||
kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
|
||||
{
|
||||
crypto_mech_type_t mech_type;
|
||||
kcf_prov_mech_desc_t *prov_mech = NULL, *prov_chain;
|
||||
kcf_prov_mech_desc_t **prev_entry_next;
|
||||
kcf_mech_entry_t *mech_entry;
|
||||
crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;
|
||||
|
||||
ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
|
||||
|
||||
/* get the KCF mech type that was assigned to the mechanism */
|
||||
if ((mech_type = kcf_mech_hash_find(mech_name)) ==
|
||||
CRYPTO_MECH_INVALID) {
|
||||
/*
|
||||
* Provider was not allowed for this mech due to policy or
|
||||
* configuration.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
/* get a ptr to the mech_entry that was created */
|
||||
if (kcf_get_mech_entry(mech_type, &mech_entry) != KCF_SUCCESS) {
|
||||
/*
|
||||
* Provider was not allowed for this mech due to policy or
|
||||
* configuration.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
|
||||
switch (prov_desc->pd_prov_type) {
|
||||
|
||||
case CRYPTO_HW_PROVIDER:
|
||||
/* find the provider in the mech_entry chain */
|
||||
prev_entry_next = &mech_entry->me_hw_prov_chain;
|
||||
prov_mech = mech_entry->me_hw_prov_chain;
|
||||
while (prov_mech != NULL &&
|
||||
prov_mech->pm_prov_desc != prov_desc) {
|
||||
prev_entry_next = &prov_mech->pm_next;
|
||||
prov_mech = prov_mech->pm_next;
|
||||
}
|
||||
|
||||
if (prov_mech == NULL) {
|
||||
/* entry not found, simply return */
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* remove provider entry from mech_entry chain */
|
||||
*prev_entry_next = prov_mech->pm_next;
|
||||
ASSERT(mech_entry->me_num_hwprov > 0);
|
||||
mech_entry->me_num_hwprov--;
|
||||
break;
|
||||
|
||||
case CRYPTO_SW_PROVIDER:
|
||||
if (mech_entry->me_sw_prov == NULL ||
|
||||
mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
|
||||
/* not the software provider for this mechanism */
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
return;
|
||||
}
|
||||
prov_mech = mech_entry->me_sw_prov;
|
||||
mech_entry->me_sw_prov = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
|
||||
/* Free the dual ops cross-reference lists */
|
||||
mil = prov_mech->pm_mi_list;
|
||||
while (mil != NULL) {
|
||||
next = mil->ml_next;
|
||||
if (kcf_get_mech_entry(mil->ml_kcf_mechid,
|
||||
&mech_entry) != KCF_SUCCESS) {
|
||||
mil = next;
|
||||
continue;
|
||||
}
|
||||
|
||||
mutex_enter(&mech_entry->me_mutex);
|
||||
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
|
||||
prov_chain = mech_entry->me_hw_prov_chain;
|
||||
else
|
||||
prov_chain = mech_entry->me_sw_prov;
|
||||
|
||||
while (prov_chain != NULL) {
|
||||
if (prov_chain->pm_prov_desc == prov_desc) {
|
||||
prev_next = &prov_chain->pm_mi_list;
|
||||
mil2 = prov_chain->pm_mi_list;
|
||||
while (mil2 != NULL &&
|
||||
mil2->ml_kcf_mechid != mech_type) {
|
||||
prev_next = &mil2->ml_next;
|
||||
mil2 = mil2->ml_next;
|
||||
}
|
||||
if (mil2 != NULL) {
|
||||
*prev_next = mil2->ml_next;
|
||||
kmem_free(mil2, sizeof (*mil2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
prov_chain = prov_chain->pm_next;
|
||||
}
|
||||
|
||||
mutex_exit(&mech_entry->me_mutex);
|
||||
kmem_free(mil, sizeof (crypto_mech_info_list_t));
|
||||
mil = next;
|
||||
}
|
||||
|
||||
/* free entry */
|
||||
KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
|
||||
KCF_PROV_IREFRELE(prov_mech->pm_prov_desc);
|
||||
kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* kcf_get_mech_entry()
|
||||
*
|
||||
* Arguments:
|
||||
* . The framework mechanism type
|
||||
* . Storage for the mechanism entry
|
||||
*
|
||||
* Description:
|
||||
* Retrieves the mechanism entry for the mech.
|
||||
*
|
||||
* Context:
|
||||
* User and interrupt contexts.
|
||||
*
|
||||
* Returns:
|
||||
* KCF_MECHANISM_XXX appropriate error code.
|
||||
* KCF_SUCCESS otherwise.
|
||||
*/
|
||||
int
|
||||
kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
|
||||
{
|
||||
kcf_ops_class_t class;
|
||||
int index;
|
||||
kcf_mech_entry_tab_t *me_tab;
|
||||
|
||||
ASSERT(mep != NULL);
|
||||
|
||||
class = KCF_MECH2CLASS(mech_type);
|
||||
|
||||
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
|
||||
/* the caller won't need to know it's an invalid class */
|
||||
return (KCF_INVALID_MECH_NUMBER);
|
||||
}
|
||||
|
||||
me_tab = &kcf_mech_tabs_tab[class];
|
||||
index = KCF_MECH2INDEX(mech_type);
|
||||
|
||||
if ((index < 0) || (index >= me_tab->met_size)) {
|
||||
return (KCF_INVALID_MECH_NUMBER);
|
||||
}
|
||||
|
||||
*mep = &((me_tab->met_tab)[index]);
|
||||
|
||||
return (KCF_SUCCESS);
|
||||
}
|
||||
|
||||
/* CURRENTLY UNSUPPORTED: attempting to load the module if it isn't found */
|
||||
/*
|
||||
* Lookup the hash table for an entry that matches the mechname.
|
||||
* 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.
|
||||
*
|
||||
* If the MOD_NOAUTOUNLOAD flag is not set, a software provider is
|
||||
* in constant danger of being unloaded. For consumers that call
|
||||
* crypto_mech2id() only once, the provider will not be reloaded
|
||||
* if it becomes unloaded. If a provider gets loaded elsewhere
|
||||
* without the MOD_NOAUTOUNLOAD flag being set, we set it now.
|
||||
*/
|
||||
crypto_mech_type_t
|
||||
crypto_mech2id_common(char *mechname, boolean_t load_module)
|
||||
{
|
||||
crypto_mech_type_t mt = kcf_mech_hash_find(mechname);
|
||||
return (mt);
|
||||
}
|
229
module/icp/core/kcf_prov_lib.c
Normal file
229
module/icp/core/kcf_prov_lib.c
Normal file
@ -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);
|
||||
}
|
638
module/icp/core/kcf_prov_tabs.c
Normal file
638
module/icp/core/kcf_prov_tabs.c
Normal file
@ -0,0 +1,638 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the core Kernel Cryptographic Framework.
|
||||
* It implements the management of tables of Providers. Entries to
|
||||
* added and removed when cryptographic providers register with
|
||||
* and unregister from the framework, respectively. The KCF scheduler
|
||||
* and ioctl pseudo driver call this function to obtain the list
|
||||
* of available providers.
|
||||
*
|
||||
* The provider table is indexed by crypto_provider_id_t. Each
|
||||
* element of the table contains a pointer to a provider descriptor,
|
||||
* or NULL if the entry is free.
|
||||
*
|
||||
* This file also implements helper functions to allocate and free
|
||||
* provider descriptors.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/crypto/sched_impl.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
|
||||
#define KCF_MAX_PROVIDERS 512 /* max number of providers */
|
||||
|
||||
/*
|
||||
* Prov_tab is an array of providers which is updated when
|
||||
* a crypto provider registers with kcf. The provider calls the
|
||||
* SPI routine, crypto_register_provider(), which in turn calls
|
||||
* kcf_prov_tab_add_provider().
|
||||
*
|
||||
* A provider unregisters by calling crypto_unregister_provider()
|
||||
* which triggers the removal of the prov_tab entry.
|
||||
* It also calls kcf_remove_mech_provider().
|
||||
*
|
||||
* prov_tab entries are not updated from kcf.conf or by cryptoadm(1M).
|
||||
*/
|
||||
static kcf_provider_desc_t **prov_tab = NULL;
|
||||
static kmutex_t prov_tab_mutex; /* ensure exclusive access to the table */
|
||||
static uint_t prov_tab_num = 0; /* number of providers in table */
|
||||
static uint_t prov_tab_max = KCF_MAX_PROVIDERS;
|
||||
|
||||
void
|
||||
kcf_prov_tab_destroy(void)
|
||||
{
|
||||
if (prov_tab) kmem_free(prov_tab, prov_tab_max *
|
||||
sizeof (kcf_provider_desc_t *));
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a mutex and the KCF providers table, prov_tab.
|
||||
* The providers table is dynamically allocated with prov_tab_max entries.
|
||||
* Called from kcf module _init().
|
||||
*/
|
||||
void
|
||||
kcf_prov_tab_init(void)
|
||||
{
|
||||
mutex_init(&prov_tab_mutex, NULL, MUTEX_DEFAULT, NULL);
|
||||
|
||||
prov_tab = kmem_zalloc(prov_tab_max * sizeof (kcf_provider_desc_t *),
|
||||
KM_SLEEP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a provider to the provider table. If no free entry can be found
|
||||
* for the new provider, returns CRYPTO_HOST_MEMORY. Otherwise, add
|
||||
* the provider to the table, initialize the pd_prov_id field
|
||||
* of the specified provider descriptor to the index in that table,
|
||||
* and return CRYPTO_SUCCESS. Note that a REFHOLD is done on the
|
||||
* provider when pointed to by a table entry.
|
||||
*/
|
||||
int
|
||||
kcf_prov_tab_add_provider(kcf_provider_desc_t *prov_desc)
|
||||
{
|
||||
uint_t i;
|
||||
|
||||
ASSERT(prov_tab != NULL);
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
|
||||
/* find free slot in providers table */
|
||||
for (i = 1; i < KCF_MAX_PROVIDERS && prov_tab[i] != NULL; i++)
|
||||
;
|
||||
if (i == KCF_MAX_PROVIDERS) {
|
||||
/* ran out of providers entries */
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
cmn_err(CE_WARN, "out of providers entries");
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
}
|
||||
|
||||
/* initialize entry */
|
||||
prov_tab[i] = prov_desc;
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
KCF_PROV_IREFHOLD(prov_desc);
|
||||
prov_tab_num++;
|
||||
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
/* update provider descriptor */
|
||||
prov_desc->pd_prov_id = i;
|
||||
|
||||
/*
|
||||
* The KCF-private provider handle is defined as the internal
|
||||
* provider id.
|
||||
*/
|
||||
prov_desc->pd_kcf_prov_handle =
|
||||
(crypto_kcf_provider_handle_t)prov_desc->pd_prov_id;
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the provider specified by its id. A REFRELE is done on the
|
||||
* corresponding provider descriptor before this function returns.
|
||||
* Returns CRYPTO_UNKNOWN_PROVIDER if the provider id is not valid.
|
||||
*/
|
||||
int
|
||||
kcf_prov_tab_rem_provider(crypto_provider_id_t prov_id)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
|
||||
ASSERT(prov_tab != NULL);
|
||||
ASSERT(prov_tab_num >= 0);
|
||||
|
||||
/*
|
||||
* Validate provider id, since it can be specified by a 3rd-party
|
||||
* provider.
|
||||
*/
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
if (prov_id >= KCF_MAX_PROVIDERS ||
|
||||
((prov_desc = prov_tab[prov_id]) == NULL)) {
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
return (CRYPTO_INVALID_PROVIDER_ID);
|
||||
}
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
/*
|
||||
* The provider id must remain valid until the associated provider
|
||||
* descriptor is freed. For this reason, we simply release our
|
||||
* reference to the descriptor here. When the reference count
|
||||
* reaches zero, kcf_free_provider_desc() will be invoked and
|
||||
* the associated entry in the providers table will be released
|
||||
* at that time.
|
||||
*/
|
||||
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
KCF_PROV_IREFRELE(prov_desc);
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the provider descriptor corresponding to the specified
|
||||
* provider id. A REFHOLD is done on the descriptor before it is
|
||||
* returned to the caller. It is the responsibility of the caller
|
||||
* to do a REFRELE once it is done with the provider descriptor.
|
||||
*/
|
||||
kcf_provider_desc_t *
|
||||
kcf_prov_tab_lookup(crypto_provider_id_t prov_id)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
|
||||
prov_desc = prov_tab[prov_id];
|
||||
|
||||
if (prov_desc == NULL) {
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
return (prov_desc);
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_ops_v1(crypto_ops_t *src, crypto_ops_t *dst, uint_t *mech_list_count)
|
||||
{
|
||||
if (src->co_control_ops != NULL)
|
||||
dst->co_control_ops = kmem_alloc(sizeof (crypto_control_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_digest_ops != NULL)
|
||||
dst->co_digest_ops = kmem_alloc(sizeof (crypto_digest_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_cipher_ops != NULL)
|
||||
dst->co_cipher_ops = kmem_alloc(sizeof (crypto_cipher_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_mac_ops != NULL)
|
||||
dst->co_mac_ops = kmem_alloc(sizeof (crypto_mac_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_sign_ops != NULL)
|
||||
dst->co_sign_ops = kmem_alloc(sizeof (crypto_sign_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_verify_ops != NULL)
|
||||
dst->co_verify_ops = kmem_alloc(sizeof (crypto_verify_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_dual_ops != NULL)
|
||||
dst->co_dual_ops = kmem_alloc(sizeof (crypto_dual_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_dual_cipher_mac_ops != NULL)
|
||||
dst->co_dual_cipher_mac_ops = kmem_alloc(
|
||||
sizeof (crypto_dual_cipher_mac_ops_t), KM_SLEEP);
|
||||
|
||||
if (src->co_random_ops != NULL) {
|
||||
dst->co_random_ops = kmem_alloc(
|
||||
sizeof (crypto_random_number_ops_t), KM_SLEEP);
|
||||
|
||||
/*
|
||||
* Allocate storage to store the array of supported mechanisms
|
||||
* specified by provider. We allocate extra mechanism storage
|
||||
* if the provider has random_ops since we keep an internal
|
||||
* mechanism, SUN_RANDOM, in this case.
|
||||
*/
|
||||
(*mech_list_count)++;
|
||||
}
|
||||
|
||||
if (src->co_session_ops != NULL)
|
||||
dst->co_session_ops = kmem_alloc(sizeof (crypto_session_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_object_ops != NULL)
|
||||
dst->co_object_ops = kmem_alloc(sizeof (crypto_object_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_key_ops != NULL)
|
||||
dst->co_key_ops = kmem_alloc(sizeof (crypto_key_ops_t),
|
||||
KM_SLEEP);
|
||||
|
||||
if (src->co_provider_ops != NULL)
|
||||
dst->co_provider_ops = kmem_alloc(
|
||||
sizeof (crypto_provider_management_ops_t), KM_SLEEP);
|
||||
|
||||
if (src->co_ctx_ops != NULL)
|
||||
dst->co_ctx_ops = kmem_alloc(sizeof (crypto_ctx_ops_t),
|
||||
KM_SLEEP);
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_ops_v2(crypto_ops_t *src, crypto_ops_t *dst)
|
||||
{
|
||||
if (src->co_mech_ops != NULL)
|
||||
dst->co_mech_ops = kmem_alloc(sizeof (crypto_mech_ops_t),
|
||||
KM_SLEEP);
|
||||
}
|
||||
|
||||
static void
|
||||
allocate_ops_v3(crypto_ops_t *src, crypto_ops_t *dst)
|
||||
{
|
||||
if (src->co_nostore_key_ops != NULL)
|
||||
dst->co_nostore_key_ops =
|
||||
kmem_alloc(sizeof (crypto_nostore_key_ops_t), KM_SLEEP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a provider descriptor. mech_list_count specifies the
|
||||
* number of mechanisms supported by the providers, and is used
|
||||
* to allocate storage for the mechanism table.
|
||||
* This function may sleep while allocating memory, which is OK
|
||||
* since it is invoked from user context during provider registration.
|
||||
*/
|
||||
kcf_provider_desc_t *
|
||||
kcf_alloc_provider_desc(crypto_provider_info_t *info)
|
||||
{
|
||||
int i, j;
|
||||
kcf_provider_desc_t *desc;
|
||||
uint_t mech_list_count = info->pi_mech_list_count;
|
||||
crypto_ops_t *src_ops = info->pi_ops_vector;
|
||||
|
||||
desc = kmem_zalloc(sizeof (kcf_provider_desc_t), KM_SLEEP);
|
||||
|
||||
/*
|
||||
* pd_description serves two purposes
|
||||
* - Appears as a blank padded PKCS#11 style string, that will be
|
||||
* returned to applications in CK_SLOT_INFO.slotDescription.
|
||||
* This means that we should not have a null character in the
|
||||
* first CRYPTO_PROVIDER_DESCR_MAX_LEN bytes.
|
||||
* - Appears as a null-terminated string that can be used by
|
||||
* other kcf routines.
|
||||
*
|
||||
* So, we allocate enough room for one extra null terminator
|
||||
* which keeps every one happy.
|
||||
*/
|
||||
desc->pd_description = kmem_alloc(CRYPTO_PROVIDER_DESCR_MAX_LEN + 1,
|
||||
KM_SLEEP);
|
||||
(void) memset(desc->pd_description, ' ',
|
||||
CRYPTO_PROVIDER_DESCR_MAX_LEN);
|
||||
desc->pd_description[CRYPTO_PROVIDER_DESCR_MAX_LEN] = '\0';
|
||||
|
||||
/*
|
||||
* Since the framework does not require the ops vector specified
|
||||
* by the providers during registration to be persistent,
|
||||
* KCF needs to allocate storage where copies of the ops
|
||||
* vectors are copied.
|
||||
*/
|
||||
desc->pd_ops_vector = kmem_zalloc(sizeof (crypto_ops_t), KM_SLEEP);
|
||||
|
||||
if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
allocate_ops_v1(src_ops, desc->pd_ops_vector, &mech_list_count);
|
||||
if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2)
|
||||
allocate_ops_v2(src_ops, desc->pd_ops_vector);
|
||||
if (info->pi_interface_version == CRYPTO_SPI_VERSION_3)
|
||||
allocate_ops_v3(src_ops, desc->pd_ops_vector);
|
||||
}
|
||||
|
||||
desc->pd_mech_list_count = mech_list_count;
|
||||
desc->pd_mechanisms = kmem_zalloc(sizeof (crypto_mech_info_t) *
|
||||
mech_list_count, KM_SLEEP);
|
||||
for (i = 0; i < KCF_OPS_CLASSSIZE; i++)
|
||||
for (j = 0; j < KCF_MAXMECHTAB; j++)
|
||||
desc->pd_mech_indx[i][j] = KCF_INVALID_INDX;
|
||||
|
||||
desc->pd_prov_id = KCF_PROVID_INVALID;
|
||||
desc->pd_state = KCF_PROV_ALLOCATED;
|
||||
|
||||
mutex_init(&desc->pd_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
cv_init(&desc->pd_resume_cv, NULL, CV_DEFAULT, NULL);
|
||||
cv_init(&desc->pd_remove_cv, NULL, CV_DEFAULT, NULL);
|
||||
|
||||
return (desc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by KCF_PROV_REFRELE when a provider's reference count drops
|
||||
* to zero. We free the descriptor when the last reference is released.
|
||||
* However, for software providers, we do not free it when there is an
|
||||
* unregister thread waiting. We signal that thread in this case and
|
||||
* that thread is responsible for freeing the descriptor.
|
||||
*/
|
||||
void
|
||||
kcf_provider_zero_refcnt(kcf_provider_desc_t *desc)
|
||||
{
|
||||
mutex_enter(&desc->pd_lock);
|
||||
switch (desc->pd_prov_type) {
|
||||
case CRYPTO_SW_PROVIDER:
|
||||
if (desc->pd_state == KCF_PROV_REMOVED ||
|
||||
desc->pd_state == KCF_PROV_DISABLED) {
|
||||
desc->pd_state = KCF_PROV_FREED;
|
||||
cv_broadcast(&desc->pd_remove_cv);
|
||||
mutex_exit(&desc->pd_lock);
|
||||
break;
|
||||
}
|
||||
/* FALLTHRU */
|
||||
|
||||
case CRYPTO_HW_PROVIDER:
|
||||
case CRYPTO_LOGICAL_PROVIDER:
|
||||
mutex_exit(&desc->pd_lock);
|
||||
kcf_free_provider_desc(desc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free a provider descriptor.
|
||||
*/
|
||||
void
|
||||
kcf_free_provider_desc(kcf_provider_desc_t *desc)
|
||||
{
|
||||
if (desc == NULL)
|
||||
return;
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
if (desc->pd_prov_id != KCF_PROVID_INVALID) {
|
||||
/* release the associated providers table entry */
|
||||
ASSERT(prov_tab[desc->pd_prov_id] != NULL);
|
||||
prov_tab[desc->pd_prov_id] = NULL;
|
||||
prov_tab_num--;
|
||||
}
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
/* free the kernel memory associated with the provider descriptor */
|
||||
|
||||
if (desc->pd_description != NULL)
|
||||
kmem_free(desc->pd_description,
|
||||
CRYPTO_PROVIDER_DESCR_MAX_LEN + 1);
|
||||
|
||||
if (desc->pd_ops_vector != NULL) {
|
||||
|
||||
if (desc->pd_ops_vector->co_control_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_control_ops,
|
||||
sizeof (crypto_control_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_digest_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_digest_ops,
|
||||
sizeof (crypto_digest_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_cipher_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_cipher_ops,
|
||||
sizeof (crypto_cipher_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_mac_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_mac_ops,
|
||||
sizeof (crypto_mac_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_sign_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_sign_ops,
|
||||
sizeof (crypto_sign_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_verify_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_verify_ops,
|
||||
sizeof (crypto_verify_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_dual_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_dual_ops,
|
||||
sizeof (crypto_dual_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_dual_cipher_mac_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_dual_cipher_mac_ops,
|
||||
sizeof (crypto_dual_cipher_mac_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_random_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_random_ops,
|
||||
sizeof (crypto_random_number_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_session_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_session_ops,
|
||||
sizeof (crypto_session_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_object_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_object_ops,
|
||||
sizeof (crypto_object_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_key_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_key_ops,
|
||||
sizeof (crypto_key_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_provider_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_provider_ops,
|
||||
sizeof (crypto_provider_management_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_ctx_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_ctx_ops,
|
||||
sizeof (crypto_ctx_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_mech_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_mech_ops,
|
||||
sizeof (crypto_mech_ops_t));
|
||||
|
||||
if (desc->pd_ops_vector->co_nostore_key_ops != NULL)
|
||||
kmem_free(desc->pd_ops_vector->co_nostore_key_ops,
|
||||
sizeof (crypto_nostore_key_ops_t));
|
||||
|
||||
kmem_free(desc->pd_ops_vector, sizeof (crypto_ops_t));
|
||||
}
|
||||
|
||||
if (desc->pd_mechanisms != NULL)
|
||||
/* free the memory associated with the mechanism info's */
|
||||
kmem_free(desc->pd_mechanisms, sizeof (crypto_mech_info_t) *
|
||||
desc->pd_mech_list_count);
|
||||
|
||||
if (desc->pd_sched_info.ks_taskq != NULL)
|
||||
taskq_destroy(desc->pd_sched_info.ks_taskq);
|
||||
|
||||
kmem_free(desc, sizeof (kcf_provider_desc_t));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns an array of hardware and logical provider descriptors,
|
||||
* a.k.a the PKCS#11 slot list. A REFHOLD is done on each descriptor
|
||||
* before the array is returned. The entire table can be freed by
|
||||
* calling kcf_free_provider_tab().
|
||||
*/
|
||||
int
|
||||
kcf_get_slot_list(uint_t *count, kcf_provider_desc_t ***array,
|
||||
boolean_t unverified)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
kcf_provider_desc_t **p = NULL;
|
||||
char *last;
|
||||
uint_t cnt = 0;
|
||||
uint_t i, j;
|
||||
int rval = CRYPTO_SUCCESS;
|
||||
size_t n, final_size;
|
||||
|
||||
/* count the providers */
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
for (i = 0; i < KCF_MAX_PROVIDERS; i++) {
|
||||
if ((prov_desc = prov_tab[i]) != NULL &&
|
||||
((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
|
||||
prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
|
||||
if (KCF_IS_PROV_USABLE(prov_desc) ||
|
||||
(unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
if (cnt == 0)
|
||||
goto out;
|
||||
|
||||
n = cnt * sizeof (kcf_provider_desc_t *);
|
||||
again:
|
||||
p = kmem_zalloc(n, KM_SLEEP);
|
||||
|
||||
/* pointer to last entry in the array */
|
||||
last = (char *)&p[cnt-1];
|
||||
|
||||
mutex_enter(&prov_tab_mutex);
|
||||
/* fill the slot list */
|
||||
for (i = 0, j = 0; i < KCF_MAX_PROVIDERS; i++) {
|
||||
if ((prov_desc = prov_tab[i]) != NULL &&
|
||||
((prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
(prov_desc->pd_flags & CRYPTO_HIDE_PROVIDER) == 0) ||
|
||||
prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER)) {
|
||||
if (KCF_IS_PROV_USABLE(prov_desc) ||
|
||||
(unverified && KCF_IS_PROV_UNVERIFIED(prov_desc))) {
|
||||
if ((char *)&p[j] > last) {
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
kcf_free_provider_tab(cnt, p);
|
||||
n = n << 1;
|
||||
cnt = cnt << 1;
|
||||
goto again;
|
||||
}
|
||||
p[j++] = prov_desc;
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_exit(&prov_tab_mutex);
|
||||
|
||||
final_size = j * sizeof (kcf_provider_desc_t *);
|
||||
cnt = j;
|
||||
ASSERT(final_size <= n);
|
||||
|
||||
/* check if buffer we allocated is too large */
|
||||
if (final_size < n) {
|
||||
char *final_buffer = NULL;
|
||||
|
||||
if (final_size > 0) {
|
||||
final_buffer = kmem_alloc(final_size, KM_SLEEP);
|
||||
bcopy(p, final_buffer, final_size);
|
||||
}
|
||||
kmem_free(p, n);
|
||||
p = (kcf_provider_desc_t **)final_buffer;
|
||||
}
|
||||
out:
|
||||
*count = cnt;
|
||||
*array = p;
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an array of hardware provider descriptors. A REFRELE
|
||||
* is done on each descriptor before the table is freed.
|
||||
*/
|
||||
void
|
||||
kcf_free_provider_tab(uint_t count, kcf_provider_desc_t **array)
|
||||
{
|
||||
kcf_provider_desc_t *prov_desc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((prov_desc = array[i]) != NULL) {
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
}
|
||||
}
|
||||
kmem_free(array, count * sizeof (kcf_provider_desc_t *));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns in the location pointed to by pd a pointer to the descriptor
|
||||
* for the software provider for the specified mechanism.
|
||||
* The provider descriptor is returned held and it is the caller's
|
||||
* responsibility to release it when done. The mechanism entry
|
||||
* is returned if the optional argument mep is non NULL.
|
||||
*
|
||||
* Returns one of the CRYPTO_ * error codes on failure, and
|
||||
* CRYPTO_SUCCESS on success.
|
||||
*/
|
||||
int
|
||||
kcf_get_sw_prov(crypto_mech_type_t mech_type, kcf_provider_desc_t **pd,
|
||||
kcf_mech_entry_t **mep, boolean_t log_warn)
|
||||
{
|
||||
kcf_mech_entry_t *me;
|
||||
|
||||
/* get the mechanism entry for this mechanism */
|
||||
if (kcf_get_mech_entry(mech_type, &me) != KCF_SUCCESS)
|
||||
return (CRYPTO_MECHANISM_INVALID);
|
||||
|
||||
/*
|
||||
* Get the software provider for this mechanism.
|
||||
* Lock the mech_entry until we grab the 'pd'.
|
||||
*/
|
||||
mutex_enter(&me->me_mutex);
|
||||
|
||||
if (me->me_sw_prov == NULL ||
|
||||
(*pd = me->me_sw_prov->pm_prov_desc) == NULL) {
|
||||
/* no SW provider for this mechanism */
|
||||
if (log_warn)
|
||||
cmn_err(CE_WARN, "no SW provider for \"%s\"\n",
|
||||
me->me_name);
|
||||
mutex_exit(&me->me_mutex);
|
||||
return (CRYPTO_MECH_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
KCF_PROV_REFHOLD(*pd);
|
||||
mutex_exit(&me->me_mutex);
|
||||
|
||||
if (mep != NULL)
|
||||
*mep = me;
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
1763
module/icp/core/kcf_sched.c
Normal file
1763
module/icp/core/kcf_sched.c
Normal file
File diff suppressed because it is too large
Load Diff
152
module/icp/illumos-crypto.c
Normal file
152
module/icp/illumos-crypto.c
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#else
|
||||
#define __exit
|
||||
#define __init
|
||||
#endif
|
||||
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/api.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/crypto/sched_impl.h>
|
||||
#include <sys/modhash_impl.h>
|
||||
#include <sys/crypto/icp.h>
|
||||
|
||||
/*
|
||||
* Changes made to the original Illumos Crypto Layer for the ICP:
|
||||
*
|
||||
* Several changes were needed to allow the Illumos Crypto Layer
|
||||
* to work in the Linux kernel. Almost all of the changes fall into
|
||||
* one of the following categories:
|
||||
*
|
||||
* 1) Moving the syntax to the C90: This was mostly a matter of
|
||||
* changing func() definitions to func(void). In a few cases,
|
||||
* initializations of structs with unions needed to have brackets
|
||||
* added.
|
||||
*
|
||||
* 2) Changes to allow userspace compilation: The ICP is meant to be
|
||||
* compiled and used in both userspace and kernel space (for ztest and
|
||||
* libzfs), so the _KERNEL macros did not make sense anymore. For the
|
||||
* same reason, many header includes were also changed to use
|
||||
* sys/zfs_context.h
|
||||
*
|
||||
* 3) Moving to a statically compiled architecture: At some point in
|
||||
* the future it may make sense to have encryption algorithms that are
|
||||
* loadable into the ICP at runtime via separate kernel modules.
|
||||
* However, considering that this code will probably not see much use
|
||||
* outside of zfs and zfs encryption only requires aes and sha256
|
||||
* algorithms it seemed like more trouble than it was worth to port over
|
||||
* Illumos's kernel module structure to a Linux kernel module. In
|
||||
* addition, The Illumos code related to keeping track of kernel modules
|
||||
* is very much tied to the Illumos OS and proved difficult to port to
|
||||
* Linux. Therefore, the structure of the ICP was simplified to work
|
||||
* statically and several pieces of code responsible for keeping track
|
||||
* of Illumos kernel modules were removed and simplified. All module
|
||||
* initialization and destruction is now called in this file during
|
||||
* Linux kernel module loading and unloading.
|
||||
*
|
||||
* 4) Adding destructors: The Illumos Crypto Layer is built into
|
||||
* the Illumos kernel and is not meant to be unloaded. Some destructors
|
||||
* were added to allow the ICP to be unloaded without leaking
|
||||
* structures.
|
||||
*
|
||||
* 5) Removing CRYPTO_DATA_MBLK related structures and code:
|
||||
* crypto_data_t can have 3 formats, CRYPTO_DATA_RAW, CRYPTO_DATA_UIO,
|
||||
* and CRYPTO_DATA_MBLK. ZFS only requires the first 2 formats, as the
|
||||
* last one is related to streamed data. To simplify the port, code
|
||||
* related to this format was removed.
|
||||
*
|
||||
* 6) Changes for architecture specific code: Some changes were needed
|
||||
* to make architecture specific assembly compile. The biggest change
|
||||
* here was to functions related to detecting CPU capabilities for amd64.
|
||||
* The Illumos Crypto Layer used called into the Illumos kernel's API
|
||||
* to discover these. They have been converted to instead use the
|
||||
* 'cpuid' instruction as per the Intel spec. In addition, references to
|
||||
* the sun4u' and sparc architectures have been removed so that these
|
||||
* will use the generic implementation.
|
||||
*
|
||||
* 7) Removing sha384 and sha512 code: The sha code was actually very
|
||||
* wasy to port. However, the generic sha384 and sha512 code actually
|
||||
* exceeds the stack size on arm and powerpc architectures. In an effort
|
||||
* to remove warnings, this code was removed.
|
||||
*
|
||||
* 8) Change large allocations from kmem_alloc() to vmem_alloc(): In
|
||||
* testing the ICP with the ZFS encryption code, a few allocations were
|
||||
* found that could potentially be very large. These caused the SPL to
|
||||
* throw warnings and so they were changed to use vmem_alloc().
|
||||
*
|
||||
* 9) Makefiles: Makefiles were added that would work with the existing
|
||||
* ZFS Makefiles.
|
||||
*/
|
||||
|
||||
void __exit
|
||||
icp_fini(void)
|
||||
{
|
||||
sha2_mod_fini();
|
||||
sha1_mod_fini();
|
||||
aes_mod_fini();
|
||||
kcf_sched_destroy();
|
||||
kcf_prov_tab_destroy();
|
||||
kcf_destroy_mech_tabs();
|
||||
mod_hash_fini();
|
||||
}
|
||||
|
||||
/* roughly equivalent to kcf.c: _init() */
|
||||
int __init
|
||||
icp_init(void)
|
||||
{
|
||||
/* initialize the mod hash module */
|
||||
mod_hash_init();
|
||||
|
||||
/* initialize the mechanisms tables supported out-of-the-box */
|
||||
kcf_init_mech_tabs();
|
||||
|
||||
/* initialize the providers tables */
|
||||
kcf_prov_tab_init();
|
||||
|
||||
/*
|
||||
* Initialize scheduling structures. Note that this does NOT
|
||||
* start any threads since it might not be safe to do so.
|
||||
*/
|
||||
kcf_sched_init();
|
||||
|
||||
/* initialize algorithms */
|
||||
aes_mod_init();
|
||||
sha1_mod_init();
|
||||
sha2_mod_init();
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined(_KERNEL) && defined(HAVE_SPL)
|
||||
module_exit(icp_fini);
|
||||
module_init(icp_init);
|
||||
MODULE_LICENSE("CDDL");
|
||||
#endif
|
170
module/icp/include/aes/aes_impl.h
Normal file
170
module/icp/include/aes/aes_impl.h
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _AES_IMPL_H
|
||||
#define _AES_IMPL_H
|
||||
|
||||
/*
|
||||
* Common definitions used by AES.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
|
||||
/* Similar to sysmacros.h IS_P2ALIGNED, but checks two pointers: */
|
||||
#define IS_P2ALIGNED2(v, w, a) \
|
||||
((((uintptr_t)(v) | (uintptr_t)(w)) & ((uintptr_t)(a) - 1)) == 0)
|
||||
|
||||
#define AES_BLOCK_LEN 16 /* bytes */
|
||||
/* Round constant length, in number of 32-bit elements: */
|
||||
#define RC_LENGTH (5 * ((AES_BLOCK_LEN) / 4 - 2))
|
||||
|
||||
#define AES_COPY_BLOCK(src, dst) \
|
||||
(dst)[0] = (src)[0]; \
|
||||
(dst)[1] = (src)[1]; \
|
||||
(dst)[2] = (src)[2]; \
|
||||
(dst)[3] = (src)[3]; \
|
||||
(dst)[4] = (src)[4]; \
|
||||
(dst)[5] = (src)[5]; \
|
||||
(dst)[6] = (src)[6]; \
|
||||
(dst)[7] = (src)[7]; \
|
||||
(dst)[8] = (src)[8]; \
|
||||
(dst)[9] = (src)[9]; \
|
||||
(dst)[10] = (src)[10]; \
|
||||
(dst)[11] = (src)[11]; \
|
||||
(dst)[12] = (src)[12]; \
|
||||
(dst)[13] = (src)[13]; \
|
||||
(dst)[14] = (src)[14]; \
|
||||
(dst)[15] = (src)[15]
|
||||
|
||||
#define AES_XOR_BLOCK(src, dst) \
|
||||
(dst)[0] ^= (src)[0]; \
|
||||
(dst)[1] ^= (src)[1]; \
|
||||
(dst)[2] ^= (src)[2]; \
|
||||
(dst)[3] ^= (src)[3]; \
|
||||
(dst)[4] ^= (src)[4]; \
|
||||
(dst)[5] ^= (src)[5]; \
|
||||
(dst)[6] ^= (src)[6]; \
|
||||
(dst)[7] ^= (src)[7]; \
|
||||
(dst)[8] ^= (src)[8]; \
|
||||
(dst)[9] ^= (src)[9]; \
|
||||
(dst)[10] ^= (src)[10]; \
|
||||
(dst)[11] ^= (src)[11]; \
|
||||
(dst)[12] ^= (src)[12]; \
|
||||
(dst)[13] ^= (src)[13]; \
|
||||
(dst)[14] ^= (src)[14]; \
|
||||
(dst)[15] ^= (src)[15]
|
||||
|
||||
/* AES key size definitions */
|
||||
#define AES_MINBITS 128
|
||||
#define AES_MINBYTES ((AES_MINBITS) >> 3)
|
||||
#define AES_MAXBITS 256
|
||||
#define AES_MAXBYTES ((AES_MAXBITS) >> 3)
|
||||
|
||||
#define AES_MIN_KEY_BYTES ((AES_MINBITS) >> 3)
|
||||
#define AES_MAX_KEY_BYTES ((AES_MAXBITS) >> 3)
|
||||
#define AES_192_KEY_BYTES 24
|
||||
#define AES_IV_LEN 16
|
||||
|
||||
/* AES key schedule may be implemented with 32- or 64-bit elements: */
|
||||
#define AES_32BIT_KS 32
|
||||
#define AES_64BIT_KS 64
|
||||
|
||||
#define MAX_AES_NR 14 /* Maximum number of rounds */
|
||||
#define MAX_AES_NB 4 /* Number of columns comprising a state */
|
||||
|
||||
typedef union {
|
||||
#ifdef sun4u
|
||||
uint64_t ks64[((MAX_AES_NR) + 1) * (MAX_AES_NB)];
|
||||
#endif
|
||||
uint32_t ks32[((MAX_AES_NR) + 1) * (MAX_AES_NB)];
|
||||
} aes_ks_t;
|
||||
|
||||
/* aes_key.flags value: */
|
||||
#define INTEL_AES_NI_CAPABLE 0x1 /* AES-NI instructions present */
|
||||
|
||||
typedef struct aes_key aes_key_t;
|
||||
struct aes_key {
|
||||
aes_ks_t encr_ks; /* encryption key schedule */
|
||||
aes_ks_t decr_ks; /* decryption key schedule */
|
||||
#ifdef __amd64
|
||||
long double align128; /* Align fields above for Intel AES-NI */
|
||||
int flags; /* implementation-dependent flags */
|
||||
#endif /* __amd64 */
|
||||
int nr; /* number of rounds (10, 12, or 14) */
|
||||
int type; /* key schedule size (32 or 64 bits) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Core AES functions.
|
||||
* ks and keysched are pointers to aes_key_t.
|
||||
* They are declared void* as they are intended to be opaque types.
|
||||
* Use function aes_alloc_keysched() to allocate memory for ks and keysched.
|
||||
*/
|
||||
extern void *aes_alloc_keysched(size_t *size, int kmflag);
|
||||
extern void aes_init_keysched(const uint8_t *cipherKey, uint_t keyBits,
|
||||
void *keysched);
|
||||
extern int aes_encrypt_block(const void *ks, const uint8_t *pt, uint8_t *ct);
|
||||
extern int aes_decrypt_block(const void *ks, const uint8_t *ct, uint8_t *pt);
|
||||
|
||||
/*
|
||||
* AES mode functions.
|
||||
* The first 2 functions operate on 16-byte AES blocks.
|
||||
*/
|
||||
extern void aes_copy_block(uint8_t *in, uint8_t *out);
|
||||
extern void aes_xor_block(uint8_t *data, uint8_t *dst);
|
||||
|
||||
/* Note: ctx is a pointer to aes_ctx_t defined in modes.h */
|
||||
extern int aes_encrypt_contiguous_blocks(void *ctx, char *data, size_t length,
|
||||
crypto_data_t *out);
|
||||
extern int aes_decrypt_contiguous_blocks(void *ctx, char *data, size_t length,
|
||||
crypto_data_t *out);
|
||||
|
||||
/*
|
||||
* The following definitions and declarations are only used by AES FIPS POST
|
||||
*/
|
||||
#ifdef _AES_IMPL
|
||||
|
||||
typedef enum aes_mech_type {
|
||||
AES_ECB_MECH_INFO_TYPE, /* SUN_CKM_AES_ECB */
|
||||
AES_CBC_MECH_INFO_TYPE, /* SUN_CKM_AES_CBC */
|
||||
AES_CBC_PAD_MECH_INFO_TYPE, /* SUN_CKM_AES_CBC_PAD */
|
||||
AES_CTR_MECH_INFO_TYPE, /* SUN_CKM_AES_CTR */
|
||||
AES_CCM_MECH_INFO_TYPE, /* SUN_CKM_AES_CCM */
|
||||
AES_GCM_MECH_INFO_TYPE, /* SUN_CKM_AES_GCM */
|
||||
AES_GMAC_MECH_INFO_TYPE /* SUN_CKM_AES_GMAC */
|
||||
} aes_mech_type_t;
|
||||
|
||||
#endif /* _AES_IMPL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _AES_IMPL_H */
|
385
module/icp/include/modes/modes.h
Normal file
385
module/icp/include/modes/modes.h
Normal file
@ -0,0 +1,385 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_CRYPTO_MODES_H
|
||||
#define _COMMON_CRYPTO_MODES_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
|
||||
#define ECB_MODE 0x00000002
|
||||
#define CBC_MODE 0x00000004
|
||||
#define CTR_MODE 0x00000008
|
||||
#define CCM_MODE 0x00000010
|
||||
#define GCM_MODE 0x00000020
|
||||
#define GMAC_MODE 0x00000040
|
||||
|
||||
/*
|
||||
* cc_keysched: Pointer to key schedule.
|
||||
*
|
||||
* cc_keysched_len: Length of the key schedule.
|
||||
*
|
||||
* cc_remainder: This is for residual data, i.e. data that can't
|
||||
* be processed because there are too few bytes.
|
||||
* Must wait until more data arrives.
|
||||
*
|
||||
* cc_remainder_len: Number of bytes in cc_remainder.
|
||||
*
|
||||
* cc_iv: Scratch buffer that sometimes contains the IV.
|
||||
*
|
||||
* cc_lastp: Pointer to previous block of ciphertext.
|
||||
*
|
||||
* cc_copy_to: Pointer to where encrypted residual data needs
|
||||
* to be copied.
|
||||
*
|
||||
* cc_flags: PROVIDER_OWNS_KEY_SCHEDULE
|
||||
* When a context is freed, it is necessary
|
||||
* to know whether the key schedule was allocated
|
||||
* by the caller, or internally, e.g. an init routine.
|
||||
* If allocated by the latter, then it needs to be freed.
|
||||
*
|
||||
* ECB_MODE, CBC_MODE, CTR_MODE, or CCM_MODE
|
||||
*/
|
||||
struct common_ctx {
|
||||
void *cc_keysched;
|
||||
size_t cc_keysched_len;
|
||||
uint64_t cc_iv[2];
|
||||
uint64_t cc_remainder[2];
|
||||
size_t cc_remainder_len;
|
||||
uint8_t *cc_lastp;
|
||||
uint8_t *cc_copy_to;
|
||||
uint32_t cc_flags;
|
||||
};
|
||||
|
||||
typedef struct common_ctx common_ctx_t;
|
||||
|
||||
typedef struct ecb_ctx {
|
||||
struct common_ctx ecb_common;
|
||||
uint64_t ecb_lastblock[2];
|
||||
} ecb_ctx_t;
|
||||
|
||||
#define ecb_keysched ecb_common.cc_keysched
|
||||
#define ecb_keysched_len ecb_common.cc_keysched_len
|
||||
#define ecb_iv ecb_common.cc_iv
|
||||
#define ecb_remainder ecb_common.cc_remainder
|
||||
#define ecb_remainder_len ecb_common.cc_remainder_len
|
||||
#define ecb_lastp ecb_common.cc_lastp
|
||||
#define ecb_copy_to ecb_common.cc_copy_to
|
||||
#define ecb_flags ecb_common.cc_flags
|
||||
|
||||
typedef struct cbc_ctx {
|
||||
struct common_ctx cbc_common;
|
||||
uint64_t cbc_lastblock[2];
|
||||
} cbc_ctx_t;
|
||||
|
||||
#define cbc_keysched cbc_common.cc_keysched
|
||||
#define cbc_keysched_len cbc_common.cc_keysched_len
|
||||
#define cbc_iv cbc_common.cc_iv
|
||||
#define cbc_remainder cbc_common.cc_remainder
|
||||
#define cbc_remainder_len cbc_common.cc_remainder_len
|
||||
#define cbc_lastp cbc_common.cc_lastp
|
||||
#define cbc_copy_to cbc_common.cc_copy_to
|
||||
#define cbc_flags cbc_common.cc_flags
|
||||
|
||||
/*
|
||||
* ctr_lower_mask Bit-mask for lower 8 bytes of counter block.
|
||||
* ctr_upper_mask Bit-mask for upper 8 bytes of counter block.
|
||||
*/
|
||||
typedef struct ctr_ctx {
|
||||
struct common_ctx ctr_common;
|
||||
uint64_t ctr_lower_mask;
|
||||
uint64_t ctr_upper_mask;
|
||||
uint32_t ctr_tmp[4];
|
||||
} ctr_ctx_t;
|
||||
|
||||
/*
|
||||
* ctr_cb Counter block.
|
||||
*/
|
||||
#define ctr_keysched ctr_common.cc_keysched
|
||||
#define ctr_keysched_len ctr_common.cc_keysched_len
|
||||
#define ctr_cb ctr_common.cc_iv
|
||||
#define ctr_remainder ctr_common.cc_remainder
|
||||
#define ctr_remainder_len ctr_common.cc_remainder_len
|
||||
#define ctr_lastp ctr_common.cc_lastp
|
||||
#define ctr_copy_to ctr_common.cc_copy_to
|
||||
#define ctr_flags ctr_common.cc_flags
|
||||
|
||||
/*
|
||||
*
|
||||
* ccm_mac_len: Stores length of the MAC in CCM mode.
|
||||
* ccm_mac_buf: Stores the intermediate value for MAC in CCM encrypt.
|
||||
* In CCM decrypt, stores the input MAC value.
|
||||
* ccm_data_len: Length of the plaintext for CCM mode encrypt, or
|
||||
* length of the ciphertext for CCM mode decrypt.
|
||||
* ccm_processed_data_len:
|
||||
* Length of processed plaintext in CCM mode encrypt,
|
||||
* or length of processed ciphertext for CCM mode decrypt.
|
||||
* ccm_processed_mac_len:
|
||||
* Length of MAC data accumulated in CCM mode decrypt.
|
||||
*
|
||||
* ccm_pt_buf: Only used in CCM mode decrypt. It stores the
|
||||
* decrypted plaintext to be returned when
|
||||
* MAC verification succeeds in decrypt_final.
|
||||
* Memory for this should be allocated in the AES module.
|
||||
*
|
||||
*/
|
||||
typedef struct ccm_ctx {
|
||||
struct common_ctx ccm_common;
|
||||
uint32_t ccm_tmp[4];
|
||||
size_t ccm_mac_len;
|
||||
uint64_t ccm_mac_buf[2];
|
||||
size_t ccm_data_len;
|
||||
size_t ccm_processed_data_len;
|
||||
size_t ccm_processed_mac_len;
|
||||
uint8_t *ccm_pt_buf;
|
||||
uint64_t ccm_mac_input_buf[2];
|
||||
uint64_t ccm_counter_mask;
|
||||
} ccm_ctx_t;
|
||||
|
||||
#define ccm_keysched ccm_common.cc_keysched
|
||||
#define ccm_keysched_len ccm_common.cc_keysched_len
|
||||
#define ccm_cb ccm_common.cc_iv
|
||||
#define ccm_remainder ccm_common.cc_remainder
|
||||
#define ccm_remainder_len ccm_common.cc_remainder_len
|
||||
#define ccm_lastp ccm_common.cc_lastp
|
||||
#define ccm_copy_to ccm_common.cc_copy_to
|
||||
#define ccm_flags ccm_common.cc_flags
|
||||
|
||||
/*
|
||||
* gcm_tag_len: Length of authentication tag.
|
||||
*
|
||||
* gcm_ghash: Stores output from the GHASH function.
|
||||
*
|
||||
* gcm_processed_data_len:
|
||||
* Length of processed plaintext (encrypt) or
|
||||
* length of processed ciphertext (decrypt).
|
||||
*
|
||||
* gcm_pt_buf: Stores the decrypted plaintext returned by
|
||||
* decrypt_final when the computed authentication
|
||||
* tag matches the user supplied tag.
|
||||
*
|
||||
* gcm_pt_buf_len: Length of the plaintext buffer.
|
||||
*
|
||||
* gcm_H: Subkey.
|
||||
*
|
||||
* gcm_J0: Pre-counter block generated from the IV.
|
||||
*
|
||||
* gcm_len_a_len_c: 64-bit representations of the bit lengths of
|
||||
* AAD and ciphertext.
|
||||
*
|
||||
* gcm_kmflag: Current value of kmflag. Used only for allocating
|
||||
* the plaintext buffer during decryption.
|
||||
*/
|
||||
typedef struct gcm_ctx {
|
||||
struct common_ctx gcm_common;
|
||||
size_t gcm_tag_len;
|
||||
size_t gcm_processed_data_len;
|
||||
size_t gcm_pt_buf_len;
|
||||
uint32_t gcm_tmp[4];
|
||||
uint64_t gcm_ghash[2];
|
||||
uint64_t gcm_H[2];
|
||||
uint64_t gcm_J0[2];
|
||||
uint64_t gcm_len_a_len_c[2];
|
||||
uint8_t *gcm_pt_buf;
|
||||
int gcm_kmflag;
|
||||
} gcm_ctx_t;
|
||||
|
||||
#define gcm_keysched gcm_common.cc_keysched
|
||||
#define gcm_keysched_len gcm_common.cc_keysched_len
|
||||
#define gcm_cb gcm_common.cc_iv
|
||||
#define gcm_remainder gcm_common.cc_remainder
|
||||
#define gcm_remainder_len gcm_common.cc_remainder_len
|
||||
#define gcm_lastp gcm_common.cc_lastp
|
||||
#define gcm_copy_to gcm_common.cc_copy_to
|
||||
#define gcm_flags gcm_common.cc_flags
|
||||
|
||||
#define AES_GMAC_IV_LEN 12
|
||||
#define AES_GMAC_TAG_BITS 128
|
||||
|
||||
typedef struct aes_ctx {
|
||||
union {
|
||||
ecb_ctx_t acu_ecb;
|
||||
cbc_ctx_t acu_cbc;
|
||||
ctr_ctx_t acu_ctr;
|
||||
ccm_ctx_t acu_ccm;
|
||||
gcm_ctx_t acu_gcm;
|
||||
} acu;
|
||||
} aes_ctx_t;
|
||||
|
||||
#define ac_flags acu.acu_ecb.ecb_common.cc_flags
|
||||
#define ac_remainder_len acu.acu_ecb.ecb_common.cc_remainder_len
|
||||
#define ac_keysched acu.acu_ecb.ecb_common.cc_keysched
|
||||
#define ac_keysched_len acu.acu_ecb.ecb_common.cc_keysched_len
|
||||
#define ac_iv acu.acu_ecb.ecb_common.cc_iv
|
||||
#define ac_lastp acu.acu_ecb.ecb_common.cc_lastp
|
||||
#define ac_pt_buf acu.acu_ccm.ccm_pt_buf
|
||||
#define ac_mac_len acu.acu_ccm.ccm_mac_len
|
||||
#define ac_data_len acu.acu_ccm.ccm_data_len
|
||||
#define ac_processed_mac_len acu.acu_ccm.ccm_processed_mac_len
|
||||
#define ac_processed_data_len acu.acu_ccm.ccm_processed_data_len
|
||||
#define ac_tag_len acu.acu_gcm.gcm_tag_len
|
||||
|
||||
typedef struct blowfish_ctx {
|
||||
union {
|
||||
ecb_ctx_t bcu_ecb;
|
||||
cbc_ctx_t bcu_cbc;
|
||||
} bcu;
|
||||
} blowfish_ctx_t;
|
||||
|
||||
#define bc_flags bcu.bcu_ecb.ecb_common.cc_flags
|
||||
#define bc_remainder_len bcu.bcu_ecb.ecb_common.cc_remainder_len
|
||||
#define bc_keysched bcu.bcu_ecb.ecb_common.cc_keysched
|
||||
#define bc_keysched_len bcu.bcu_ecb.ecb_common.cc_keysched_len
|
||||
#define bc_iv bcu.bcu_ecb.ecb_common.cc_iv
|
||||
#define bc_lastp bcu.bcu_ecb.ecb_common.cc_lastp
|
||||
|
||||
typedef struct des_ctx {
|
||||
union {
|
||||
ecb_ctx_t dcu_ecb;
|
||||
cbc_ctx_t dcu_cbc;
|
||||
} dcu;
|
||||
} des_ctx_t;
|
||||
|
||||
#define dc_flags dcu.dcu_ecb.ecb_common.cc_flags
|
||||
#define dc_remainder_len dcu.dcu_ecb.ecb_common.cc_remainder_len
|
||||
#define dc_keysched dcu.dcu_ecb.ecb_common.cc_keysched
|
||||
#define dc_keysched_len dcu.dcu_ecb.ecb_common.cc_keysched_len
|
||||
#define dc_iv dcu.dcu_ecb.ecb_common.cc_iv
|
||||
#define dc_lastp dcu.dcu_ecb.ecb_common.cc_lastp
|
||||
|
||||
extern int ecb_cipher_contiguous_blocks(ecb_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t, int (*cipher)(const void *, const uint8_t *,
|
||||
uint8_t *));
|
||||
|
||||
extern int cbc_encrypt_contiguous_blocks(cbc_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*encrypt)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int cbc_decrypt_contiguous_blocks(cbc_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*decrypt)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int ctr_mode_contiguous_blocks(ctr_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*cipher)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int ccm_mode_encrypt_contiguous_blocks(ccm_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int ccm_mode_decrypt_contiguous_blocks(ccm_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int gcm_mode_encrypt_contiguous_blocks(gcm_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int gcm_mode_decrypt_contiguous_blocks(gcm_ctx_t *, char *, size_t,
|
||||
crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
int ccm_encrypt_final(ccm_ctx_t *, crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
int gcm_encrypt_final(gcm_ctx_t *, crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int ccm_decrypt_final(ccm_ctx_t *, crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int gcm_decrypt_final(gcm_ctx_t *, crypto_data_t *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int ctr_mode_final(ctr_ctx_t *, crypto_data_t *,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *));
|
||||
|
||||
extern int cbc_init_ctx(cbc_ctx_t *, char *, size_t, size_t,
|
||||
void (*copy_block)(uint8_t *, uint64_t *));
|
||||
|
||||
extern int ctr_init_ctx(ctr_ctx_t *, ulong_t, uint8_t *,
|
||||
void (*copy_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int ccm_init_ctx(ccm_ctx_t *, char *, int, boolean_t, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int gcm_init_ctx(gcm_ctx_t *, char *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern int gmac_init_ctx(gcm_ctx_t *, char *, size_t,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *),
|
||||
void (*copy_block)(uint8_t *, uint8_t *),
|
||||
void (*xor_block)(uint8_t *, uint8_t *));
|
||||
|
||||
extern void calculate_ccm_mac(ccm_ctx_t *, uint8_t *,
|
||||
int (*encrypt_block)(const void *, const uint8_t *, uint8_t *));
|
||||
|
||||
extern void gcm_mul(uint64_t *, uint64_t *, uint64_t *);
|
||||
|
||||
extern void crypto_init_ptrs(crypto_data_t *, void **, offset_t *);
|
||||
extern void crypto_get_ptrs(crypto_data_t *, void **, offset_t *,
|
||||
uint8_t **, size_t *, uint8_t **, size_t);
|
||||
|
||||
extern void *ecb_alloc_ctx(int);
|
||||
extern void *cbc_alloc_ctx(int);
|
||||
extern void *ctr_alloc_ctx(int);
|
||||
extern void *ccm_alloc_ctx(int);
|
||||
extern void *gcm_alloc_ctx(int);
|
||||
extern void *gmac_alloc_ctx(int);
|
||||
extern void crypto_free_mode_ctx(void *);
|
||||
extern void gcm_set_kmflag(gcm_ctx_t *, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _COMMON_CRYPTO_MODES_H */
|
61
module/icp/include/sha1/sha1.h
Normal file
61
module/icp/include/sha1/sha1.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SHA1_H
|
||||
#define _SYS_SHA1_H
|
||||
|
||||
#include <sys/types.h> /* for uint_* */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NOTE: n2rng (Niagara2 RNG driver) accesses the state field of
|
||||
* SHA1_CTX directly. NEVER change this structure without verifying
|
||||
* compatiblity with n2rng. The important thing is that the state
|
||||
* must be in a field declared as uint32_t state[5].
|
||||
*/
|
||||
/* SHA-1 context. */
|
||||
typedef struct {
|
||||
uint32_t state[5]; /* state (ABCDE) */
|
||||
uint32_t count[2]; /* number of bits, modulo 2^64 (msb first) */
|
||||
union {
|
||||
uint8_t buf8[64]; /* undigested input */
|
||||
uint32_t buf32[16]; /* realigned input */
|
||||
} buf_un;
|
||||
} SHA1_CTX;
|
||||
|
||||
#define SHA1_DIGEST_LENGTH 20
|
||||
|
||||
void SHA1Init(SHA1_CTX *);
|
||||
void SHA1Update(SHA1_CTX *, const void *, size_t);
|
||||
void SHA1Final(void *, SHA1_CTX *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_SHA1_H */
|
65
module/icp/include/sha1/sha1_consts.h
Normal file
65
module/icp/include/sha1/sha1_consts.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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) 1998, by Sun Microsystems, Inc.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SHA1_CONSTS_H
|
||||
#define _SYS_SHA1_CONSTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* as explained in sha1.c, loading 32-bit constants on a sparc is expensive
|
||||
* since it involves both a `sethi' and an `or'. thus, we instead use `ld'
|
||||
* to load the constants from an array called `sha1_consts'. however, on
|
||||
* intel (and perhaps other processors), it is cheaper to load the constant
|
||||
* directly. thus, the c code in SHA1Transform() uses the macro SHA1_CONST()
|
||||
* which either expands to a constant or an array reference, depending on
|
||||
* the architecture the code is being compiled for.
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* uint32_t */
|
||||
|
||||
extern const uint32_t sha1_consts[];
|
||||
|
||||
#if defined(__sparc)
|
||||
#define SHA1_CONST(x) (sha1_consts[x])
|
||||
#else
|
||||
#define SHA1_CONST(x) (SHA1_CONST_ ## x)
|
||||
#endif
|
||||
|
||||
/* constants, as provided in FIPS 180-1 */
|
||||
|
||||
#define SHA1_CONST_0 0x5a827999U
|
||||
#define SHA1_CONST_1 0x6ed9eba1U
|
||||
#define SHA1_CONST_2 0x8f1bbcdcU
|
||||
#define SHA1_CONST_3 0xca62c1d6U
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_SHA1_CONSTS_H */
|
73
module/icp/include/sha1/sha1_impl.h
Normal file
73
module/icp/include/sha1/sha1_impl.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_IMPL_H
|
||||
#define _SHA1_IMPL_H
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SHA1_HASH_SIZE 20 /* SHA_1 digest length in bytes */
|
||||
#define SHA1_DIGEST_LENGTH 20 /* SHA1 digest length in bytes */
|
||||
#define SHA1_HMAC_BLOCK_SIZE 64 /* SHA1-HMAC block size */
|
||||
#define SHA1_HMAC_MIN_KEY_LEN 1 /* SHA1-HMAC min key length in bytes */
|
||||
#define SHA1_HMAC_MAX_KEY_LEN INT_MAX /* SHA1-HMAC max key length in bytes */
|
||||
#define SHA1_HMAC_INTS_PER_BLOCK (SHA1_HMAC_BLOCK_SIZE/sizeof (uint32_t))
|
||||
|
||||
/*
|
||||
* CSPI information (entry points, provider info, etc.)
|
||||
*/
|
||||
typedef enum sha1_mech_type {
|
||||
SHA1_MECH_INFO_TYPE, /* SUN_CKM_SHA1 */
|
||||
SHA1_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA1_HMAC */
|
||||
SHA1_HMAC_GEN_MECH_INFO_TYPE /* SUN_CKM_SHA1_HMAC_GENERAL */
|
||||
} sha1_mech_type_t;
|
||||
|
||||
/*
|
||||
* Context for SHA1 mechanism.
|
||||
*/
|
||||
typedef struct sha1_ctx {
|
||||
sha1_mech_type_t sc_mech_type; /* type of context */
|
||||
SHA1_CTX sc_sha1_ctx; /* SHA1 context */
|
||||
} sha1_ctx_t;
|
||||
|
||||
/*
|
||||
* Context for SHA1-HMAC and SHA1-HMAC-GENERAL mechanisms.
|
||||
*/
|
||||
typedef struct sha1_hmac_ctx {
|
||||
sha1_mech_type_t hc_mech_type; /* type of context */
|
||||
uint32_t hc_digest_len; /* digest len in bytes */
|
||||
SHA1_CTX hc_icontext; /* inner SHA1 context */
|
||||
SHA1_CTX hc_ocontext; /* outer SHA1 context */
|
||||
} sha1_hmac_ctx_t;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SHA1_IMPL_H */
|
116
module/icp/include/sha2/sha2.h
Normal file
116
module/icp/include/sha2/sha2.h
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* Copyright 2013 Saso Kiselkov. All rights reserved. */
|
||||
|
||||
#ifndef _SYS_SHA2_H
|
||||
#define _SYS_SHA2_H
|
||||
|
||||
#include <sys/types.h> /* for uint_* */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SHA2_HMAC_MIN_KEY_LEN 1 /* SHA2-HMAC min key length in bytes */
|
||||
#define SHA2_HMAC_MAX_KEY_LEN INT_MAX /* SHA2-HMAC max key length in bytes */
|
||||
|
||||
#define SHA256_DIGEST_LENGTH 32 /* SHA256 digest length in bytes */
|
||||
|
||||
#define SHA256_HMAC_BLOCK_SIZE 64 /* SHA256-HMAC block size */
|
||||
|
||||
#define SHA256 0
|
||||
#define SHA256_HMAC 1
|
||||
#define SHA256_HMAC_GEN 2
|
||||
|
||||
/*
|
||||
* SHA2 context.
|
||||
* The contents of this structure are a private interface between the
|
||||
* Init/Update/Final calls of the functions defined below.
|
||||
* Callers must never attempt to read or write any of the fields
|
||||
* in this structure directly.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t algotype; /* Algorithm Type */
|
||||
|
||||
/* state (ABCDEFGH) */
|
||||
union {
|
||||
uint32_t s32[8]; /* for SHA256 */
|
||||
uint64_t s64[8]; /* for SHA384/512 */
|
||||
} state;
|
||||
/* number of bits */
|
||||
union {
|
||||
uint32_t c32[2]; /* for SHA256 , modulo 2^64 */
|
||||
uint64_t c64[2]; /* for SHA384/512, modulo 2^128 */
|
||||
} count;
|
||||
union {
|
||||
uint8_t buf8[128]; /* undigested input */
|
||||
uint32_t buf32[32]; /* realigned input */
|
||||
uint64_t buf64[16]; /* realigned input */
|
||||
} buf_un;
|
||||
} SHA2_CTX;
|
||||
|
||||
typedef SHA2_CTX SHA256_CTX;
|
||||
typedef SHA2_CTX SHA384_CTX;
|
||||
typedef SHA2_CTX SHA512_CTX;
|
||||
|
||||
extern void SHA2Init(uint64_t mech, SHA2_CTX *);
|
||||
|
||||
extern void SHA2Update(SHA2_CTX *, const void *, size_t);
|
||||
|
||||
extern void SHA2Final(void *, SHA2_CTX *);
|
||||
|
||||
extern void SHA256Init(SHA256_CTX *);
|
||||
|
||||
extern void SHA256Update(SHA256_CTX *, const void *, size_t);
|
||||
|
||||
extern void SHA256Final(void *, SHA256_CTX *);
|
||||
|
||||
#ifdef _SHA2_IMPL
|
||||
/*
|
||||
* The following types/functions are all private to the implementation
|
||||
* of the SHA2 functions and must not be used by consumers of the interface
|
||||
*/
|
||||
|
||||
/*
|
||||
* List of support mechanisms in this module.
|
||||
*
|
||||
* It is important to note that in the module, division or modulus calculations
|
||||
* are used on the enumerated type to determine which mechanism is being used;
|
||||
* therefore, changing the order or additional mechanisms should be done
|
||||
* carefully
|
||||
*/
|
||||
typedef enum sha2_mech_type {
|
||||
SHA256_MECH_INFO_TYPE, /* SUN_CKM_SHA256 */
|
||||
SHA256_HMAC_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC */
|
||||
SHA256_HMAC_GEN_MECH_INFO_TYPE, /* SUN_CKM_SHA256_HMAC_GENERAL */
|
||||
} sha2_mech_type_t;
|
||||
|
||||
#endif /* _SHA2_IMPL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_SHA2_H */
|
219
module/icp/include/sha2/sha2_consts.h
Normal file
219
module/icp/include/sha2/sha2_consts.h
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_SHA2_CONSTS_H
|
||||
#define _SYS_SHA2_CONSTS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Loading 32-bit constants on a sparc is expensive since it involves both
|
||||
* a `sethi' and an `or'. thus, we instead use `ld' to load the constants
|
||||
* from an array called `sha2_consts'. however, on intel (and perhaps other
|
||||
* processors), it is cheaper to load the constant directly. thus, the c
|
||||
* code in SHA transform functions uses the macro SHA2_CONST() which either
|
||||
* expands to a constant or an array reference, depending on
|
||||
* the architecture the code is being compiled for.
|
||||
*
|
||||
* SHA512 constants are used for SHA384
|
||||
*/
|
||||
|
||||
#include <sys/types.h> /* uint32_t */
|
||||
|
||||
extern const uint32_t sha256_consts[];
|
||||
extern const uint64_t sha512_consts[];
|
||||
|
||||
#if defined(__sparc)
|
||||
#define SHA256_CONST(x) (sha256_consts[x])
|
||||
#define SHA512_CONST(x) (sha512_consts[x])
|
||||
#else
|
||||
#define SHA256_CONST(x) (SHA256_CONST_ ## x)
|
||||
#define SHA512_CONST(x) (SHA512_CONST_ ## x)
|
||||
#endif
|
||||
|
||||
/* constants, as provided in FIPS 180-2 */
|
||||
|
||||
#define SHA256_CONST_0 0x428a2f98U
|
||||
#define SHA256_CONST_1 0x71374491U
|
||||
#define SHA256_CONST_2 0xb5c0fbcfU
|
||||
#define SHA256_CONST_3 0xe9b5dba5U
|
||||
#define SHA256_CONST_4 0x3956c25bU
|
||||
#define SHA256_CONST_5 0x59f111f1U
|
||||
#define SHA256_CONST_6 0x923f82a4U
|
||||
#define SHA256_CONST_7 0xab1c5ed5U
|
||||
|
||||
#define SHA256_CONST_8 0xd807aa98U
|
||||
#define SHA256_CONST_9 0x12835b01U
|
||||
#define SHA256_CONST_10 0x243185beU
|
||||
#define SHA256_CONST_11 0x550c7dc3U
|
||||
#define SHA256_CONST_12 0x72be5d74U
|
||||
#define SHA256_CONST_13 0x80deb1feU
|
||||
#define SHA256_CONST_14 0x9bdc06a7U
|
||||
#define SHA256_CONST_15 0xc19bf174U
|
||||
|
||||
#define SHA256_CONST_16 0xe49b69c1U
|
||||
#define SHA256_CONST_17 0xefbe4786U
|
||||
#define SHA256_CONST_18 0x0fc19dc6U
|
||||
#define SHA256_CONST_19 0x240ca1ccU
|
||||
#define SHA256_CONST_20 0x2de92c6fU
|
||||
#define SHA256_CONST_21 0x4a7484aaU
|
||||
#define SHA256_CONST_22 0x5cb0a9dcU
|
||||
#define SHA256_CONST_23 0x76f988daU
|
||||
|
||||
#define SHA256_CONST_24 0x983e5152U
|
||||
#define SHA256_CONST_25 0xa831c66dU
|
||||
#define SHA256_CONST_26 0xb00327c8U
|
||||
#define SHA256_CONST_27 0xbf597fc7U
|
||||
#define SHA256_CONST_28 0xc6e00bf3U
|
||||
#define SHA256_CONST_29 0xd5a79147U
|
||||
#define SHA256_CONST_30 0x06ca6351U
|
||||
#define SHA256_CONST_31 0x14292967U
|
||||
|
||||
#define SHA256_CONST_32 0x27b70a85U
|
||||
#define SHA256_CONST_33 0x2e1b2138U
|
||||
#define SHA256_CONST_34 0x4d2c6dfcU
|
||||
#define SHA256_CONST_35 0x53380d13U
|
||||
#define SHA256_CONST_36 0x650a7354U
|
||||
#define SHA256_CONST_37 0x766a0abbU
|
||||
#define SHA256_CONST_38 0x81c2c92eU
|
||||
#define SHA256_CONST_39 0x92722c85U
|
||||
|
||||
#define SHA256_CONST_40 0xa2bfe8a1U
|
||||
#define SHA256_CONST_41 0xa81a664bU
|
||||
#define SHA256_CONST_42 0xc24b8b70U
|
||||
#define SHA256_CONST_43 0xc76c51a3U
|
||||
#define SHA256_CONST_44 0xd192e819U
|
||||
#define SHA256_CONST_45 0xd6990624U
|
||||
#define SHA256_CONST_46 0xf40e3585U
|
||||
#define SHA256_CONST_47 0x106aa070U
|
||||
|
||||
#define SHA256_CONST_48 0x19a4c116U
|
||||
#define SHA256_CONST_49 0x1e376c08U
|
||||
#define SHA256_CONST_50 0x2748774cU
|
||||
#define SHA256_CONST_51 0x34b0bcb5U
|
||||
#define SHA256_CONST_52 0x391c0cb3U
|
||||
#define SHA256_CONST_53 0x4ed8aa4aU
|
||||
#define SHA256_CONST_54 0x5b9cca4fU
|
||||
#define SHA256_CONST_55 0x682e6ff3U
|
||||
|
||||
#define SHA256_CONST_56 0x748f82eeU
|
||||
#define SHA256_CONST_57 0x78a5636fU
|
||||
#define SHA256_CONST_58 0x84c87814U
|
||||
#define SHA256_CONST_59 0x8cc70208U
|
||||
#define SHA256_CONST_60 0x90befffaU
|
||||
#define SHA256_CONST_61 0xa4506cebU
|
||||
#define SHA256_CONST_62 0xbef9a3f7U
|
||||
#define SHA256_CONST_63 0xc67178f2U
|
||||
|
||||
#define SHA512_CONST_0 0x428a2f98d728ae22ULL
|
||||
#define SHA512_CONST_1 0x7137449123ef65cdULL
|
||||
#define SHA512_CONST_2 0xb5c0fbcfec4d3b2fULL
|
||||
#define SHA512_CONST_3 0xe9b5dba58189dbbcULL
|
||||
#define SHA512_CONST_4 0x3956c25bf348b538ULL
|
||||
#define SHA512_CONST_5 0x59f111f1b605d019ULL
|
||||
#define SHA512_CONST_6 0x923f82a4af194f9bULL
|
||||
#define SHA512_CONST_7 0xab1c5ed5da6d8118ULL
|
||||
#define SHA512_CONST_8 0xd807aa98a3030242ULL
|
||||
#define SHA512_CONST_9 0x12835b0145706fbeULL
|
||||
#define SHA512_CONST_10 0x243185be4ee4b28cULL
|
||||
#define SHA512_CONST_11 0x550c7dc3d5ffb4e2ULL
|
||||
#define SHA512_CONST_12 0x72be5d74f27b896fULL
|
||||
#define SHA512_CONST_13 0x80deb1fe3b1696b1ULL
|
||||
#define SHA512_CONST_14 0x9bdc06a725c71235ULL
|
||||
#define SHA512_CONST_15 0xc19bf174cf692694ULL
|
||||
#define SHA512_CONST_16 0xe49b69c19ef14ad2ULL
|
||||
#define SHA512_CONST_17 0xefbe4786384f25e3ULL
|
||||
#define SHA512_CONST_18 0x0fc19dc68b8cd5b5ULL
|
||||
#define SHA512_CONST_19 0x240ca1cc77ac9c65ULL
|
||||
#define SHA512_CONST_20 0x2de92c6f592b0275ULL
|
||||
#define SHA512_CONST_21 0x4a7484aa6ea6e483ULL
|
||||
#define SHA512_CONST_22 0x5cb0a9dcbd41fbd4ULL
|
||||
#define SHA512_CONST_23 0x76f988da831153b5ULL
|
||||
#define SHA512_CONST_24 0x983e5152ee66dfabULL
|
||||
#define SHA512_CONST_25 0xa831c66d2db43210ULL
|
||||
#define SHA512_CONST_26 0xb00327c898fb213fULL
|
||||
#define SHA512_CONST_27 0xbf597fc7beef0ee4ULL
|
||||
#define SHA512_CONST_28 0xc6e00bf33da88fc2ULL
|
||||
#define SHA512_CONST_29 0xd5a79147930aa725ULL
|
||||
#define SHA512_CONST_30 0x06ca6351e003826fULL
|
||||
#define SHA512_CONST_31 0x142929670a0e6e70ULL
|
||||
#define SHA512_CONST_32 0x27b70a8546d22ffcULL
|
||||
#define SHA512_CONST_33 0x2e1b21385c26c926ULL
|
||||
#define SHA512_CONST_34 0x4d2c6dfc5ac42aedULL
|
||||
#define SHA512_CONST_35 0x53380d139d95b3dfULL
|
||||
#define SHA512_CONST_36 0x650a73548baf63deULL
|
||||
#define SHA512_CONST_37 0x766a0abb3c77b2a8ULL
|
||||
#define SHA512_CONST_38 0x81c2c92e47edaee6ULL
|
||||
#define SHA512_CONST_39 0x92722c851482353bULL
|
||||
#define SHA512_CONST_40 0xa2bfe8a14cf10364ULL
|
||||
#define SHA512_CONST_41 0xa81a664bbc423001ULL
|
||||
#define SHA512_CONST_42 0xc24b8b70d0f89791ULL
|
||||
#define SHA512_CONST_43 0xc76c51a30654be30ULL
|
||||
#define SHA512_CONST_44 0xd192e819d6ef5218ULL
|
||||
#define SHA512_CONST_45 0xd69906245565a910ULL
|
||||
#define SHA512_CONST_46 0xf40e35855771202aULL
|
||||
#define SHA512_CONST_47 0x106aa07032bbd1b8ULL
|
||||
#define SHA512_CONST_48 0x19a4c116b8d2d0c8ULL
|
||||
#define SHA512_CONST_49 0x1e376c085141ab53ULL
|
||||
#define SHA512_CONST_50 0x2748774cdf8eeb99ULL
|
||||
#define SHA512_CONST_51 0x34b0bcb5e19b48a8ULL
|
||||
#define SHA512_CONST_52 0x391c0cb3c5c95a63ULL
|
||||
#define SHA512_CONST_53 0x4ed8aa4ae3418acbULL
|
||||
#define SHA512_CONST_54 0x5b9cca4f7763e373ULL
|
||||
#define SHA512_CONST_55 0x682e6ff3d6b2b8a3ULL
|
||||
#define SHA512_CONST_56 0x748f82ee5defb2fcULL
|
||||
#define SHA512_CONST_57 0x78a5636f43172f60ULL
|
||||
#define SHA512_CONST_58 0x84c87814a1f0ab72ULL
|
||||
#define SHA512_CONST_59 0x8cc702081a6439ecULL
|
||||
#define SHA512_CONST_60 0x90befffa23631e28ULL
|
||||
#define SHA512_CONST_61 0xa4506cebde82bde9ULL
|
||||
#define SHA512_CONST_62 0xbef9a3f7b2c67915ULL
|
||||
#define SHA512_CONST_63 0xc67178f2e372532bULL
|
||||
#define SHA512_CONST_64 0xca273eceea26619cULL
|
||||
#define SHA512_CONST_65 0xd186b8c721c0c207ULL
|
||||
#define SHA512_CONST_66 0xeada7dd6cde0eb1eULL
|
||||
#define SHA512_CONST_67 0xf57d4f7fee6ed178ULL
|
||||
#define SHA512_CONST_68 0x06f067aa72176fbaULL
|
||||
#define SHA512_CONST_69 0x0a637dc5a2c898a6ULL
|
||||
#define SHA512_CONST_70 0x113f9804bef90daeULL
|
||||
#define SHA512_CONST_71 0x1b710b35131c471bULL
|
||||
#define SHA512_CONST_72 0x28db77f523047d84ULL
|
||||
#define SHA512_CONST_73 0x32caab7b40c72493ULL
|
||||
#define SHA512_CONST_74 0x3c9ebe0a15c9bebcULL
|
||||
#define SHA512_CONST_75 0x431d67c49c100d4cULL
|
||||
#define SHA512_CONST_76 0x4cc5d4becb3e42b6ULL
|
||||
#define SHA512_CONST_77 0x597f299cfc657e2aULL
|
||||
#define SHA512_CONST_78 0x5fcb6fab3ad6faecULL
|
||||
#define SHA512_CONST_79 0x6c44198c4a475817ULL
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_SHA2_CONSTS_H */
|
62
module/icp/include/sha2/sha2_impl.h
Normal file
62
module/icp/include/sha2/sha2_impl.h
Normal file
@ -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://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.
|
||||
*/
|
||||
|
||||
#ifndef _SHA2_IMPL_H
|
||||
#define _SHA2_IMPL_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
SHA1_TYPE,
|
||||
SHA256_TYPE,
|
||||
SHA384_TYPE,
|
||||
SHA512_TYPE
|
||||
} sha2_mech_t;
|
||||
|
||||
/*
|
||||
* Context for SHA2 mechanism.
|
||||
*/
|
||||
typedef struct sha2_ctx {
|
||||
sha2_mech_type_t sc_mech_type; /* type of context */
|
||||
SHA2_CTX sc_sha2_ctx; /* SHA2 context */
|
||||
} sha2_ctx_t;
|
||||
|
||||
/*
|
||||
* Context for SHA2 HMAC and HMAC GENERAL mechanisms.
|
||||
*/
|
||||
typedef struct sha2_hmac_ctx {
|
||||
sha2_mech_type_t hc_mech_type; /* type of context */
|
||||
uint32_t hc_digest_len; /* digest len in bytes */
|
||||
SHA2_CTX hc_icontext; /* inner SHA2 context */
|
||||
SHA2_CTX hc_ocontext; /* outer SHA2 context */
|
||||
} sha2_hmac_ctx_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SHA2_IMPL_H */
|
36
module/icp/include/sys/asm_linkage.h
Normal file
36
module/icp/include/sys/asm_linkage.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_ASM_LINKAGE_H
|
||||
#define _SYS_ASM_LINKAGE_H
|
||||
|
||||
#if defined(__i386) || defined(__amd64)
|
||||
|
||||
#include <sys/ia32/asm_linkage.h> /* XX64 x86/sys/asm_linkage.h */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_ASM_LINKAGE_H */
|
183
module/icp/include/sys/bitmap.h
Normal file
183
module/icp/include/sys/bitmap.h
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
|
||||
#ifndef _SYS_BITMAP_H
|
||||
#define _SYS_BITMAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && defined(_ASM_INLINES) && \
|
||||
(defined(__i386) || defined(__amd64))
|
||||
#include <asm/bitmap.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Operations on bitmaps of arbitrary size
|
||||
* A bitmap is a vector of 1 or more ulong_t's.
|
||||
* The user of the package is responsible for range checks and keeping
|
||||
* track of sizes.
|
||||
*/
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_ULSHIFT 6 /* log base 2 of BT_NBIPUL, to extract word index */
|
||||
#define BT_ULSHIFT32 5 /* log base 2 of BT_NBIPUL, to extract word index */
|
||||
#else
|
||||
#define BT_ULSHIFT 5 /* log base 2 of BT_NBIPUL, to extract word index */
|
||||
#endif
|
||||
|
||||
#define BT_NBIPUL (1 << BT_ULSHIFT) /* n bits per ulong_t */
|
||||
#define BT_ULMASK (BT_NBIPUL - 1) /* to extract bit index */
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_NBIPUL32 (1 << BT_ULSHIFT32) /* n bits per ulong_t */
|
||||
#define BT_ULMASK32 (BT_NBIPUL32 - 1) /* to extract bit index */
|
||||
#define BT_ULMAXMASK 0xffffffffffffffff /* used by bt_getlowbit */
|
||||
#else
|
||||
#define BT_ULMAXMASK 0xffffffff
|
||||
#endif
|
||||
|
||||
/*
|
||||
* bitmap is a ulong_t *, bitindex an index_t
|
||||
*
|
||||
* The macros BT_WIM and BT_BIW internal; there is no need
|
||||
* for users of this package to use them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* word in map
|
||||
*/
|
||||
#define BT_WIM(bitmap, bitindex) \
|
||||
((bitmap)[(bitindex) >> BT_ULSHIFT])
|
||||
/*
|
||||
* bit in word
|
||||
*/
|
||||
#define BT_BIW(bitindex) \
|
||||
(1UL << ((bitindex) & BT_ULMASK))
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_WIM32(bitmap, bitindex) \
|
||||
((bitmap)[(bitindex) >> BT_ULSHIFT32])
|
||||
|
||||
#define BT_BIW32(bitindex) \
|
||||
(1UL << ((bitindex) & BT_ULMASK32))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These are public macros
|
||||
*
|
||||
* BT_BITOUL == n bits to n ulong_t's
|
||||
*/
|
||||
#define BT_BITOUL(nbits) \
|
||||
(((nbits) + BT_NBIPUL - 1l) / BT_NBIPUL)
|
||||
#define BT_SIZEOFMAP(nbits) \
|
||||
(BT_BITOUL(nbits) * sizeof (ulong_t))
|
||||
#define BT_TEST(bitmap, bitindex) \
|
||||
((BT_WIM((bitmap), (bitindex)) & BT_BIW(bitindex)) ? 1 : 0)
|
||||
#define BT_SET(bitmap, bitindex) \
|
||||
{ BT_WIM((bitmap), (bitindex)) |= BT_BIW(bitindex); }
|
||||
#define BT_CLEAR(bitmap, bitindex) \
|
||||
{ BT_WIM((bitmap), (bitindex)) &= ~BT_BIW(bitindex); }
|
||||
|
||||
#ifdef _LP64
|
||||
#define BT_BITOUL32(nbits) \
|
||||
(((nbits) + BT_NBIPUL32 - 1l) / BT_NBIPUL32)
|
||||
#define BT_SIZEOFMAP32(nbits) \
|
||||
(BT_BITOUL32(nbits) * sizeof (uint_t))
|
||||
#define BT_TEST32(bitmap, bitindex) \
|
||||
((BT_WIM32((bitmap), (bitindex)) & BT_BIW32(bitindex)) ? 1 : 0)
|
||||
#define BT_SET32(bitmap, bitindex) \
|
||||
{ BT_WIM32((bitmap), (bitindex)) |= BT_BIW32(bitindex); }
|
||||
#define BT_CLEAR32(bitmap, bitindex) \
|
||||
{ BT_WIM32((bitmap), (bitindex)) &= ~BT_BIW32(bitindex); }
|
||||
#endif /* _LP64 */
|
||||
|
||||
|
||||
/*
|
||||
* BIT_ONLYONESET is a private macro not designed for bitmaps of
|
||||
* arbitrary size. u must be an unsigned integer/long. It returns
|
||||
* true if one and only one bit is set in u.
|
||||
*/
|
||||
#define BIT_ONLYONESET(u) \
|
||||
((((u) == 0) ? 0 : ((u) & ((u) - 1)) == 0))
|
||||
|
||||
#ifndef _ASM
|
||||
|
||||
/*
|
||||
* return next available bit index from map with specified number of bits
|
||||
*/
|
||||
extern index_t bt_availbit(ulong_t *bitmap, size_t nbits);
|
||||
/*
|
||||
* find the highest order bit that is on, and is within or below
|
||||
* the word specified by wx
|
||||
*/
|
||||
extern int bt_gethighbit(ulong_t *mapp, int wx);
|
||||
extern int bt_range(ulong_t *bitmap, size_t *pos1, size_t *pos2,
|
||||
size_t end_pos);
|
||||
extern int bt_getlowbit(ulong_t *bitmap, size_t start, size_t stop);
|
||||
extern void bt_copy(ulong_t *, ulong_t *, ulong_t);
|
||||
|
||||
/*
|
||||
* find the parity
|
||||
*/
|
||||
extern int odd_parity(ulong_t);
|
||||
|
||||
/*
|
||||
* Atomically set/clear bits
|
||||
* Atomic exclusive operations will set "result" to "-1"
|
||||
* if the bit is already set/cleared. "result" will be set
|
||||
* to 0 otherwise.
|
||||
*/
|
||||
#define BT_ATOMIC_SET(bitmap, bitindex) \
|
||||
{ atomic_or_long(&(BT_WIM(bitmap, bitindex)), BT_BIW(bitindex)); }
|
||||
#define BT_ATOMIC_CLEAR(bitmap, bitindex) \
|
||||
{ atomic_and_long(&(BT_WIM(bitmap, bitindex)), ~BT_BIW(bitindex)); }
|
||||
|
||||
#define BT_ATOMIC_SET_EXCL(bitmap, bitindex, result) \
|
||||
{ result = atomic_set_long_excl(&(BT_WIM(bitmap, bitindex)), \
|
||||
(bitindex) % BT_NBIPUL); }
|
||||
#define BT_ATOMIC_CLEAR_EXCL(bitmap, bitindex, result) \
|
||||
{ result = atomic_clear_long_excl(&(BT_WIM(bitmap, bitindex)), \
|
||||
(bitindex) % BT_NBIPUL); }
|
||||
|
||||
/*
|
||||
* Extracts bits between index h (high, inclusive) and l (low, exclusive) from
|
||||
* u, which must be an unsigned integer.
|
||||
*/
|
||||
#define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
|
||||
|
||||
#endif /* _ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_BITMAP_H */
|
137
module/icp/include/sys/crypto/elfsign.h
Normal file
137
module/icp/include/sys/crypto/elfsign.h
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_ELFSIGN_H
|
||||
#define _SYS_CRYPTO_ELFSIGN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Consolidation Private Interface for elfsign/libpkcs11/kcfd
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
|
||||
/*
|
||||
* Project Private structures and types used for communication between kcfd
|
||||
* and KCF over the door.
|
||||
*/
|
||||
|
||||
typedef enum ELFsign_status_e {
|
||||
ELFSIGN_UNKNOWN,
|
||||
ELFSIGN_SUCCESS,
|
||||
ELFSIGN_FAILED,
|
||||
ELFSIGN_NOTSIGNED,
|
||||
ELFSIGN_INVALID_CERTPATH,
|
||||
ELFSIGN_INVALID_ELFOBJ,
|
||||
ELFSIGN_RESTRICTED
|
||||
} ELFsign_status_t;
|
||||
|
||||
#define KCF_KCFD_VERSION1 1
|
||||
#define SIG_MAX_LENGTH 1024
|
||||
|
||||
#define ELF_SIGNATURE_SECTION ".SUNW_signature"
|
||||
|
||||
typedef struct kcf_door_arg_s {
|
||||
short da_version;
|
||||
boolean_t da_iskernel;
|
||||
|
||||
union {
|
||||
char filename[MAXPATHLEN]; /* For request */
|
||||
|
||||
struct kcf_door_result_s { /* For response */
|
||||
ELFsign_status_t status;
|
||||
uint32_t siglen;
|
||||
uchar_t signature[1];
|
||||
} result;
|
||||
} da_u;
|
||||
} kcf_door_arg_t;
|
||||
|
||||
typedef uint32_t filesig_vers_t;
|
||||
|
||||
/*
|
||||
* File Signature Structure
|
||||
* Applicable to ELF and other file formats
|
||||
*/
|
||||
struct filesignatures {
|
||||
uint32_t filesig_cnt; /* count of signatures */
|
||||
uint32_t filesig_pad; /* unused */
|
||||
union {
|
||||
char filesig_data[1];
|
||||
struct filesig { /* one of these for each signature */
|
||||
uint32_t filesig_size;
|
||||
filesig_vers_t filesig_version;
|
||||
union {
|
||||
struct filesig_version1 {
|
||||
uint32_t filesig_v1_dnsize;
|
||||
uint32_t filesig_v1_sigsize;
|
||||
uint32_t filesig_v1_oidsize;
|
||||
char filesig_v1_data[1];
|
||||
} filesig_v1;
|
||||
struct filesig_version3 {
|
||||
uint64_t filesig_v3_time;
|
||||
uint32_t filesig_v3_dnsize;
|
||||
uint32_t filesig_v3_sigsize;
|
||||
uint32_t filesig_v3_oidsize;
|
||||
char filesig_v3_data[1];
|
||||
} filesig_v3;
|
||||
} _u2;
|
||||
} filesig_sig;
|
||||
uint64_t filesig_align;
|
||||
} _u1;
|
||||
};
|
||||
#define filesig_sig _u1.filesig_sig
|
||||
|
||||
#define filesig_v1_dnsize _u2.filesig_v1.filesig_v1_dnsize
|
||||
#define filesig_v1_sigsize _u2.filesig_v1.filesig_v1_sigsize
|
||||
#define filesig_v1_oidsize _u2.filesig_v1.filesig_v1_oidsize
|
||||
#define filesig_v1_data _u2.filesig_v1.filesig_v1_data
|
||||
|
||||
#define filesig_v3_time _u2.filesig_v3.filesig_v3_time
|
||||
#define filesig_v3_dnsize _u2.filesig_v3.filesig_v3_dnsize
|
||||
#define filesig_v3_sigsize _u2.filesig_v3.filesig_v3_sigsize
|
||||
#define filesig_v3_oidsize _u2.filesig_v3.filesig_v3_oidsize
|
||||
#define filesig_v3_data _u2.filesig_v3.filesig_v3_data
|
||||
|
||||
#define filesig_ALIGN(s) (((s) + sizeof (uint64_t) - 1) & \
|
||||
(-sizeof (uint64_t)))
|
||||
#define filesig_next(ptr) (struct filesig *)((void *)((char *)(ptr) + \
|
||||
filesig_ALIGN((ptr)->filesig_size)))
|
||||
|
||||
#define FILESIG_UNKNOWN 0 /* unrecognized version */
|
||||
#define FILESIG_VERSION1 1 /* version1, all but sig section */
|
||||
#define FILESIG_VERSION2 2 /* version1 format, SHF_ALLOC only */
|
||||
#define FILESIG_VERSION3 3 /* version3, all but sig section */
|
||||
#define FILESIG_VERSION4 4 /* version3 format, SHF_ALLOC only */
|
||||
|
||||
#define _PATH_KCFD_DOOR "/etc/svc/volatile/kcfd_door"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_ELFSIGN_H */
|
1370
module/icp/include/sys/crypto/impl.h
Normal file
1370
module/icp/include/sys/crypto/impl.h
Normal file
File diff suppressed because it is too large
Load Diff
1483
module/icp/include/sys/crypto/ioctl.h
Normal file
1483
module/icp/include/sys/crypto/ioctl.h
Normal file
File diff suppressed because it is too large
Load Diff
136
module/icp/include/sys/crypto/ioctladmin.h
Normal file
136
module/icp/include/sys/crypto/ioctladmin.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_IOCTLADMIN_H
|
||||
#define _SYS_CRYPTO_IOCTLADMIN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
|
||||
#define ADMIN_IOCTL_DEVICE "/dev/cryptoadm"
|
||||
|
||||
#define CRYPTOADMIN(x) (('y' << 8) | (x))
|
||||
|
||||
/*
|
||||
* Administrative IOCTLs
|
||||
*/
|
||||
|
||||
typedef struct crypto_get_dev_list {
|
||||
uint_t dl_return_value;
|
||||
uint_t dl_dev_count;
|
||||
crypto_dev_list_entry_t dl_devs[1];
|
||||
} crypto_get_dev_list_t;
|
||||
|
||||
typedef struct crypto_get_soft_list {
|
||||
uint_t sl_return_value;
|
||||
uint_t sl_soft_count;
|
||||
size_t sl_soft_len;
|
||||
caddr_t sl_soft_names;
|
||||
} crypto_get_soft_list_t;
|
||||
|
||||
typedef struct crypto_get_dev_info {
|
||||
uint_t di_return_value;
|
||||
char di_dev_name[MAXNAMELEN];
|
||||
uint_t di_dev_instance;
|
||||
uint_t di_count;
|
||||
crypto_mech_name_t di_list[1];
|
||||
} crypto_get_dev_info_t;
|
||||
|
||||
typedef struct crypto_get_soft_info {
|
||||
uint_t si_return_value;
|
||||
char si_name[MAXNAMELEN];
|
||||
uint_t si_count;
|
||||
crypto_mech_name_t si_list[1];
|
||||
} crypto_get_soft_info_t;
|
||||
|
||||
typedef struct crypto_load_dev_disabled {
|
||||
uint_t dd_return_value;
|
||||
char dd_dev_name[MAXNAMELEN];
|
||||
uint_t dd_dev_instance;
|
||||
uint_t dd_count;
|
||||
crypto_mech_name_t dd_list[1];
|
||||
} crypto_load_dev_disabled_t;
|
||||
|
||||
typedef struct crypto_load_soft_disabled {
|
||||
uint_t sd_return_value;
|
||||
char sd_name[MAXNAMELEN];
|
||||
uint_t sd_count;
|
||||
crypto_mech_name_t sd_list[1];
|
||||
} crypto_load_soft_disabled_t;
|
||||
|
||||
typedef struct crypto_unload_soft_module {
|
||||
uint_t sm_return_value;
|
||||
char sm_name[MAXNAMELEN];
|
||||
} crypto_unload_soft_module_t;
|
||||
|
||||
typedef struct crypto_load_soft_config {
|
||||
uint_t sc_return_value;
|
||||
char sc_name[MAXNAMELEN];
|
||||
uint_t sc_count;
|
||||
crypto_mech_name_t sc_list[1];
|
||||
} crypto_load_soft_config_t;
|
||||
|
||||
typedef struct crypto_load_door {
|
||||
uint_t ld_return_value;
|
||||
uint_t ld_did;
|
||||
} crypto_load_door_t;
|
||||
|
||||
#ifdef _KERNEL
|
||||
#ifdef _SYSCALL32
|
||||
|
||||
typedef struct crypto_get_soft_list32 {
|
||||
uint32_t sl_return_value;
|
||||
uint32_t sl_soft_count;
|
||||
size32_t sl_soft_len;
|
||||
caddr32_t sl_soft_names;
|
||||
} crypto_get_soft_list32_t;
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#define CRYPTO_GET_VERSION CRYPTOADMIN(1)
|
||||
#define CRYPTO_GET_DEV_LIST CRYPTOADMIN(2)
|
||||
#define CRYPTO_GET_SOFT_LIST CRYPTOADMIN(3)
|
||||
#define CRYPTO_GET_DEV_INFO CRYPTOADMIN(4)
|
||||
#define CRYPTO_GET_SOFT_INFO CRYPTOADMIN(5)
|
||||
#define CRYPTO_LOAD_DEV_DISABLED CRYPTOADMIN(8)
|
||||
#define CRYPTO_LOAD_SOFT_DISABLED CRYPTOADMIN(9)
|
||||
#define CRYPTO_UNLOAD_SOFT_MODULE CRYPTOADMIN(10)
|
||||
#define CRYPTO_LOAD_SOFT_CONFIG CRYPTOADMIN(11)
|
||||
#define CRYPTO_POOL_CREATE CRYPTOADMIN(12)
|
||||
#define CRYPTO_POOL_WAIT CRYPTOADMIN(13)
|
||||
#define CRYPTO_POOL_RUN CRYPTOADMIN(14)
|
||||
#define CRYPTO_LOAD_DOOR CRYPTOADMIN(15)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_IOCTLADMIN_H */
|
630
module/icp/include/sys/crypto/ops_impl.h
Normal file
630
module/icp/include/sys/crypto/ops_impl.h
Normal file
@ -0,0 +1,630 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_OPS_IMPL_H
|
||||
#define _SYS_CRYPTO_OPS_IMPL_H
|
||||
|
||||
/*
|
||||
* Scheduler internal structures.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/api.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/crypto/common.h>
|
||||
|
||||
/*
|
||||
* The parameters needed for each function group are batched
|
||||
* in one structure. This is much simpler than having a
|
||||
* separate structure for each function.
|
||||
*
|
||||
* In some cases, a field is generically named to keep the
|
||||
* structure small. The comments indicate these cases.
|
||||
*/
|
||||
typedef struct kcf_digest_ops_params {
|
||||
crypto_session_id_t do_sid;
|
||||
crypto_mech_type_t do_framework_mechtype;
|
||||
crypto_mechanism_t do_mech;
|
||||
crypto_data_t *do_data;
|
||||
crypto_data_t *do_digest;
|
||||
crypto_key_t *do_digest_key; /* Argument for digest_key() */
|
||||
} kcf_digest_ops_params_t;
|
||||
|
||||
typedef struct kcf_mac_ops_params {
|
||||
crypto_session_id_t mo_sid;
|
||||
crypto_mech_type_t mo_framework_mechtype;
|
||||
crypto_mechanism_t mo_mech;
|
||||
crypto_key_t *mo_key;
|
||||
crypto_data_t *mo_data;
|
||||
crypto_data_t *mo_mac;
|
||||
crypto_spi_ctx_template_t mo_templ;
|
||||
} kcf_mac_ops_params_t;
|
||||
|
||||
typedef struct kcf_encrypt_ops_params {
|
||||
crypto_session_id_t eo_sid;
|
||||
crypto_mech_type_t eo_framework_mechtype;
|
||||
crypto_mechanism_t eo_mech;
|
||||
crypto_key_t *eo_key;
|
||||
crypto_data_t *eo_plaintext;
|
||||
crypto_data_t *eo_ciphertext;
|
||||
crypto_spi_ctx_template_t eo_templ;
|
||||
} kcf_encrypt_ops_params_t;
|
||||
|
||||
typedef struct kcf_decrypt_ops_params {
|
||||
crypto_session_id_t dop_sid;
|
||||
crypto_mech_type_t dop_framework_mechtype;
|
||||
crypto_mechanism_t dop_mech;
|
||||
crypto_key_t *dop_key;
|
||||
crypto_data_t *dop_ciphertext;
|
||||
crypto_data_t *dop_plaintext;
|
||||
crypto_spi_ctx_template_t dop_templ;
|
||||
} kcf_decrypt_ops_params_t;
|
||||
|
||||
typedef struct kcf_sign_ops_params {
|
||||
crypto_session_id_t so_sid;
|
||||
crypto_mech_type_t so_framework_mechtype;
|
||||
crypto_mechanism_t so_mech;
|
||||
crypto_key_t *so_key;
|
||||
crypto_data_t *so_data;
|
||||
crypto_data_t *so_signature;
|
||||
crypto_spi_ctx_template_t so_templ;
|
||||
} kcf_sign_ops_params_t;
|
||||
|
||||
typedef struct kcf_verify_ops_params {
|
||||
crypto_session_id_t vo_sid;
|
||||
crypto_mech_type_t vo_framework_mechtype;
|
||||
crypto_mechanism_t vo_mech;
|
||||
crypto_key_t *vo_key;
|
||||
crypto_data_t *vo_data;
|
||||
crypto_data_t *vo_signature;
|
||||
crypto_spi_ctx_template_t vo_templ;
|
||||
} kcf_verify_ops_params_t;
|
||||
|
||||
typedef struct kcf_encrypt_mac_ops_params {
|
||||
crypto_session_id_t em_sid;
|
||||
crypto_mech_type_t em_framework_encr_mechtype;
|
||||
crypto_mechanism_t em_encr_mech;
|
||||
crypto_key_t *em_encr_key;
|
||||
crypto_mech_type_t em_framework_mac_mechtype;
|
||||
crypto_mechanism_t em_mac_mech;
|
||||
crypto_key_t *em_mac_key;
|
||||
crypto_data_t *em_plaintext;
|
||||
crypto_dual_data_t *em_ciphertext;
|
||||
crypto_data_t *em_mac;
|
||||
crypto_spi_ctx_template_t em_encr_templ;
|
||||
crypto_spi_ctx_template_t em_mac_templ;
|
||||
} kcf_encrypt_mac_ops_params_t;
|
||||
|
||||
typedef struct kcf_mac_decrypt_ops_params {
|
||||
crypto_session_id_t md_sid;
|
||||
crypto_mech_type_t md_framework_mac_mechtype;
|
||||
crypto_mechanism_t md_mac_mech;
|
||||
crypto_key_t *md_mac_key;
|
||||
crypto_mech_type_t md_framework_decr_mechtype;
|
||||
crypto_mechanism_t md_decr_mech;
|
||||
crypto_key_t *md_decr_key;
|
||||
crypto_dual_data_t *md_ciphertext;
|
||||
crypto_data_t *md_mac;
|
||||
crypto_data_t *md_plaintext;
|
||||
crypto_spi_ctx_template_t md_mac_templ;
|
||||
crypto_spi_ctx_template_t md_decr_templ;
|
||||
} kcf_mac_decrypt_ops_params_t;
|
||||
|
||||
typedef struct kcf_random_number_ops_params {
|
||||
crypto_session_id_t rn_sid;
|
||||
uchar_t *rn_buf;
|
||||
size_t rn_buflen;
|
||||
uint_t rn_entropy_est;
|
||||
uint32_t rn_flags;
|
||||
} kcf_random_number_ops_params_t;
|
||||
|
||||
/*
|
||||
* so_pd is useful when the provider descriptor (pd) supplying the
|
||||
* provider handle is different from the pd supplying the ops vector.
|
||||
* This is the case for session open/close where so_pd can be the pd
|
||||
* of a logical provider. The pd supplying the ops vector is passed
|
||||
* as an argument to kcf_submit_request().
|
||||
*/
|
||||
typedef struct kcf_session_ops_params {
|
||||
crypto_session_id_t *so_sid_ptr;
|
||||
crypto_session_id_t so_sid;
|
||||
crypto_user_type_t so_user_type;
|
||||
char *so_pin;
|
||||
size_t so_pin_len;
|
||||
kcf_provider_desc_t *so_pd;
|
||||
} kcf_session_ops_params_t;
|
||||
|
||||
typedef struct kcf_object_ops_params {
|
||||
crypto_session_id_t oo_sid;
|
||||
crypto_object_id_t oo_object_id;
|
||||
crypto_object_attribute_t *oo_template;
|
||||
uint_t oo_attribute_count;
|
||||
crypto_object_id_t *oo_object_id_ptr;
|
||||
size_t *oo_object_size;
|
||||
void **oo_find_init_pp_ptr;
|
||||
void *oo_find_pp;
|
||||
uint_t oo_max_object_count;
|
||||
uint_t *oo_object_count_ptr;
|
||||
} kcf_object_ops_params_t;
|
||||
|
||||
/*
|
||||
* ko_key is used to encode wrapping key in key_wrap() and
|
||||
* unwrapping key in key_unwrap(). ko_key_template and
|
||||
* ko_key_attribute_count are used to encode public template
|
||||
* and public template attr count in key_generate_pair().
|
||||
* kops->ko_key_object_id_ptr is used to encode public key
|
||||
* in key_generate_pair().
|
||||
*/
|
||||
typedef struct kcf_key_ops_params {
|
||||
crypto_session_id_t ko_sid;
|
||||
crypto_mech_type_t ko_framework_mechtype;
|
||||
crypto_mechanism_t ko_mech;
|
||||
crypto_object_attribute_t *ko_key_template;
|
||||
uint_t ko_key_attribute_count;
|
||||
crypto_object_id_t *ko_key_object_id_ptr;
|
||||
crypto_object_attribute_t *ko_private_key_template;
|
||||
uint_t ko_private_key_attribute_count;
|
||||
crypto_object_id_t *ko_private_key_object_id_ptr;
|
||||
crypto_key_t *ko_key;
|
||||
uchar_t *ko_wrapped_key;
|
||||
size_t *ko_wrapped_key_len_ptr;
|
||||
crypto_object_attribute_t *ko_out_template1;
|
||||
crypto_object_attribute_t *ko_out_template2;
|
||||
uint_t ko_out_attribute_count1;
|
||||
uint_t ko_out_attribute_count2;
|
||||
} kcf_key_ops_params_t;
|
||||
|
||||
/*
|
||||
* po_pin and po_pin_len are used to encode new_pin and new_pin_len
|
||||
* when wrapping set_pin() function parameters.
|
||||
*
|
||||
* po_pd is useful when the provider descriptor (pd) supplying the
|
||||
* provider handle is different from the pd supplying the ops vector.
|
||||
* This is true for the ext_info provider entry point where po_pd
|
||||
* can be the pd of a logical provider. The pd supplying the ops vector
|
||||
* is passed as an argument to kcf_submit_request().
|
||||
*/
|
||||
typedef struct kcf_provmgmt_ops_params {
|
||||
crypto_session_id_t po_sid;
|
||||
char *po_pin;
|
||||
size_t po_pin_len;
|
||||
char *po_old_pin;
|
||||
size_t po_old_pin_len;
|
||||
char *po_label;
|
||||
crypto_provider_ext_info_t *po_ext_info;
|
||||
kcf_provider_desc_t *po_pd;
|
||||
} kcf_provmgmt_ops_params_t;
|
||||
|
||||
/*
|
||||
* The operation type within a function group.
|
||||
*/
|
||||
typedef enum kcf_op_type {
|
||||
/* common ops for all mechanisms */
|
||||
KCF_OP_INIT = 1,
|
||||
KCF_OP_SINGLE, /* pkcs11 sense. So, INIT is already done */
|
||||
KCF_OP_UPDATE,
|
||||
KCF_OP_FINAL,
|
||||
KCF_OP_ATOMIC,
|
||||
|
||||
/* digest_key op */
|
||||
KCF_OP_DIGEST_KEY,
|
||||
|
||||
/* mac specific op */
|
||||
KCF_OP_MAC_VERIFY_ATOMIC,
|
||||
|
||||
/* mac/cipher specific op */
|
||||
KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC,
|
||||
|
||||
/* sign_recover ops */
|
||||
KCF_OP_SIGN_RECOVER_INIT,
|
||||
KCF_OP_SIGN_RECOVER,
|
||||
KCF_OP_SIGN_RECOVER_ATOMIC,
|
||||
|
||||
/* verify_recover ops */
|
||||
KCF_OP_VERIFY_RECOVER_INIT,
|
||||
KCF_OP_VERIFY_RECOVER,
|
||||
KCF_OP_VERIFY_RECOVER_ATOMIC,
|
||||
|
||||
/* random number ops */
|
||||
KCF_OP_RANDOM_SEED,
|
||||
KCF_OP_RANDOM_GENERATE,
|
||||
|
||||
/* session management ops */
|
||||
KCF_OP_SESSION_OPEN,
|
||||
KCF_OP_SESSION_CLOSE,
|
||||
KCF_OP_SESSION_LOGIN,
|
||||
KCF_OP_SESSION_LOGOUT,
|
||||
|
||||
/* object management ops */
|
||||
KCF_OP_OBJECT_CREATE,
|
||||
KCF_OP_OBJECT_COPY,
|
||||
KCF_OP_OBJECT_DESTROY,
|
||||
KCF_OP_OBJECT_GET_SIZE,
|
||||
KCF_OP_OBJECT_GET_ATTRIBUTE_VALUE,
|
||||
KCF_OP_OBJECT_SET_ATTRIBUTE_VALUE,
|
||||
KCF_OP_OBJECT_FIND_INIT,
|
||||
KCF_OP_OBJECT_FIND,
|
||||
KCF_OP_OBJECT_FIND_FINAL,
|
||||
|
||||
/* key management ops */
|
||||
KCF_OP_KEY_GENERATE,
|
||||
KCF_OP_KEY_GENERATE_PAIR,
|
||||
KCF_OP_KEY_WRAP,
|
||||
KCF_OP_KEY_UNWRAP,
|
||||
KCF_OP_KEY_DERIVE,
|
||||
KCF_OP_KEY_CHECK,
|
||||
|
||||
/* provider management ops */
|
||||
KCF_OP_MGMT_EXTINFO,
|
||||
KCF_OP_MGMT_INITTOKEN,
|
||||
KCF_OP_MGMT_INITPIN,
|
||||
KCF_OP_MGMT_SETPIN
|
||||
} kcf_op_type_t;
|
||||
|
||||
/*
|
||||
* The operation groups that need wrapping of parameters. This is somewhat
|
||||
* similar to the function group type in spi.h except that this also includes
|
||||
* all the functions that don't have a mechanism.
|
||||
*
|
||||
* The wrapper macros should never take these enum values as an argument.
|
||||
* Rather, they are assigned in the macro itself since they are known
|
||||
* from the macro name.
|
||||
*/
|
||||
typedef enum kcf_op_group {
|
||||
KCF_OG_DIGEST = 1,
|
||||
KCF_OG_MAC,
|
||||
KCF_OG_ENCRYPT,
|
||||
KCF_OG_DECRYPT,
|
||||
KCF_OG_SIGN,
|
||||
KCF_OG_VERIFY,
|
||||
KCF_OG_ENCRYPT_MAC,
|
||||
KCF_OG_MAC_DECRYPT,
|
||||
KCF_OG_RANDOM,
|
||||
KCF_OG_SESSION,
|
||||
KCF_OG_OBJECT,
|
||||
KCF_OG_KEY,
|
||||
KCF_OG_PROVMGMT,
|
||||
KCF_OG_NOSTORE_KEY
|
||||
} kcf_op_group_t;
|
||||
|
||||
/*
|
||||
* The kcf_op_type_t enum values used here should be only for those
|
||||
* operations for which there is a k-api routine in sys/crypto/api.h.
|
||||
*/
|
||||
#define IS_INIT_OP(ftype) ((ftype) == KCF_OP_INIT)
|
||||
#define IS_SINGLE_OP(ftype) ((ftype) == KCF_OP_SINGLE)
|
||||
#define IS_UPDATE_OP(ftype) ((ftype) == KCF_OP_UPDATE)
|
||||
#define IS_FINAL_OP(ftype) ((ftype) == KCF_OP_FINAL)
|
||||
#define IS_ATOMIC_OP(ftype) ( \
|
||||
(ftype) == KCF_OP_ATOMIC || (ftype) == KCF_OP_MAC_VERIFY_ATOMIC || \
|
||||
(ftype) == KCF_OP_MAC_VERIFY_DECRYPT_ATOMIC || \
|
||||
(ftype) == KCF_OP_SIGN_RECOVER_ATOMIC || \
|
||||
(ftype) == KCF_OP_VERIFY_RECOVER_ATOMIC)
|
||||
|
||||
/*
|
||||
* Keep the parameters associated with a request around.
|
||||
* We need to pass them to the SPI.
|
||||
*/
|
||||
typedef struct kcf_req_params {
|
||||
kcf_op_group_t rp_opgrp;
|
||||
kcf_op_type_t rp_optype;
|
||||
|
||||
union {
|
||||
kcf_digest_ops_params_t digest_params;
|
||||
kcf_mac_ops_params_t mac_params;
|
||||
kcf_encrypt_ops_params_t encrypt_params;
|
||||
kcf_decrypt_ops_params_t decrypt_params;
|
||||
kcf_sign_ops_params_t sign_params;
|
||||
kcf_verify_ops_params_t verify_params;
|
||||
kcf_encrypt_mac_ops_params_t encrypt_mac_params;
|
||||
kcf_mac_decrypt_ops_params_t mac_decrypt_params;
|
||||
kcf_random_number_ops_params_t random_number_params;
|
||||
kcf_session_ops_params_t session_params;
|
||||
kcf_object_ops_params_t object_params;
|
||||
kcf_key_ops_params_t key_params;
|
||||
kcf_provmgmt_ops_params_t provmgmt_params;
|
||||
} rp_u;
|
||||
} kcf_req_params_t;
|
||||
|
||||
|
||||
/*
|
||||
* The ioctl/k-api code should bundle the parameters into a kcf_req_params_t
|
||||
* structure before calling a scheduler routine. The following macros are
|
||||
* available for that purpose.
|
||||
*
|
||||
* For the most part, the macro arguments closely correspond to the
|
||||
* function parameters. In some cases, we use generic names. The comments
|
||||
* for the structure should indicate these cases.
|
||||
*/
|
||||
#define KCF_WRAP_DIGEST_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
|
||||
_data, _digest) { \
|
||||
kcf_digest_ops_params_t *dops = &(req)->rp_u.digest_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_DIGEST; \
|
||||
(req)->rp_optype = ftype; \
|
||||
dops->do_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
dops->do_mech = *mechp; \
|
||||
dops->do_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
dops->do_digest_key = _key; \
|
||||
dops->do_data = _data; \
|
||||
dops->do_digest = _digest; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_MAC_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
|
||||
_data, _mac, _templ) { \
|
||||
kcf_mac_ops_params_t *mops = &(req)->rp_u.mac_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_MAC; \
|
||||
(req)->rp_optype = ftype; \
|
||||
mops->mo_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
mops->mo_mech = *mechp; \
|
||||
mops->mo_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
mops->mo_key = _key; \
|
||||
mops->mo_data = _data; \
|
||||
mops->mo_mac = _mac; \
|
||||
mops->mo_templ = _templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_ENCRYPT_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
|
||||
_plaintext, _ciphertext, _templ) { \
|
||||
kcf_encrypt_ops_params_t *cops = &(req)->rp_u.encrypt_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_ENCRYPT; \
|
||||
(req)->rp_optype = ftype; \
|
||||
cops->eo_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
cops->eo_mech = *mechp; \
|
||||
cops->eo_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
cops->eo_key = _key; \
|
||||
cops->eo_plaintext = _plaintext; \
|
||||
cops->eo_ciphertext = _ciphertext; \
|
||||
cops->eo_templ = _templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_DECRYPT_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
|
||||
_ciphertext, _plaintext, _templ) { \
|
||||
kcf_decrypt_ops_params_t *cops = &(req)->rp_u.decrypt_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_DECRYPT; \
|
||||
(req)->rp_optype = ftype; \
|
||||
cops->dop_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
cops->dop_mech = *mechp; \
|
||||
cops->dop_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
cops->dop_key = _key; \
|
||||
cops->dop_ciphertext = _ciphertext; \
|
||||
cops->dop_plaintext = _plaintext; \
|
||||
cops->dop_templ = _templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_SIGN_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
|
||||
_data, _signature, _templ) { \
|
||||
kcf_sign_ops_params_t *sops = &(req)->rp_u.sign_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_SIGN; \
|
||||
(req)->rp_optype = ftype; \
|
||||
sops->so_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
sops->so_mech = *mechp; \
|
||||
sops->so_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
sops->so_key = _key; \
|
||||
sops->so_data = _data; \
|
||||
sops->so_signature = _signature; \
|
||||
sops->so_templ = _templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_VERIFY_OPS_PARAMS(req, ftype, _sid, _mech, _key, \
|
||||
_data, _signature, _templ) { \
|
||||
kcf_verify_ops_params_t *vops = &(req)->rp_u.verify_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_VERIFY; \
|
||||
(req)->rp_optype = ftype; \
|
||||
vops->vo_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
vops->vo_mech = *mechp; \
|
||||
vops->vo_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
vops->vo_key = _key; \
|
||||
vops->vo_data = _data; \
|
||||
vops->vo_signature = _signature; \
|
||||
vops->vo_templ = _templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_ENCRYPT_MAC_OPS_PARAMS(req, ftype, _sid, _encr_key, \
|
||||
_mac_key, _plaintext, _ciphertext, _mac, _encr_templ, _mac_templ) { \
|
||||
kcf_encrypt_mac_ops_params_t *cmops = &(req)->rp_u.encrypt_mac_params; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_ENCRYPT_MAC; \
|
||||
(req)->rp_optype = ftype; \
|
||||
cmops->em_sid = _sid; \
|
||||
cmops->em_encr_key = _encr_key; \
|
||||
cmops->em_mac_key = _mac_key; \
|
||||
cmops->em_plaintext = _plaintext; \
|
||||
cmops->em_ciphertext = _ciphertext; \
|
||||
cmops->em_mac = _mac; \
|
||||
cmops->em_encr_templ = _encr_templ; \
|
||||
cmops->em_mac_templ = _mac_templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_MAC_DECRYPT_OPS_PARAMS(req, ftype, _sid, _mac_key, \
|
||||
_decr_key, _ciphertext, _mac, _plaintext, _mac_templ, _decr_templ) { \
|
||||
kcf_mac_decrypt_ops_params_t *cmops = &(req)->rp_u.mac_decrypt_params; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_MAC_DECRYPT; \
|
||||
(req)->rp_optype = ftype; \
|
||||
cmops->md_sid = _sid; \
|
||||
cmops->md_mac_key = _mac_key; \
|
||||
cmops->md_decr_key = _decr_key; \
|
||||
cmops->md_ciphertext = _ciphertext; \
|
||||
cmops->md_mac = _mac; \
|
||||
cmops->md_plaintext = _plaintext; \
|
||||
cmops->md_mac_templ = _mac_templ; \
|
||||
cmops->md_decr_templ = _decr_templ; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_RANDOM_OPS_PARAMS(req, ftype, _sid, _buf, _buflen, \
|
||||
_est, _flags) { \
|
||||
kcf_random_number_ops_params_t *rops = \
|
||||
&(req)->rp_u.random_number_params; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_RANDOM; \
|
||||
(req)->rp_optype = ftype; \
|
||||
rops->rn_sid = _sid; \
|
||||
rops->rn_buf = _buf; \
|
||||
rops->rn_buflen = _buflen; \
|
||||
rops->rn_entropy_est = _est; \
|
||||
rops->rn_flags = _flags; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_SESSION_OPS_PARAMS(req, ftype, _sid_ptr, _sid, \
|
||||
_user_type, _pin, _pin_len, _pd) { \
|
||||
kcf_session_ops_params_t *sops = &(req)->rp_u.session_params; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_SESSION; \
|
||||
(req)->rp_optype = ftype; \
|
||||
sops->so_sid_ptr = _sid_ptr; \
|
||||
sops->so_sid = _sid; \
|
||||
sops->so_user_type = _user_type; \
|
||||
sops->so_pin = _pin; \
|
||||
sops->so_pin_len = _pin_len; \
|
||||
sops->so_pd = _pd; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_OBJECT_OPS_PARAMS(req, ftype, _sid, _object_id, \
|
||||
_template, _attribute_count, _object_id_ptr, _object_size, \
|
||||
_find_init_pp_ptr, _find_pp, _max_object_count, _object_count_ptr) { \
|
||||
kcf_object_ops_params_t *jops = &(req)->rp_u.object_params; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_OBJECT; \
|
||||
(req)->rp_optype = ftype; \
|
||||
jops->oo_sid = _sid; \
|
||||
jops->oo_object_id = _object_id; \
|
||||
jops->oo_template = _template; \
|
||||
jops->oo_attribute_count = _attribute_count; \
|
||||
jops->oo_object_id_ptr = _object_id_ptr; \
|
||||
jops->oo_object_size = _object_size; \
|
||||
jops->oo_find_init_pp_ptr = _find_init_pp_ptr; \
|
||||
jops->oo_find_pp = _find_pp; \
|
||||
jops->oo_max_object_count = _max_object_count; \
|
||||
jops->oo_object_count_ptr = _object_count_ptr; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_KEY_OPS_PARAMS(req, ftype, _sid, _mech, _key_template, \
|
||||
_key_attribute_count, _key_object_id_ptr, _private_key_template, \
|
||||
_private_key_attribute_count, _private_key_object_id_ptr, \
|
||||
_key, _wrapped_key, _wrapped_key_len_ptr) { \
|
||||
kcf_key_ops_params_t *kops = &(req)->rp_u.key_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_KEY; \
|
||||
(req)->rp_optype = ftype; \
|
||||
kops->ko_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
kops->ko_mech = *mechp; \
|
||||
kops->ko_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
kops->ko_key_template = _key_template; \
|
||||
kops->ko_key_attribute_count = _key_attribute_count; \
|
||||
kops->ko_key_object_id_ptr = _key_object_id_ptr; \
|
||||
kops->ko_private_key_template = _private_key_template; \
|
||||
kops->ko_private_key_attribute_count = _private_key_attribute_count; \
|
||||
kops->ko_private_key_object_id_ptr = _private_key_object_id_ptr; \
|
||||
kops->ko_key = _key; \
|
||||
kops->ko_wrapped_key = _wrapped_key; \
|
||||
kops->ko_wrapped_key_len_ptr = _wrapped_key_len_ptr; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_PROVMGMT_OPS_PARAMS(req, ftype, _sid, _old_pin, \
|
||||
_old_pin_len, _pin, _pin_len, _label, _ext_info, _pd) { \
|
||||
kcf_provmgmt_ops_params_t *pops = &(req)->rp_u.provmgmt_params; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_PROVMGMT; \
|
||||
(req)->rp_optype = ftype; \
|
||||
pops->po_sid = _sid; \
|
||||
pops->po_pin = _pin; \
|
||||
pops->po_pin_len = _pin_len; \
|
||||
pops->po_old_pin = _old_pin; \
|
||||
pops->po_old_pin_len = _old_pin_len; \
|
||||
pops->po_label = _label; \
|
||||
pops->po_ext_info = _ext_info; \
|
||||
pops->po_pd = _pd; \
|
||||
}
|
||||
|
||||
#define KCF_WRAP_NOSTORE_KEY_OPS_PARAMS(req, ftype, _sid, _mech, \
|
||||
_key_template, _key_attribute_count, _private_key_template, \
|
||||
_private_key_attribute_count, _key, _out_template1, \
|
||||
_out_attribute_count1, _out_template2, _out_attribute_count2) { \
|
||||
kcf_key_ops_params_t *kops = &(req)->rp_u.key_params; \
|
||||
crypto_mechanism_t *mechp = _mech; \
|
||||
\
|
||||
(req)->rp_opgrp = KCF_OG_NOSTORE_KEY; \
|
||||
(req)->rp_optype = ftype; \
|
||||
kops->ko_sid = _sid; \
|
||||
if (mechp != NULL) { \
|
||||
kops->ko_mech = *mechp; \
|
||||
kops->ko_framework_mechtype = mechp->cm_type; \
|
||||
} \
|
||||
kops->ko_key_template = _key_template; \
|
||||
kops->ko_key_attribute_count = _key_attribute_count; \
|
||||
kops->ko_key_object_id_ptr = NULL; \
|
||||
kops->ko_private_key_template = _private_key_template; \
|
||||
kops->ko_private_key_attribute_count = _private_key_attribute_count; \
|
||||
kops->ko_private_key_object_id_ptr = NULL; \
|
||||
kops->ko_key = _key; \
|
||||
kops->ko_wrapped_key = NULL; \
|
||||
kops->ko_wrapped_key_len_ptr = 0; \
|
||||
kops->ko_out_template1 = _out_template1; \
|
||||
kops->ko_out_template2 = _out_template2; \
|
||||
kops->ko_out_attribute_count1 = _out_attribute_count1; \
|
||||
kops->ko_out_attribute_count2 = _out_attribute_count2; \
|
||||
}
|
||||
|
||||
#define KCF_SET_PROVIDER_MECHNUM(fmtype, pd, mechp) \
|
||||
(mechp)->cm_type = \
|
||||
KCF_TO_PROV_MECHNUM(pd, fmtype);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_OPS_IMPL_H */
|
531
module/icp/include/sys/crypto/sched_impl.h
Normal file
531
module/icp/include/sys/crypto/sched_impl.h
Normal file
@ -0,0 +1,531 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_SCHED_IMPL_H
|
||||
#define _SYS_CRYPTO_SCHED_IMPL_H
|
||||
|
||||
/*
|
||||
* Scheduler internal structures.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/api.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/ops_impl.h>
|
||||
|
||||
typedef void (kcf_func_t)(void *, int);
|
||||
|
||||
typedef enum kcf_req_status {
|
||||
REQ_ALLOCATED = 1,
|
||||
REQ_WAITING, /* At the framework level */
|
||||
REQ_INPROGRESS, /* At the provider level */
|
||||
REQ_DONE,
|
||||
REQ_CANCELED
|
||||
} kcf_req_status_t;
|
||||
|
||||
typedef enum kcf_call_type {
|
||||
CRYPTO_SYNCH = 1,
|
||||
CRYPTO_ASYNCH
|
||||
} kcf_call_type_t;
|
||||
|
||||
#define CHECK_RESTRICT(crq) (crq != NULL && \
|
||||
((crq)->cr_flag & CRYPTO_RESTRICTED))
|
||||
|
||||
#define CHECK_RESTRICT_FALSE B_FALSE
|
||||
|
||||
#define CHECK_FASTPATH(crq, pd) ((crq) == NULL || \
|
||||
!((crq)->cr_flag & CRYPTO_ALWAYS_QUEUE)) && \
|
||||
(pd)->pd_prov_type == CRYPTO_SW_PROVIDER
|
||||
|
||||
#define KCF_KMFLAG(crq) (((crq) == NULL) ? KM_SLEEP : KM_NOSLEEP)
|
||||
|
||||
/*
|
||||
* The framework keeps an internal handle to use in the adaptive
|
||||
* asynchronous case. This is the case when a client has the
|
||||
* CRYPTO_ALWAYS_QUEUE bit clear and a software provider is used for
|
||||
* the request. The request is completed in the context of the calling
|
||||
* thread and kernel memory must be allocated with KM_NOSLEEP.
|
||||
*
|
||||
* The framework passes a pointer to the handle in crypto_req_handle_t
|
||||
* argument when it calls the SPI of the software provider. The macros
|
||||
* KCF_RHNDL() and KCF_SWFP_RHNDL() are used to do this.
|
||||
*
|
||||
* When a provider asks the framework for kmflag value via
|
||||
* crypto_kmflag(9S) we use REQHNDL2_KMFLAG() macro.
|
||||
*/
|
||||
extern ulong_t kcf_swprov_hndl;
|
||||
#define KCF_RHNDL(kmflag) (((kmflag) == KM_SLEEP) ? NULL : &kcf_swprov_hndl)
|
||||
#define KCF_SWFP_RHNDL(crq) (((crq) == NULL) ? NULL : &kcf_swprov_hndl)
|
||||
#define REQHNDL2_KMFLAG(rhndl) \
|
||||
((rhndl == &kcf_swprov_hndl) ? KM_NOSLEEP : KM_SLEEP)
|
||||
|
||||
/* Internal call_req flags. They start after the public ones in api.h */
|
||||
|
||||
#define CRYPTO_SETDUAL 0x00001000 /* Set the 'cont' boolean before */
|
||||
/* submitting the request */
|
||||
#define KCF_ISDUALREQ(crq) \
|
||||
(((crq) == NULL) ? B_FALSE : (crq->cr_flag & CRYPTO_SETDUAL))
|
||||
|
||||
typedef struct kcf_prov_tried {
|
||||
kcf_provider_desc_t *pt_pd;
|
||||
struct kcf_prov_tried *pt_next;
|
||||
} kcf_prov_tried_t;
|
||||
|
||||
#define IS_FG_SUPPORTED(mdesc, fg) \
|
||||
(((mdesc)->pm_mech_info.cm_func_group_mask & (fg)) != 0)
|
||||
|
||||
#define IS_PROVIDER_TRIED(pd, tlist) \
|
||||
(tlist != NULL && is_in_triedlist(pd, tlist))
|
||||
|
||||
#define IS_RECOVERABLE(error) \
|
||||
(error == CRYPTO_BUFFER_TOO_BIG || \
|
||||
error == CRYPTO_BUSY || \
|
||||
error == CRYPTO_DEVICE_ERROR || \
|
||||
error == CRYPTO_DEVICE_MEMORY || \
|
||||
error == CRYPTO_KEY_SIZE_RANGE || \
|
||||
error == CRYPTO_NO_PERMISSION)
|
||||
|
||||
#define KCF_ATOMIC_INCR(x) atomic_add_32(&(x), 1)
|
||||
#define KCF_ATOMIC_DECR(x) atomic_add_32(&(x), -1)
|
||||
|
||||
/*
|
||||
* Node structure for synchronous requests.
|
||||
*/
|
||||
typedef struct kcf_sreq_node {
|
||||
/* Should always be the first field in this structure */
|
||||
kcf_call_type_t sn_type;
|
||||
/*
|
||||
* sn_cv and sr_lock are used to wait for the
|
||||
* operation to complete. sn_lock also protects
|
||||
* the sn_state field.
|
||||
*/
|
||||
kcondvar_t sn_cv;
|
||||
kmutex_t sn_lock;
|
||||
kcf_req_status_t sn_state;
|
||||
|
||||
/*
|
||||
* Return value from the operation. This will be
|
||||
* one of the CRYPTO_* errors defined in common.h.
|
||||
*/
|
||||
int sn_rv;
|
||||
|
||||
/*
|
||||
* parameters to call the SPI with. This can be
|
||||
* a pointer as we know the caller context/stack stays.
|
||||
*/
|
||||
struct kcf_req_params *sn_params;
|
||||
|
||||
/* Internal context for this request */
|
||||
struct kcf_context *sn_context;
|
||||
|
||||
/* Provider handling this request */
|
||||
kcf_provider_desc_t *sn_provider;
|
||||
} kcf_sreq_node_t;
|
||||
|
||||
/*
|
||||
* Node structure for asynchronous requests. A node can be on
|
||||
* on a chain of requests hanging of the internal context
|
||||
* structure and can be in the global software provider queue.
|
||||
*/
|
||||
typedef struct kcf_areq_node {
|
||||
/* Should always be the first field in this structure */
|
||||
kcf_call_type_t an_type;
|
||||
|
||||
/* an_lock protects the field an_state */
|
||||
kmutex_t an_lock;
|
||||
kcf_req_status_t an_state;
|
||||
crypto_call_req_t an_reqarg;
|
||||
|
||||
/*
|
||||
* parameters to call the SPI with. We need to
|
||||
* save the params since the caller stack can go away.
|
||||
*/
|
||||
struct kcf_req_params an_params;
|
||||
|
||||
/*
|
||||
* The next two fields should be NULL for operations that
|
||||
* don't need a context.
|
||||
*/
|
||||
/* Internal context for this request */
|
||||
struct kcf_context *an_context;
|
||||
|
||||
/* next in chain of requests for context */
|
||||
struct kcf_areq_node *an_ctxchain_next;
|
||||
|
||||
kcondvar_t an_turn_cv;
|
||||
boolean_t an_is_my_turn;
|
||||
boolean_t an_isdual; /* for internal reuse */
|
||||
|
||||
/*
|
||||
* Next and previous nodes in the global software
|
||||
* queue. These fields are NULL for a hardware
|
||||
* provider since we use a taskq there.
|
||||
*/
|
||||
struct kcf_areq_node *an_next;
|
||||
struct kcf_areq_node *an_prev;
|
||||
|
||||
/* Provider handling this request */
|
||||
kcf_provider_desc_t *an_provider;
|
||||
kcf_prov_tried_t *an_tried_plist;
|
||||
|
||||
struct kcf_areq_node *an_idnext; /* Next in ID hash */
|
||||
struct kcf_areq_node *an_idprev; /* Prev in ID hash */
|
||||
kcondvar_t an_done; /* Signal request completion */
|
||||
uint_t an_refcnt;
|
||||
} kcf_areq_node_t;
|
||||
|
||||
#define KCF_AREQ_REFHOLD(areq) { \
|
||||
atomic_add_32(&(areq)->an_refcnt, 1); \
|
||||
ASSERT((areq)->an_refcnt != 0); \
|
||||
}
|
||||
|
||||
#define KCF_AREQ_REFRELE(areq) { \
|
||||
ASSERT((areq)->an_refcnt != 0); \
|
||||
membar_exit(); \
|
||||
if (atomic_add_32_nv(&(areq)->an_refcnt, -1) == 0) \
|
||||
kcf_free_req(areq); \
|
||||
}
|
||||
|
||||
#define GET_REQ_TYPE(arg) *((kcf_call_type_t *)(arg))
|
||||
|
||||
#define NOTIFY_CLIENT(areq, err) (*(areq)->an_reqarg.cr_callback_func)(\
|
||||
(areq)->an_reqarg.cr_callback_arg, err);
|
||||
|
||||
/* For internally generated call requests for dual operations */
|
||||
typedef struct kcf_call_req {
|
||||
crypto_call_req_t kr_callreq; /* external client call req */
|
||||
kcf_req_params_t kr_params; /* Params saved for next call */
|
||||
kcf_areq_node_t *kr_areq; /* Use this areq */
|
||||
off_t kr_saveoffset;
|
||||
size_t kr_savelen;
|
||||
} kcf_dual_req_t;
|
||||
|
||||
/*
|
||||
* The following are some what similar to macros in callo.h, which implement
|
||||
* callout tables.
|
||||
*
|
||||
* The lower four bits of the ID are used to encode the table ID to
|
||||
* index in to. The REQID_COUNTER_HIGH bit is used to avoid any check for
|
||||
* wrap around when generating ID. We assume that there won't be a request
|
||||
* which takes more time than 2^^(sizeof (long) - 5) other requests submitted
|
||||
* after it. This ensures there won't be any ID collision.
|
||||
*/
|
||||
#define REQID_COUNTER_HIGH (1UL << (8 * sizeof (long) - 1))
|
||||
#define REQID_COUNTER_SHIFT 4
|
||||
#define REQID_COUNTER_LOW (1 << REQID_COUNTER_SHIFT)
|
||||
#define REQID_TABLES 16
|
||||
#define REQID_TABLE_MASK (REQID_TABLES - 1)
|
||||
|
||||
#define REQID_BUCKETS 512
|
||||
#define REQID_BUCKET_MASK (REQID_BUCKETS - 1)
|
||||
#define REQID_HASH(id) (((id) >> REQID_COUNTER_SHIFT) & REQID_BUCKET_MASK)
|
||||
|
||||
#define GET_REQID(areq) (areq)->an_reqarg.cr_reqid
|
||||
#define SET_REQID(areq, val) GET_REQID(areq) = val
|
||||
|
||||
/*
|
||||
* Hash table for async requests.
|
||||
*/
|
||||
typedef struct kcf_reqid_table {
|
||||
kmutex_t rt_lock;
|
||||
crypto_req_id_t rt_curid;
|
||||
kcf_areq_node_t *rt_idhash[REQID_BUCKETS];
|
||||
} kcf_reqid_table_t;
|
||||
|
||||
/*
|
||||
* Global software provider queue structure. Requests to be
|
||||
* handled by a SW provider and have the ALWAYS_QUEUE flag set
|
||||
* get queued here.
|
||||
*/
|
||||
typedef struct kcf_global_swq {
|
||||
/*
|
||||
* gs_cv and gs_lock are used to wait for new requests.
|
||||
* gs_lock protects the changes to the queue.
|
||||
*/
|
||||
kcondvar_t gs_cv;
|
||||
kmutex_t gs_lock;
|
||||
uint_t gs_njobs;
|
||||
uint_t gs_maxjobs;
|
||||
kcf_areq_node_t *gs_first;
|
||||
kcf_areq_node_t *gs_last;
|
||||
} kcf_global_swq_t;
|
||||
|
||||
|
||||
/*
|
||||
* Internal representation of a canonical context. We contain crypto_ctx_t
|
||||
* structure in order to have just one memory allocation. The SPI
|
||||
* ((crypto_ctx_t *)ctx)->cc_framework_private maps to this structure.
|
||||
*/
|
||||
typedef struct kcf_context {
|
||||
crypto_ctx_t kc_glbl_ctx;
|
||||
uint_t kc_refcnt;
|
||||
kmutex_t kc_in_use_lock;
|
||||
/*
|
||||
* kc_req_chain_first and kc_req_chain_last are used to chain
|
||||
* multiple async requests using the same context. They should be
|
||||
* NULL for sync requests.
|
||||
*/
|
||||
kcf_areq_node_t *kc_req_chain_first;
|
||||
kcf_areq_node_t *kc_req_chain_last;
|
||||
kcf_provider_desc_t *kc_prov_desc; /* Prov. descriptor */
|
||||
kcf_provider_desc_t *kc_sw_prov_desc; /* Prov. descriptor */
|
||||
kcf_mech_entry_t *kc_mech;
|
||||
struct kcf_context *kc_secondctx; /* for dual contexts */
|
||||
} kcf_context_t;
|
||||
|
||||
/*
|
||||
* Bump up the reference count on the framework private context. A
|
||||
* global context or a request that references this structure should
|
||||
* do a hold.
|
||||
*/
|
||||
#define KCF_CONTEXT_REFHOLD(ictx) { \
|
||||
atomic_add_32(&(ictx)->kc_refcnt, 1); \
|
||||
ASSERT((ictx)->kc_refcnt != 0); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the reference count on the framework private context.
|
||||
* When the last reference is released, the framework private
|
||||
* context structure is freed along with the global context.
|
||||
*/
|
||||
#define KCF_CONTEXT_REFRELE(ictx) { \
|
||||
ASSERT((ictx)->kc_refcnt != 0); \
|
||||
membar_exit(); \
|
||||
if (atomic_add_32_nv(&(ictx)->kc_refcnt, -1) == 0) \
|
||||
kcf_free_context(ictx); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we can release the context now. In case of CRYPTO_QUEUED
|
||||
* we do not release it as we can do it only after the provider notified
|
||||
* us. In case of CRYPTO_BUSY, the client can retry the request using
|
||||
* the context, so we do not release the context.
|
||||
*
|
||||
* This macro should be called only from the final routine in
|
||||
* an init/update/final sequence. We do not release the context in case
|
||||
* of update operations. We require the consumer to free it
|
||||
* explicitly, in case it wants to abandon the operation. This is done
|
||||
* as there may be mechanisms in ECB mode that can continue even if
|
||||
* an operation on a block fails.
|
||||
*/
|
||||
#define KCF_CONTEXT_COND_RELEASE(rv, kcf_ctx) { \
|
||||
if (KCF_CONTEXT_DONE(rv)) \
|
||||
KCF_CONTEXT_REFRELE(kcf_ctx); \
|
||||
}
|
||||
|
||||
/*
|
||||
* This macro determines whether we're done with a context.
|
||||
*/
|
||||
#define KCF_CONTEXT_DONE(rv) \
|
||||
((rv) != CRYPTO_QUEUED && (rv) != CRYPTO_BUSY && \
|
||||
(rv) != CRYPTO_BUFFER_TOO_SMALL)
|
||||
|
||||
/*
|
||||
* A crypto_ctx_template_t is internally a pointer to this struct
|
||||
*/
|
||||
typedef struct kcf_ctx_template {
|
||||
crypto_kcf_provider_handle_t ct_prov_handle; /* provider handle */
|
||||
uint_t ct_generation; /* generation # */
|
||||
size_t ct_size; /* for freeing */
|
||||
crypto_spi_ctx_template_t ct_prov_tmpl; /* context template */
|
||||
/* from the SW prov */
|
||||
} kcf_ctx_template_t;
|
||||
|
||||
/*
|
||||
* Structure for pool of threads working on global software queue.
|
||||
*/
|
||||
typedef struct kcf_pool {
|
||||
uint32_t kp_threads; /* Number of threads in pool */
|
||||
uint32_t kp_idlethreads; /* Idle threads in pool */
|
||||
uint32_t kp_blockedthreads; /* Blocked threads in pool */
|
||||
|
||||
/*
|
||||
* cv & lock to monitor the condition when no threads
|
||||
* are around. In this case the failover thread kicks in.
|
||||
*/
|
||||
kcondvar_t kp_nothr_cv;
|
||||
kmutex_t kp_thread_lock;
|
||||
|
||||
/* Userspace thread creator variables. */
|
||||
boolean_t kp_signal_create_thread; /* Create requested flag */
|
||||
int kp_nthrs; /* # of threads to create */
|
||||
boolean_t kp_user_waiting; /* Thread waiting for work */
|
||||
|
||||
/*
|
||||
* cv & lock for the condition where more threads need to be
|
||||
* created. kp_user_lock also protects the three fileds above.
|
||||
*/
|
||||
kcondvar_t kp_user_cv; /* Creator cond. variable */
|
||||
kmutex_t kp_user_lock; /* Creator lock */
|
||||
} kcf_pool_t;
|
||||
|
||||
|
||||
/*
|
||||
* State of a crypto bufcall element.
|
||||
*/
|
||||
typedef enum cbuf_state {
|
||||
CBUF_FREE = 1,
|
||||
CBUF_WAITING,
|
||||
CBUF_RUNNING
|
||||
} cbuf_state_t;
|
||||
|
||||
/*
|
||||
* Structure of a crypto bufcall element.
|
||||
*/
|
||||
typedef struct kcf_cbuf_elem {
|
||||
/*
|
||||
* lock and cv to wait for CBUF_RUNNING to be done
|
||||
* kc_lock also protects kc_state.
|
||||
*/
|
||||
kmutex_t kc_lock;
|
||||
kcondvar_t kc_cv;
|
||||
cbuf_state_t kc_state;
|
||||
|
||||
struct kcf_cbuf_elem *kc_next;
|
||||
struct kcf_cbuf_elem *kc_prev;
|
||||
|
||||
void (*kc_func)(void *arg);
|
||||
void *kc_arg;
|
||||
} kcf_cbuf_elem_t;
|
||||
|
||||
/*
|
||||
* State of a notify element.
|
||||
*/
|
||||
typedef enum ntfy_elem_state {
|
||||
NTFY_WAITING = 1,
|
||||
NTFY_RUNNING
|
||||
} ntfy_elem_state_t;
|
||||
|
||||
/*
|
||||
* Structure of a notify list element.
|
||||
*/
|
||||
typedef struct kcf_ntfy_elem {
|
||||
/*
|
||||
* lock and cv to wait for NTFY_RUNNING to be done.
|
||||
* kn_lock also protects kn_state.
|
||||
*/
|
||||
kmutex_t kn_lock;
|
||||
kcondvar_t kn_cv;
|
||||
ntfy_elem_state_t kn_state;
|
||||
|
||||
struct kcf_ntfy_elem *kn_next;
|
||||
struct kcf_ntfy_elem *kn_prev;
|
||||
|
||||
crypto_notify_callback_t kn_func;
|
||||
uint32_t kn_event_mask;
|
||||
} kcf_ntfy_elem_t;
|
||||
|
||||
|
||||
/*
|
||||
* The following values are based on the assumption that it would
|
||||
* take around eight cpus to load a hardware provider (This is true for
|
||||
* at least one product) and a kernel client may come from different
|
||||
* low-priority interrupt levels. We will have CYRPTO_TASKQ_MIN number
|
||||
* of cached taskq entries. The CRYPTO_TASKQ_MAX number is based on
|
||||
* a throughput of 1GB/s using 512-byte buffers. These are just
|
||||
* reasonable estimates and might need to change in future.
|
||||
*/
|
||||
#define CRYPTO_TASKQ_THREADS 8
|
||||
#define CYRPTO_TASKQ_MIN 64
|
||||
#define CRYPTO_TASKQ_MAX 2 * 1024 * 1024
|
||||
|
||||
extern int crypto_taskq_threads;
|
||||
extern int crypto_taskq_minalloc;
|
||||
extern int crypto_taskq_maxalloc;
|
||||
extern kcf_global_swq_t *gswq;
|
||||
extern int kcf_maxthreads;
|
||||
extern int kcf_minthreads;
|
||||
|
||||
/*
|
||||
* All pending crypto bufcalls are put on a list. cbuf_list_lock
|
||||
* protects changes to this list.
|
||||
*/
|
||||
extern kmutex_t cbuf_list_lock;
|
||||
extern kcondvar_t cbuf_list_cv;
|
||||
|
||||
/*
|
||||
* All event subscribers are put on a list. kcf_notify_list_lock
|
||||
* protects changes to this list.
|
||||
*/
|
||||
extern kmutex_t ntfy_list_lock;
|
||||
extern kcondvar_t ntfy_list_cv;
|
||||
|
||||
boolean_t kcf_get_next_logical_provider_member(kcf_provider_desc_t *,
|
||||
kcf_provider_desc_t *, kcf_provider_desc_t **);
|
||||
extern int kcf_get_hardware_provider(crypto_mech_type_t, crypto_mech_type_t,
|
||||
boolean_t, kcf_provider_desc_t *, kcf_provider_desc_t **,
|
||||
crypto_func_group_t);
|
||||
extern int kcf_get_hardware_provider_nomech(offset_t, offset_t,
|
||||
boolean_t, kcf_provider_desc_t *, kcf_provider_desc_t **);
|
||||
extern void kcf_free_triedlist(kcf_prov_tried_t *);
|
||||
extern kcf_prov_tried_t *kcf_insert_triedlist(kcf_prov_tried_t **,
|
||||
kcf_provider_desc_t *, int);
|
||||
extern kcf_provider_desc_t *kcf_get_mech_provider(crypto_mech_type_t,
|
||||
kcf_mech_entry_t **, int *, kcf_prov_tried_t *, crypto_func_group_t,
|
||||
boolean_t, size_t);
|
||||
extern kcf_provider_desc_t *kcf_get_dual_provider(crypto_mechanism_t *,
|
||||
crypto_mechanism_t *, kcf_mech_entry_t **, crypto_mech_type_t *,
|
||||
crypto_mech_type_t *, int *, kcf_prov_tried_t *,
|
||||
crypto_func_group_t, crypto_func_group_t, boolean_t, size_t);
|
||||
extern crypto_ctx_t *kcf_new_ctx(crypto_call_req_t *, kcf_provider_desc_t *,
|
||||
crypto_session_id_t);
|
||||
extern int kcf_submit_request(kcf_provider_desc_t *, crypto_ctx_t *,
|
||||
crypto_call_req_t *, kcf_req_params_t *, boolean_t);
|
||||
extern void kcf_sched_destroy(void);
|
||||
extern void kcf_sched_init(void);
|
||||
extern void kcf_sched_start(void);
|
||||
extern void kcf_sop_done(kcf_sreq_node_t *, int);
|
||||
extern void kcf_aop_done(kcf_areq_node_t *, int);
|
||||
extern int common_submit_request(kcf_provider_desc_t *,
|
||||
crypto_ctx_t *, kcf_req_params_t *, crypto_req_handle_t);
|
||||
extern void kcf_free_context(kcf_context_t *);
|
||||
|
||||
extern int kcf_svc_wait(int *);
|
||||
extern int kcf_svc_do_run(void);
|
||||
extern int kcf_need_signature_verification(kcf_provider_desc_t *);
|
||||
extern void kcf_verify_signature(void *);
|
||||
extern struct modctl *kcf_get_modctl(crypto_provider_info_t *);
|
||||
extern void verify_unverified_providers(void);
|
||||
extern void kcf_free_req(kcf_areq_node_t *areq);
|
||||
extern void crypto_bufcall_service(void);
|
||||
|
||||
extern void kcf_walk_ntfylist(uint32_t, void *);
|
||||
extern void kcf_do_notify(kcf_provider_desc_t *, boolean_t);
|
||||
|
||||
extern kcf_dual_req_t *kcf_alloc_req(crypto_call_req_t *);
|
||||
extern void kcf_next_req(void *, int);
|
||||
extern void kcf_last_req(void *, int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_SCHED_IMPL_H */
|
721
module/icp/include/sys/crypto/spi.h
Normal file
721
module/icp/include/sys/crypto/spi.h
Normal file
@ -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://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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_CRYPTO_SPI_H
|
||||
#define _SYS_CRYPTO_SPI_H
|
||||
|
||||
/*
|
||||
* CSPI: Cryptographic Service Provider Interface.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define CRYPTO_SPI_VERSION_1 1
|
||||
#define CRYPTO_SPI_VERSION_2 2
|
||||
#define CRYPTO_SPI_VERSION_3 3
|
||||
|
||||
/*
|
||||
* Provider-private handle. This handle is specified by a provider
|
||||
* when it registers by means of the pi_provider_handle field of
|
||||
* the crypto_provider_info structure, and passed to the provider
|
||||
* when its entry points are invoked.
|
||||
*/
|
||||
typedef void *crypto_provider_handle_t;
|
||||
|
||||
/*
|
||||
* Context templates can be used to by software providers to pre-process
|
||||
* keying material, such as key schedules. They are allocated by
|
||||
* a software provider create_ctx_template(9E) entry point, and passed
|
||||
* as argument to initialization and atomic provider entry points.
|
||||
*/
|
||||
typedef void *crypto_spi_ctx_template_t;
|
||||
|
||||
/*
|
||||
* Request handles are used by the kernel to identify an asynchronous
|
||||
* request being processed by a provider. It is passed by the kernel
|
||||
* to a hardware provider when submitting a request, and must be
|
||||
* specified by a provider when calling crypto_op_notification(9F)
|
||||
*/
|
||||
typedef void *crypto_req_handle_t;
|
||||
|
||||
/* Values for cc_flags field */
|
||||
#define CRYPTO_INIT_OPSTATE 0x00000001 /* allocate and init cc_opstate */
|
||||
#define CRYPTO_USE_OPSTATE 0x00000002 /* .. start using it as context */
|
||||
|
||||
/*
|
||||
* The context structure is passed from the kernel to a provider.
|
||||
* It contains the information needed to process a multi-part or
|
||||
* single part operation. The context structure is not used
|
||||
* by atomic operations.
|
||||
*
|
||||
* Parameters needed to perform a cryptographic operation, such
|
||||
* as keys, mechanisms, input and output buffers, are passed
|
||||
* as separate arguments to Provider routines.
|
||||
*/
|
||||
typedef struct crypto_ctx {
|
||||
crypto_provider_handle_t cc_provider;
|
||||
crypto_session_id_t cc_session;
|
||||
void *cc_provider_private; /* owned by provider */
|
||||
void *cc_framework_private; /* owned by framework */
|
||||
uint32_t cc_flags; /* flags */
|
||||
void *cc_opstate; /* state */
|
||||
} crypto_ctx_t;
|
||||
|
||||
/*
|
||||
* Extended provider information.
|
||||
*/
|
||||
|
||||
/*
|
||||
* valid values for ei_flags field of extended info structure
|
||||
* They match the RSA Security, Inc PKCS#11 tokenInfo flags.
|
||||
*/
|
||||
#define CRYPTO_EXTF_RNG 0x00000001
|
||||
#define CRYPTO_EXTF_WRITE_PROTECTED 0x00000002
|
||||
#define CRYPTO_EXTF_LOGIN_REQUIRED 0x00000004
|
||||
#define CRYPTO_EXTF_USER_PIN_INITIALIZED 0x00000008
|
||||
#define CRYPTO_EXTF_CLOCK_ON_TOKEN 0x00000040
|
||||
#define CRYPTO_EXTF_PROTECTED_AUTHENTICATION_PATH 0x00000100
|
||||
#define CRYPTO_EXTF_DUAL_CRYPTO_OPERATIONS 0x00000200
|
||||
#define CRYPTO_EXTF_TOKEN_INITIALIZED 0x00000400
|
||||
#define CRYPTO_EXTF_USER_PIN_COUNT_LOW 0x00010000
|
||||
#define CRYPTO_EXTF_USER_PIN_FINAL_TRY 0x00020000
|
||||
#define CRYPTO_EXTF_USER_PIN_LOCKED 0x00040000
|
||||
#define CRYPTO_EXTF_USER_PIN_TO_BE_CHANGED 0x00080000
|
||||
#define CRYPTO_EXTF_SO_PIN_COUNT_LOW 0x00100000
|
||||
#define CRYPTO_EXTF_SO_PIN_FINAL_TRY 0x00200000
|
||||
#define CRYPTO_EXTF_SO_PIN_LOCKED 0x00400000
|
||||
#define CRYPTO_EXTF_SO_PIN_TO_BE_CHANGED 0x00800000
|
||||
|
||||
/*
|
||||
* The crypto_control_ops structure contains pointers to control
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_control_ops {
|
||||
void (*provider_status)(crypto_provider_handle_t, uint_t *);
|
||||
} crypto_control_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_ctx_ops structure contains points to context and context
|
||||
* templates management operations for cryptographic providers. It is
|
||||
* passed through the crypto_ops(9S) structure when providers register
|
||||
* with the kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_ctx_ops {
|
||||
int (*create_ctx_template)(crypto_provider_handle_t,
|
||||
crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_spi_ctx_template_t *, size_t *, crypto_req_handle_t);
|
||||
int (*free_context)(crypto_ctx_t *);
|
||||
} crypto_ctx_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_digest_ops structure contains pointers to digest
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_digest_ops {
|
||||
int (*digest_init)(crypto_ctx_t *, crypto_mechanism_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*digest)(crypto_ctx_t *, crypto_data_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*digest_update)(crypto_ctx_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*digest_key)(crypto_ctx_t *, crypto_key_t *, crypto_req_handle_t);
|
||||
int (*digest_final)(crypto_ctx_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*digest_atomic)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_data_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
} crypto_digest_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_cipher_ops structure contains pointers to encryption
|
||||
* and decryption operations for cryptographic providers. It is
|
||||
* passed through the crypto_ops(9S) structure when providers register
|
||||
* with the kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_cipher_ops {
|
||||
int (*encrypt_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
int (*encrypt)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*encrypt_update)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*encrypt_final)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*encrypt_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);
|
||||
|
||||
int (*decrypt_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
int (*decrypt)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*decrypt_update)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*decrypt_final)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*decrypt_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);
|
||||
} crypto_cipher_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_mac_ops structure contains pointers to MAC
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_mac_ops {
|
||||
int (*mac_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
int (*mac)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*mac_update)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*mac_final)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*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);
|
||||
int (*mac_verify_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);
|
||||
} crypto_mac_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_sign_ops structure contains pointers to signing
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_sign_ops {
|
||||
int (*sign_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
|
||||
crypto_req_handle_t);
|
||||
int (*sign)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*sign_update)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*sign_final)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*sign_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);
|
||||
int (*sign_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
|
||||
crypto_key_t *, crypto_spi_ctx_template_t,
|
||||
crypto_req_handle_t);
|
||||
int (*sign_recover)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*sign_recover_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);
|
||||
} crypto_sign_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_verify_ops structure contains pointers to verify
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_verify_ops {
|
||||
int (*verify_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_spi_ctx_template_t,
|
||||
crypto_req_handle_t);
|
||||
int (*do_verify)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*verify_update)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*verify_final)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*verify_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);
|
||||
int (*verify_recover_init)(crypto_ctx_t *, crypto_mechanism_t *,
|
||||
crypto_key_t *, crypto_spi_ctx_template_t,
|
||||
crypto_req_handle_t);
|
||||
int (*verify_recover)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*verify_recover_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);
|
||||
} crypto_verify_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_dual_ops structure contains pointers to dual
|
||||
* cipher and sign/verify operations for cryptographic providers.
|
||||
* It is passed through the crypto_ops(9S) structure when
|
||||
* providers register with the kernel using
|
||||
* crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_dual_ops {
|
||||
int (*digest_encrypt_update)(
|
||||
crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*decrypt_digest_update)(
|
||||
crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*sign_encrypt_update)(
|
||||
crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
int (*decrypt_verify_update)(
|
||||
crypto_ctx_t *, crypto_ctx_t *, crypto_data_t *,
|
||||
crypto_data_t *, crypto_req_handle_t);
|
||||
} crypto_dual_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_dual_cipher_mac_ops structure contains pointers to dual
|
||||
* cipher and MAC operations for cryptographic providers.
|
||||
* It is passed through the crypto_ops(9S) structure when
|
||||
* providers register with the kernel using
|
||||
* crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_dual_cipher_mac_ops {
|
||||
int (*encrypt_mac_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
|
||||
crypto_key_t *, crypto_spi_ctx_template_t,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
int (*encrypt_mac)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_dual_data_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*encrypt_mac_update)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_dual_data_t *, crypto_req_handle_t);
|
||||
int (*encrypt_mac_final)(crypto_ctx_t *,
|
||||
crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*encrypt_mac_atomic)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
|
||||
crypto_key_t *, crypto_data_t *, crypto_dual_data_t *,
|
||||
crypto_data_t *, crypto_spi_ctx_template_t,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
|
||||
int (*mac_decrypt_init)(crypto_ctx_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_mechanism_t *,
|
||||
crypto_key_t *, crypto_spi_ctx_template_t,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
int (*mac_decrypt)(crypto_ctx_t *,
|
||||
crypto_dual_data_t *, crypto_data_t *, crypto_data_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*mac_decrypt_update)(crypto_ctx_t *,
|
||||
crypto_dual_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*mac_decrypt_final)(crypto_ctx_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_req_handle_t);
|
||||
int (*mac_decrypt_atomic)(crypto_provider_handle_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
int (*mac_verify_decrypt_atomic)(crypto_provider_handle_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *, crypto_key_t *,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_dual_data_t *,
|
||||
crypto_data_t *, crypto_data_t *, crypto_spi_ctx_template_t,
|
||||
crypto_spi_ctx_template_t, crypto_req_handle_t);
|
||||
} crypto_dual_cipher_mac_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_random_number_ops structure contains pointers to random
|
||||
* number operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_random_number_ops {
|
||||
int (*seed_random)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
uchar_t *, size_t, uint_t, uint32_t, crypto_req_handle_t);
|
||||
int (*generate_random)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
uchar_t *, size_t, crypto_req_handle_t);
|
||||
} crypto_random_number_ops_t;
|
||||
|
||||
/*
|
||||
* Flag values for seed_random.
|
||||
*/
|
||||
#define CRYPTO_SEED_NOW 0x00000001
|
||||
|
||||
/*
|
||||
* The crypto_session_ops structure contains pointers to session
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_session_ops {
|
||||
int (*session_open)(crypto_provider_handle_t, crypto_session_id_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*session_close)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_req_handle_t);
|
||||
int (*session_login)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_user_type_t, char *, size_t, crypto_req_handle_t);
|
||||
int (*session_logout)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_req_handle_t);
|
||||
} crypto_session_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_object_ops structure contains pointers to object
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_object_ops {
|
||||
int (*object_create)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
|
||||
crypto_req_handle_t);
|
||||
int (*object_copy)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_object_id_t, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_id_t *, crypto_req_handle_t);
|
||||
int (*object_destroy)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_object_id_t, crypto_req_handle_t);
|
||||
int (*object_get_size)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_object_id_t, size_t *, crypto_req_handle_t);
|
||||
int (*object_get_attribute_value)(crypto_provider_handle_t,
|
||||
crypto_session_id_t, crypto_object_id_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
|
||||
int (*object_set_attribute_value)(crypto_provider_handle_t,
|
||||
crypto_session_id_t, crypto_object_id_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
|
||||
int (*object_find_init)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_object_attribute_t *, uint_t, void **,
|
||||
crypto_req_handle_t);
|
||||
int (*object_find)(crypto_provider_handle_t, void *,
|
||||
crypto_object_id_t *, uint_t, uint_t *, crypto_req_handle_t);
|
||||
int (*object_find_final)(crypto_provider_handle_t, void *,
|
||||
crypto_req_handle_t);
|
||||
} crypto_object_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_key_ops structure contains pointers to key
|
||||
* operations for cryptographic providers. It is passed through
|
||||
* the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_key_ops {
|
||||
int (*key_generate)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_id_t *, crypto_req_handle_t);
|
||||
int (*key_generate_pair)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_id_t *,
|
||||
crypto_object_id_t *, crypto_req_handle_t);
|
||||
int (*key_wrap)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_object_id_t *,
|
||||
uchar_t *, size_t *, crypto_req_handle_t);
|
||||
int (*key_unwrap)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, uchar_t *, size_t *,
|
||||
crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_id_t *, crypto_req_handle_t);
|
||||
int (*key_derive)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
|
||||
uint_t, crypto_object_id_t *, crypto_req_handle_t);
|
||||
int (*key_check)(crypto_provider_handle_t, crypto_mechanism_t *,
|
||||
crypto_key_t *);
|
||||
} crypto_key_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_provider_management_ops structure contains pointers
|
||||
* to management operations for cryptographic providers. It is passed
|
||||
* through the crypto_ops(9S) structure when providers register with the
|
||||
* kernel using crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_provider_management_ops {
|
||||
int (*ext_info)(crypto_provider_handle_t,
|
||||
crypto_provider_ext_info_t *, crypto_req_handle_t);
|
||||
int (*init_token)(crypto_provider_handle_t, char *, size_t,
|
||||
char *, crypto_req_handle_t);
|
||||
int (*init_pin)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
char *, size_t, crypto_req_handle_t);
|
||||
int (*set_pin)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
char *, size_t, char *, size_t, crypto_req_handle_t);
|
||||
} crypto_provider_management_ops_t;
|
||||
|
||||
typedef struct crypto_mech_ops {
|
||||
int (*copyin_mechanism)(crypto_provider_handle_t,
|
||||
crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
|
||||
int (*copyout_mechanism)(crypto_provider_handle_t,
|
||||
crypto_mechanism_t *, crypto_mechanism_t *, int *, int);
|
||||
int (*free_mechanism)(crypto_provider_handle_t, crypto_mechanism_t *);
|
||||
} crypto_mech_ops_t;
|
||||
|
||||
typedef struct crypto_nostore_key_ops {
|
||||
int (*nostore_key_generate)(crypto_provider_handle_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
|
||||
uint_t, crypto_req_handle_t);
|
||||
int (*nostore_key_generate_pair)(crypto_provider_handle_t,
|
||||
crypto_session_id_t, crypto_mechanism_t *,
|
||||
crypto_object_attribute_t *, uint_t, crypto_object_attribute_t *,
|
||||
uint_t, crypto_object_attribute_t *, uint_t,
|
||||
crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
|
||||
int (*nostore_key_derive)(crypto_provider_handle_t, crypto_session_id_t,
|
||||
crypto_mechanism_t *, crypto_key_t *, crypto_object_attribute_t *,
|
||||
uint_t, crypto_object_attribute_t *, uint_t, crypto_req_handle_t);
|
||||
} crypto_nostore_key_ops_t;
|
||||
|
||||
/*
|
||||
* The crypto_ops(9S) structure contains the structures containing
|
||||
* the pointers to functions implemented by cryptographic providers.
|
||||
* It is specified as part of the crypto_provider_info(9S)
|
||||
* supplied by a provider when it registers with the kernel
|
||||
* by calling crypto_register_provider(9F).
|
||||
*/
|
||||
typedef struct crypto_ops_v1 {
|
||||
crypto_control_ops_t *co_control_ops;
|
||||
crypto_digest_ops_t *co_digest_ops;
|
||||
crypto_cipher_ops_t *co_cipher_ops;
|
||||
crypto_mac_ops_t *co_mac_ops;
|
||||
crypto_sign_ops_t *co_sign_ops;
|
||||
crypto_verify_ops_t *co_verify_ops;
|
||||
crypto_dual_ops_t *co_dual_ops;
|
||||
crypto_dual_cipher_mac_ops_t *co_dual_cipher_mac_ops;
|
||||
crypto_random_number_ops_t *co_random_ops;
|
||||
crypto_session_ops_t *co_session_ops;
|
||||
crypto_object_ops_t *co_object_ops;
|
||||
crypto_key_ops_t *co_key_ops;
|
||||
crypto_provider_management_ops_t *co_provider_ops;
|
||||
crypto_ctx_ops_t *co_ctx_ops;
|
||||
} crypto_ops_v1_t;
|
||||
|
||||
typedef struct crypto_ops_v2 {
|
||||
crypto_ops_v1_t v1_ops;
|
||||
crypto_mech_ops_t *co_mech_ops;
|
||||
} crypto_ops_v2_t;
|
||||
|
||||
typedef struct crypto_ops_v3 {
|
||||
crypto_ops_v2_t v2_ops;
|
||||
crypto_nostore_key_ops_t *co_nostore_key_ops;
|
||||
} crypto_ops_v3_t;
|
||||
|
||||
typedef struct crypto_ops {
|
||||
union {
|
||||
crypto_ops_v3_t cou_v3;
|
||||
crypto_ops_v2_t cou_v2;
|
||||
crypto_ops_v1_t cou_v1;
|
||||
} cou;
|
||||
} crypto_ops_t;
|
||||
|
||||
#define co_control_ops cou.cou_v1.co_control_ops
|
||||
#define co_digest_ops cou.cou_v1.co_digest_ops
|
||||
#define co_cipher_ops cou.cou_v1.co_cipher_ops
|
||||
#define co_mac_ops cou.cou_v1.co_mac_ops
|
||||
#define co_sign_ops cou.cou_v1.co_sign_ops
|
||||
#define co_verify_ops cou.cou_v1.co_verify_ops
|
||||
#define co_dual_ops cou.cou_v1.co_dual_ops
|
||||
#define co_dual_cipher_mac_ops cou.cou_v1.co_dual_cipher_mac_ops
|
||||
#define co_random_ops cou.cou_v1.co_random_ops
|
||||
#define co_session_ops cou.cou_v1.co_session_ops
|
||||
#define co_object_ops cou.cou_v1.co_object_ops
|
||||
#define co_key_ops cou.cou_v1.co_key_ops
|
||||
#define co_provider_ops cou.cou_v1.co_provider_ops
|
||||
#define co_ctx_ops cou.cou_v1.co_ctx_ops
|
||||
#define co_mech_ops cou.cou_v2.co_mech_ops
|
||||
#define co_nostore_key_ops cou.cou_v3.co_nostore_key_ops
|
||||
|
||||
/*
|
||||
* The mechanism info structure crypto_mech_info_t contains a function group
|
||||
* bit mask cm_func_group_mask. This field, of type crypto_func_group_t,
|
||||
* specifies the provider entry point that can be used a particular
|
||||
* mechanism. The function group mask is a combination of the following values.
|
||||
*/
|
||||
|
||||
typedef uint32_t crypto_func_group_t;
|
||||
|
||||
|
||||
#define CRYPTO_FG_ENCRYPT 0x00000001 /* encrypt_init() */
|
||||
#define CRYPTO_FG_DECRYPT 0x00000002 /* decrypt_init() */
|
||||
#define CRYPTO_FG_DIGEST 0x00000004 /* digest_init() */
|
||||
#define CRYPTO_FG_SIGN 0x00000008 /* sign_init() */
|
||||
#define CRYPTO_FG_SIGN_RECOVER 0x00000010 /* sign_recover_init() */
|
||||
#define CRYPTO_FG_VERIFY 0x00000020 /* verify_init() */
|
||||
#define CRYPTO_FG_VERIFY_RECOVER 0x00000040 /* verify_recover_init() */
|
||||
#define CRYPTO_FG_GENERATE 0x00000080 /* key_generate() */
|
||||
#define CRYPTO_FG_GENERATE_KEY_PAIR 0x00000100 /* key_generate_pair() */
|
||||
#define CRYPTO_FG_WRAP 0x00000200 /* key_wrap() */
|
||||
#define CRYPTO_FG_UNWRAP 0x00000400 /* key_unwrap() */
|
||||
#define CRYPTO_FG_DERIVE 0x00000800 /* key_derive() */
|
||||
#define CRYPTO_FG_MAC 0x00001000 /* mac_init() */
|
||||
#define CRYPTO_FG_ENCRYPT_MAC 0x00002000 /* encrypt_mac_init() */
|
||||
#define CRYPTO_FG_MAC_DECRYPT 0x00004000 /* decrypt_mac_init() */
|
||||
#define CRYPTO_FG_ENCRYPT_ATOMIC 0x00008000 /* encrypt_atomic() */
|
||||
#define CRYPTO_FG_DECRYPT_ATOMIC 0x00010000 /* decrypt_atomic() */
|
||||
#define CRYPTO_FG_MAC_ATOMIC 0x00020000 /* mac_atomic() */
|
||||
#define CRYPTO_FG_DIGEST_ATOMIC 0x00040000 /* digest_atomic() */
|
||||
#define CRYPTO_FG_SIGN_ATOMIC 0x00080000 /* sign_atomic() */
|
||||
#define CRYPTO_FG_SIGN_RECOVER_ATOMIC 0x00100000 /* sign_recover_atomic() */
|
||||
#define CRYPTO_FG_VERIFY_ATOMIC 0x00200000 /* verify_atomic() */
|
||||
#define CRYPTO_FG_VERIFY_RECOVER_ATOMIC 0x00400000 /* verify_recover_atomic() */
|
||||
#define CRYPTO_FG_ENCRYPT_MAC_ATOMIC 0x00800000 /* encrypt_mac_atomic() */
|
||||
#define CRYPTO_FG_MAC_DECRYPT_ATOMIC 0x01000000 /* mac_decrypt_atomic() */
|
||||
#define CRYPTO_FG_RESERVED 0x80000000
|
||||
|
||||
/*
|
||||
* Maximum length of the pi_provider_description field of the
|
||||
* crypto_provider_info structure.
|
||||
*/
|
||||
#define CRYPTO_PROVIDER_DESCR_MAX_LEN 64
|
||||
|
||||
|
||||
/* Bit mask for all the simple operations */
|
||||
#define CRYPTO_FG_SIMPLEOP_MASK (CRYPTO_FG_ENCRYPT | CRYPTO_FG_DECRYPT | \
|
||||
CRYPTO_FG_DIGEST | CRYPTO_FG_SIGN | CRYPTO_FG_VERIFY | CRYPTO_FG_MAC | \
|
||||
CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC | \
|
||||
CRYPTO_FG_MAC_ATOMIC | CRYPTO_FG_DIGEST_ATOMIC | CRYPTO_FG_SIGN_ATOMIC | \
|
||||
CRYPTO_FG_VERIFY_ATOMIC)
|
||||
|
||||
/* Bit mask for all the dual operations */
|
||||
#define CRYPTO_FG_MAC_CIPHER_MASK (CRYPTO_FG_ENCRYPT_MAC | \
|
||||
CRYPTO_FG_MAC_DECRYPT | CRYPTO_FG_ENCRYPT_MAC_ATOMIC | \
|
||||
CRYPTO_FG_MAC_DECRYPT_ATOMIC)
|
||||
|
||||
/* Add other combos to CRYPTO_FG_DUAL_MASK */
|
||||
#define CRYPTO_FG_DUAL_MASK CRYPTO_FG_MAC_CIPHER_MASK
|
||||
|
||||
/*
|
||||
* The crypto_mech_info structure specifies one of the mechanisms
|
||||
* supported by a cryptographic provider. The pi_mechanisms field of
|
||||
* the crypto_provider_info structure contains a pointer to an array
|
||||
* of crypto_mech_info's.
|
||||
*/
|
||||
typedef struct crypto_mech_info {
|
||||
crypto_mech_name_t cm_mech_name;
|
||||
crypto_mech_type_t cm_mech_number;
|
||||
crypto_func_group_t cm_func_group_mask;
|
||||
ssize_t cm_min_key_length;
|
||||
ssize_t cm_max_key_length;
|
||||
uint32_t cm_mech_flags;
|
||||
} crypto_mech_info_t;
|
||||
|
||||
/* Alias the old name to the new name for compatibility. */
|
||||
#define cm_keysize_unit cm_mech_flags
|
||||
|
||||
/*
|
||||
* The following is used by a provider that sets
|
||||
* CRYPTO_HASH_NO_UPDATE. It needs to specify the maximum
|
||||
* input data size it can digest in this field.
|
||||
*/
|
||||
#define cm_max_input_length cm_max_key_length
|
||||
|
||||
/*
|
||||
* crypto_kcf_provider_handle_t is a handle allocated by the kernel.
|
||||
* It is returned after the provider registers with
|
||||
* crypto_register_provider(), and must be specified by the provider
|
||||
* when calling crypto_unregister_provider(), and
|
||||
* crypto_provider_notification().
|
||||
*/
|
||||
typedef uint_t crypto_kcf_provider_handle_t;
|
||||
|
||||
/*
|
||||
* Provider information. Passed as argument to crypto_register_provider(9F).
|
||||
* Describes the provider and its capabilities. Multiple providers can
|
||||
* register for the same device instance. In this case, the same
|
||||
* pi_provider_dev must be specified with a different pi_provider_handle.
|
||||
*/
|
||||
typedef struct crypto_provider_info_v1 {
|
||||
uint_t pi_interface_version;
|
||||
char *pi_provider_description;
|
||||
crypto_provider_type_t pi_provider_type;
|
||||
crypto_provider_handle_t pi_provider_handle;
|
||||
crypto_ops_t *pi_ops_vector;
|
||||
uint_t pi_mech_list_count;
|
||||
crypto_mech_info_t *pi_mechanisms;
|
||||
uint_t pi_logical_provider_count;
|
||||
crypto_kcf_provider_handle_t *pi_logical_providers;
|
||||
} crypto_provider_info_v1_t;
|
||||
|
||||
typedef struct crypto_provider_info_v2 {
|
||||
crypto_provider_info_v1_t v1_info;
|
||||
uint_t pi_flags;
|
||||
} crypto_provider_info_v2_t;
|
||||
|
||||
typedef struct crypto_provider_info {
|
||||
union {
|
||||
crypto_provider_info_v2_t piu_v2;
|
||||
crypto_provider_info_v1_t piu_v1;
|
||||
} piu;
|
||||
} crypto_provider_info_t;
|
||||
|
||||
#define pi_interface_version piu.piu_v1.pi_interface_version
|
||||
#define pi_provider_description piu.piu_v1.pi_provider_description
|
||||
#define pi_provider_type piu.piu_v1.pi_provider_type
|
||||
#define pi_provider_handle piu.piu_v1.pi_provider_handle
|
||||
#define pi_ops_vector piu.piu_v1.pi_ops_vector
|
||||
#define pi_mech_list_count piu.piu_v1.pi_mech_list_count
|
||||
#define pi_mechanisms piu.piu_v1.pi_mechanisms
|
||||
#define pi_logical_provider_count piu.piu_v1.pi_logical_provider_count
|
||||
#define pi_logical_providers piu.piu_v1.pi_logical_providers
|
||||
#define pi_flags piu.piu_v2.pi_flags
|
||||
|
||||
/* hidden providers can only be accessed via a logical provider */
|
||||
#define CRYPTO_HIDE_PROVIDER 0x00000001
|
||||
/*
|
||||
* provider can not do multi-part digest (updates) and has a limit
|
||||
* on maximum input data that it can digest.
|
||||
*/
|
||||
#define CRYPTO_HASH_NO_UPDATE 0x00000002
|
||||
|
||||
/* provider can handle the request without returning a CRYPTO_QUEUED */
|
||||
#define CRYPTO_SYNCHRONOUS 0x00000004
|
||||
|
||||
#define CRYPTO_PIFLAGS_RESERVED2 0x40000000
|
||||
#define CRYPTO_PIFLAGS_RESERVED1 0x80000000
|
||||
|
||||
/*
|
||||
* Provider status passed by a provider to crypto_provider_notification(9F)
|
||||
* and returned by the provider_stauts(9E) entry point.
|
||||
*/
|
||||
#define CRYPTO_PROVIDER_READY 0
|
||||
#define CRYPTO_PROVIDER_BUSY 1
|
||||
#define CRYPTO_PROVIDER_FAILED 2
|
||||
|
||||
/*
|
||||
* Functions exported by Solaris to cryptographic providers. Providers
|
||||
* call these functions to register and unregister, notify the kernel
|
||||
* of state changes, and notify the kernel when a asynchronous request
|
||||
* completed.
|
||||
*/
|
||||
extern int crypto_register_provider(crypto_provider_info_t *,
|
||||
crypto_kcf_provider_handle_t *);
|
||||
extern int crypto_unregister_provider(crypto_kcf_provider_handle_t);
|
||||
extern void crypto_provider_notification(crypto_kcf_provider_handle_t, uint_t);
|
||||
extern void crypto_op_notification(crypto_req_handle_t, int);
|
||||
extern int crypto_kmflag(crypto_req_handle_t);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CRYPTO_SPI_H */
|
307
module/icp/include/sys/ia32/asm_linkage.h
Normal file
307
module/icp/include/sys/ia32/asm_linkage.h
Normal file
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _IA32_SYS_ASM_LINKAGE_H
|
||||
#define _IA32_SYS_ASM_LINKAGE_H
|
||||
|
||||
#include <sys/stack.h>
|
||||
#include <sys/trap.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _ASM /* The remainder of this file is only for assembly files */
|
||||
|
||||
/*
|
||||
* make annoying differences in assembler syntax go away
|
||||
*/
|
||||
|
||||
/*
|
||||
* D16 and A16 are used to insert instructions prefixes; the
|
||||
* macros help the assembler code be slightly more portable.
|
||||
*/
|
||||
#if !defined(__GNUC_AS__)
|
||||
/*
|
||||
* /usr/ccs/bin/as prefixes are parsed as separate instructions
|
||||
*/
|
||||
#define D16 data16;
|
||||
#define A16 addr16;
|
||||
|
||||
/*
|
||||
* (There are some weird constructs in constant expressions)
|
||||
*/
|
||||
#define _CONST(const) [const]
|
||||
#define _BITNOT(const) -1!_CONST(const)
|
||||
#define _MUL(a, b) _CONST(a \* b)
|
||||
|
||||
#else
|
||||
/*
|
||||
* Why not use the 'data16' and 'addr16' prefixes .. well, the
|
||||
* assembler doesn't quite believe in real mode, and thus argues with
|
||||
* us about what we're trying to do.
|
||||
*/
|
||||
#define D16 .byte 0x66;
|
||||
#define A16 .byte 0x67;
|
||||
|
||||
#define _CONST(const) (const)
|
||||
#define _BITNOT(const) ~_CONST(const)
|
||||
#define _MUL(a, b) _CONST(a * b)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* C pointers are different sizes between i386 and amd64.
|
||||
* These constants can be used to compute offsets into pointer arrays.
|
||||
*/
|
||||
#if defined(__amd64)
|
||||
#define CLONGSHIFT 3
|
||||
#define CLONGSIZE 8
|
||||
#define CLONGMASK 7
|
||||
#elif defined(__i386)
|
||||
#define CLONGSHIFT 2
|
||||
#define CLONGSIZE 4
|
||||
#define CLONGMASK 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Since we know we're either ILP32 or LP64 ..
|
||||
*/
|
||||
#define CPTRSHIFT CLONGSHIFT
|
||||
#define CPTRSIZE CLONGSIZE
|
||||
#define CPTRMASK CLONGMASK
|
||||
|
||||
#if CPTRSIZE != (1 << CPTRSHIFT) || CLONGSIZE != (1 << CLONGSHIFT)
|
||||
#error "inconsistent shift constants"
|
||||
#endif
|
||||
|
||||
#if CPTRMASK != (CPTRSIZE - 1) || CLONGMASK != (CLONGSIZE - 1)
|
||||
#error "inconsistent mask constants"
|
||||
#endif
|
||||
|
||||
#define ASM_ENTRY_ALIGN 16
|
||||
|
||||
/*
|
||||
* SSE register alignment and save areas
|
||||
*/
|
||||
|
||||
#define XMM_SIZE 16
|
||||
#define XMM_ALIGN 16
|
||||
|
||||
#if defined(__amd64)
|
||||
|
||||
#define SAVE_XMM_PROLOG(sreg, nreg) \
|
||||
subq $_CONST(_MUL(XMM_SIZE, nreg)), %rsp; \
|
||||
movq %rsp, sreg
|
||||
|
||||
#define RSTOR_XMM_EPILOG(sreg, nreg) \
|
||||
addq $_CONST(_MUL(XMM_SIZE, nreg)), %rsp
|
||||
|
||||
#elif defined(__i386)
|
||||
|
||||
#define SAVE_XMM_PROLOG(sreg, nreg) \
|
||||
subl $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp; \
|
||||
movl %esp, sreg; \
|
||||
addl $XMM_ALIGN, sreg; \
|
||||
andl $_BITNOT(XMM_ALIGN-1), sreg
|
||||
|
||||
#define RSTOR_XMM_EPILOG(sreg, nreg) \
|
||||
addl $_CONST(_MUL(XMM_SIZE, nreg) + XMM_ALIGN), %esp;
|
||||
|
||||
#endif /* __i386 */
|
||||
|
||||
/*
|
||||
* profiling causes definitions of the MCOUNT and RTMCOUNT
|
||||
* particular to the type
|
||||
*/
|
||||
#ifdef GPROF
|
||||
|
||||
#define MCOUNT(x) \
|
||||
pushl %ebp; \
|
||||
movl %esp, %ebp; \
|
||||
call _mcount; \
|
||||
popl %ebp
|
||||
|
||||
#endif /* GPROF */
|
||||
|
||||
#ifdef PROF
|
||||
|
||||
#define MCOUNT(x) \
|
||||
/* CSTYLED */ \
|
||||
.lcomm .L_/**/x/**/1, 4, 4; \
|
||||
pushl %ebp; \
|
||||
movl %esp, %ebp; \
|
||||
/* CSTYLED */ \
|
||||
movl $.L_/**/x/**/1, %edx; \
|
||||
call _mcount; \
|
||||
popl %ebp
|
||||
|
||||
#endif /* PROF */
|
||||
|
||||
/*
|
||||
* if we are not profiling, MCOUNT should be defined to nothing
|
||||
*/
|
||||
#if !defined(PROF) && !defined(GPROF)
|
||||
#define MCOUNT(x)
|
||||
#endif /* !defined(PROF) && !defined(GPROF) */
|
||||
|
||||
#define RTMCOUNT(x) MCOUNT(x)
|
||||
|
||||
/*
|
||||
* Macro to define weak symbol aliases. These are similar to the ANSI-C
|
||||
* #pragma weak _name = name
|
||||
* except a compiler can determine type. The assembler must be told. Hence,
|
||||
* the second parameter must be the type of the symbol (i.e.: function,...)
|
||||
*/
|
||||
#define ANSI_PRAGMA_WEAK(sym, stype) \
|
||||
/* CSTYLED */ \
|
||||
.weak _/**/sym; \
|
||||
/* CSTYLED */ \
|
||||
.type _/**/sym, @stype; \
|
||||
/* CSTYLED */ \
|
||||
_/**/sym = sym
|
||||
|
||||
/*
|
||||
* Like ANSI_PRAGMA_WEAK(), but for unrelated names, as in:
|
||||
* #pragma weak sym1 = sym2
|
||||
*/
|
||||
#define ANSI_PRAGMA_WEAK2(sym1, sym2, stype) \
|
||||
.weak sym1; \
|
||||
.type sym1, @stype; \
|
||||
sym1 = sym2
|
||||
|
||||
/*
|
||||
* ENTRY provides the standard procedure entry code and an easy way to
|
||||
* insert the calls to mcount for profiling. ENTRY_NP is identical, but
|
||||
* never calls mcount.
|
||||
*/
|
||||
#define ENTRY(x) \
|
||||
.text; \
|
||||
.align ASM_ENTRY_ALIGN; \
|
||||
.globl x; \
|
||||
.type x, @function; \
|
||||
x: MCOUNT(x)
|
||||
|
||||
#define ENTRY_NP(x) \
|
||||
.text; \
|
||||
.align ASM_ENTRY_ALIGN; \
|
||||
.globl x; \
|
||||
.type x, @function; \
|
||||
x:
|
||||
|
||||
#define RTENTRY(x) \
|
||||
.text; \
|
||||
.align ASM_ENTRY_ALIGN; \
|
||||
.globl x; \
|
||||
.type x, @function; \
|
||||
x: RTMCOUNT(x)
|
||||
|
||||
/*
|
||||
* ENTRY2 is identical to ENTRY but provides two labels for the entry point.
|
||||
*/
|
||||
#define ENTRY2(x, y) \
|
||||
.text; \
|
||||
.align ASM_ENTRY_ALIGN; \
|
||||
.globl x, y; \
|
||||
.type x, @function; \
|
||||
.type y, @function; \
|
||||
/* CSTYLED */ \
|
||||
x: ; \
|
||||
y: MCOUNT(x)
|
||||
|
||||
#define ENTRY_NP2(x, y) \
|
||||
.text; \
|
||||
.align ASM_ENTRY_ALIGN; \
|
||||
.globl x, y; \
|
||||
.type x, @function; \
|
||||
.type y, @function; \
|
||||
/* CSTYLED */ \
|
||||
x: ; \
|
||||
y:
|
||||
|
||||
|
||||
/*
|
||||
* ALTENTRY provides for additional entry points.
|
||||
*/
|
||||
#define ALTENTRY(x) \
|
||||
.globl x; \
|
||||
.type x, @function; \
|
||||
x:
|
||||
|
||||
/*
|
||||
* DGDEF and DGDEF2 provide global data declarations.
|
||||
*
|
||||
* DGDEF provides a word aligned word of storage.
|
||||
*
|
||||
* DGDEF2 allocates "sz" bytes of storage with **NO** alignment. This
|
||||
* implies this macro is best used for byte arrays.
|
||||
*
|
||||
* DGDEF3 allocates "sz" bytes of storage with "algn" alignment.
|
||||
*/
|
||||
#define DGDEF2(name, sz) \
|
||||
.data; \
|
||||
.globl name; \
|
||||
.type name, @object; \
|
||||
.size name, sz; \
|
||||
name:
|
||||
|
||||
#define DGDEF3(name, sz, algn) \
|
||||
.data; \
|
||||
.align algn; \
|
||||
.globl name; \
|
||||
.type name, @object; \
|
||||
.size name, sz; \
|
||||
name:
|
||||
|
||||
#define DGDEF(name) DGDEF3(name, 4, 4)
|
||||
|
||||
/*
|
||||
* SET_SIZE trails a function and set the size for the ELF symbol table.
|
||||
*/
|
||||
#define SET_SIZE(x) \
|
||||
.size x, [.-x]
|
||||
|
||||
/*
|
||||
* NWORD provides native word value.
|
||||
*/
|
||||
#if defined(__amd64)
|
||||
|
||||
/*CSTYLED*/
|
||||
#define NWORD quad
|
||||
|
||||
#elif defined(__i386)
|
||||
|
||||
#define NWORD long
|
||||
|
||||
#endif /* __i386 */
|
||||
|
||||
#endif /* _ASM */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _IA32_SYS_ASM_LINKAGE_H */
|
160
module/icp/include/sys/ia32/stack.h
Normal file
160
module/icp/include/sys/ia32/stack.h
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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 2004 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _IA32_SYS_STACK_H
|
||||
#define _IA32_SYS_STACK_H
|
||||
|
||||
#if !defined(_ASM)
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In the x86 world, a stack frame looks like this:
|
||||
*
|
||||
* |--------------------------|
|
||||
* 4n+8(%ebp) ->| argument word n |
|
||||
* | ... | (Previous frame)
|
||||
* 8(%ebp) ->| argument word 0 |
|
||||
* |--------------------------|--------------------
|
||||
* 4(%ebp) ->| return address |
|
||||
* |--------------------------|
|
||||
* 0(%ebp) ->| previous %ebp (optional) |
|
||||
* |--------------------------|
|
||||
* -4(%ebp) ->| unspecified | (Current frame)
|
||||
* | ... |
|
||||
* 0(%esp) ->| variable size |
|
||||
* |--------------------------|
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stack alignment macros.
|
||||
*/
|
||||
|
||||
#define STACK_ALIGN32 4
|
||||
#define STACK_ENTRY_ALIGN32 4
|
||||
#define STACK_BIAS32 0
|
||||
#define SA32(x) (((x)+(STACK_ALIGN32-1)) & ~(STACK_ALIGN32-1))
|
||||
#define STACK_RESERVE32 0
|
||||
#define MINFRAME32 0
|
||||
|
||||
#if defined(__amd64)
|
||||
|
||||
/*
|
||||
* In the amd64 world, a stack frame looks like this:
|
||||
*
|
||||
* |--------------------------|
|
||||
* 8n+16(%rbp)->| argument word n |
|
||||
* | ... | (Previous frame)
|
||||
* 16(%rbp) ->| argument word 0 |
|
||||
* |--------------------------|--------------------
|
||||
* 8(%rbp) ->| return address |
|
||||
* |--------------------------|
|
||||
* 0(%rbp) ->| previous %rbp |
|
||||
* |--------------------------|
|
||||
* -8(%rbp) ->| unspecified | (Current frame)
|
||||
* | ... |
|
||||
* 0(%rsp) ->| variable size |
|
||||
* |--------------------------|
|
||||
* -128(%rsp) ->| reserved for function |
|
||||
* |--------------------------|
|
||||
*
|
||||
* The end of the input argument area must be aligned on a 16-byte
|
||||
* boundary; i.e. (%rsp - 8) % 16 == 0 at function entry.
|
||||
*
|
||||
* The 128-byte location beyond %rsp is considered to be reserved for
|
||||
* functions and is NOT modified by signal handlers. It can be used
|
||||
* to store temporary data that is not needed across function calls.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Stack alignment macros.
|
||||
*/
|
||||
|
||||
#define STACK_ALIGN64 16
|
||||
#define STACK_ENTRY_ALIGN64 8
|
||||
#define STACK_BIAS64 0
|
||||
#define SA64(x) (((x)+(STACK_ALIGN64-1)) & ~(STACK_ALIGN64-1))
|
||||
#define STACK_RESERVE64 128
|
||||
#define MINFRAME64 0
|
||||
|
||||
#define STACK_ALIGN STACK_ALIGN64
|
||||
#define STACK_ENTRY_ALIGN STACK_ENTRY_ALIGN64
|
||||
#define STACK_BIAS STACK_BIAS64
|
||||
#define SA(x) SA64(x)
|
||||
#define STACK_RESERVE STACK_RESERVE64
|
||||
#define MINFRAME MINFRAME64
|
||||
|
||||
#elif defined(__i386)
|
||||
|
||||
#define STACK_ALIGN STACK_ALIGN32
|
||||
#define STACK_ENTRY_ALIGN STACK_ENTRY_ALIGN32
|
||||
#define STACK_BIAS STACK_BIAS32
|
||||
#define SA(x) SA32(x)
|
||||
#define STACK_RESERVE STACK_RESERVE32
|
||||
#define MINFRAME MINFRAME32
|
||||
|
||||
#endif /* __i386 */
|
||||
|
||||
#if defined(_KERNEL) && !defined(_ASM)
|
||||
|
||||
#if defined(DEBUG)
|
||||
#if STACK_ALIGN == 4
|
||||
#define ASSERT_STACK_ALIGNED() \
|
||||
{ \
|
||||
uint32_t __tmp; \
|
||||
ASSERT((((uintptr_t)&__tmp) & (STACK_ALIGN - 1)) == 0); \
|
||||
}
|
||||
#elif (STACK_ALIGN == 16) && (_LONG_DOUBLE_ALIGNMENT == 16)
|
||||
#define ASSERT_STACK_ALIGNED() \
|
||||
{ \
|
||||
long double __tmp; \
|
||||
ASSERT((((uintptr_t)&__tmp) & (STACK_ALIGN - 1)) == 0); \
|
||||
}
|
||||
#endif
|
||||
#else /* DEBUG */
|
||||
#define ASSERT_STACK_ALIGNED()
|
||||
#endif /* DEBUG */
|
||||
|
||||
struct regs;
|
||||
|
||||
void traceregs(struct regs *);
|
||||
void traceback(caddr_t);
|
||||
|
||||
#endif /* defined(_KERNEL) && !defined(_ASM) */
|
||||
|
||||
#define STACK_GROWTH_DOWN /* stacks grow from high to low addresses */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _IA32_SYS_STACK_H */
|
107
module/icp/include/sys/ia32/trap.h
Normal file
107
module/icp/include/sys/ia32/trap.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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) 1990, 1991 UNIX System Laboratories, Inc. */
|
||||
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
|
||||
/* All Rights Reserved */
|
||||
|
||||
/*
|
||||
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _IA32_SYS_TRAP_H
|
||||
#define _IA32_SYS_TRAP_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Trap type values
|
||||
*/
|
||||
|
||||
#define T_ZERODIV 0x0 /* #de divide by 0 error */
|
||||
#define T_SGLSTP 0x1 /* #db single step */
|
||||
#define T_NMIFLT 0x2 /* NMI */
|
||||
#define T_BPTFLT 0x3 /* #bp breakpoint fault, INT3 insn */
|
||||
#define T_OVFLW 0x4 /* #of INTO overflow fault */
|
||||
#define T_BOUNDFLT 0x5 /* #br BOUND insn fault */
|
||||
#define T_ILLINST 0x6 /* #ud invalid opcode fault */
|
||||
#define T_NOEXTFLT 0x7 /* #nm device not available: x87 */
|
||||
#define T_DBLFLT 0x8 /* #df double fault */
|
||||
#define T_EXTOVRFLT 0x9 /* [not generated: 386 only] */
|
||||
#define T_TSSFLT 0xa /* #ts invalid TSS fault */
|
||||
#define T_SEGFLT 0xb /* #np segment not present fault */
|
||||
#define T_STKFLT 0xc /* #ss stack fault */
|
||||
#define T_GPFLT 0xd /* #gp general protection fault */
|
||||
#define T_PGFLT 0xe /* #pf page fault */
|
||||
#define T_EXTERRFLT 0x10 /* #mf x87 FPU error fault */
|
||||
#define T_ALIGNMENT 0x11 /* #ac alignment check error */
|
||||
#define T_MCE 0x12 /* #mc machine check exception */
|
||||
#define T_SIMDFPE 0x13 /* #xm SSE/SSE exception */
|
||||
#define T_DBGENTR 0x14 /* debugger entry */
|
||||
#define T_ENDPERR 0x21 /* emulated extension error flt */
|
||||
#define T_ENOEXTFLT 0x20 /* emulated ext not present */
|
||||
#define T_FASTTRAP 0xd2 /* fast system call */
|
||||
#define T_SYSCALLINT 0x91 /* general system call */
|
||||
#define T_DTRACE_RET 0x7f /* DTrace pid return */
|
||||
#define T_INT80 0x80 /* int80 handler for linux emulation */
|
||||
#define T_SOFTINT 0x50fd /* pseudo softint trap type */
|
||||
|
||||
/*
|
||||
* Pseudo traps.
|
||||
*/
|
||||
#define T_INTERRUPT 0x100
|
||||
#define T_FAULT 0x200
|
||||
#define T_AST 0x400
|
||||
#define T_SYSCALL 0x180
|
||||
|
||||
|
||||
/*
|
||||
* Values of error code on stack in case of page fault
|
||||
*/
|
||||
|
||||
#define PF_ERR_MASK 0x01 /* Mask for error bit */
|
||||
#define PF_ERR_PAGE 0x00 /* page not present */
|
||||
#define PF_ERR_PROT 0x01 /* protection error */
|
||||
#define PF_ERR_WRITE 0x02 /* fault caused by write (else read) */
|
||||
#define PF_ERR_USER 0x04 /* processor was in user mode */
|
||||
/* (else supervisor) */
|
||||
#define PF_ERR_EXEC 0x10 /* attempt to execute a No eXec page (AMD) */
|
||||
|
||||
/*
|
||||
* Definitions for fast system call subfunctions
|
||||
*/
|
||||
#define T_FNULL 0 /* Null trap for testing */
|
||||
#define T_FGETFP 1 /* Get emulated FP context */
|
||||
#define T_FSETFP 2 /* Set emulated FP context */
|
||||
#define T_GETHRTIME 3 /* Get high resolution time */
|
||||
#define T_GETHRVTIME 4 /* Get high resolution virtual time */
|
||||
#define T_GETHRESTIME 5 /* Get high resolution time */
|
||||
#define T_GETLGRP 6 /* Get home lgrpid */
|
||||
|
||||
#define T_LASTFAST 6 /* Last valid subfunction */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _IA32_SYS_TRAP_H */
|
477
module/icp/include/sys/modctl.h
Normal file
477
module/icp/include/sys/modctl.h
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_MODCTL_H
|
||||
#define _SYS_MODCTL_H
|
||||
|
||||
/*
|
||||
* loadable module support.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct modlmisc;
|
||||
struct modlinkage;
|
||||
|
||||
/*
|
||||
* The following structure defines the operations used by modctl
|
||||
* to load and unload modules. Each supported loadable module type
|
||||
* requires a set of mod_ops.
|
||||
*/
|
||||
struct mod_ops {
|
||||
int (*modm_install)(struct modlmisc *, struct modlinkage *);
|
||||
int (*modm_remove)(struct modlmisc *, struct modlinkage *);
|
||||
int (*modm_info)(void *, struct modlinkage *, int *);
|
||||
};
|
||||
|
||||
/*
|
||||
* The defined set of mod_ops structures for each loadable module type
|
||||
* Defined in modctl.c
|
||||
*/
|
||||
extern struct mod_ops mod_brandops;
|
||||
#if defined(__i386) || defined(__amd64)
|
||||
extern struct mod_ops mod_cpuops;
|
||||
#endif
|
||||
extern struct mod_ops mod_cryptoops;
|
||||
extern struct mod_ops mod_driverops;
|
||||
extern struct mod_ops mod_execops;
|
||||
extern struct mod_ops mod_fsops;
|
||||
extern struct mod_ops mod_miscops;
|
||||
extern struct mod_ops mod_schedops;
|
||||
extern struct mod_ops mod_strmodops;
|
||||
extern struct mod_ops mod_syscallops;
|
||||
extern struct mod_ops mod_sockmodops;
|
||||
#ifdef _SYSCALL32_IMPL
|
||||
extern struct mod_ops mod_syscallops32;
|
||||
#endif
|
||||
extern struct mod_ops mod_dacfops;
|
||||
extern struct mod_ops mod_ippops;
|
||||
extern struct mod_ops mod_pcbeops;
|
||||
extern struct mod_ops mod_devfsops;
|
||||
extern struct mod_ops mod_kiconvops;
|
||||
|
||||
/*
|
||||
* Definitions for the module specific linkage structures.
|
||||
* The first two fields are the same in all of the structures.
|
||||
* The linkinfo is for informational purposes only and is returned by
|
||||
* modctl with the MODINFO cmd.
|
||||
*/
|
||||
|
||||
/* For cryptographic providers */
|
||||
struct modlcrypto {
|
||||
struct mod_ops *crypto_modops;
|
||||
char *crypto_linkinfo;
|
||||
};
|
||||
|
||||
/* For misc */
|
||||
struct modlmisc {
|
||||
struct mod_ops *misc_modops;
|
||||
char *misc_linkinfo;
|
||||
};
|
||||
|
||||
/*
|
||||
* Revision number of loadable modules support. This is the value
|
||||
* that must be used in the modlinkage structure.
|
||||
*/
|
||||
#define MODREV_1 1
|
||||
|
||||
/*
|
||||
* The modlinkage structure is the structure that the module writer
|
||||
* provides to the routines to install, remove, and stat a module.
|
||||
* The ml_linkage element is an array of pointers to linkage structures.
|
||||
* For most modules there is only one linkage structure. We allocate
|
||||
* enough space for 3 linkage structures which happens to be the most
|
||||
* we have in any sun supplied module. For those modules with more
|
||||
* than 3 linkage structures (which is very unlikely), a modlinkage
|
||||
* structure must be kmem_alloc'd in the module wrapper to be big enough
|
||||
* for all of the linkage structures.
|
||||
*/
|
||||
struct modlinkage {
|
||||
int ml_rev; /* rev of loadable modules system */
|
||||
#ifdef _LP64
|
||||
void *ml_linkage[7]; /* more space in 64-bit OS */
|
||||
#else
|
||||
void *ml_linkage[4]; /* NULL terminated list of */
|
||||
/* linkage structures */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* commands. These are the commands supported by the modctl system call.
|
||||
*/
|
||||
#define MODLOAD 0
|
||||
#define MODUNLOAD 1
|
||||
#define MODINFO 2
|
||||
#define MODRESERVED 3
|
||||
#define MODSETMINIROOT 4
|
||||
#define MODADDMAJBIND 5
|
||||
#define MODGETPATH 6
|
||||
#define MODREADSYSBIND 7
|
||||
#define MODGETMAJBIND 8
|
||||
#define MODGETNAME 9
|
||||
#define MODSIZEOF_DEVID 10
|
||||
#define MODGETDEVID 11
|
||||
#define MODSIZEOF_MINORNAME 12
|
||||
#define MODGETMINORNAME 13
|
||||
#define MODGETPATHLEN 14
|
||||
#define MODEVENTS 15
|
||||
#define MODGETFBNAME 16
|
||||
#define MODREREADDACF 17
|
||||
#define MODLOADDRVCONF 18
|
||||
#define MODUNLOADDRVCONF 19
|
||||
#define MODREMMAJBIND 20
|
||||
#define MODDEVT2INSTANCE 21
|
||||
#define MODGETDEVFSPATH_LEN 22
|
||||
#define MODGETDEVFSPATH 23
|
||||
#define MODDEVID2PATHS 24
|
||||
#define MODSETDEVPOLICY 26
|
||||
#define MODGETDEVPOLICY 27
|
||||
#define MODALLOCPRIV 28
|
||||
#define MODGETDEVPOLICYBYNAME 29
|
||||
#define MODLOADMINORPERM 31
|
||||
#define MODADDMINORPERM 32
|
||||
#define MODREMMINORPERM 33
|
||||
#define MODREMDRVCLEANUP 34
|
||||
#define MODDEVEXISTS 35
|
||||
#define MODDEVREADDIR 36
|
||||
#define MODDEVNAME 37
|
||||
#define MODGETDEVFSPATH_MI_LEN 38
|
||||
#define MODGETDEVFSPATH_MI 39
|
||||
#define MODRETIRE 40
|
||||
#define MODUNRETIRE 41
|
||||
#define MODISRETIRED 42
|
||||
#define MODDEVEMPTYDIR 43
|
||||
#define MODREMDRVALIAS 44
|
||||
|
||||
/*
|
||||
* sub cmds for MODEVENTS
|
||||
*/
|
||||
#define MODEVENTS_FLUSH 0
|
||||
#define MODEVENTS_FLUSH_DUMP 1
|
||||
#define MODEVENTS_SET_DOOR_UPCALL_FILENAME 2
|
||||
#define MODEVENTS_GETDATA 3
|
||||
#define MODEVENTS_FREEDATA 4
|
||||
#define MODEVENTS_POST_EVENT 5
|
||||
#define MODEVENTS_REGISTER_EVENT 6
|
||||
|
||||
/*
|
||||
* devname subcmds for MODDEVNAME
|
||||
*/
|
||||
#define MODDEVNAME_LOOKUPDOOR 0
|
||||
#define MODDEVNAME_DEVFSADMNODE 1
|
||||
#define MODDEVNAME_NSMAPS 2
|
||||
#define MODDEVNAME_PROFILE 3
|
||||
#define MODDEVNAME_RECONFIG 4
|
||||
#define MODDEVNAME_SYSAVAIL 5
|
||||
|
||||
|
||||
/*
|
||||
* Data structure passed to modconfig command in kernel to build devfs tree
|
||||
*/
|
||||
|
||||
struct aliases {
|
||||
struct aliases *a_next;
|
||||
char *a_name;
|
||||
int a_len;
|
||||
};
|
||||
|
||||
#define MAXMODCONFNAME 256
|
||||
|
||||
struct modconfig {
|
||||
char drvname[MAXMODCONFNAME];
|
||||
char drvclass[MAXMODCONFNAME];
|
||||
int major;
|
||||
int flags;
|
||||
int num_aliases;
|
||||
struct aliases *ap;
|
||||
};
|
||||
|
||||
#if defined(_SYSCALL32)
|
||||
|
||||
struct aliases32 {
|
||||
caddr32_t a_next;
|
||||
caddr32_t a_name;
|
||||
int32_t a_len;
|
||||
};
|
||||
|
||||
struct modconfig32 {
|
||||
char drvname[MAXMODCONFNAME];
|
||||
char drvclass[MAXMODCONFNAME];
|
||||
int32_t major;
|
||||
int32_t flags;
|
||||
int32_t num_aliases;
|
||||
caddr32_t ap;
|
||||
};
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
|
||||
/* flags for modconfig */
|
||||
#define MOD_UNBIND_OVERRIDE 0x01 /* fail unbind if in use */
|
||||
|
||||
/*
|
||||
* Max module path length
|
||||
*/
|
||||
#define MOD_MAXPATH 256
|
||||
|
||||
/*
|
||||
* Default search path for modules ADDITIONAL to the directory
|
||||
* where the kernel components we booted from are.
|
||||
*
|
||||
* Most often, this will be "/platform/{platform}/kernel /kernel /usr/kernel",
|
||||
* but we don't wire it down here.
|
||||
*/
|
||||
#define MOD_DEFPATH "/kernel /usr/kernel"
|
||||
|
||||
/*
|
||||
* Default file name extension for autoloading modules.
|
||||
*/
|
||||
#define MOD_DEFEXT ""
|
||||
|
||||
/*
|
||||
* Parameters for modinfo
|
||||
*/
|
||||
#define MODMAXNAMELEN 32 /* max module name length */
|
||||
#define MODMAXLINKINFOLEN 32 /* max link info length */
|
||||
|
||||
/*
|
||||
* Module specific information.
|
||||
*/
|
||||
struct modspecific_info {
|
||||
char msi_linkinfo[MODMAXLINKINFOLEN]; /* name in linkage struct */
|
||||
int msi_p0; /* module specific information */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure returned by modctl with MODINFO command.
|
||||
*/
|
||||
#define MODMAXLINK 10 /* max linkages modinfo can handle */
|
||||
|
||||
struct modinfo {
|
||||
int mi_info; /* Flags for info wanted */
|
||||
int mi_state; /* Flags for module state */
|
||||
int mi_id; /* id of this loaded module */
|
||||
int mi_nextid; /* id of next module or -1 */
|
||||
caddr_t mi_base; /* virtual addr of text */
|
||||
size_t mi_size; /* size of module in bytes */
|
||||
int mi_rev; /* loadable modules rev */
|
||||
int mi_loadcnt; /* # of times loaded */
|
||||
char mi_name[MODMAXNAMELEN]; /* name of module */
|
||||
struct modspecific_info mi_msinfo[MODMAXLINK];
|
||||
/* mod specific info */
|
||||
};
|
||||
|
||||
|
||||
#if defined(_SYSCALL32)
|
||||
|
||||
#define MODMAXNAMELEN32 32 /* max module name length */
|
||||
#define MODMAXLINKINFOLEN32 32 /* max link info length */
|
||||
#define MODMAXLINK32 10 /* max linkages modinfo can handle */
|
||||
|
||||
struct modspecific_info32 {
|
||||
char msi_linkinfo[MODMAXLINKINFOLEN32]; /* name in linkage struct */
|
||||
int32_t msi_p0; /* module specific information */
|
||||
};
|
||||
|
||||
struct modinfo32 {
|
||||
int32_t mi_info; /* Flags for info wanted */
|
||||
int32_t mi_state; /* Flags for module state */
|
||||
int32_t mi_id; /* id of this loaded module */
|
||||
int32_t mi_nextid; /* id of next module or -1 */
|
||||
caddr32_t mi_base; /* virtual addr of text */
|
||||
uint32_t mi_size; /* size of module in bytes */
|
||||
int32_t mi_rev; /* loadable modules rev */
|
||||
int32_t mi_loadcnt; /* # of times loaded */
|
||||
char mi_name[MODMAXNAMELEN32]; /* name of module */
|
||||
struct modspecific_info32 mi_msinfo[MODMAXLINK32];
|
||||
/* mod specific info */
|
||||
};
|
||||
|
||||
#endif /* _SYSCALL32 */
|
||||
|
||||
/* Values for mi_info flags */
|
||||
#define MI_INFO_ONE 1
|
||||
#define MI_INFO_ALL 2
|
||||
#define MI_INFO_CNT 4
|
||||
#define MI_INFO_LINKAGE 8 /* used internally to extract modlinkage */
|
||||
/*
|
||||
* MI_INFO_NOBASE indicates caller does not need mi_base. Failure to use this
|
||||
* flag may lead 32-bit apps to receive an EOVERFLOW error from modctl(MODINFO)
|
||||
* when used with a 64-bit kernel.
|
||||
*/
|
||||
#define MI_INFO_NOBASE 16
|
||||
|
||||
/* Values for mi_state */
|
||||
#define MI_LOADED 1
|
||||
#define MI_INSTALLED 2
|
||||
|
||||
/*
|
||||
* Macros to vector to the appropriate module specific routine.
|
||||
*/
|
||||
#define MODL_INSTALL(MODL, MODLP) \
|
||||
(*(MODL)->misc_modops->modm_install)(MODL, MODLP)
|
||||
#define MODL_REMOVE(MODL, MODLP) \
|
||||
(*(MODL)->misc_modops->modm_remove)(MODL, MODLP)
|
||||
#define MODL_INFO(MODL, MODLP, P0) \
|
||||
(*(MODL)->misc_modops->modm_info)(MODL, MODLP, P0)
|
||||
|
||||
/*
|
||||
* Definitions for stubs
|
||||
*/
|
||||
struct mod_stub_info {
|
||||
uintptr_t mods_func_adr;
|
||||
struct mod_modinfo *mods_modinfo;
|
||||
uintptr_t mods_stub_adr;
|
||||
int (*mods_errfcn)(void);
|
||||
int mods_flag; /* flags defined below */
|
||||
};
|
||||
|
||||
/*
|
||||
* Definitions for mods_flag.
|
||||
*/
|
||||
#define MODS_WEAK 0x01 /* weak stub (not loaded if called) */
|
||||
#define MODS_NOUNLOAD 0x02 /* module not unloadable (no _fini()) */
|
||||
#define MODS_INSTALLED 0x10 /* module installed */
|
||||
|
||||
struct mod_modinfo {
|
||||
char *modm_module_name;
|
||||
struct modctl *mp;
|
||||
struct mod_stub_info modm_stubs[1];
|
||||
};
|
||||
|
||||
struct modctl_list {
|
||||
struct modctl_list *modl_next;
|
||||
struct modctl *modl_modp;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure to manage a loadable module.
|
||||
* Note: the module (mod_mp) structure's "text" and "text_size" information
|
||||
* are replicated in the modctl structure so that mod_containing_pc()
|
||||
* doesn't have to grab any locks (modctls are persistent; modules are not.)
|
||||
*/
|
||||
typedef struct modctl {
|
||||
struct modctl *mod_next; /* &modules based list */
|
||||
struct modctl *mod_prev;
|
||||
int mod_id;
|
||||
void *mod_mp;
|
||||
kthread_t *mod_inprogress_thread;
|
||||
struct mod_modinfo *mod_modinfo;
|
||||
struct modlinkage *mod_linkage;
|
||||
char *mod_filename;
|
||||
char *mod_modname;
|
||||
|
||||
char mod_busy; /* inprogress_thread has locked */
|
||||
char mod_want; /* someone waiting for unlock */
|
||||
char mod_prim; /* primary module */
|
||||
|
||||
int mod_ref; /* ref count - from dependent or stub */
|
||||
|
||||
char mod_loaded; /* module in memory */
|
||||
char mod_installed; /* post _init pre _fini */
|
||||
char mod_loadflags;
|
||||
char mod_delay_unload; /* deferred unload */
|
||||
|
||||
struct modctl_list *mod_requisites; /* mods this one depends on. */
|
||||
void *__unused; /* NOTE: reuse (same size) is OK, */
|
||||
/* deletion causes mdb.vs.core issues */
|
||||
int mod_loadcnt; /* number of times mod was loaded */
|
||||
int mod_nenabled; /* # of enabled DTrace probes in mod */
|
||||
char *mod_text;
|
||||
size_t mod_text_size;
|
||||
|
||||
int mod_gencount; /* # times loaded/unloaded */
|
||||
struct modctl *mod_requisite_loading; /* mod circular dependency */
|
||||
} modctl_t;
|
||||
|
||||
/*
|
||||
* mod_loadflags
|
||||
*/
|
||||
|
||||
#define MOD_NOAUTOUNLOAD 0x1 /* Auto mod-unloader skips this mod */
|
||||
#define MOD_NONOTIFY 0x2 /* No krtld notifications on (un)load */
|
||||
#define MOD_NOUNLOAD 0x4 /* Assume EBUSY for all _fini's */
|
||||
|
||||
#define MOD_BIND_HASHSIZE 64
|
||||
#define MOD_BIND_HASHMASK (MOD_BIND_HASHSIZE-1)
|
||||
|
||||
typedef int modid_t;
|
||||
|
||||
/*
|
||||
* global function and data declarations
|
||||
*/
|
||||
extern kmutex_t mod_lock;
|
||||
|
||||
extern char *systemfile;
|
||||
extern char **syscallnames;
|
||||
extern int moddebug;
|
||||
|
||||
/*
|
||||
* this is the head of a doubly linked list. Only the next and prev
|
||||
* pointers are used
|
||||
*/
|
||||
extern modctl_t modules;
|
||||
|
||||
/*
|
||||
* Only the following are part of the DDI/DKI
|
||||
*/
|
||||
extern int mod_install(struct modlinkage *);
|
||||
extern int mod_remove(struct modlinkage *);
|
||||
extern int mod_info(struct modlinkage *, struct modinfo *);
|
||||
|
||||
/*
|
||||
* bit definitions for moddebug.
|
||||
*/
|
||||
#define MODDEBUG_LOADMSG 0x80000000 /* print "[un]loading..." msg */
|
||||
#define MODDEBUG_ERRMSG 0x40000000 /* print detailed error msgs */
|
||||
#define MODDEBUG_LOADMSG2 0x20000000 /* print 2nd level msgs */
|
||||
#define MODDEBUG_RETIRE 0x10000000 /* print retire msgs */
|
||||
#define MODDEBUG_BINDING 0x00040000 /* driver/alias binding */
|
||||
#define MODDEBUG_FINI_EBUSY 0x00020000 /* pretend fini returns EBUSY */
|
||||
#define MODDEBUG_NOAUL_IPP 0x00010000 /* no Autounloading ipp mods */
|
||||
#define MODDEBUG_NOAUL_DACF 0x00008000 /* no Autounloading dacf mods */
|
||||
#define MODDEBUG_KEEPTEXT 0x00004000 /* keep text after unloading */
|
||||
#define MODDEBUG_NOAUL_DRV 0x00001000 /* no Autounloading Drivers */
|
||||
#define MODDEBUG_NOAUL_EXEC 0x00000800 /* no Autounloading Execs */
|
||||
#define MODDEBUG_NOAUL_FS 0x00000400 /* no Autounloading File sys */
|
||||
#define MODDEBUG_NOAUL_MISC 0x00000200 /* no Autounloading misc */
|
||||
#define MODDEBUG_NOAUL_SCHED 0x00000100 /* no Autounloading scheds */
|
||||
#define MODDEBUG_NOAUL_STR 0x00000080 /* no Autounloading streams */
|
||||
#define MODDEBUG_NOAUL_SYS 0x00000040 /* no Autounloading syscalls */
|
||||
#define MODDEBUG_NOCTF 0x00000020 /* do not load CTF debug data */
|
||||
#define MODDEBUG_NOAUTOUNLOAD 0x00000010 /* no autounloading at all */
|
||||
#define MODDEBUG_DDI_MOD 0x00000008 /* ddi_mod{open,sym,close} */
|
||||
#define MODDEBUG_MP_MATCH 0x00000004 /* dev_minorperm */
|
||||
#define MODDEBUG_MINORPERM 0x00000002 /* minor perm modctls */
|
||||
#define MODDEBUG_USERDEBUG 0x00000001 /* bpt after init_module() */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_MODCTL_H */
|
147
module/icp/include/sys/modhash.h
Normal file
147
module/icp/include/sys/modhash.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_MODHASH_H
|
||||
#define _SYS_MODHASH_H
|
||||
|
||||
/*
|
||||
* Generic hash implementation for the kernel.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
|
||||
/*
|
||||
* Opaque data types for storing keys and values
|
||||
*/
|
||||
typedef void *mod_hash_val_t;
|
||||
typedef void *mod_hash_key_t;
|
||||
|
||||
/*
|
||||
* Opaque data type for reservation
|
||||
*/
|
||||
typedef void *mod_hash_hndl_t;
|
||||
|
||||
/*
|
||||
* Opaque type for hash itself.
|
||||
*/
|
||||
struct mod_hash;
|
||||
typedef struct mod_hash mod_hash_t;
|
||||
|
||||
/*
|
||||
* String hash table
|
||||
*/
|
||||
mod_hash_t *mod_hash_create_strhash_nodtr(char *, size_t,
|
||||
void (*)(mod_hash_val_t));
|
||||
mod_hash_t *mod_hash_create_strhash(char *, size_t, void (*)(mod_hash_val_t));
|
||||
void mod_hash_destroy_strhash(mod_hash_t *);
|
||||
int mod_hash_strkey_cmp(mod_hash_key_t, mod_hash_key_t);
|
||||
void mod_hash_strkey_dtor(mod_hash_key_t);
|
||||
void mod_hash_strval_dtor(mod_hash_val_t);
|
||||
uint_t mod_hash_bystr(void *, mod_hash_key_t);
|
||||
|
||||
/*
|
||||
* Pointer hash table
|
||||
*/
|
||||
mod_hash_t *mod_hash_create_ptrhash(char *, size_t, void (*)(mod_hash_val_t),
|
||||
size_t);
|
||||
void mod_hash_destroy_ptrhash(mod_hash_t *);
|
||||
int mod_hash_ptrkey_cmp(mod_hash_key_t, mod_hash_key_t);
|
||||
uint_t mod_hash_byptr(void *, mod_hash_key_t);
|
||||
|
||||
/*
|
||||
* ID hash table
|
||||
*/
|
||||
mod_hash_t *mod_hash_create_idhash(char *, size_t, void (*)(mod_hash_val_t));
|
||||
void mod_hash_destroy_idhash(mod_hash_t *);
|
||||
int mod_hash_idkey_cmp(mod_hash_key_t, mod_hash_key_t);
|
||||
uint_t mod_hash_byid(void *, mod_hash_key_t);
|
||||
uint_t mod_hash_iddata_gen(size_t);
|
||||
|
||||
/*
|
||||
* Hash management functions
|
||||
*/
|
||||
mod_hash_t *mod_hash_create_extended(char *, size_t, void (*)(mod_hash_key_t),
|
||||
void (*)(mod_hash_val_t), uint_t (*)(void *, mod_hash_key_t), void *,
|
||||
int (*)(mod_hash_key_t, mod_hash_key_t), int);
|
||||
|
||||
void mod_hash_destroy_hash(mod_hash_t *);
|
||||
void mod_hash_clear(mod_hash_t *);
|
||||
|
||||
/*
|
||||
* Null key and value destructors
|
||||
*/
|
||||
void mod_hash_null_keydtor(mod_hash_key_t);
|
||||
void mod_hash_null_valdtor(mod_hash_val_t);
|
||||
|
||||
/*
|
||||
* Basic hash operations
|
||||
*/
|
||||
|
||||
/*
|
||||
* Error codes for insert, remove, find, destroy.
|
||||
*/
|
||||
#define MH_ERR_NOMEM -1
|
||||
#define MH_ERR_DUPLICATE -2
|
||||
#define MH_ERR_NOTFOUND -3
|
||||
|
||||
/*
|
||||
* Return codes for hash walkers
|
||||
*/
|
||||
#define MH_WALK_CONTINUE 0
|
||||
#define MH_WALK_TERMINATE 1
|
||||
|
||||
/*
|
||||
* Basic hash operations
|
||||
*/
|
||||
int mod_hash_insert(mod_hash_t *, mod_hash_key_t, mod_hash_val_t);
|
||||
int mod_hash_replace(mod_hash_t *, mod_hash_key_t, mod_hash_val_t);
|
||||
int mod_hash_remove(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
|
||||
int mod_hash_destroy(mod_hash_t *, mod_hash_key_t);
|
||||
int mod_hash_find(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
|
||||
int mod_hash_find_cb(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *,
|
||||
void (*)(mod_hash_key_t, mod_hash_val_t));
|
||||
int mod_hash_find_cb_rval(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *,
|
||||
int (*)(mod_hash_key_t, mod_hash_val_t), int *);
|
||||
void mod_hash_walk(mod_hash_t *,
|
||||
uint_t (*)(mod_hash_key_t, mod_hash_val_t *, void *), void *);
|
||||
|
||||
/*
|
||||
* Reserving hash operations
|
||||
*/
|
||||
int mod_hash_reserve(mod_hash_t *, mod_hash_hndl_t *);
|
||||
int mod_hash_reserve_nosleep(mod_hash_t *, mod_hash_hndl_t *);
|
||||
void mod_hash_cancel(mod_hash_t *, mod_hash_hndl_t *);
|
||||
int mod_hash_insert_reserve(mod_hash_t *, mod_hash_key_t, mod_hash_val_t,
|
||||
mod_hash_hndl_t);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_MODHASH_H */
|
108
module/icp/include/sys/modhash_impl.h
Normal file
108
module/icp/include/sys/modhash_impl.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 2006 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_MODHASH_IMPL_H
|
||||
#define _SYS_MODHASH_IMPL_H
|
||||
|
||||
/*
|
||||
* Internal details for the kernel's generic hash implementation.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/modhash.h>
|
||||
|
||||
struct mod_hash_entry {
|
||||
mod_hash_key_t mhe_key; /* stored hash key */
|
||||
mod_hash_val_t mhe_val; /* stored hash value */
|
||||
struct mod_hash_entry *mhe_next; /* next item in chain */
|
||||
};
|
||||
|
||||
struct mod_hash_stat {
|
||||
ulong_t mhs_hit; /* tried a 'find' and it succeeded */
|
||||
ulong_t mhs_miss; /* tried a 'find' but it failed */
|
||||
ulong_t mhs_coll; /* occur when insert fails because of dup's */
|
||||
ulong_t mhs_nelems; /* total number of stored key/value pairs */
|
||||
ulong_t mhs_nomem; /* number of times kmem_alloc failed */
|
||||
};
|
||||
|
||||
struct mod_hash {
|
||||
krwlock_t mh_contents; /* lock protecting contents */
|
||||
char *mh_name; /* hash name */
|
||||
int mh_sleep; /* kmem_alloc flag */
|
||||
size_t mh_nchains; /* # of elements in mh_entries */
|
||||
|
||||
/* key and val destructor */
|
||||
void (*mh_kdtor)(mod_hash_key_t);
|
||||
void (*mh_vdtor)(mod_hash_val_t);
|
||||
|
||||
/* key comparator */
|
||||
int (*mh_keycmp)(mod_hash_key_t, mod_hash_key_t);
|
||||
|
||||
/* hash algorithm, and algorithm-private data */
|
||||
uint_t (*mh_hashalg)(void *, mod_hash_key_t);
|
||||
void *mh_hashalg_data;
|
||||
|
||||
struct mod_hash *mh_next; /* next hash in list */
|
||||
|
||||
struct mod_hash_stat mh_stat;
|
||||
|
||||
struct mod_hash_entry *mh_entries[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* MH_SIZE()
|
||||
* Compute the size of a mod_hash_t, in bytes, given the number of
|
||||
* elements it contains.
|
||||
*/
|
||||
#define MH_SIZE(n) \
|
||||
(sizeof (mod_hash_t) + ((n) - 1) * (sizeof (struct mod_hash_entry *)))
|
||||
|
||||
/*
|
||||
* Module initialization; called once.
|
||||
*/
|
||||
void mod_hash_fini(void);
|
||||
void mod_hash_init(void);
|
||||
|
||||
/*
|
||||
* Internal routines. Use directly with care.
|
||||
*/
|
||||
uint_t i_mod_hash(mod_hash_t *, mod_hash_key_t);
|
||||
int i_mod_hash_insert_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t,
|
||||
mod_hash_hndl_t);
|
||||
int i_mod_hash_remove_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
|
||||
int i_mod_hash_find_nosync(mod_hash_t *, mod_hash_key_t, mod_hash_val_t *);
|
||||
void i_mod_hash_walk_nosync(mod_hash_t *, uint_t (*)(mod_hash_key_t,
|
||||
mod_hash_val_t *, void *), void *);
|
||||
void i_mod_hash_clear_nosync(mod_hash_t *hash);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_MODHASH_IMPL_H */
|
36
module/icp/include/sys/stack.h
Normal file
36
module/icp/include/sys/stack.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_STACK_H
|
||||
#define _SYS_STACK_H
|
||||
|
||||
#if defined(__i386) || defined(__amd64)
|
||||
|
||||
#include <sys/ia32/stack.h> /* XX64 x86/sys/stack.h */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_STACK_H */
|
36
module/icp/include/sys/trap.h
Normal file
36
module/icp/include/sys/trap.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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 2005 Sun Microsystems, Inc. All rights reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
|
||||
#ifndef _SYS_TRAP_H
|
||||
#define _SYS_TRAP_H
|
||||
|
||||
#if defined(__i386) || defined(__amd64)
|
||||
|
||||
#include <sys/ia32/trap.h> /* XX64 x86/sys/trap.h */
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_TRAP_H */
|
1437
module/icp/io/aes.c
Normal file
1437
module/icp/io/aes.c
Normal file
File diff suppressed because it is too large
Load Diff
1239
module/icp/io/sha1_mod.c
Normal file
1239
module/icp/io/sha1_mod.c
Normal file
File diff suppressed because it is too large
Load Diff
1307
module/icp/io/sha2_mod.c
Normal file
1307
module/icp/io/sha2_mod.c
Normal file
File diff suppressed because it is too large
Load Diff
171
module/icp/os/modconf.c
Normal file
171
module/icp/os/modconf.c
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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/modctl.h>
|
||||
|
||||
/*
|
||||
* Null operations; used for uninitialized and "misc" modules.
|
||||
*/
|
||||
static int mod_null(struct modlmisc *, struct modlinkage *);
|
||||
static int mod_infonull(void *, struct modlinkage *, int *);
|
||||
|
||||
/*
|
||||
* Cryptographic Modules
|
||||
*/
|
||||
struct mod_ops mod_cryptoops = {
|
||||
mod_null, mod_null, mod_infonull
|
||||
};
|
||||
|
||||
/*
|
||||
* Null operation; return 0.
|
||||
*/
|
||||
static int
|
||||
mod_null(struct modlmisc *modl, struct modlinkage *modlp)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Status for User modules.
|
||||
*/
|
||||
static int
|
||||
mod_infonull(void *modl, struct modlinkage *modlp, int *p0)
|
||||
{
|
||||
*p0 = -1; /* for modinfo display */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Install a module.
|
||||
* (This routine is in the Solaris SPARC DDI/DKI)
|
||||
*/
|
||||
int
|
||||
mod_install(struct modlinkage *modlp)
|
||||
{
|
||||
int retval = -1; /* No linkage structures */
|
||||
struct modlmisc **linkpp;
|
||||
struct modlmisc **linkpp1;
|
||||
|
||||
if (modlp->ml_rev != MODREV_1) {
|
||||
cmn_err(CE_WARN, "mod_install: "
|
||||
"modlinkage structure is not MODREV_1\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
|
||||
|
||||
while (*linkpp != NULL) {
|
||||
if ((retval = MODL_INSTALL(*linkpp, modlp)) != 0) {
|
||||
linkpp1 = (struct modlmisc **)&modlp->ml_linkage[0];
|
||||
|
||||
while (linkpp1 != linkpp) {
|
||||
MODL_REMOVE(*linkpp1, modlp); /* clean up */
|
||||
linkpp1++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
linkpp++;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static char *reins_err =
|
||||
"Could not reinstall %s\nReboot to correct the problem";
|
||||
|
||||
/*
|
||||
* Remove a module. This is called by the module wrapper routine.
|
||||
* (This routine is in the Solaris SPARC DDI/DKI)
|
||||
*/
|
||||
int
|
||||
mod_remove(struct modlinkage *modlp)
|
||||
{
|
||||
int retval = 0;
|
||||
struct modlmisc **linkpp, *last_linkp;
|
||||
|
||||
linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
|
||||
|
||||
while (*linkpp != NULL) {
|
||||
if ((retval = MODL_REMOVE(*linkpp, modlp)) != 0) {
|
||||
last_linkp = *linkpp;
|
||||
linkpp = (struct modlmisc **)&modlp->ml_linkage[0];
|
||||
while (*linkpp != last_linkp) {
|
||||
if (MODL_INSTALL(*linkpp, modlp) != 0) {
|
||||
cmn_err(CE_WARN, reins_err,
|
||||
(*linkpp)->misc_linkinfo);
|
||||
break;
|
||||
}
|
||||
linkpp++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
linkpp++;
|
||||
}
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get module status.
|
||||
* (This routine is in the Solaris SPARC DDI/DKI)
|
||||
*/
|
||||
int
|
||||
mod_info(struct modlinkage *modlp, struct modinfo *modinfop)
|
||||
{
|
||||
int i;
|
||||
int retval = 0;
|
||||
struct modspecific_info *msip;
|
||||
struct modlmisc **linkpp;
|
||||
|
||||
modinfop->mi_rev = modlp->ml_rev;
|
||||
|
||||
linkpp = (struct modlmisc **)modlp->ml_linkage;
|
||||
msip = &modinfop->mi_msinfo[0];
|
||||
|
||||
for (i = 0; i < MODMAXLINK; i++) {
|
||||
if (*linkpp == NULL) {
|
||||
msip->msi_linkinfo[0] = '\0';
|
||||
} else {
|
||||
(void) strncpy(msip->msi_linkinfo,
|
||||
(*linkpp)->misc_linkinfo, MODMAXLINKINFOLEN);
|
||||
retval = MODL_INFO(*linkpp, modlp, &msip->msi_p0);
|
||||
if (retval != 0)
|
||||
break;
|
||||
linkpp++;
|
||||
}
|
||||
msip++;
|
||||
}
|
||||
|
||||
if (modinfop->mi_info == MI_INFO_LINKAGE) {
|
||||
/*
|
||||
* Slight kludge used to extract the address of the
|
||||
* modlinkage structure from the module (just after
|
||||
* loading a module for the very first time)
|
||||
*/
|
||||
modinfop->mi_base = (void *)modlp;
|
||||
}
|
||||
|
||||
if (retval == 0)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
925
module/icp/os/modhash.c
Normal file
925
module/icp/os/modhash.c
Normal file
@ -0,0 +1,925 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* mod_hash: flexible hash table implementation.
|
||||
*
|
||||
* This is a reasonably fast, reasonably flexible hash table implementation
|
||||
* which features pluggable hash algorithms to support storing arbitrary keys
|
||||
* and values. It is designed to handle small (< 100,000 items) amounts of
|
||||
* data. The hash uses chaining to resolve collisions, and does not feature a
|
||||
* mechanism to grow the hash. Care must be taken to pick nchains to be large
|
||||
* enough for the application at hand, or lots of time will be wasted searching
|
||||
* hash chains.
|
||||
*
|
||||
* The client of the hash is required to supply a number of items to support
|
||||
* the various hash functions:
|
||||
*
|
||||
* - Destructor functions for the key and value being hashed.
|
||||
* A destructor is responsible for freeing an object when the hash
|
||||
* table is no longer storing it. Since keys and values can be of
|
||||
* arbitrary type, separate destructors for keys & values are used.
|
||||
* These may be mod_hash_null_keydtor and mod_hash_null_valdtor if no
|
||||
* destructor is needed for either a key or value.
|
||||
*
|
||||
* - A hashing algorithm which returns a uint_t representing a hash index
|
||||
* The number returned need _not_ be between 0 and nchains. The mod_hash
|
||||
* code will take care of doing that. The second argument (after the
|
||||
* key) to the hashing function is a void * that represents
|
||||
* hash_alg_data-- this is provided so that the hashing algrorithm can
|
||||
* maintain some state across calls, or keep algorithm-specific
|
||||
* constants associated with the hash table.
|
||||
*
|
||||
* A pointer-hashing and a string-hashing algorithm are supplied in
|
||||
* this file.
|
||||
*
|
||||
* - A key comparator (a la qsort).
|
||||
* This is used when searching the hash chain. The key comparator
|
||||
* determines if two keys match. It should follow the return value
|
||||
* semantics of strcmp.
|
||||
*
|
||||
* string and pointer comparators are supplied in this file.
|
||||
*
|
||||
* mod_hash_create_strhash() and mod_hash_create_ptrhash() provide good
|
||||
* examples of how to create a customized hash table.
|
||||
*
|
||||
* Basic hash operations:
|
||||
*
|
||||
* mod_hash_create_strhash(name, nchains, dtor),
|
||||
* create a hash using strings as keys.
|
||||
* NOTE: This create a hash which automatically cleans up the string
|
||||
* values it is given for keys.
|
||||
*
|
||||
* mod_hash_create_ptrhash(name, nchains, dtor, key_elem_size):
|
||||
* create a hash using pointers as keys.
|
||||
*
|
||||
* mod_hash_create_extended(name, nchains, kdtor, vdtor,
|
||||
* hash_alg, hash_alg_data,
|
||||
* keycmp, sleep)
|
||||
* create a customized hash table.
|
||||
*
|
||||
* mod_hash_destroy_hash(hash):
|
||||
* destroy the given hash table, calling the key and value destructors
|
||||
* on each key-value pair stored in the hash.
|
||||
*
|
||||
* mod_hash_insert(hash, key, val):
|
||||
* place a key, value pair into the given hash.
|
||||
* duplicate keys are rejected.
|
||||
*
|
||||
* mod_hash_insert_reserve(hash, key, val, handle):
|
||||
* place a key, value pair into the given hash, using handle to indicate
|
||||
* the reserved storage for the pair. (no memory allocation is needed
|
||||
* during a mod_hash_insert_reserve.) duplicate keys are rejected.
|
||||
*
|
||||
* mod_hash_reserve(hash, *handle):
|
||||
* reserve storage for a key-value pair using the memory allocation
|
||||
* policy of 'hash', returning the storage handle in 'handle'.
|
||||
*
|
||||
* mod_hash_reserve_nosleep(hash, *handle): reserve storage for a key-value
|
||||
* pair ignoring the memory allocation policy of 'hash' and always without
|
||||
* sleep, returning the storage handle in 'handle'.
|
||||
*
|
||||
* mod_hash_remove(hash, key, *val):
|
||||
* remove a key-value pair with key 'key' from 'hash', destroying the
|
||||
* stored key, and returning the value in val.
|
||||
*
|
||||
* mod_hash_replace(hash, key, val)
|
||||
* atomically remove an existing key-value pair from a hash, and replace
|
||||
* the key and value with the ones supplied. The removed key and value
|
||||
* (if any) are destroyed.
|
||||
*
|
||||
* mod_hash_destroy(hash, key):
|
||||
* remove a key-value pair with key 'key' from 'hash', destroying both
|
||||
* stored key and stored value.
|
||||
*
|
||||
* mod_hash_find(hash, key, val):
|
||||
* find a value in the hash table corresponding to the given key.
|
||||
*
|
||||
* mod_hash_find_cb(hash, key, val, found_callback)
|
||||
* find a value in the hash table corresponding to the given key.
|
||||
* If a value is found, call specified callback passing key and val to it.
|
||||
* The callback is called with the hash lock held.
|
||||
* It is intended to be used in situations where the act of locating the
|
||||
* data must also modify it - such as in reference counting schemes.
|
||||
*
|
||||
* mod_hash_walk(hash, callback(key, elem, arg), arg)
|
||||
* walks all the elements in the hashtable and invokes the callback
|
||||
* function with the key/value pair for each element. the hashtable
|
||||
* is locked for readers so the callback function should not attempt
|
||||
* to do any updates to the hashable. the callback function should
|
||||
* return MH_WALK_CONTINUE to continue walking the hashtable or
|
||||
* MH_WALK_TERMINATE to abort the walk of the hashtable.
|
||||
*
|
||||
* mod_hash_clear(hash):
|
||||
* clears the given hash table of entries, calling the key and value
|
||||
* destructors for every element in the hash.
|
||||
*/
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/bitmap.h>
|
||||
#include <sys/modhash_impl.h>
|
||||
#include <sys/sysmacros.h>
|
||||
|
||||
/*
|
||||
* MH_KEY_DESTROY()
|
||||
* Invoke the key destructor.
|
||||
*/
|
||||
#define MH_KEY_DESTROY(hash, key) ((hash->mh_kdtor)(key))
|
||||
|
||||
/*
|
||||
* MH_VAL_DESTROY()
|
||||
* Invoke the value destructor.
|
||||
*/
|
||||
#define MH_VAL_DESTROY(hash, val) ((hash->mh_vdtor)(val))
|
||||
|
||||
/*
|
||||
* MH_KEYCMP()
|
||||
* Call the key comparator for the given hash keys.
|
||||
*/
|
||||
#define MH_KEYCMP(hash, key1, key2) ((hash->mh_keycmp)(key1, key2))
|
||||
|
||||
/*
|
||||
* Cache for struct mod_hash_entry
|
||||
*/
|
||||
kmem_cache_t *mh_e_cache = NULL;
|
||||
mod_hash_t *mh_head = NULL;
|
||||
kmutex_t mh_head_lock;
|
||||
|
||||
/*
|
||||
* mod_hash_null_keydtor()
|
||||
* mod_hash_null_valdtor()
|
||||
* no-op key and value destructors.
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
mod_hash_null_keydtor(mod_hash_key_t key)
|
||||
{
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
mod_hash_null_valdtor(mod_hash_val_t val)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_bystr()
|
||||
* mod_hash_strkey_cmp()
|
||||
* mod_hash_strkey_dtor()
|
||||
* mod_hash_strval_dtor()
|
||||
* Hash and key comparison routines for hashes with string keys.
|
||||
*
|
||||
* mod_hash_create_strhash()
|
||||
* Create a hash using strings as keys
|
||||
*
|
||||
* The string hashing algorithm is from the "Dragon Book" --
|
||||
* "Compilers: Principles, Tools & Techniques", by Aho, Sethi, Ullman
|
||||
*/
|
||||
|
||||
/*ARGSUSED*/
|
||||
uint_t
|
||||
mod_hash_bystr(void *hash_data, mod_hash_key_t key)
|
||||
{
|
||||
uint_t hash = 0;
|
||||
uint_t g;
|
||||
char *p, *k = (char *)key;
|
||||
|
||||
ASSERT(k);
|
||||
for (p = k; *p != '\0'; p++) {
|
||||
hash = (hash << 4) + *p;
|
||||
if ((g = (hash & 0xf0000000)) != 0) {
|
||||
hash ^= (g >> 24);
|
||||
hash ^= g;
|
||||
}
|
||||
}
|
||||
return (hash);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_strkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
|
||||
{
|
||||
return (strcmp((char *)key1, (char *)key2));
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_strkey_dtor(mod_hash_key_t key)
|
||||
{
|
||||
char *c = (char *)key;
|
||||
kmem_free(c, strlen(c) + 1);
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_strval_dtor(mod_hash_val_t val)
|
||||
{
|
||||
char *c = (char *)val;
|
||||
kmem_free(c, strlen(c) + 1);
|
||||
}
|
||||
|
||||
mod_hash_t *
|
||||
mod_hash_create_strhash_nodtr(char *name, size_t nchains,
|
||||
void (*val_dtor)(mod_hash_val_t))
|
||||
{
|
||||
return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
|
||||
val_dtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
|
||||
}
|
||||
|
||||
mod_hash_t *
|
||||
mod_hash_create_strhash(char *name, size_t nchains,
|
||||
void (*val_dtor)(mod_hash_val_t))
|
||||
{
|
||||
return mod_hash_create_extended(name, nchains, mod_hash_strkey_dtor,
|
||||
val_dtor, mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_destroy_strhash(mod_hash_t *strhash)
|
||||
{
|
||||
ASSERT(strhash);
|
||||
mod_hash_destroy_hash(strhash);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* mod_hash_byptr()
|
||||
* mod_hash_ptrkey_cmp()
|
||||
* Hash and key comparison routines for hashes with pointer keys.
|
||||
*
|
||||
* mod_hash_create_ptrhash()
|
||||
* mod_hash_destroy_ptrhash()
|
||||
* Create a hash that uses pointers as keys. This hash algorithm
|
||||
* picks an appropriate set of middle bits in the address to hash on
|
||||
* based on the size of the hash table and a hint about the size of
|
||||
* the items pointed at.
|
||||
*/
|
||||
uint_t
|
||||
mod_hash_byptr(void *hash_data, mod_hash_key_t key)
|
||||
{
|
||||
uintptr_t k = (uintptr_t)key;
|
||||
k >>= (int)(uintptr_t)hash_data;
|
||||
|
||||
return ((uint_t)k);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_ptrkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
|
||||
{
|
||||
uintptr_t k1 = (uintptr_t)key1;
|
||||
uintptr_t k2 = (uintptr_t)key2;
|
||||
if (k1 > k2)
|
||||
return (-1);
|
||||
else if (k1 < k2)
|
||||
return (1);
|
||||
else
|
||||
return (0);
|
||||
}
|
||||
|
||||
mod_hash_t *
|
||||
mod_hash_create_ptrhash(char *name, size_t nchains,
|
||||
void (*val_dtor)(mod_hash_val_t), size_t key_elem_size)
|
||||
{
|
||||
size_t rshift;
|
||||
|
||||
/*
|
||||
* We want to hash on the bits in the middle of the address word
|
||||
* Bits far to the right in the word have little significance, and
|
||||
* are likely to all look the same (for example, an array of
|
||||
* 256-byte structures will have the bottom 8 bits of address
|
||||
* words the same). So we want to right-shift each address to
|
||||
* ignore the bottom bits.
|
||||
*
|
||||
* The high bits, which are also unused, will get taken out when
|
||||
* mod_hash takes hashkey % nchains.
|
||||
*/
|
||||
rshift = highbit(key_elem_size);
|
||||
|
||||
return mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
|
||||
val_dtor, mod_hash_byptr, (void *)rshift, mod_hash_ptrkey_cmp,
|
||||
KM_SLEEP);
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_destroy_ptrhash(mod_hash_t *hash)
|
||||
{
|
||||
ASSERT(hash);
|
||||
mod_hash_destroy_hash(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_byid()
|
||||
* mod_hash_idkey_cmp()
|
||||
* Hash and key comparison routines for hashes with 32-bit unsigned keys.
|
||||
*
|
||||
* mod_hash_create_idhash()
|
||||
* mod_hash_destroy_idhash()
|
||||
* mod_hash_iddata_gen()
|
||||
* Create a hash that uses numeric keys.
|
||||
*
|
||||
* The hash algorithm is documented in "Introduction to Algorithms"
|
||||
* (Cormen, Leiserson, Rivest); when the hash table is created, it
|
||||
* attempts to find the next largest prime above the number of hash
|
||||
* slots. The hash index is then this number times the key modulo
|
||||
* the hash size, or (key * prime) % nchains.
|
||||
*/
|
||||
uint_t
|
||||
mod_hash_byid(void *hash_data, mod_hash_key_t key)
|
||||
{
|
||||
uint_t kval = (uint_t)(uintptr_t)hash_data;
|
||||
return ((uint_t)(uintptr_t)key * (uint_t)kval);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_idkey_cmp(mod_hash_key_t key1, mod_hash_key_t key2)
|
||||
{
|
||||
return ((uint_t)(uintptr_t)key1 - (uint_t)(uintptr_t)key2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate the next largest prime number greater than nchains; this value
|
||||
* is intended to be later passed in to mod_hash_create_extended() as the
|
||||
* hash_data.
|
||||
*/
|
||||
uint_t
|
||||
mod_hash_iddata_gen(size_t nchains)
|
||||
{
|
||||
uint_t kval, i, prime;
|
||||
|
||||
/*
|
||||
* Pick the first (odd) prime greater than nchains. Make sure kval is
|
||||
* odd (so start with nchains +1 or +2 as appropriate).
|
||||
*/
|
||||
kval = (nchains % 2 == 0) ? nchains + 1 : nchains + 2;
|
||||
|
||||
for (;;) {
|
||||
prime = 1;
|
||||
for (i = 3; i * i <= kval; i += 2) {
|
||||
if (kval % i == 0)
|
||||
prime = 0;
|
||||
}
|
||||
if (prime == 1)
|
||||
break;
|
||||
kval += 2;
|
||||
}
|
||||
return (kval);
|
||||
}
|
||||
|
||||
mod_hash_t *
|
||||
mod_hash_create_idhash(char *name, size_t nchains,
|
||||
void (*val_dtor)(mod_hash_val_t))
|
||||
{
|
||||
uint_t kval = mod_hash_iddata_gen(nchains);
|
||||
|
||||
return (mod_hash_create_extended(name, nchains, mod_hash_null_keydtor,
|
||||
val_dtor, mod_hash_byid, (void *)(uintptr_t)kval,
|
||||
mod_hash_idkey_cmp, KM_SLEEP));
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_destroy_idhash(mod_hash_t *hash)
|
||||
{
|
||||
ASSERT(hash);
|
||||
mod_hash_destroy_hash(hash);
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_fini(void)
|
||||
{
|
||||
mutex_destroy(&mh_head_lock);
|
||||
|
||||
if (mh_e_cache) {
|
||||
kmem_cache_destroy(mh_e_cache);
|
||||
mh_e_cache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_init()
|
||||
* sets up globals, etc for mod_hash_*
|
||||
*/
|
||||
void
|
||||
mod_hash_init(void)
|
||||
{
|
||||
ASSERT(mh_e_cache == NULL);
|
||||
mh_e_cache = kmem_cache_create("mod_hash_entries",
|
||||
sizeof (struct mod_hash_entry), 0, NULL, NULL, NULL, NULL,
|
||||
NULL, 0);
|
||||
|
||||
mutex_init(&mh_head_lock, NULL, MUTEX_DEFAULT, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_create_extended()
|
||||
* The full-blown hash creation function.
|
||||
*
|
||||
* notes:
|
||||
* nchains - how many hash slots to create. More hash slots will
|
||||
* result in shorter hash chains, but will consume
|
||||
* slightly more memory up front.
|
||||
* sleep - should be KM_SLEEP or KM_NOSLEEP, to indicate whether
|
||||
* to sleep for memory, or fail in low-memory conditions.
|
||||
*
|
||||
* Fails only if KM_NOSLEEP was specified, and no memory was available.
|
||||
*/
|
||||
mod_hash_t *
|
||||
mod_hash_create_extended(
|
||||
char *hname, /* descriptive name for hash */
|
||||
size_t nchains, /* number of hash slots */
|
||||
void (*kdtor)(mod_hash_key_t), /* key destructor */
|
||||
void (*vdtor)(mod_hash_val_t), /* value destructor */
|
||||
uint_t (*hash_alg)(void *, mod_hash_key_t), /* hash algorithm */
|
||||
void *hash_alg_data, /* pass-thru arg for hash_alg */
|
||||
int (*keycmp)(mod_hash_key_t, mod_hash_key_t), /* key comparator */
|
||||
int sleep) /* whether to sleep for mem */
|
||||
{
|
||||
mod_hash_t *mod_hash;
|
||||
ASSERT(hname && keycmp && hash_alg && vdtor && kdtor);
|
||||
|
||||
if ((mod_hash = kmem_zalloc(MH_SIZE(nchains), sleep)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
mod_hash->mh_name = kmem_alloc(strlen(hname) + 1, sleep);
|
||||
if (mod_hash->mh_name == NULL) {
|
||||
kmem_free(mod_hash, MH_SIZE(nchains));
|
||||
return (NULL);
|
||||
}
|
||||
(void) strcpy(mod_hash->mh_name, hname);
|
||||
|
||||
rw_init(&mod_hash->mh_contents, NULL, RW_DEFAULT, NULL);
|
||||
mod_hash->mh_sleep = sleep;
|
||||
mod_hash->mh_nchains = nchains;
|
||||
mod_hash->mh_kdtor = kdtor;
|
||||
mod_hash->mh_vdtor = vdtor;
|
||||
mod_hash->mh_hashalg = hash_alg;
|
||||
mod_hash->mh_hashalg_data = hash_alg_data;
|
||||
mod_hash->mh_keycmp = keycmp;
|
||||
|
||||
/*
|
||||
* Link the hash up on the list of hashes
|
||||
*/
|
||||
mutex_enter(&mh_head_lock);
|
||||
mod_hash->mh_next = mh_head;
|
||||
mh_head = mod_hash;
|
||||
mutex_exit(&mh_head_lock);
|
||||
|
||||
return (mod_hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_destroy_hash()
|
||||
* destroy a hash table, destroying all of its stored keys and values
|
||||
* as well.
|
||||
*/
|
||||
void
|
||||
mod_hash_destroy_hash(mod_hash_t *hash)
|
||||
{
|
||||
mod_hash_t *mhp, *mhpp;
|
||||
|
||||
mutex_enter(&mh_head_lock);
|
||||
/*
|
||||
* Remove the hash from the hash list
|
||||
*/
|
||||
if (hash == mh_head) { /* removing 1st list elem */
|
||||
mh_head = mh_head->mh_next;
|
||||
} else {
|
||||
/*
|
||||
* mhpp can start out NULL since we know the 1st elem isn't the
|
||||
* droid we're looking for.
|
||||
*/
|
||||
mhpp = NULL;
|
||||
for (mhp = mh_head; mhp != NULL; mhp = mhp->mh_next) {
|
||||
if (mhp == hash) {
|
||||
mhpp->mh_next = mhp->mh_next;
|
||||
break;
|
||||
}
|
||||
mhpp = mhp;
|
||||
}
|
||||
}
|
||||
mutex_exit(&mh_head_lock);
|
||||
|
||||
/*
|
||||
* Clean out keys and values.
|
||||
*/
|
||||
mod_hash_clear(hash);
|
||||
|
||||
rw_destroy(&hash->mh_contents);
|
||||
kmem_free(hash->mh_name, strlen(hash->mh_name) + 1);
|
||||
kmem_free(hash, MH_SIZE(hash->mh_nchains));
|
||||
}
|
||||
|
||||
/*
|
||||
* i_mod_hash()
|
||||
* Call the hashing algorithm for this hash table, with the given key.
|
||||
*/
|
||||
uint_t
|
||||
i_mod_hash(mod_hash_t *hash, mod_hash_key_t key)
|
||||
{
|
||||
uint_t h;
|
||||
/*
|
||||
* Prevent div by 0 problems;
|
||||
* Also a nice shortcut when using a hash as a list
|
||||
*/
|
||||
if (hash->mh_nchains == 1)
|
||||
return (0);
|
||||
|
||||
h = (hash->mh_hashalg)(hash->mh_hashalg_data, key);
|
||||
return (h % (hash->mh_nchains - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* i_mod_hash_insert_nosync()
|
||||
* mod_hash_insert()
|
||||
* mod_hash_insert_reserve()
|
||||
* insert 'val' into the hash table, using 'key' as its key. If 'key' is
|
||||
* already a key in the hash, an error will be returned, and the key-val
|
||||
* pair will not be inserted. i_mod_hash_insert_nosync() supports a simple
|
||||
* handle abstraction, allowing hash entry allocation to be separated from
|
||||
* the hash insertion. this abstraction allows simple use of the mod_hash
|
||||
* structure in situations where mod_hash_insert() with a KM_SLEEP
|
||||
* allocation policy would otherwise be unsafe.
|
||||
*/
|
||||
int
|
||||
i_mod_hash_insert_nosync(mod_hash_t *hash, mod_hash_key_t key,
|
||||
mod_hash_val_t val, mod_hash_hndl_t handle)
|
||||
{
|
||||
uint_t hashidx;
|
||||
struct mod_hash_entry *entry;
|
||||
|
||||
ASSERT(hash);
|
||||
|
||||
/*
|
||||
* If we've not been given reserved storage, allocate storage directly,
|
||||
* using the hash's allocation policy.
|
||||
*/
|
||||
if (handle == (mod_hash_hndl_t)0) {
|
||||
entry = kmem_cache_alloc(mh_e_cache, hash->mh_sleep);
|
||||
if (entry == NULL) {
|
||||
hash->mh_stat.mhs_nomem++;
|
||||
return (MH_ERR_NOMEM);
|
||||
}
|
||||
} else {
|
||||
entry = (struct mod_hash_entry *)handle;
|
||||
}
|
||||
|
||||
hashidx = i_mod_hash(hash, key);
|
||||
entry->mhe_key = key;
|
||||
entry->mhe_val = val;
|
||||
entry->mhe_next = hash->mh_entries[hashidx];
|
||||
|
||||
hash->mh_entries[hashidx] = entry;
|
||||
hash->mh_stat.mhs_nelems++;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_insert(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t val)
|
||||
{
|
||||
int res;
|
||||
mod_hash_val_t v;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_WRITER);
|
||||
|
||||
/*
|
||||
* Disallow duplicate keys in the hash
|
||||
*/
|
||||
if (i_mod_hash_find_nosync(hash, key, &v) == 0) {
|
||||
rw_exit(&hash->mh_contents);
|
||||
hash->mh_stat.mhs_coll++;
|
||||
return (MH_ERR_DUPLICATE);
|
||||
}
|
||||
|
||||
res = i_mod_hash_insert_nosync(hash, key, val, (mod_hash_hndl_t)0);
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_insert_reserve(mod_hash_t *hash, mod_hash_key_t key,
|
||||
mod_hash_val_t val, mod_hash_hndl_t handle)
|
||||
{
|
||||
int res;
|
||||
mod_hash_val_t v;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_WRITER);
|
||||
|
||||
/*
|
||||
* Disallow duplicate keys in the hash
|
||||
*/
|
||||
if (i_mod_hash_find_nosync(hash, key, &v) == 0) {
|
||||
rw_exit(&hash->mh_contents);
|
||||
hash->mh_stat.mhs_coll++;
|
||||
return (MH_ERR_DUPLICATE);
|
||||
}
|
||||
res = i_mod_hash_insert_nosync(hash, key, val, handle);
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_reserve()
|
||||
* mod_hash_reserve_nosleep()
|
||||
* mod_hash_cancel()
|
||||
* Make or cancel a mod_hash_entry_t reservation. Reservations are used in
|
||||
* mod_hash_insert_reserve() above.
|
||||
*/
|
||||
int
|
||||
mod_hash_reserve(mod_hash_t *hash, mod_hash_hndl_t *handlep)
|
||||
{
|
||||
*handlep = kmem_cache_alloc(mh_e_cache, hash->mh_sleep);
|
||||
if (*handlep == NULL) {
|
||||
hash->mh_stat.mhs_nomem++;
|
||||
return (MH_ERR_NOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_reserve_nosleep(mod_hash_t *hash, mod_hash_hndl_t *handlep)
|
||||
{
|
||||
*handlep = kmem_cache_alloc(mh_e_cache, KM_NOSLEEP);
|
||||
if (*handlep == NULL) {
|
||||
hash->mh_stat.mhs_nomem++;
|
||||
return (MH_ERR_NOMEM);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
mod_hash_cancel(mod_hash_t *hash, mod_hash_hndl_t *handlep)
|
||||
{
|
||||
kmem_cache_free(mh_e_cache, *handlep);
|
||||
*handlep = (mod_hash_hndl_t)0;
|
||||
}
|
||||
|
||||
/*
|
||||
* i_mod_hash_remove_nosync()
|
||||
* mod_hash_remove()
|
||||
* Remove an element from the hash table.
|
||||
*/
|
||||
int
|
||||
i_mod_hash_remove_nosync(mod_hash_t *hash, mod_hash_key_t key,
|
||||
mod_hash_val_t *val)
|
||||
{
|
||||
int hashidx;
|
||||
struct mod_hash_entry *e, *ep;
|
||||
|
||||
hashidx = i_mod_hash(hash, key);
|
||||
ep = NULL; /* e's parent */
|
||||
|
||||
for (e = hash->mh_entries[hashidx]; e != NULL; e = e->mhe_next) {
|
||||
if (MH_KEYCMP(hash, e->mhe_key, key) == 0)
|
||||
break;
|
||||
ep = e;
|
||||
}
|
||||
|
||||
if (e == NULL) { /* not found */
|
||||
return (MH_ERR_NOTFOUND);
|
||||
}
|
||||
|
||||
if (ep == NULL) /* special case 1st element in bucket */
|
||||
hash->mh_entries[hashidx] = e->mhe_next;
|
||||
else
|
||||
ep->mhe_next = e->mhe_next;
|
||||
|
||||
/*
|
||||
* Clean up resources used by the node's key.
|
||||
*/
|
||||
MH_KEY_DESTROY(hash, e->mhe_key);
|
||||
|
||||
*val = e->mhe_val;
|
||||
kmem_cache_free(mh_e_cache, e);
|
||||
hash->mh_stat.mhs_nelems--;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_remove(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val)
|
||||
{
|
||||
int res;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_WRITER);
|
||||
res = i_mod_hash_remove_nosync(hash, key, val);
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_replace()
|
||||
* atomically remove an existing key-value pair from a hash, and replace
|
||||
* the key and value with the ones supplied. The removed key and value
|
||||
* (if any) are destroyed.
|
||||
*/
|
||||
int
|
||||
mod_hash_replace(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t val)
|
||||
{
|
||||
int res;
|
||||
mod_hash_val_t v;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_WRITER);
|
||||
|
||||
if (i_mod_hash_remove_nosync(hash, key, &v) == 0) {
|
||||
/*
|
||||
* mod_hash_remove() takes care of freeing up the key resources.
|
||||
*/
|
||||
MH_VAL_DESTROY(hash, v);
|
||||
}
|
||||
res = i_mod_hash_insert_nosync(hash, key, val, (mod_hash_hndl_t)0);
|
||||
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_destroy()
|
||||
* Remove an element from the hash table matching 'key', and destroy it.
|
||||
*/
|
||||
int
|
||||
mod_hash_destroy(mod_hash_t *hash, mod_hash_key_t key)
|
||||
{
|
||||
mod_hash_val_t val;
|
||||
int rv;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_WRITER);
|
||||
|
||||
if ((rv = i_mod_hash_remove_nosync(hash, key, &val)) == 0) {
|
||||
/*
|
||||
* mod_hash_remove() takes care of freeing up the key resources.
|
||||
*/
|
||||
MH_VAL_DESTROY(hash, val);
|
||||
}
|
||||
|
||||
rw_exit(&hash->mh_contents);
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* i_mod_hash_find_nosync()
|
||||
* mod_hash_find()
|
||||
* Find a value in the hash table corresponding to the given key.
|
||||
*/
|
||||
int
|
||||
i_mod_hash_find_nosync(mod_hash_t *hash, mod_hash_key_t key,
|
||||
mod_hash_val_t *val)
|
||||
{
|
||||
uint_t hashidx;
|
||||
struct mod_hash_entry *e;
|
||||
|
||||
hashidx = i_mod_hash(hash, key);
|
||||
|
||||
for (e = hash->mh_entries[hashidx]; e != NULL; e = e->mhe_next) {
|
||||
if (MH_KEYCMP(hash, e->mhe_key, key) == 0) {
|
||||
*val = e->mhe_val;
|
||||
hash->mh_stat.mhs_hit++;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
hash->mh_stat.mhs_miss++;
|
||||
return (MH_ERR_NOTFOUND);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_find(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val)
|
||||
{
|
||||
int res;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_READER);
|
||||
res = i_mod_hash_find_nosync(hash, key, val);
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_find_cb(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val,
|
||||
void (*find_cb)(mod_hash_key_t, mod_hash_val_t))
|
||||
{
|
||||
int res;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_READER);
|
||||
res = i_mod_hash_find_nosync(hash, key, val);
|
||||
if (res == 0) {
|
||||
find_cb(key, *val);
|
||||
}
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
int
|
||||
mod_hash_find_cb_rval(mod_hash_t *hash, mod_hash_key_t key, mod_hash_val_t *val,
|
||||
int (*find_cb)(mod_hash_key_t, mod_hash_val_t), int *cb_rval)
|
||||
{
|
||||
int res;
|
||||
|
||||
rw_enter(&hash->mh_contents, RW_READER);
|
||||
res = i_mod_hash_find_nosync(hash, key, val);
|
||||
if (res == 0) {
|
||||
*cb_rval = find_cb(key, *val);
|
||||
}
|
||||
rw_exit(&hash->mh_contents);
|
||||
|
||||
return (res);
|
||||
}
|
||||
|
||||
void
|
||||
i_mod_hash_walk_nosync(mod_hash_t *hash,
|
||||
uint_t (*callback)(mod_hash_key_t, mod_hash_val_t *, void *), void *arg)
|
||||
{
|
||||
struct mod_hash_entry *e;
|
||||
uint_t hashidx;
|
||||
int res = MH_WALK_CONTINUE;
|
||||
|
||||
for (hashidx = 0;
|
||||
(hashidx < (hash->mh_nchains - 1)) && (res == MH_WALK_CONTINUE);
|
||||
hashidx++) {
|
||||
e = hash->mh_entries[hashidx];
|
||||
while ((e != NULL) && (res == MH_WALK_CONTINUE)) {
|
||||
res = callback(e->mhe_key, e->mhe_val, arg);
|
||||
e = e->mhe_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* mod_hash_walk()
|
||||
* Walks all the elements in the hashtable and invokes the callback
|
||||
* function with the key/value pair for each element. The hashtable
|
||||
* is locked for readers so the callback function should not attempt
|
||||
* to do any updates to the hashable. The callback function should
|
||||
* return MH_WALK_CONTINUE to continue walking the hashtable or
|
||||
* MH_WALK_TERMINATE to abort the walk of the hashtable.
|
||||
*/
|
||||
void
|
||||
mod_hash_walk(mod_hash_t *hash,
|
||||
uint_t (*callback)(mod_hash_key_t, mod_hash_val_t *, void *), void *arg)
|
||||
{
|
||||
rw_enter(&hash->mh_contents, RW_READER);
|
||||
i_mod_hash_walk_nosync(hash, callback, arg);
|
||||
rw_exit(&hash->mh_contents);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* i_mod_hash_clear_nosync()
|
||||
* mod_hash_clear()
|
||||
* Clears the given hash table by calling the destructor of every hash
|
||||
* element and freeing up all mod_hash_entry's.
|
||||
*/
|
||||
void
|
||||
i_mod_hash_clear_nosync(mod_hash_t *hash)
|
||||
{
|
||||
int i;
|
||||
struct mod_hash_entry *e, *old_e;
|
||||
|
||||
for (i = 0; i < hash->mh_nchains; i++) {
|
||||
e = hash->mh_entries[i];
|
||||
while (e != NULL) {
|
||||
MH_KEY_DESTROY(hash, e->mhe_key);
|
||||
MH_VAL_DESTROY(hash, e->mhe_val);
|
||||
old_e = e;
|
||||
e = e->mhe_next;
|
||||
kmem_cache_free(mh_e_cache, old_e);
|
||||
}
|
||||
hash->mh_entries[i] = NULL;
|
||||
}
|
||||
hash->mh_stat.mhs_nelems = 0;
|
||||
}
|
||||
|
||||
void
|
||||
mod_hash_clear(mod_hash_t *hash)
|
||||
{
|
||||
ASSERT(hash);
|
||||
rw_enter(&hash->mh_contents, RW_WRITER);
|
||||
i_mod_hash_clear_nosync(hash);
|
||||
rw_exit(&hash->mh_contents);
|
||||
}
|
927
module/icp/spi/kcf_spi.c
Normal file
927
module/icp/spi/kcf_spi.c
Normal file
@ -0,0 +1,927 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is part of the core Kernel Cryptographic Framework.
|
||||
* It implements the SPI functions exported to cryptographic
|
||||
* providers.
|
||||
*/
|
||||
|
||||
|
||||
#include <sys/zfs_context.h>
|
||||
#include <sys/crypto/common.h>
|
||||
#include <sys/crypto/impl.h>
|
||||
#include <sys/crypto/sched_impl.h>
|
||||
#include <sys/crypto/spi.h>
|
||||
|
||||
/*
|
||||
* minalloc and maxalloc values to be used for taskq_create().
|
||||
*/
|
||||
int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
|
||||
int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
|
||||
int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
|
||||
|
||||
static void remove_provider(kcf_provider_desc_t *);
|
||||
static void process_logical_providers(crypto_provider_info_t *,
|
||||
kcf_provider_desc_t *);
|
||||
static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
|
||||
static int kcf_prov_kstat_update(kstat_t *, int);
|
||||
static void delete_kstat(kcf_provider_desc_t *);
|
||||
|
||||
static kcf_prov_stats_t kcf_stats_ks_data_template = {
|
||||
{ "kcf_ops_total", KSTAT_DATA_UINT64 },
|
||||
{ "kcf_ops_passed", KSTAT_DATA_UINT64 },
|
||||
{ "kcf_ops_failed", KSTAT_DATA_UINT64 },
|
||||
{ "kcf_ops_returned_busy", KSTAT_DATA_UINT64 }
|
||||
};
|
||||
|
||||
#define KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
|
||||
*((dst)->ops) = *((src)->ops);
|
||||
|
||||
/*
|
||||
* Copy an ops vector from src to dst. Used during provider registration
|
||||
* to copy the ops vector from the provider info structure to the
|
||||
* provider descriptor maintained by KCF.
|
||||
* Copying the ops vector specified by the provider is needed since the
|
||||
* framework does not require the provider info structure to be
|
||||
* persistent.
|
||||
*/
|
||||
static void
|
||||
copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
|
||||
{
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
|
||||
{
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
|
||||
{
|
||||
KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used to add cryptographic providers to the KEF framework.
|
||||
* Providers pass a crypto_provider_info structure to crypto_register_provider()
|
||||
* and get back a handle. The crypto_provider_info structure contains a
|
||||
* list of mechanisms supported by the provider and an ops vector containing
|
||||
* provider entry points. Hardware providers call this routine in their attach
|
||||
* routines. Software providers call this routine in their _init() routine.
|
||||
*/
|
||||
int
|
||||
crypto_register_provider(crypto_provider_info_t *info,
|
||||
crypto_kcf_provider_handle_t *handle)
|
||||
{
|
||||
char ks_name[KSTAT_STRLEN];
|
||||
|
||||
kcf_provider_desc_t *prov_desc = NULL;
|
||||
int ret = CRYPTO_ARGUMENTS_BAD;
|
||||
|
||||
if (info->pi_interface_version > CRYPTO_SPI_VERSION_3)
|
||||
return (CRYPTO_VERSION_MISMATCH);
|
||||
|
||||
/*
|
||||
* Check provider type, must be software, hardware, or logical.
|
||||
*/
|
||||
if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
|
||||
info->pi_provider_type != CRYPTO_SW_PROVIDER &&
|
||||
info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
|
||||
/*
|
||||
* Allocate and initialize a new provider descriptor. We also
|
||||
* hold it and release it when done.
|
||||
*/
|
||||
prov_desc = kcf_alloc_provider_desc(info);
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
|
||||
prov_desc->pd_prov_type = info->pi_provider_type;
|
||||
|
||||
/* provider-private handle, opaque to KCF */
|
||||
prov_desc->pd_prov_handle = info->pi_provider_handle;
|
||||
|
||||
/* copy provider description string */
|
||||
if (info->pi_provider_description != NULL) {
|
||||
/*
|
||||
* pi_provider_descriptor is a string that can contain
|
||||
* up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
|
||||
* INCLUDING the terminating null character. A bcopy()
|
||||
* is necessary here as pd_description should not have
|
||||
* a null character. See comments in kcf_alloc_provider_desc()
|
||||
* for details on pd_description field.
|
||||
*/
|
||||
bcopy(info->pi_provider_description, prov_desc->pd_description,
|
||||
MIN(strlen(info->pi_provider_description),
|
||||
(size_t)CRYPTO_PROVIDER_DESCR_MAX_LEN));
|
||||
}
|
||||
|
||||
if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
if (info->pi_ops_vector == NULL) {
|
||||
goto bail;
|
||||
}
|
||||
copy_ops_vector_v1(info->pi_ops_vector,
|
||||
prov_desc->pd_ops_vector);
|
||||
if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
|
||||
copy_ops_vector_v2(info->pi_ops_vector,
|
||||
prov_desc->pd_ops_vector);
|
||||
prov_desc->pd_flags = info->pi_flags;
|
||||
}
|
||||
if (info->pi_interface_version == CRYPTO_SPI_VERSION_3) {
|
||||
copy_ops_vector_v3(info->pi_ops_vector,
|
||||
prov_desc->pd_ops_vector);
|
||||
}
|
||||
}
|
||||
|
||||
/* object_ops and nostore_key_ops are mutually exclusive */
|
||||
if (prov_desc->pd_ops_vector->co_object_ops &&
|
||||
prov_desc->pd_ops_vector->co_nostore_key_ops) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/* process the mechanisms supported by the provider */
|
||||
if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
|
||||
goto bail;
|
||||
|
||||
/*
|
||||
* Add provider to providers tables, also sets the descriptor
|
||||
* pd_prov_id field.
|
||||
*/
|
||||
if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
|
||||
undo_register_provider(prov_desc, B_FALSE);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* We create a taskq only for a hardware provider. The global
|
||||
* software queue is used for software providers. We handle ordering
|
||||
* of multi-part requests in the taskq routine. So, it is safe to
|
||||
* have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
|
||||
* to keep some entries cached to improve performance.
|
||||
*/
|
||||
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
|
||||
prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq",
|
||||
crypto_taskq_threads, minclsyspri,
|
||||
crypto_taskq_minalloc, crypto_taskq_maxalloc,
|
||||
TASKQ_PREPOPULATE);
|
||||
else
|
||||
prov_desc->pd_sched_info.ks_taskq = NULL;
|
||||
|
||||
/* no kernel session to logical providers */
|
||||
if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
/*
|
||||
* Open a session for session-oriented providers. This session
|
||||
* is used for all kernel consumers. This is fine as a provider
|
||||
* is required to support multiple thread access to a session.
|
||||
* We can do this only after the taskq has been created as we
|
||||
* do a kcf_submit_request() to open the session.
|
||||
*/
|
||||
if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
|
||||
kcf_req_params_t params;
|
||||
|
||||
KCF_WRAP_SESSION_OPS_PARAMS(¶ms,
|
||||
KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
|
||||
CRYPTO_USER, NULL, 0, prov_desc);
|
||||
ret = kcf_submit_request(prov_desc, NULL, NULL, ¶ms,
|
||||
B_FALSE);
|
||||
|
||||
if (ret != CRYPTO_SUCCESS) {
|
||||
undo_register_provider(prov_desc, B_TRUE);
|
||||
ret = CRYPTO_FAILED;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
/*
|
||||
* Create the kstat for this provider. There is a kstat
|
||||
* installed for each successfully registered provider.
|
||||
* This kstat is deleted, when the provider unregisters.
|
||||
*/
|
||||
if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
|
||||
(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
|
||||
"NONAME", "provider_stats");
|
||||
} else {
|
||||
(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
|
||||
"NONAME", 0,
|
||||
prov_desc->pd_prov_id, "provider_stats");
|
||||
}
|
||||
|
||||
prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
|
||||
KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
|
||||
sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
|
||||
|
||||
if (prov_desc->pd_kstat != NULL) {
|
||||
bcopy(&kcf_stats_ks_data_template,
|
||||
&prov_desc->pd_ks_data,
|
||||
sizeof (kcf_stats_ks_data_template));
|
||||
prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
|
||||
KCF_PROV_REFHOLD(prov_desc);
|
||||
KCF_PROV_IREFHOLD(prov_desc);
|
||||
prov_desc->pd_kstat->ks_private = prov_desc;
|
||||
prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
|
||||
kstat_install(prov_desc->pd_kstat);
|
||||
}
|
||||
}
|
||||
|
||||
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
|
||||
process_logical_providers(info, prov_desc);
|
||||
|
||||
mutex_enter(&prov_desc->pd_lock);
|
||||
prov_desc->pd_state = KCF_PROV_READY;
|
||||
mutex_exit(&prov_desc->pd_lock);
|
||||
kcf_do_notify(prov_desc, B_TRUE);
|
||||
|
||||
*handle = prov_desc->pd_kcf_prov_handle;
|
||||
ret = CRYPTO_SUCCESS;
|
||||
|
||||
bail:
|
||||
KCF_PROV_REFRELE(prov_desc);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used to notify the framework when a provider is being
|
||||
* removed. Hardware providers call this routine in their detach routines.
|
||||
* Software providers call this routine in their _fini() routine.
|
||||
*/
|
||||
int
|
||||
crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
|
||||
{
|
||||
uint_t mech_idx;
|
||||
kcf_provider_desc_t *desc;
|
||||
kcf_prov_state_t saved_state;
|
||||
|
||||
/* lookup provider descriptor */
|
||||
if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
|
||||
return (CRYPTO_UNKNOWN_PROVIDER);
|
||||
|
||||
mutex_enter(&desc->pd_lock);
|
||||
/*
|
||||
* Check if any other thread is disabling or removing
|
||||
* this provider. We return if this is the case.
|
||||
*/
|
||||
if (desc->pd_state >= KCF_PROV_DISABLED) {
|
||||
mutex_exit(&desc->pd_lock);
|
||||
/* Release reference held by kcf_prov_tab_lookup(). */
|
||||
KCF_PROV_REFRELE(desc);
|
||||
return (CRYPTO_BUSY);
|
||||
}
|
||||
|
||||
saved_state = desc->pd_state;
|
||||
desc->pd_state = KCF_PROV_REMOVED;
|
||||
|
||||
if (saved_state == KCF_PROV_BUSY) {
|
||||
/*
|
||||
* The per-provider taskq threads may be waiting. We
|
||||
* signal them so that they can start failing requests.
|
||||
*/
|
||||
cv_broadcast(&desc->pd_resume_cv);
|
||||
}
|
||||
|
||||
if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
|
||||
/*
|
||||
* Check if this provider is currently being used.
|
||||
* pd_irefcnt is the number of holds from the internal
|
||||
* structures. We add one to account for the above lookup.
|
||||
*/
|
||||
if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
|
||||
desc->pd_state = saved_state;
|
||||
mutex_exit(&desc->pd_lock);
|
||||
/* Release reference held by kcf_prov_tab_lookup(). */
|
||||
KCF_PROV_REFRELE(desc);
|
||||
/*
|
||||
* The administrator presumably will stop the clients
|
||||
* thus removing the holds, when they get the busy
|
||||
* return value. Any retry will succeed then.
|
||||
*/
|
||||
return (CRYPTO_BUSY);
|
||||
}
|
||||
}
|
||||
mutex_exit(&desc->pd_lock);
|
||||
|
||||
if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
|
||||
remove_provider(desc);
|
||||
}
|
||||
|
||||
if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
/* remove the provider from the mechanisms tables */
|
||||
for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
|
||||
mech_idx++) {
|
||||
kcf_remove_mech_provider(
|
||||
desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
/* remove provider from providers table */
|
||||
if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
|
||||
CRYPTO_SUCCESS) {
|
||||
/* Release reference held by kcf_prov_tab_lookup(). */
|
||||
KCF_PROV_REFRELE(desc);
|
||||
return (CRYPTO_UNKNOWN_PROVIDER);
|
||||
}
|
||||
|
||||
delete_kstat(desc);
|
||||
|
||||
if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
|
||||
/* Release reference held by kcf_prov_tab_lookup(). */
|
||||
KCF_PROV_REFRELE(desc);
|
||||
|
||||
/*
|
||||
* Wait till the existing requests complete.
|
||||
*/
|
||||
mutex_enter(&desc->pd_lock);
|
||||
while (desc->pd_state != KCF_PROV_FREED)
|
||||
cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
|
||||
mutex_exit(&desc->pd_lock);
|
||||
} else {
|
||||
/*
|
||||
* Wait until requests that have been sent to the provider
|
||||
* complete.
|
||||
*/
|
||||
mutex_enter(&desc->pd_lock);
|
||||
while (desc->pd_irefcnt > 0)
|
||||
cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
|
||||
mutex_exit(&desc->pd_lock);
|
||||
}
|
||||
|
||||
kcf_do_notify(desc, B_FALSE);
|
||||
|
||||
if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
|
||||
/*
|
||||
* This is the only place where kcf_free_provider_desc()
|
||||
* is called directly. KCF_PROV_REFRELE() should free the
|
||||
* structure in all other places.
|
||||
*/
|
||||
ASSERT(desc->pd_state == KCF_PROV_FREED &&
|
||||
desc->pd_refcnt == 0);
|
||||
kcf_free_provider_desc(desc);
|
||||
} else {
|
||||
KCF_PROV_REFRELE(desc);
|
||||
}
|
||||
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used to notify the framework that the state of
|
||||
* a cryptographic provider has changed. Valid state codes are:
|
||||
*
|
||||
* CRYPTO_PROVIDER_READY
|
||||
* The provider indicates that it can process more requests. A provider
|
||||
* will notify with this event if it previously has notified us with a
|
||||
* CRYPTO_PROVIDER_BUSY.
|
||||
*
|
||||
* CRYPTO_PROVIDER_BUSY
|
||||
* The provider can not take more requests.
|
||||
*
|
||||
* CRYPTO_PROVIDER_FAILED
|
||||
* The provider encountered an internal error. The framework will not
|
||||
* be sending any more requests to the provider. The provider may notify
|
||||
* with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
|
||||
*
|
||||
* This routine can be called from user or interrupt context.
|
||||
*/
|
||||
void
|
||||
crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
|
||||
{
|
||||
kcf_provider_desc_t *pd;
|
||||
|
||||
/* lookup the provider from the given handle */
|
||||
if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
|
||||
return;
|
||||
|
||||
mutex_enter(&pd->pd_lock);
|
||||
|
||||
if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
|
||||
goto out;
|
||||
|
||||
if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
cmn_err(CE_WARN, "crypto_provider_notification: "
|
||||
"logical provider (%x) ignored\n", handle);
|
||||
goto out;
|
||||
}
|
||||
switch (state) {
|
||||
case CRYPTO_PROVIDER_READY:
|
||||
switch (pd->pd_state) {
|
||||
case KCF_PROV_BUSY:
|
||||
pd->pd_state = KCF_PROV_READY;
|
||||
/*
|
||||
* Signal the per-provider taskq threads that they
|
||||
* can start submitting requests.
|
||||
*/
|
||||
cv_broadcast(&pd->pd_resume_cv);
|
||||
break;
|
||||
|
||||
case KCF_PROV_FAILED:
|
||||
/*
|
||||
* The provider recovered from the error. Let us
|
||||
* use it now.
|
||||
*/
|
||||
pd->pd_state = KCF_PROV_READY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CRYPTO_PROVIDER_BUSY:
|
||||
switch (pd->pd_state) {
|
||||
case KCF_PROV_READY:
|
||||
pd->pd_state = KCF_PROV_BUSY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CRYPTO_PROVIDER_FAILED:
|
||||
/*
|
||||
* We note the failure and return. The per-provider taskq
|
||||
* threads check this flag and start failing the
|
||||
* requests, if it is set. See process_req_hwp() for details.
|
||||
*/
|
||||
switch (pd->pd_state) {
|
||||
case KCF_PROV_READY:
|
||||
pd->pd_state = KCF_PROV_FAILED;
|
||||
break;
|
||||
|
||||
case KCF_PROV_BUSY:
|
||||
pd->pd_state = KCF_PROV_FAILED;
|
||||
/*
|
||||
* The per-provider taskq threads may be waiting. We
|
||||
* signal them so that they can start failing requests.
|
||||
*/
|
||||
cv_broadcast(&pd->pd_resume_cv);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
out:
|
||||
mutex_exit(&pd->pd_lock);
|
||||
KCF_PROV_REFRELE(pd);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used to notify the framework the result of
|
||||
* an asynchronous request handled by a provider. Valid error
|
||||
* codes are the same as the CRYPTO_* errors defined in common.h.
|
||||
*
|
||||
* This routine can be called from user or interrupt context.
|
||||
*/
|
||||
void
|
||||
crypto_op_notification(crypto_req_handle_t handle, int error)
|
||||
{
|
||||
kcf_call_type_t ctype;
|
||||
|
||||
if (handle == NULL)
|
||||
return;
|
||||
|
||||
if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
|
||||
kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
|
||||
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
sreq->sn_provider->pd_sched_info.ks_nfails++;
|
||||
KCF_PROV_IREFRELE(sreq->sn_provider);
|
||||
kcf_sop_done(sreq, error);
|
||||
} else {
|
||||
kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
|
||||
|
||||
ASSERT(ctype == CRYPTO_ASYNCH);
|
||||
if (error != CRYPTO_SUCCESS)
|
||||
areq->an_provider->pd_sched_info.ks_nfails++;
|
||||
KCF_PROV_IREFRELE(areq->an_provider);
|
||||
kcf_aop_done(areq, error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine is used by software providers to determine
|
||||
* whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
|
||||
* Note that hardware providers can always use KM_SLEEP. So,
|
||||
* they do not need to call this routine.
|
||||
*
|
||||
* This routine can be called from user or interrupt context.
|
||||
*/
|
||||
int
|
||||
crypto_kmflag(crypto_req_handle_t handle)
|
||||
{
|
||||
return (REQHNDL2_KMFLAG(handle));
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the mechanism info structures specified by the provider
|
||||
* during registration. A NULL crypto_provider_info_t indicates
|
||||
* an already initialized provider descriptor.
|
||||
*
|
||||
* Mechanisms are not added to the kernel's mechanism table if the
|
||||
* provider is a logical provider.
|
||||
*
|
||||
* Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
|
||||
* of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
|
||||
* if the table of mechanisms is full.
|
||||
*/
|
||||
static int
|
||||
init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
|
||||
{
|
||||
uint_t mech_idx;
|
||||
uint_t cleanup_idx;
|
||||
int err = CRYPTO_SUCCESS;
|
||||
kcf_prov_mech_desc_t *pmd;
|
||||
int desc_use_count = 0;
|
||||
int mcount = desc->pd_mech_list_count;
|
||||
|
||||
if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
|
||||
if (info != NULL) {
|
||||
ASSERT(info->pi_mechanisms != NULL);
|
||||
bcopy(info->pi_mechanisms, desc->pd_mechanisms,
|
||||
sizeof (crypto_mech_info_t) * mcount);
|
||||
}
|
||||
return (CRYPTO_SUCCESS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the mechanism list from the provider info to the provider
|
||||
* descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
|
||||
* element if the provider has random_ops since we keep an internal
|
||||
* mechanism, SUN_RANDOM, in this case.
|
||||
*/
|
||||
if (info != NULL) {
|
||||
if (info->pi_ops_vector->co_random_ops != NULL) {
|
||||
crypto_mech_info_t *rand_mi;
|
||||
|
||||
/*
|
||||
* Need the following check as it is possible to have
|
||||
* a provider that implements just random_ops and has
|
||||
* pi_mechanisms == NULL.
|
||||
*/
|
||||
if (info->pi_mechanisms != NULL) {
|
||||
bcopy(info->pi_mechanisms, desc->pd_mechanisms,
|
||||
sizeof (crypto_mech_info_t) * (mcount - 1));
|
||||
}
|
||||
rand_mi = &desc->pd_mechanisms[mcount - 1];
|
||||
|
||||
bzero(rand_mi, sizeof (crypto_mech_info_t));
|
||||
(void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
|
||||
} else {
|
||||
ASSERT(info->pi_mechanisms != NULL);
|
||||
bcopy(info->pi_mechanisms, desc->pd_mechanisms,
|
||||
sizeof (crypto_mech_info_t) * mcount);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each mechanism support by the provider, add the provider
|
||||
* to the corresponding KCF mechanism mech_entry chain.
|
||||
*/
|
||||
for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
|
||||
crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
|
||||
|
||||
if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
|
||||
(mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
|
||||
err = CRYPTO_ARGUMENTS_BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
if (desc->pd_flags & CRYPTO_HASH_NO_UPDATE &&
|
||||
mi->cm_func_group_mask & CRYPTO_FG_DIGEST) {
|
||||
/*
|
||||
* We ask the provider to specify the limit
|
||||
* per hash mechanism. But, in practice, a
|
||||
* hardware limitation means all hash mechanisms
|
||||
* will have the same maximum size allowed for
|
||||
* input data. So, we make it a per provider
|
||||
* limit to keep it simple.
|
||||
*/
|
||||
if (mi->cm_max_input_length == 0) {
|
||||
err = CRYPTO_ARGUMENTS_BAD;
|
||||
break;
|
||||
} else {
|
||||
desc->pd_hash_limit = mi->cm_max_input_length;
|
||||
}
|
||||
}
|
||||
|
||||
if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
|
||||
KCF_SUCCESS)
|
||||
break;
|
||||
|
||||
if (pmd == NULL)
|
||||
continue;
|
||||
|
||||
/* The provider will be used for this mechanism */
|
||||
desc_use_count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow multiple software providers with disabled mechanisms
|
||||
* to register. Subsequent enabling of mechanisms will result in
|
||||
* an unsupported configuration, i.e. multiple software providers
|
||||
* per mechanism.
|
||||
*/
|
||||
if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
|
||||
if (err == KCF_SUCCESS)
|
||||
return (CRYPTO_SUCCESS);
|
||||
|
||||
/*
|
||||
* An error occurred while adding the mechanism, cleanup
|
||||
* and bail.
|
||||
*/
|
||||
for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
|
||||
kcf_remove_mech_provider(
|
||||
desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
|
||||
}
|
||||
|
||||
if (err == KCF_MECH_TAB_FULL)
|
||||
return (CRYPTO_HOST_MEMORY);
|
||||
|
||||
return (CRYPTO_ARGUMENTS_BAD);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update routine for kstat. Only privileged users are allowed to
|
||||
* access this information, since this information is sensitive.
|
||||
* There are some cryptographic attacks (e.g. traffic analysis)
|
||||
* which can use this information.
|
||||
*/
|
||||
static int
|
||||
kcf_prov_kstat_update(kstat_t *ksp, int rw)
|
||||
{
|
||||
kcf_prov_stats_t *ks_data;
|
||||
kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
|
||||
|
||||
if (rw == KSTAT_WRITE)
|
||||
return (EACCES);
|
||||
|
||||
ks_data = ksp->ks_data;
|
||||
|
||||
ks_data->ps_ops_total.value.ui64 =
|
||||
pd->pd_sched_info.ks_ndispatches;
|
||||
ks_data->ps_ops_failed.value.ui64 =
|
||||
pd->pd_sched_info.ks_nfails;
|
||||
ks_data->ps_ops_busy_rval.value.ui64 =
|
||||
pd->pd_sched_info.ks_nbusy_rval;
|
||||
ks_data->ps_ops_passed.value.ui64 =
|
||||
pd->pd_sched_info.ks_ndispatches -
|
||||
pd->pd_sched_info.ks_nfails -
|
||||
pd->pd_sched_info.ks_nbusy_rval;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Utility routine called from failure paths in crypto_register_provider()
|
||||
* and from crypto_load_soft_disabled().
|
||||
*/
|
||||
void
|
||||
undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
|
||||
{
|
||||
uint_t mech_idx;
|
||||
|
||||
/* remove the provider from the mechanisms tables */
|
||||
for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
|
||||
mech_idx++) {
|
||||
kcf_remove_mech_provider(
|
||||
desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
|
||||
}
|
||||
|
||||
/* remove provider from providers table */
|
||||
if (remove_prov)
|
||||
(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility routine called from crypto_load_soft_disabled(). Callers
|
||||
* should have done a prior undo_register_provider().
|
||||
*/
|
||||
void
|
||||
redo_register_provider(kcf_provider_desc_t *pd)
|
||||
{
|
||||
/* process the mechanisms supported by the provider */
|
||||
(void) init_prov_mechs(NULL, pd);
|
||||
|
||||
/*
|
||||
* Hold provider in providers table. We should not call
|
||||
* kcf_prov_tab_add_provider() here as the provider descriptor
|
||||
* is still valid which means it has an entry in the provider
|
||||
* table.
|
||||
*/
|
||||
KCF_PROV_REFHOLD(pd);
|
||||
KCF_PROV_IREFHOLD(pd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add provider (p1) to another provider's array of providers (p2).
|
||||
* Hardware and logical providers use this array to cross-reference
|
||||
* each other.
|
||||
*/
|
||||
static void
|
||||
add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
|
||||
{
|
||||
kcf_provider_list_t *new;
|
||||
|
||||
new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
|
||||
mutex_enter(&p2->pd_lock);
|
||||
new->pl_next = p2->pd_provider_list;
|
||||
p2->pd_provider_list = new;
|
||||
KCF_PROV_IREFHOLD(p1);
|
||||
new->pl_provider = p1;
|
||||
mutex_exit(&p2->pd_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove provider (p1) from another provider's array of providers (p2).
|
||||
* Hardware and logical providers use this array to cross-reference
|
||||
* each other.
|
||||
*/
|
||||
static void
|
||||
remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
|
||||
{
|
||||
|
||||
kcf_provider_list_t *pl = NULL, **prev;
|
||||
|
||||
mutex_enter(&p2->pd_lock);
|
||||
for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
|
||||
pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
|
||||
if (pl->pl_provider == p1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p1 == NULL) {
|
||||
mutex_exit(&p2->pd_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* detach and free kcf_provider_list structure */
|
||||
KCF_PROV_IREFRELE(p1);
|
||||
*prev = pl->pl_next;
|
||||
kmem_free(pl, sizeof (*pl));
|
||||
mutex_exit(&p2->pd_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an array of logical provider handles (crypto_provider_id)
|
||||
* stored in a crypto_provider_info structure into an array of provider
|
||||
* descriptors (kcf_provider_desc_t) attached to a logical provider.
|
||||
*/
|
||||
static void
|
||||
process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
|
||||
{
|
||||
kcf_provider_desc_t *lp;
|
||||
crypto_provider_id_t handle;
|
||||
int count = info->pi_logical_provider_count;
|
||||
int i;
|
||||
|
||||
/* add hardware provider to each logical provider */
|
||||
for (i = 0; i < count; i++) {
|
||||
handle = info->pi_logical_providers[i];
|
||||
lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
|
||||
if (lp == NULL) {
|
||||
continue;
|
||||
}
|
||||
add_provider_to_array(hp, lp);
|
||||
hp->pd_flags |= KCF_LPROV_MEMBER;
|
||||
|
||||
/*
|
||||
* A hardware provider has to have the provider descriptor of
|
||||
* every logical provider it belongs to, so it can be removed
|
||||
* from the logical provider if the hardware provider
|
||||
* unregisters from the framework.
|
||||
*/
|
||||
add_provider_to_array(lp, hp);
|
||||
KCF_PROV_REFRELE(lp);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine removes a provider from all of the logical or
|
||||
* hardware providers it belongs to, and frees the provider's
|
||||
* array of pointers to providers.
|
||||
*/
|
||||
static void
|
||||
remove_provider(kcf_provider_desc_t *pp)
|
||||
{
|
||||
kcf_provider_desc_t *p;
|
||||
kcf_provider_list_t *e, *next;
|
||||
|
||||
mutex_enter(&pp->pd_lock);
|
||||
for (e = pp->pd_provider_list; e != NULL; e = next) {
|
||||
p = e->pl_provider;
|
||||
remove_provider_from_array(pp, p);
|
||||
if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
|
||||
p->pd_provider_list == NULL)
|
||||
p->pd_flags &= ~KCF_LPROV_MEMBER;
|
||||
KCF_PROV_IREFRELE(p);
|
||||
next = e->pl_next;
|
||||
kmem_free(e, sizeof (*e));
|
||||
}
|
||||
pp->pd_provider_list = NULL;
|
||||
mutex_exit(&pp->pd_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Dispatch events as needed for a provider. is_added flag tells
|
||||
* whether the provider is registering or unregistering.
|
||||
*/
|
||||
void
|
||||
kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
|
||||
{
|
||||
int i;
|
||||
crypto_notify_event_change_t ec;
|
||||
|
||||
ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
|
||||
|
||||
/*
|
||||
* Inform interested clients of the mechanisms becoming
|
||||
* available/unavailable. We skip this for logical providers
|
||||
* as they do not affect mechanisms.
|
||||
*/
|
||||
if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
|
||||
ec.ec_provider_type = prov_desc->pd_prov_type;
|
||||
ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
|
||||
CRYPTO_MECH_REMOVED;
|
||||
for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
|
||||
(void) strncpy(ec.ec_mech_name,
|
||||
prov_desc->pd_mechanisms[i].cm_mech_name,
|
||||
CRYPTO_MAX_MECH_NAME);
|
||||
kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Inform interested clients about the new or departing provider.
|
||||
* In case of a logical provider, we need to notify the event only
|
||||
* for the logical provider and not for the underlying
|
||||
* providers which are known by the KCF_LPROV_MEMBER bit.
|
||||
*/
|
||||
if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
|
||||
(prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
|
||||
kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
|
||||
CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
delete_kstat(kcf_provider_desc_t *desc)
|
||||
{
|
||||
/* destroy the kstat created for this provider */
|
||||
if (desc->pd_kstat != NULL) {
|
||||
kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
|
||||
|
||||
/* release reference held by desc->pd_kstat->ks_private */
|
||||
ASSERT(desc == kspd);
|
||||
kstat_delete(kspd->pd_kstat);
|
||||
desc->pd_kstat = NULL;
|
||||
KCF_PROV_REFRELE(kspd);
|
||||
KCF_PROV_IREFRELE(kspd);
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ if [ -f "${basedir}/../${SCRIPT_CONFIG}" ]; then
|
||||
. "${basedir}/../${SCRIPT_CONFIG}"
|
||||
else
|
||||
KERNEL_MODULES=(zlib_deflate zlib_inflate)
|
||||
MODULES=(spl splat zavl znvpair zunicode zcommon zfs)
|
||||
MODULES=(spl splat zavl znvpair zunicode zcommon icp zfs)
|
||||
fi
|
||||
|
||||
PROG="<define PROG>"
|
||||
|
@ -82,6 +82,7 @@ export ZFS_MODULES=( \
|
||||
${MODDIR}/nvpair/znvpair.ko \
|
||||
${MODDIR}/unicode/zunicode.ko \
|
||||
${MODDIR}/zcommon/zcommon.ko \
|
||||
${MODDIR}/icp/icp.ko \
|
||||
${MODDIR}/zfs/zfs.ko \
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user