Merge d9d69c1b97
into 1713aa7b4d
This commit is contained in:
commit
bb0aa38627
|
@ -124,6 +124,7 @@ cstyle:
|
||||||
! -name 'zfs_config.*' ! -name '*.mod.c' \
|
! -name 'zfs_config.*' ! -name '*.mod.c' \
|
||||||
! -name 'opt_global.h' ! -name '*_if*.h' \
|
! -name 'opt_global.h' ! -name '*_if*.h' \
|
||||||
! -name 'zstd_compat_wrapper.h' \
|
! -name 'zstd_compat_wrapper.h' \
|
||||||
|
! -name 'monocypher.[ch]' \
|
||||||
! -path './module/zstd/lib/*' \
|
! -path './module/zstd/lib/*' \
|
||||||
! -path './include/sys/lua/*' \
|
! -path './include/sys/lua/*' \
|
||||||
! -path './module/lua/l*.[ch]' \
|
! -path './module/lua/l*.[ch]' \
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#define SUN_CKM_AES_CCM "CKM_AES_CCM"
|
#define SUN_CKM_AES_CCM "CKM_AES_CCM"
|
||||||
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
|
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
|
||||||
#define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC"
|
#define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC"
|
||||||
|
#define SUN_CKM_CHACHA20_POLY1305 "CKM_CHACHA20_POLY1305"
|
||||||
|
|
||||||
#define CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1)
|
#define CRYPTO_BITS2BYTES(n) ((n) == 0 ? 0 : (((n) - 1) >> 3) + 1)
|
||||||
#define CRYPTO_BYTES2BITS(n) ((n) << 3)
|
#define CRYPTO_BYTES2BITS(n) ((n) << 3)
|
||||||
|
|
|
@ -82,6 +82,7 @@ typedef uint32_t crypto_keysize_unit_t;
|
||||||
#define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC"
|
#define SUN_CKM_SHA512_HMAC "CKM_SHA512_HMAC"
|
||||||
#define SUN_CKM_AES_CCM "CKM_AES_CCM"
|
#define SUN_CKM_AES_CCM "CKM_AES_CCM"
|
||||||
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
|
#define SUN_CKM_AES_GCM "CKM_AES_GCM"
|
||||||
|
#define SUN_CKM_CHACHA20_POLY1305 "CKM_CHACHA20_POLY1305"
|
||||||
|
|
||||||
/* Data arguments of cryptographic operations */
|
/* Data arguments of cryptographic operations */
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
#ifndef _SYS_CRYPTO_ALGS_H
|
#ifndef _SYS_CRYPTO_ALGS_H
|
||||||
#define _SYS_CRYPTO_ALGS_H
|
#define _SYS_CRYPTO_ALGS_H
|
||||||
|
|
||||||
|
int chapoly_mod_init(void);
|
||||||
|
int chapoly_mod_fini(void);
|
||||||
|
|
||||||
int aes_mod_init(void);
|
int aes_mod_init(void);
|
||||||
int aes_mod_fini(void);
|
int aes_mod_fini(void);
|
||||||
|
|
||||||
|
|
|
@ -1906,6 +1906,7 @@ enum zio_encrypt {
|
||||||
ZIO_CRYPT_AES_128_GCM,
|
ZIO_CRYPT_AES_128_GCM,
|
||||||
ZIO_CRYPT_AES_192_GCM,
|
ZIO_CRYPT_AES_192_GCM,
|
||||||
ZIO_CRYPT_AES_256_GCM,
|
ZIO_CRYPT_AES_256_GCM,
|
||||||
|
ZIO_CRYPT_CHACHA20_POLY1305,
|
||||||
ZIO_CRYPT_FUNCTIONS
|
ZIO_CRYPT_FUNCTIONS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ struct zbookmark_phys;
|
||||||
typedef enum zio_crypt_type {
|
typedef enum zio_crypt_type {
|
||||||
ZC_TYPE_NONE = 0,
|
ZC_TYPE_NONE = 0,
|
||||||
ZC_TYPE_CCM,
|
ZC_TYPE_CCM,
|
||||||
ZC_TYPE_GCM
|
ZC_TYPE_GCM,
|
||||||
|
ZC_TYPE_CHACHA20_POLY1305,
|
||||||
} zio_crypt_type_t;
|
} zio_crypt_type_t;
|
||||||
|
|
||||||
/* table of supported crypto algorithms, modes and keylengths. */
|
/* table of supported crypto algorithms, modes and keylengths. */
|
||||||
|
@ -60,7 +61,7 @@ typedef struct zio_crypt_info {
|
||||||
#else
|
#else
|
||||||
crypto_mech_name_t ci_mechname;
|
crypto_mech_name_t ci_mechname;
|
||||||
#endif
|
#endif
|
||||||
/* cipher mode type (GCM, CCM) */
|
/* cipher mode type (GCM, CCM, ChaCha20-Poly1305) */
|
||||||
zio_crypt_type_t ci_crypt_type;
|
zio_crypt_type_t ci_crypt_type;
|
||||||
|
|
||||||
/* length of the encryption key */
|
/* length of the encryption key */
|
||||||
|
|
|
@ -83,6 +83,7 @@ typedef enum spa_feature {
|
||||||
SPA_FEATURE_REDACTION_LIST_SPILL,
|
SPA_FEATURE_REDACTION_LIST_SPILL,
|
||||||
SPA_FEATURE_RAIDZ_EXPANSION,
|
SPA_FEATURE_RAIDZ_EXPANSION,
|
||||||
SPA_FEATURE_FAST_DEDUP,
|
SPA_FEATURE_FAST_DEDUP,
|
||||||
|
SPA_FEATURE_CHACHA20_POLY1305,
|
||||||
SPA_FEATURES
|
SPA_FEATURES
|
||||||
} spa_feature_t;
|
} spa_feature_t;
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,10 @@ nodist_libicp_la_SOURCES = \
|
||||||
module/icp/algs/skein/skein_block.c \
|
module/icp/algs/skein/skein_block.c \
|
||||||
module/icp/algs/skein/skein_iv.c \
|
module/icp/algs/skein/skein_iv.c \
|
||||||
module/icp/illumos-crypto.c \
|
module/icp/illumos-crypto.c \
|
||||||
|
module/icp/monocypher.c \
|
||||||
module/icp/io/aes.c \
|
module/icp/io/aes.c \
|
||||||
module/icp/io/sha2_mod.c \
|
module/icp/io/sha2_mod.c \
|
||||||
|
module/icp/io/chapoly.c \
|
||||||
module/icp/core/kcf_sched.c \
|
module/icp/core/kcf_sched.c \
|
||||||
module/icp/core/kcf_prov_lib.c \
|
module/icp/core/kcf_prov_lib.c \
|
||||||
module/icp/core/kcf_callprov.c \
|
module/icp/core/kcf_callprov.c \
|
||||||
|
|
|
@ -625,7 +625,7 @@
|
||||||
<elf-symbol name='fletcher_4_superscalar_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='fletcher_4_superscalar_ops' size='128' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
<elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='libzfs_config_ops' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
<elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='sa_protocol_names' size='16' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
<elf-symbol name='spa_feature_table' size='2352' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='spa_feature_table' size='2408' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
<elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='zfeature_checks_disable' size='4' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
<elf-symbol name='zfs_deleg_perm_tab' size='512' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='zfs_deleg_perm_tab' size='512' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
<elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
<elf-symbol name='zfs_history_event_names' size='328' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
|
||||||
|
@ -6024,7 +6024,8 @@
|
||||||
<enumerator name='SPA_FEATURE_REDACTION_LIST_SPILL' value='39'/>
|
<enumerator name='SPA_FEATURE_REDACTION_LIST_SPILL' value='39'/>
|
||||||
<enumerator name='SPA_FEATURE_RAIDZ_EXPANSION' value='40'/>
|
<enumerator name='SPA_FEATURE_RAIDZ_EXPANSION' value='40'/>
|
||||||
<enumerator name='SPA_FEATURE_FAST_DEDUP' value='41'/>
|
<enumerator name='SPA_FEATURE_FAST_DEDUP' value='41'/>
|
||||||
<enumerator name='SPA_FEATURES' value='42'/>
|
<enumerator name='SPA_FEATURE_CHACHA20_POLY1305' value='42'/>
|
||||||
|
<enumerator name='SPA_FEATURES' value='43'/>
|
||||||
</enum-decl>
|
</enum-decl>
|
||||||
<typedef-decl name='spa_feature_t' type-id='33ecb627' id='d6618c78'/>
|
<typedef-decl name='spa_feature_t' type-id='33ecb627' id='d6618c78'/>
|
||||||
<qualified-type-def type-id='80f4b756' const='yes' id='b99c00c9'/>
|
<qualified-type-def type-id='80f4b756' const='yes' id='b99c00c9'/>
|
||||||
|
@ -9188,8 +9189,8 @@
|
||||||
</function-decl>
|
</function-decl>
|
||||||
</abi-instr>
|
</abi-instr>
|
||||||
<abi-instr address-size='64' path='module/zcommon/zfeature_common.c' language='LANG_C99'>
|
<abi-instr address-size='64' path='module/zcommon/zfeature_common.c' language='LANG_C99'>
|
||||||
<array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='18816' id='b937914f'>
|
<array-type-def dimensions='1' type-id='83f29ca2' size-in-bits='19264' id='bd39d632'>
|
||||||
<subrange length='42' type-id='7359adad' id='cb7c937f'/>
|
<subrange length='43' type-id='7359adad' id='8f7e73a2'/>
|
||||||
</array-type-def>
|
</array-type-def>
|
||||||
<enum-decl name='zfeature_flags' id='6db816a4'>
|
<enum-decl name='zfeature_flags' id='6db816a4'>
|
||||||
<underlying-type type-id='9cac1fee'/>
|
<underlying-type type-id='9cac1fee'/>
|
||||||
|
@ -9266,7 +9267,7 @@
|
||||||
<pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
|
<pointer-type-def type-id='611586a1' size-in-bits='64' id='2e243169'/>
|
||||||
<qualified-type-def type-id='eaa32e2f' const='yes' id='83be723c'/>
|
<qualified-type-def type-id='eaa32e2f' const='yes' id='83be723c'/>
|
||||||
<pointer-type-def type-id='83be723c' size-in-bits='64' id='7acd98a2'/>
|
<pointer-type-def type-id='83be723c' size-in-bits='64' id='7acd98a2'/>
|
||||||
<var-decl name='spa_feature_table' type-id='b937914f' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
|
<var-decl name='spa_feature_table' type-id='bd39d632' mangled-name='spa_feature_table' visibility='default' elf-symbol-id='spa_feature_table'/>
|
||||||
<var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
|
<var-decl name='zfeature_checks_disable' type-id='c19b74c3' mangled-name='zfeature_checks_disable' visibility='default' elf-symbol-id='zfeature_checks_disable'/>
|
||||||
<function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
|
<function-decl name='opendir' visibility='default' binding='global' size-in-bits='64'>
|
||||||
<parameter type-id='80f4b756'/>
|
<parameter type-id='80f4b756'/>
|
||||||
|
|
|
@ -37,8 +37,9 @@
|
||||||
.\" Copyright 2019 Joyent, Inc.
|
.\" Copyright 2019 Joyent, Inc.
|
||||||
.\" Copyright (c) 2019, Kjeld Schouten-Lebbing
|
.\" Copyright (c) 2019, Kjeld Schouten-Lebbing
|
||||||
.\" Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
|
.\" Copyright (c) 2022 Hewlett Packard Enterprise Development LP.
|
||||||
|
.\" Copyright (c) 2023, Rob Norris <robn@despairlabs.com>
|
||||||
.\"
|
.\"
|
||||||
.Dd June 29, 2024
|
.Dd July 26, 2024
|
||||||
.Dt ZFSPROPS 7
|
.Dt ZFSPROPS 7
|
||||||
.Os
|
.Os
|
||||||
.
|
.
|
||||||
|
@ -1077,7 +1078,7 @@ This property can also be referred to by its shortened column name,
|
||||||
.It Xo
|
.It Xo
|
||||||
.Sy encryption Ns = Ns Sy off Ns | Ns Sy on Ns | Ns Sy aes-128-ccm Ns | Ns
|
.Sy encryption Ns = Ns Sy off Ns | Ns Sy on Ns | Ns Sy aes-128-ccm Ns | Ns
|
||||||
.Sy aes-192-ccm Ns | Ns Sy aes-256-ccm Ns | Ns Sy aes-128-gcm Ns | Ns
|
.Sy aes-192-ccm Ns | Ns Sy aes-256-ccm Ns | Ns Sy aes-128-gcm Ns | Ns
|
||||||
.Sy aes-192-gcm Ns | Ns Sy aes-256-gcm
|
.Sy aes-192-gcm Ns | Ns Sy aes-256-gcm Ns | Ns Sy chacha20-poly1305
|
||||||
.Xc
|
.Xc
|
||||||
Controls the encryption cipher suite (block cipher, key length, and mode) used
|
Controls the encryption cipher suite (block cipher, key length, and mode) used
|
||||||
for this dataset.
|
for this dataset.
|
||||||
|
@ -1096,6 +1097,12 @@ selected, which is currently
|
||||||
In order to provide consistent data protection, encryption must be specified at
|
In order to provide consistent data protection, encryption must be specified at
|
||||||
dataset creation time and it cannot be changed afterwards.
|
dataset creation time and it cannot be changed afterwards.
|
||||||
.Pp
|
.Pp
|
||||||
|
On systems lacking hardware-accelerated AES (many non-x86 boards)
|
||||||
|
.Sy chacha20-poly1305
|
||||||
|
will usually offer better performance without compromising security.
|
||||||
|
On x86, or when datasets may be mounted on on older versions of ZFS, an AES
|
||||||
|
suite is the best choice.
|
||||||
|
.Pp
|
||||||
For more details and caveats about encryption see the
|
For more details and caveats about encryption see the
|
||||||
.Sx Encryption
|
.Sx Encryption
|
||||||
section of
|
section of
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
.\" Copyright (c) 2019, Allan Jude
|
.\" Copyright (c) 2019, Allan Jude
|
||||||
.\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
|
.\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org>
|
||||||
.\" Copyright (c) 2023, Klara Inc.
|
.\" Copyright (c) 2023, Klara Inc.
|
||||||
|
.\" Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||||
.\"
|
.\"
|
||||||
.Dd February 14, 2024
|
.Dd August 23, 2024
|
||||||
.Dt ZPOOL-FEATURES 7
|
.Dt ZPOOL-FEATURES 7
|
||||||
.Os
|
.Os
|
||||||
.
|
.
|
||||||
|
@ -411,6 +412,21 @@ returned to the
|
||||||
.Sy enabled
|
.Sy enabled
|
||||||
state when all bookmarks with these fields are destroyed.
|
state when all bookmarks with these fields are destroyed.
|
||||||
.
|
.
|
||||||
|
.feature org.openzfs chacha20_poly1305 no encryption extensible_dataset
|
||||||
|
This feature enables the use of the ChaCha20-Poly1305 cipher suite for encrypted
|
||||||
|
datasets.
|
||||||
|
On systems lacking hardware-accelerated AES (many non-x86 boards), this suite
|
||||||
|
will usually offer better performance than AES suites without compromising
|
||||||
|
security.
|
||||||
|
.Pp
|
||||||
|
This feature becomes
|
||||||
|
.Sy active
|
||||||
|
when an encrypted dataset is created with
|
||||||
|
.Nm encryption Ns = Ns Sy chacha20-poly1305
|
||||||
|
and will be returned to the
|
||||||
|
.Sy enabled
|
||||||
|
state when all datasets that use this feature are destroyed.
|
||||||
|
.
|
||||||
.feature org.openzfs device_rebuild yes
|
.feature org.openzfs device_rebuild yes
|
||||||
This feature enables the ability for the
|
This feature enables the ability for the
|
||||||
.Nm zpool Cm attach
|
.Nm zpool Cm attach
|
||||||
|
|
|
@ -120,8 +120,10 @@ ICP_OBJS := \
|
||||||
core/kcf_prov_tabs.o \
|
core/kcf_prov_tabs.o \
|
||||||
core/kcf_sched.o \
|
core/kcf_sched.o \
|
||||||
illumos-crypto.o \
|
illumos-crypto.o \
|
||||||
|
monocypher.o \
|
||||||
io/aes.o \
|
io/aes.o \
|
||||||
io/sha2_mod.o \
|
io/sha2_mod.o \
|
||||||
|
io/chapoly.o \
|
||||||
spi/kcf_spi.o
|
spi/kcf_spi.o
|
||||||
|
|
||||||
ICP_OBJS_X86_64 := \
|
ICP_OBJS_X86_64 := \
|
||||||
|
|
|
@ -109,6 +109,7 @@ icp_fini(void)
|
||||||
{
|
{
|
||||||
sha2_mod_fini();
|
sha2_mod_fini();
|
||||||
aes_mod_fini();
|
aes_mod_fini();
|
||||||
|
chapoly_mod_fini();
|
||||||
kcf_sched_destroy();
|
kcf_sched_destroy();
|
||||||
kcf_prov_tab_destroy();
|
kcf_prov_tab_destroy();
|
||||||
kcf_destroy_mech_tabs();
|
kcf_destroy_mech_tabs();
|
||||||
|
@ -131,6 +132,7 @@ icp_init(void)
|
||||||
kcf_sched_init();
|
kcf_sched_init();
|
||||||
|
|
||||||
/* initialize algorithms */
|
/* initialize algorithms */
|
||||||
|
chapoly_mod_init();
|
||||||
aes_mod_init();
|
aes_mod_init();
|
||||||
sha2_mod_init();
|
sha2_mod_init();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017-2019, Loup Vaillant
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "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 COPYRIGHT
|
||||||
|
* HOLDER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Monocypher 4.0.2 (Poly1305, Chacha20, and supporting utilities)
|
||||||
|
* adapted for OpenZFS by Rob Norris <robn@despairlabs.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: this follows the Monocypher style rather than the OpenZFS style to
|
||||||
|
* keep the diff to the bare minimum. This is important for making it easy to
|
||||||
|
* compare the two and confirm that they are in fact the same. The diff should
|
||||||
|
* be almost entirely in deleted lines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MONOCYPHER_H
|
||||||
|
#define MONOCYPHER_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
||||||
|
// Constant time comparisons
|
||||||
|
// -------------------------
|
||||||
|
|
||||||
|
// Return 0 if a and b are equal, -1 otherwise
|
||||||
|
int crypto_verify16(const uint8_t a[16], const uint8_t b[16]);
|
||||||
|
|
||||||
|
// Erase sensitive data
|
||||||
|
// --------------------
|
||||||
|
void crypto_wipe(void *secret, size_t size);
|
||||||
|
|
||||||
|
|
||||||
|
// Chacha20
|
||||||
|
// --------
|
||||||
|
|
||||||
|
// Unauthenticated stream cipher.
|
||||||
|
// Don't forget to add authentication.
|
||||||
|
uint32_t crypto_chacha20_ietf(uint8_t *cipher_text,
|
||||||
|
const uint8_t *plain_text,
|
||||||
|
size_t text_size,
|
||||||
|
const uint8_t key[32],
|
||||||
|
const uint8_t nonce[12],
|
||||||
|
uint32_t ctr);
|
||||||
|
|
||||||
|
|
||||||
|
// Poly 1305
|
||||||
|
// ---------
|
||||||
|
|
||||||
|
// This is a *one time* authenticator.
|
||||||
|
// Disclosing the mac reveals the key.
|
||||||
|
|
||||||
|
// Incremental interface
|
||||||
|
typedef struct {
|
||||||
|
// Do not rely on the size or contents of this type,
|
||||||
|
// for they may change without notice.
|
||||||
|
uint8_t c[16]; // chunk of the message
|
||||||
|
size_t c_idx; // How many bytes are there in the chunk.
|
||||||
|
uint32_t r [4]; // constant multiplier (from the secret key)
|
||||||
|
uint32_t pad[4]; // random number added at the end (from the secret key)
|
||||||
|
uint32_t h [5]; // accumulated hash
|
||||||
|
} crypto_poly1305_ctx;
|
||||||
|
|
||||||
|
void crypto_poly1305_init (crypto_poly1305_ctx *ctx, const uint8_t key[32]);
|
||||||
|
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
|
||||||
|
const uint8_t *message, size_t message_size);
|
||||||
|
void crypto_poly1305_final (crypto_poly1305_ctx *ctx, uint8_t mac[16]);
|
||||||
|
|
||||||
|
#endif /* MONOCYPHER_H */
|
|
@ -0,0 +1,492 @@
|
||||||
|
/*
|
||||||
|
* 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 https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ChaCha20-Poly1305 (RFC 8439) provider
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/zfs_context.h>
|
||||||
|
#include <sys/crypto/common.h>
|
||||||
|
#include <sys/crypto/impl.h>
|
||||||
|
#include <sys/crypto/icp.h>
|
||||||
|
#include <monocypher.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* convenient constants for readability. you can't change these; they're fixed
|
||||||
|
* to match defines and buffer sizes elsewhere.
|
||||||
|
*/
|
||||||
|
#define CP_BLOCK_SIZE (64)
|
||||||
|
#define CP_KEY_SIZE (32)
|
||||||
|
#define CP_MAC_SIZE (16)
|
||||||
|
#define CP_IV_SIZE (12)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* pointers back to the callers key and iv */
|
||||||
|
const uint8_t *key;
|
||||||
|
const uint8_t *iv;
|
||||||
|
|
||||||
|
/* poly1305 mac state */
|
||||||
|
crypto_poly1305_ctx poly;
|
||||||
|
|
||||||
|
/* counter value for next block */
|
||||||
|
uint32_t counter;
|
||||||
|
|
||||||
|
/* cipher output buffer and working space */
|
||||||
|
uint8_t temp[CP_BLOCK_SIZE];
|
||||||
|
|
||||||
|
/* bytes waiting for a complete block before they can be encrypted */
|
||||||
|
uint8_t pending[CP_BLOCK_SIZE];
|
||||||
|
size_t npending;
|
||||||
|
|
||||||
|
/* decrypt; data bytes remaining */
|
||||||
|
size_t datalen;
|
||||||
|
|
||||||
|
/* decrypt; pointer to pre-auth holding buffer */
|
||||||
|
/* (extra allocation past end of chapoly_ctx) */
|
||||||
|
uint8_t *unauthp;
|
||||||
|
} chapoly_ctx;
|
||||||
|
|
||||||
|
/* a bunch of zeroes for padding the poly1305 sequence */
|
||||||
|
static const uint8_t zero_pad[16] = {0};
|
||||||
|
|
||||||
|
static void
|
||||||
|
chapoly_init(chapoly_ctx *cpctx, const crypto_key_t *key, const uint8_t *iv)
|
||||||
|
{
|
||||||
|
cpctx->key = (const uint8_t *) key->ck_data;
|
||||||
|
cpctx->iv = (const uint8_t *) iv;
|
||||||
|
|
||||||
|
/* create the poly1305 key from the chacha block 0 keystream */
|
||||||
|
cpctx->counter = crypto_chacha20_ietf(
|
||||||
|
cpctx->temp, NULL, CP_KEY_SIZE,
|
||||||
|
cpctx->key, cpctx->iv, 0);
|
||||||
|
|
||||||
|
/* and intialise the context */
|
||||||
|
crypto_poly1305_init(&cpctx->poly, cpctx->temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapoly_encrypt_contiguous_blocks(
|
||||||
|
void *_cpctx, char *data, size_t length, crypto_data_t *out)
|
||||||
|
{
|
||||||
|
chapoly_ctx *cpctx = (chapoly_ctx *) _cpctx;
|
||||||
|
|
||||||
|
uint8_t *datap = (uint8_t *)data;
|
||||||
|
size_t nremaining = length;
|
||||||
|
|
||||||
|
size_t need;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/* if there's anything in the pending buffer, try to empty it */
|
||||||
|
if (cpctx->npending > 0) {
|
||||||
|
/* take no more than we need to fill the temp buffer */
|
||||||
|
/* (one block), otherwise whatever is left */
|
||||||
|
need = nremaining > CP_BLOCK_SIZE - cpctx->npending ?
|
||||||
|
CP_BLOCK_SIZE - cpctx->npending : nremaining;
|
||||||
|
|
||||||
|
/* try fill that buffer */
|
||||||
|
memcpy(cpctx->pending + cpctx->npending, datap, need);
|
||||||
|
datap += need;
|
||||||
|
nremaining -= need;
|
||||||
|
cpctx->npending += need;
|
||||||
|
|
||||||
|
/* if we consumed everything and there's still not a full */
|
||||||
|
/* block then we've done all we can for now */
|
||||||
|
if (cpctx->npending < CP_BLOCK_SIZE) {
|
||||||
|
ASSERT0(nremaining);
|
||||||
|
return (CRYPTO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* full block pending, process it */
|
||||||
|
cpctx->counter = crypto_chacha20_ietf(
|
||||||
|
cpctx->temp, cpctx->pending, CP_BLOCK_SIZE,
|
||||||
|
cpctx->key, cpctx->iv, cpctx->counter);
|
||||||
|
|
||||||
|
/* copy it to the output buffers */
|
||||||
|
rv = crypto_put_output_data(cpctx->temp, out, CP_BLOCK_SIZE);
|
||||||
|
if (rv != CRYPTO_SUCCESS)
|
||||||
|
return (rv);
|
||||||
|
|
||||||
|
/* update offset */
|
||||||
|
out->cd_offset += CP_BLOCK_SIZE;
|
||||||
|
|
||||||
|
/* update the mac */
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, cpctx->temp, CP_BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* pending buffer now drained */
|
||||||
|
cpctx->npending = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* process as many complete blocks as we can */
|
||||||
|
while (nremaining >= CP_BLOCK_SIZE) {
|
||||||
|
|
||||||
|
/* process one block */
|
||||||
|
cpctx->counter = crypto_chacha20_ietf(
|
||||||
|
cpctx->temp, datap, CP_BLOCK_SIZE,
|
||||||
|
cpctx->key, cpctx->iv, cpctx->counter);
|
||||||
|
|
||||||
|
/* copy it to the output buffers */
|
||||||
|
rv = crypto_put_output_data(cpctx->temp, out, CP_BLOCK_SIZE);
|
||||||
|
if (rv != CRYPTO_SUCCESS)
|
||||||
|
return (rv);
|
||||||
|
|
||||||
|
/* update offset */
|
||||||
|
out->cd_offset += CP_BLOCK_SIZE;
|
||||||
|
|
||||||
|
/* update the mac */
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, cpctx->temp, CP_BLOCK_SIZE);
|
||||||
|
|
||||||
|
/* done a block */
|
||||||
|
datap += CP_BLOCK_SIZE;
|
||||||
|
nremaining -= CP_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer anything left over for next time */
|
||||||
|
if (nremaining > 0) {
|
||||||
|
ASSERT3U(nremaining, <, CP_BLOCK_SIZE);
|
||||||
|
|
||||||
|
memcpy(cpctx->pending, datap, nremaining);
|
||||||
|
cpctx->npending = nremaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CRYPTO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapoly_encrypt_atomic(crypto_mechanism_t *mechanism,
|
||||||
|
crypto_key_t *key, crypto_data_t *plaintext, crypto_data_t *ciphertext,
|
||||||
|
crypto_spi_ctx_template_t __attribute__((unused)) template)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/* We don't actually do GCM here, its just the default parameter */
|
||||||
|
/* option in zio_do_crypt_uio and has everything we need, so its */
|
||||||
|
/* easier to just take that instead of making our own thing. */
|
||||||
|
const CK_AES_GCM_PARAMS *gcmp =
|
||||||
|
(CK_AES_GCM_PARAMS *) mechanism->cm_param;
|
||||||
|
const uint8_t *iv = gcmp->pIv;
|
||||||
|
|
||||||
|
/* chacha20 invariants */
|
||||||
|
ASSERT3U(CRYPTO_BITS2BYTES(key->ck_length), ==, CP_KEY_SIZE);
|
||||||
|
ASSERT3U(gcmp->ulIvLen, ==, CP_IV_SIZE);
|
||||||
|
|
||||||
|
chapoly_ctx *cpctx = kmem_alloc(sizeof (chapoly_ctx), KM_SLEEP);
|
||||||
|
if (cpctx == NULL)
|
||||||
|
return (CRYPTO_HOST_MEMORY);
|
||||||
|
memset(cpctx, 0, sizeof (chapoly_ctx));
|
||||||
|
|
||||||
|
chapoly_init(cpctx, key, iv);
|
||||||
|
|
||||||
|
/* mix additional data into the mac */
|
||||||
|
crypto_poly1305_update(&cpctx->poly, gcmp->pAAD, gcmp->ulAADLen);
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, zero_pad, (~(gcmp->ulAADLen) + 1) & 0xf);
|
||||||
|
|
||||||
|
off_t saved_offset = ciphertext->cd_offset;
|
||||||
|
size_t saved_length = ciphertext->cd_length;
|
||||||
|
|
||||||
|
switch (plaintext->cd_format) {
|
||||||
|
case CRYPTO_DATA_RAW:
|
||||||
|
rv = crypto_update_iov(
|
||||||
|
cpctx, plaintext, ciphertext,
|
||||||
|
chapoly_encrypt_contiguous_blocks);
|
||||||
|
break;
|
||||||
|
case CRYPTO_DATA_UIO:
|
||||||
|
rv = crypto_update_uio(
|
||||||
|
cpctx, plaintext, ciphertext,
|
||||||
|
chapoly_encrypt_contiguous_blocks);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rv = CRYPTO_ARGUMENTS_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv == CRYPTO_SUCCESS) {
|
||||||
|
/* process and emit anything in the pending buffer */
|
||||||
|
if (cpctx->npending > 0) {
|
||||||
|
crypto_chacha20_ietf(
|
||||||
|
cpctx->temp, cpctx->pending, cpctx->npending,
|
||||||
|
cpctx->key, cpctx->iv, cpctx->counter);
|
||||||
|
|
||||||
|
/* write the last bit of the ciphertext */
|
||||||
|
rv = crypto_put_output_data(
|
||||||
|
cpctx->temp, ciphertext, cpctx->npending);
|
||||||
|
if (rv != CRYPTO_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
ciphertext->cd_offset += cpctx->npending;
|
||||||
|
|
||||||
|
/* and update the mac */
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, cpctx->temp, cpctx->npending);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* finish the mac */
|
||||||
|
uint64_t sizes[2] = {
|
||||||
|
LE_64(gcmp->ulAADLen), LE_64(plaintext->cd_length)
|
||||||
|
};
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, zero_pad,
|
||||||
|
(~(plaintext->cd_length) + 1) & 0xf);
|
||||||
|
crypto_poly1305_update(&cpctx->poly, (uint8_t *)sizes, 16);
|
||||||
|
crypto_poly1305_final(&cpctx->poly, cpctx->temp);
|
||||||
|
|
||||||
|
/* and write it out */
|
||||||
|
rv = crypto_put_output_data(
|
||||||
|
cpctx->temp, ciphertext, CP_MAC_SIZE);
|
||||||
|
if (rv != CRYPTO_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
ciphertext->cd_offset += CP_MAC_SIZE;
|
||||||
|
|
||||||
|
ciphertext->cd_length = ciphertext->cd_offset - saved_offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ciphertext->cd_length = saved_length;
|
||||||
|
ciphertext->cd_offset = saved_offset;
|
||||||
|
|
||||||
|
out:
|
||||||
|
crypto_wipe(cpctx, sizeof (chapoly_ctx));
|
||||||
|
kmem_free(cpctx, sizeof (chapoly_ctx));
|
||||||
|
return (rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapoly_decrypt_contiguous_blocks(
|
||||||
|
void *_cpctx, char *data, size_t length,
|
||||||
|
crypto_data_t __attribute__((unused)) *out)
|
||||||
|
{
|
||||||
|
chapoly_ctx *cpctx = (chapoly_ctx *) _cpctx;
|
||||||
|
size_t need;
|
||||||
|
|
||||||
|
if (cpctx->datalen > 0) {
|
||||||
|
/* these are data bytes */
|
||||||
|
|
||||||
|
/* don't take more than we need; the mac might be on the end */
|
||||||
|
need = length > cpctx->datalen ? cpctx->datalen : length;
|
||||||
|
|
||||||
|
/* copy the ciphertext to a buffer we made for it */
|
||||||
|
memcpy(cpctx->unauthp, data, need);
|
||||||
|
cpctx->unauthp += need;
|
||||||
|
cpctx->datalen -= need;
|
||||||
|
|
||||||
|
/* update the mac */
|
||||||
|
crypto_poly1305_update(&cpctx->poly, (uint8_t *)data, need);
|
||||||
|
|
||||||
|
/* update how much we're still expecting */
|
||||||
|
length -= need;
|
||||||
|
data += need;
|
||||||
|
|
||||||
|
/* if we consumed the whole buffer, we're done */
|
||||||
|
if (length == 0)
|
||||||
|
return (CRYPTO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* these are mac bytes */
|
||||||
|
|
||||||
|
/* assume that the mac always arrives in a single block, not split */
|
||||||
|
/* over blocks. this is true for OpenZFS at least */
|
||||||
|
if (length != CP_MAC_SIZE)
|
||||||
|
return (CRYPTO_DATA_LEN_RANGE);
|
||||||
|
|
||||||
|
/* leave the incoming mac in the temp buffer */
|
||||||
|
memcpy(cpctx->temp, data, 16);
|
||||||
|
|
||||||
|
return (CRYPTO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapoly_decrypt_finish(
|
||||||
|
chapoly_ctx *cpctx, size_t length, crypto_data_t *out)
|
||||||
|
{
|
||||||
|
uint8_t *datap = (uint8_t *)cpctx + sizeof (chapoly_ctx);
|
||||||
|
size_t nremaining = length;
|
||||||
|
|
||||||
|
size_t need;
|
||||||
|
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
while (nremaining > 0) {
|
||||||
|
/* take no more than we need to fill the temp buffer */
|
||||||
|
/* (one block), otherwise whatever is left */
|
||||||
|
need = nremaining > CP_BLOCK_SIZE ? CP_BLOCK_SIZE : nremaining;
|
||||||
|
|
||||||
|
/* process a block */
|
||||||
|
cpctx->counter = crypto_chacha20_ietf(
|
||||||
|
cpctx->temp, datap, need,
|
||||||
|
cpctx->key, cpctx->iv, cpctx->counter);
|
||||||
|
|
||||||
|
/* copy it into the output buffers */
|
||||||
|
rv = crypto_put_output_data(cpctx->temp, out, need);
|
||||||
|
if (rv != CRYPTO_SUCCESS)
|
||||||
|
return (rv);
|
||||||
|
|
||||||
|
/* update offset */
|
||||||
|
out->cd_offset += need;
|
||||||
|
|
||||||
|
/* update remaining */
|
||||||
|
nremaining -= need;
|
||||||
|
datap += need;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CRYPTO_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
chapoly_decrypt_atomic(crypto_mechanism_t *mechanism,
|
||||||
|
crypto_key_t *key, crypto_data_t *ciphertext, crypto_data_t *plaintext,
|
||||||
|
crypto_spi_ctx_template_t __attribute__((unused)) template)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/* We don't actually do GCM here, its just the default parameter */
|
||||||
|
/* option in zio_do_crypt_uio and has everything we need, so its */
|
||||||
|
/* easier to just take that instead of making our own thing. */
|
||||||
|
const CK_AES_GCM_PARAMS *gcmp =
|
||||||
|
(CK_AES_GCM_PARAMS*) mechanism->cm_param;
|
||||||
|
const uint8_t *iv = gcmp->pIv;
|
||||||
|
|
||||||
|
/* chacha20 invariants */
|
||||||
|
ASSERT3U(CRYPTO_BITS2BYTES(key->ck_length), ==, CP_KEY_SIZE);
|
||||||
|
ASSERT3U(gcmp->ulIvLen, ==, CP_IV_SIZE);
|
||||||
|
ASSERT3U(CRYPTO_BITS2BYTES(gcmp->ulTagBits), ==, CP_MAC_SIZE);
|
||||||
|
|
||||||
|
size_t datalen = ciphertext->cd_length - CP_MAC_SIZE;
|
||||||
|
|
||||||
|
chapoly_ctx *cpctx = vmem_alloc(
|
||||||
|
sizeof (chapoly_ctx) + datalen, KM_SLEEP);
|
||||||
|
if (cpctx == NULL)
|
||||||
|
return (CRYPTO_HOST_MEMORY);
|
||||||
|
memset(cpctx, 0, sizeof (chapoly_ctx) + datalen);
|
||||||
|
|
||||||
|
chapoly_init(cpctx, key, iv);
|
||||||
|
|
||||||
|
/* mix additional data into the mac */
|
||||||
|
crypto_poly1305_update(&cpctx->poly, gcmp->pAAD, gcmp->ulAADLen);
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, zero_pad, (~(gcmp->ulAADLen) + 1) & 0xf);
|
||||||
|
|
||||||
|
cpctx->datalen = datalen;
|
||||||
|
cpctx->unauthp = (uint8_t *)cpctx + sizeof (chapoly_ctx);
|
||||||
|
|
||||||
|
off_t saved_offset = plaintext->cd_offset;
|
||||||
|
size_t saved_length = plaintext->cd_length;
|
||||||
|
|
||||||
|
switch (ciphertext->cd_format) {
|
||||||
|
case CRYPTO_DATA_RAW:
|
||||||
|
rv = crypto_update_iov(
|
||||||
|
cpctx, ciphertext, plaintext,
|
||||||
|
chapoly_decrypt_contiguous_blocks);
|
||||||
|
break;
|
||||||
|
case CRYPTO_DATA_UIO:
|
||||||
|
rv = crypto_update_uio(
|
||||||
|
cpctx, ciphertext, plaintext,
|
||||||
|
chapoly_decrypt_contiguous_blocks);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rv = CRYPTO_ARGUMENTS_BAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv == CRYPTO_SUCCESS) {
|
||||||
|
/* finish the mac. the incoming mac is at that start of the */
|
||||||
|
/* temp buffer, so we'll write the computed one after it */
|
||||||
|
uint64_t sizes[2] = {
|
||||||
|
LE_64(gcmp->ulAADLen), LE_64(datalen)
|
||||||
|
};
|
||||||
|
crypto_poly1305_update(
|
||||||
|
&cpctx->poly, zero_pad, (~(datalen) + 1) & 0xf);
|
||||||
|
crypto_poly1305_update(&cpctx->poly, (uint8_t *)sizes, 16);
|
||||||
|
crypto_poly1305_final(&cpctx->poly, cpctx->temp + CP_MAC_SIZE);
|
||||||
|
|
||||||
|
/* now compare them */
|
||||||
|
if (crypto_verify16(
|
||||||
|
cpctx->temp, cpctx->temp + CP_MAC_SIZE) != 0)
|
||||||
|
rv = CRYPTO_INVALID_MAC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mac checks out; we're ready to decrypt */
|
||||||
|
if (rv == CRYPTO_SUCCESS)
|
||||||
|
/* mac has been checked, now we can decrypt */
|
||||||
|
rv = chapoly_decrypt_finish(cpctx, datalen, plaintext);
|
||||||
|
|
||||||
|
if (rv == CRYPTO_SUCCESS)
|
||||||
|
plaintext->cd_length = plaintext->cd_offset - saved_offset;
|
||||||
|
else
|
||||||
|
plaintext->cd_length = saved_length;
|
||||||
|
plaintext->cd_offset = saved_offset;
|
||||||
|
|
||||||
|
crypto_wipe(cpctx, sizeof (chapoly_ctx) + datalen);
|
||||||
|
vmem_free(cpctx, sizeof (chapoly_ctx) + datalen);
|
||||||
|
return (rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const crypto_mech_info_t chapoly_mech_info_tab[] = {
|
||||||
|
{SUN_CKM_CHACHA20_POLY1305, 0,
|
||||||
|
CRYPTO_FG_ENCRYPT_ATOMIC | CRYPTO_FG_DECRYPT_ATOMIC },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const crypto_cipher_ops_t chapoly_cipher_ops = {
|
||||||
|
.encrypt_atomic = chapoly_encrypt_atomic,
|
||||||
|
.decrypt_atomic = chapoly_decrypt_atomic
|
||||||
|
};
|
||||||
|
|
||||||
|
static const crypto_ops_t chapoly_crypto_ops = {
|
||||||
|
.co_cipher_ops = &chapoly_cipher_ops,
|
||||||
|
.co_mac_ops = NULL,
|
||||||
|
.co_ctx_ops = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const crypto_provider_info_t chapoly_prov_info = {
|
||||||
|
"Chacha20-Poly1305 Software Provider",
|
||||||
|
&chapoly_crypto_ops,
|
||||||
|
sizeof (chapoly_mech_info_tab) / sizeof (crypto_mech_info_t),
|
||||||
|
chapoly_mech_info_tab
|
||||||
|
};
|
||||||
|
|
||||||
|
static crypto_kcf_provider_handle_t chapoly_prov_handle = 0;
|
||||||
|
|
||||||
|
int
|
||||||
|
chapoly_mod_init(void)
|
||||||
|
{
|
||||||
|
/* Register with KCF. If the registration fails, remove the module. */
|
||||||
|
if (crypto_register_provider(&chapoly_prov_info, &chapoly_prov_handle))
|
||||||
|
return (EACCES);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
chapoly_mod_fini(void)
|
||||||
|
{
|
||||||
|
/* Unregister from KCF if module is registered */
|
||||||
|
if (chapoly_prov_handle != 0) {
|
||||||
|
if (crypto_unregister_provider(chapoly_prov_handle))
|
||||||
|
return (EBUSY);
|
||||||
|
|
||||||
|
chapoly_prov_handle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
|
@ -0,0 +1,377 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017-2019, Loup Vaillant
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "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 COPYRIGHT
|
||||||
|
* HOLDER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Monocypher 4.0.2 (Poly1305, Chacha20, and supporting utilities)
|
||||||
|
* adapted for OpenZFS by Rob Norris <robn@despairlabs.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: this follows the Monocypher style rather than the OpenZFS style to
|
||||||
|
* keep the diff to the bare minimum. This is important for making it easy to
|
||||||
|
* compare the two and confirm that they are in fact the same. The diff should
|
||||||
|
* be almost entirely in deleted lines.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "monocypher.h"
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
/// Utilities ///
|
||||||
|
/////////////////
|
||||||
|
#define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++)
|
||||||
|
#define FOR(i, start, end) FOR_T(size_t, i, start, end)
|
||||||
|
#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
|
||||||
|
#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
|
||||||
|
#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OpenZFS: userspace libicp build on Linux will already have MIN/MAX defined
|
||||||
|
* through sys/types.h -> sys/param.h. Undefine them and let Monocypher use its
|
||||||
|
* own, in case they change in some important way in the future.
|
||||||
|
*/
|
||||||
|
#undef MIN
|
||||||
|
#undef MAX
|
||||||
|
#define MIN(a, b) ((a) <= (b) ? (a) : (b))
|
||||||
|
#define MAX(a, b) ((a) >= (b) ? (a) : (b))
|
||||||
|
|
||||||
|
typedef int8_t i8;
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef int16_t i16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef int32_t i32;
|
||||||
|
typedef int64_t i64;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
static const u8 zero[128] = {0};
|
||||||
|
|
||||||
|
// returns the smallest positive integer y such that
|
||||||
|
// (x + y) % pow_2 == 0
|
||||||
|
// Basically, y is the "gap" missing to align x.
|
||||||
|
// Only works when pow_2 is a power of 2.
|
||||||
|
// Note: we use ~x+1 instead of -x to avoid compiler warnings
|
||||||
|
static size_t gap(size_t x, size_t pow_2)
|
||||||
|
{
|
||||||
|
return (~x + 1) & (pow_2 - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 load32_le(const u8 s[4])
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((u32)s[0] << 0) |
|
||||||
|
((u32)s[1] << 8) |
|
||||||
|
((u32)s[2] << 16) |
|
||||||
|
((u32)s[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 load64_le(const u8 s[8])
|
||||||
|
{
|
||||||
|
return load32_le(s) | ((u64)load32_le(s+4) << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void store32_le(u8 out[4], u32 in)
|
||||||
|
{
|
||||||
|
out[0] = in & 0xff;
|
||||||
|
out[1] = (in >> 8) & 0xff;
|
||||||
|
out[2] = (in >> 16) & 0xff;
|
||||||
|
out[3] = (in >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load32_le_buf (u32 *dst, const u8 *src, size_t size) {
|
||||||
|
FOR(i, 0, size) { dst[i] = load32_le(src + i*4); }
|
||||||
|
}
|
||||||
|
|
||||||
|
static u32 rotl32(u32 x, u32 n) { return (x << n) ^ (x >> (32 - n)); }
|
||||||
|
|
||||||
|
static int neq0(u64 diff)
|
||||||
|
{
|
||||||
|
// constant time comparison to zero
|
||||||
|
// return diff != 0 ? -1 : 0
|
||||||
|
u64 half = (diff >> 32) | ((u32)diff);
|
||||||
|
return (1 & ((half - 1) >> 32)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 x16(const u8 a[16], const u8 b[16])
|
||||||
|
{
|
||||||
|
return (load64_le(a + 0) ^ load64_le(b + 0))
|
||||||
|
| (load64_le(a + 8) ^ load64_le(b + 8));
|
||||||
|
}
|
||||||
|
int crypto_verify16(const u8 a[16], const u8 b[16]){ return neq0(x16(a, b)); }
|
||||||
|
|
||||||
|
void crypto_wipe(void *secret, size_t size)
|
||||||
|
{
|
||||||
|
volatile u8 *v_secret = (u8*)secret;
|
||||||
|
ZERO(v_secret, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
/// Chacha 20 ///
|
||||||
|
/////////////////
|
||||||
|
#define QUARTERROUND(a, b, c, d) \
|
||||||
|
a += b; d = rotl32(d ^ a, 16); \
|
||||||
|
c += d; b = rotl32(b ^ c, 12); \
|
||||||
|
a += b; d = rotl32(d ^ a, 8); \
|
||||||
|
c += d; b = rotl32(b ^ c, 7)
|
||||||
|
|
||||||
|
static void chacha20_rounds(u32 out[16], const u32 in[16])
|
||||||
|
{
|
||||||
|
// The temporary variables make Chacha20 10% faster.
|
||||||
|
u32 t0 = in[ 0]; u32 t1 = in[ 1]; u32 t2 = in[ 2]; u32 t3 = in[ 3];
|
||||||
|
u32 t4 = in[ 4]; u32 t5 = in[ 5]; u32 t6 = in[ 6]; u32 t7 = in[ 7];
|
||||||
|
u32 t8 = in[ 8]; u32 t9 = in[ 9]; u32 t10 = in[10]; u32 t11 = in[11];
|
||||||
|
u32 t12 = in[12]; u32 t13 = in[13]; u32 t14 = in[14]; u32 t15 = in[15];
|
||||||
|
|
||||||
|
FOR (i, 0, 10) { // 20 rounds, 2 rounds per loop.
|
||||||
|
QUARTERROUND(t0, t4, t8 , t12); // column 0
|
||||||
|
QUARTERROUND(t1, t5, t9 , t13); // column 1
|
||||||
|
QUARTERROUND(t2, t6, t10, t14); // column 2
|
||||||
|
QUARTERROUND(t3, t7, t11, t15); // column 3
|
||||||
|
QUARTERROUND(t0, t5, t10, t15); // diagonal 0
|
||||||
|
QUARTERROUND(t1, t6, t11, t12); // diagonal 1
|
||||||
|
QUARTERROUND(t2, t7, t8 , t13); // diagonal 2
|
||||||
|
QUARTERROUND(t3, t4, t9 , t14); // diagonal 3
|
||||||
|
}
|
||||||
|
out[ 0] = t0; out[ 1] = t1; out[ 2] = t2; out[ 3] = t3;
|
||||||
|
out[ 4] = t4; out[ 5] = t5; out[ 6] = t6; out[ 7] = t7;
|
||||||
|
out[ 8] = t8; out[ 9] = t9; out[10] = t10; out[11] = t11;
|
||||||
|
out[12] = t12; out[13] = t13; out[14] = t14; out[15] = t15;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const u8 *chacha20_constant = (const u8*)"expand 32-byte k"; // 16 bytes
|
||||||
|
|
||||||
|
static u64 crypto_chacha20_djb(u8 *cipher_text, const u8 *plain_text,
|
||||||
|
size_t text_size, const u8 key[32], const u8 nonce[8],
|
||||||
|
u64 ctr)
|
||||||
|
{
|
||||||
|
u32 input[16];
|
||||||
|
load32_le_buf(input , chacha20_constant, 4);
|
||||||
|
load32_le_buf(input + 4, key , 8);
|
||||||
|
load32_le_buf(input + 14, nonce , 2);
|
||||||
|
input[12] = (u32) ctr;
|
||||||
|
input[13] = (u32)(ctr >> 32);
|
||||||
|
|
||||||
|
// Whole blocks
|
||||||
|
u32 pool[16];
|
||||||
|
size_t nb_blocks = text_size >> 6;
|
||||||
|
FOR (i, 0, nb_blocks) {
|
||||||
|
chacha20_rounds(pool, input);
|
||||||
|
if (plain_text != 0) {
|
||||||
|
FOR (j, 0, 16) {
|
||||||
|
u32 p = pool[j] + input[j];
|
||||||
|
store32_le(cipher_text, p ^ load32_le(plain_text));
|
||||||
|
cipher_text += 4;
|
||||||
|
plain_text += 4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FOR (j, 0, 16) {
|
||||||
|
u32 p = pool[j] + input[j];
|
||||||
|
store32_le(cipher_text, p);
|
||||||
|
cipher_text += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input[12]++;
|
||||||
|
if (input[12] == 0) {
|
||||||
|
input[13]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text_size &= 63;
|
||||||
|
|
||||||
|
// Last (incomplete) block
|
||||||
|
if (text_size > 0) {
|
||||||
|
if (plain_text == 0) {
|
||||||
|
plain_text = zero;
|
||||||
|
}
|
||||||
|
chacha20_rounds(pool, input);
|
||||||
|
u8 tmp[64];
|
||||||
|
FOR (i, 0, 16) {
|
||||||
|
store32_le(tmp + i*4, pool[i] + input[i]);
|
||||||
|
}
|
||||||
|
FOR (i, 0, text_size) {
|
||||||
|
cipher_text[i] = tmp[i] ^ plain_text[i];
|
||||||
|
}
|
||||||
|
WIPE_BUFFER(tmp);
|
||||||
|
}
|
||||||
|
ctr = input[12] + ((u64)input[13] << 32) + (text_size > 0);
|
||||||
|
|
||||||
|
WIPE_BUFFER(pool);
|
||||||
|
WIPE_BUFFER(input);
|
||||||
|
return ctr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 crypto_chacha20_ietf(u8 *cipher_text, const u8 *plain_text,
|
||||||
|
size_t text_size,
|
||||||
|
const u8 key[32], const u8 nonce[12], u32 ctr)
|
||||||
|
{
|
||||||
|
u64 big_ctr = ctr + ((u64)load32_le(nonce) << 32);
|
||||||
|
return (u32)crypto_chacha20_djb(cipher_text, plain_text, text_size,
|
||||||
|
key, nonce + 4, big_ctr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
/// Poly 1305 ///
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
// h = (h + c) * r
|
||||||
|
// preconditions:
|
||||||
|
// ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
|
||||||
|
// ctx->r <= 0ffffffc_0ffffffc_0ffffffc_0fffffff
|
||||||
|
// end <= 1
|
||||||
|
// Postcondition:
|
||||||
|
// ctx->h <= 4_ffffffff_ffffffff_ffffffff_ffffffff
|
||||||
|
static void poly_blocks(crypto_poly1305_ctx *ctx, const u8 *in,
|
||||||
|
size_t nb_blocks, unsigned end)
|
||||||
|
{
|
||||||
|
// Local all the things!
|
||||||
|
const u32 r0 = ctx->r[0];
|
||||||
|
const u32 r1 = ctx->r[1];
|
||||||
|
const u32 r2 = ctx->r[2];
|
||||||
|
const u32 r3 = ctx->r[3];
|
||||||
|
const u32 rr0 = (r0 >> 2) * 5; // lose 2 bits...
|
||||||
|
const u32 rr1 = (r1 >> 2) + r1; // rr1 == (r1 >> 2) * 5
|
||||||
|
const u32 rr2 = (r2 >> 2) + r2; // rr1 == (r2 >> 2) * 5
|
||||||
|
const u32 rr3 = (r3 >> 2) + r3; // rr1 == (r3 >> 2) * 5
|
||||||
|
const u32 rr4 = r0 & 3; // ...recover 2 bits
|
||||||
|
u32 h0 = ctx->h[0];
|
||||||
|
u32 h1 = ctx->h[1];
|
||||||
|
u32 h2 = ctx->h[2];
|
||||||
|
u32 h3 = ctx->h[3];
|
||||||
|
u32 h4 = ctx->h[4];
|
||||||
|
|
||||||
|
FOR (i, 0, nb_blocks) {
|
||||||
|
// h + c, without carry propagation
|
||||||
|
const u64 s0 = (u64)h0 + load32_le(in); in += 4;
|
||||||
|
const u64 s1 = (u64)h1 + load32_le(in); in += 4;
|
||||||
|
const u64 s2 = (u64)h2 + load32_le(in); in += 4;
|
||||||
|
const u64 s3 = (u64)h3 + load32_le(in); in += 4;
|
||||||
|
const u32 s4 = h4 + end;
|
||||||
|
|
||||||
|
// (h + c) * r, without carry propagation
|
||||||
|
const u64 x0 = s0*r0+ s1*rr3+ s2*rr2+ s3*rr1+ s4*rr0;
|
||||||
|
const u64 x1 = s0*r1+ s1*r0 + s2*rr3+ s3*rr2+ s4*rr1;
|
||||||
|
const u64 x2 = s0*r2+ s1*r1 + s2*r0 + s3*rr3+ s4*rr2;
|
||||||
|
const u64 x3 = s0*r3+ s1*r2 + s2*r1 + s3*r0 + s4*rr3;
|
||||||
|
const u32 x4 = s4*rr4;
|
||||||
|
|
||||||
|
// partial reduction modulo 2^130 - 5
|
||||||
|
const u32 u5 = x4 + (x3 >> 32); // u5 <= 7ffffff5
|
||||||
|
const u64 u0 = (u5 >> 2) * 5 + (x0 & 0xffffffff);
|
||||||
|
const u64 u1 = (u0 >> 32) + (x1 & 0xffffffff) + (x0 >> 32);
|
||||||
|
const u64 u2 = (u1 >> 32) + (x2 & 0xffffffff) + (x1 >> 32);
|
||||||
|
const u64 u3 = (u2 >> 32) + (x3 & 0xffffffff) + (x2 >> 32);
|
||||||
|
const u32 u4 = (u3 >> 32) + (u5 & 3); // u4 <= 4
|
||||||
|
|
||||||
|
// Update the hash
|
||||||
|
h0 = u0 & 0xffffffff;
|
||||||
|
h1 = u1 & 0xffffffff;
|
||||||
|
h2 = u2 & 0xffffffff;
|
||||||
|
h3 = u3 & 0xffffffff;
|
||||||
|
h4 = u4;
|
||||||
|
}
|
||||||
|
ctx->h[0] = h0;
|
||||||
|
ctx->h[1] = h1;
|
||||||
|
ctx->h[2] = h2;
|
||||||
|
ctx->h[3] = h3;
|
||||||
|
ctx->h[4] = h4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_poly1305_init(crypto_poly1305_ctx *ctx, const u8 key[32])
|
||||||
|
{
|
||||||
|
ZERO(ctx->h, 5); // Initial hash is zero
|
||||||
|
ctx->c_idx = 0;
|
||||||
|
// load r and pad (r has some of its bits cleared)
|
||||||
|
load32_le_buf(ctx->r , key , 4);
|
||||||
|
load32_le_buf(ctx->pad, key+16, 4);
|
||||||
|
FOR (i, 0, 1) { ctx->r[i] &= 0x0fffffff; }
|
||||||
|
FOR (i, 1, 4) { ctx->r[i] &= 0x0ffffffc; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_poly1305_update(crypto_poly1305_ctx *ctx,
|
||||||
|
const u8 *message, size_t message_size)
|
||||||
|
{
|
||||||
|
// Avoid undefined NULL pointer increments with empty messages
|
||||||
|
if (message_size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Align ourselves with block boundaries
|
||||||
|
size_t aligned = MIN(gap(ctx->c_idx, 16), message_size);
|
||||||
|
FOR (i, 0, aligned) {
|
||||||
|
ctx->c[ctx->c_idx] = *message;
|
||||||
|
ctx->c_idx++;
|
||||||
|
message++;
|
||||||
|
message_size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If block is complete, process it
|
||||||
|
if (ctx->c_idx == 16) {
|
||||||
|
poly_blocks(ctx, ctx->c, 1, 1);
|
||||||
|
ctx->c_idx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the message block by block
|
||||||
|
size_t nb_blocks = message_size >> 4;
|
||||||
|
poly_blocks(ctx, message, nb_blocks, 1);
|
||||||
|
message += nb_blocks << 4;
|
||||||
|
message_size &= 15;
|
||||||
|
|
||||||
|
// remaining bytes (we never complete a block here)
|
||||||
|
FOR (i, 0, message_size) {
|
||||||
|
ctx->c[ctx->c_idx] = message[i];
|
||||||
|
ctx->c_idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_poly1305_final(crypto_poly1305_ctx *ctx, u8 mac[16])
|
||||||
|
{
|
||||||
|
// Process the last block (if any)
|
||||||
|
// We move the final 1 according to remaining input length
|
||||||
|
// (this will add less than 2^130 to the last input block)
|
||||||
|
if (ctx->c_idx != 0) {
|
||||||
|
ZERO(ctx->c + ctx->c_idx, 16 - ctx->c_idx);
|
||||||
|
ctx->c[ctx->c_idx] = 1;
|
||||||
|
poly_blocks(ctx, ctx->c, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if we should subtract 2^130-5 by performing the
|
||||||
|
// corresponding carry propagation.
|
||||||
|
u64 c = 5;
|
||||||
|
FOR (i, 0, 4) {
|
||||||
|
c += ctx->h[i];
|
||||||
|
c >>= 32;
|
||||||
|
}
|
||||||
|
c += ctx->h[4];
|
||||||
|
c = (c >> 2) * 5; // shift the carry back to the beginning
|
||||||
|
// c now indicates how many times we should subtract 2^130-5 (0 or 1)
|
||||||
|
FOR (i, 0, 4) {
|
||||||
|
c += (u64)ctx->h[i] + ctx->pad[i];
|
||||||
|
store32_le(mac + i*4, (u32)c);
|
||||||
|
c = c >> 32;
|
||||||
|
}
|
||||||
|
WIPE_CTX(ctx);
|
||||||
|
}
|
|
@ -294,6 +294,17 @@ freebsd_crypt_newsession(freebsd_crypt_session_t *sessp,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ZC_TYPE_CHACHA20_POLY1305:
|
||||||
|
csp.csp_cipher_alg = CRYPTO_CHACHA20_POLY1305;
|
||||||
|
csp.csp_ivlen = CHACHA20_POLY1305_IV_LEN;
|
||||||
|
switch (key->ck_length/8) {
|
||||||
|
case CHACHA20_POLY1305_KEY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error = EINVAL;
|
||||||
|
goto bad;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error = ENOTSUP;
|
error = ENOTSUP;
|
||||||
goto bad;
|
goto bad;
|
||||||
|
|
|
@ -194,15 +194,26 @@ typedef struct blkptr_auth_buf {
|
||||||
} blkptr_auth_buf_t;
|
} blkptr_auth_buf_t;
|
||||||
|
|
||||||
const zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = {
|
const zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = {
|
||||||
{"", ZC_TYPE_NONE, 0, "inherit"},
|
{"", ZC_TYPE_NONE,
|
||||||
{"", ZC_TYPE_NONE, 0, "on"},
|
0, "inherit"},
|
||||||
{"", ZC_TYPE_NONE, 0, "off"},
|
{"", ZC_TYPE_NONE,
|
||||||
{SUN_CKM_AES_CCM, ZC_TYPE_CCM, 16, "aes-128-ccm"},
|
0, "on"},
|
||||||
{SUN_CKM_AES_CCM, ZC_TYPE_CCM, 24, "aes-192-ccm"},
|
{"", ZC_TYPE_NONE,
|
||||||
{SUN_CKM_AES_CCM, ZC_TYPE_CCM, 32, "aes-256-ccm"},
|
0, "off"},
|
||||||
{SUN_CKM_AES_GCM, ZC_TYPE_GCM, 16, "aes-128-gcm"},
|
{SUN_CKM_AES_CCM, ZC_TYPE_CCM,
|
||||||
{SUN_CKM_AES_GCM, ZC_TYPE_GCM, 24, "aes-192-gcm"},
|
16, "aes-128-ccm"},
|
||||||
{SUN_CKM_AES_GCM, ZC_TYPE_GCM, 32, "aes-256-gcm"}
|
{SUN_CKM_AES_CCM, ZC_TYPE_CCM,
|
||||||
|
24, "aes-192-ccm"},
|
||||||
|
{SUN_CKM_AES_CCM, ZC_TYPE_CCM,
|
||||||
|
32, "aes-256-ccm"},
|
||||||
|
{SUN_CKM_AES_GCM, ZC_TYPE_GCM,
|
||||||
|
16, "aes-128-gcm"},
|
||||||
|
{SUN_CKM_AES_GCM, ZC_TYPE_GCM,
|
||||||
|
24, "aes-192-gcm"},
|
||||||
|
{SUN_CKM_AES_GCM, ZC_TYPE_GCM,
|
||||||
|
32, "aes-256-gcm"},
|
||||||
|
{SUN_CKM_CHACHA20_POLY1305, ZC_TYPE_CHACHA20_POLY1305,
|
||||||
|
32, "chacha20-poly1305"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -238,7 +249,8 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key)
|
||||||
|
|
||||||
ci = &zio_crypt_table[crypt];
|
ci = &zio_crypt_table[crypt];
|
||||||
if (ci->ci_crypt_type != ZC_TYPE_GCM &&
|
if (ci->ci_crypt_type != ZC_TYPE_GCM &&
|
||||||
ci->ci_crypt_type != ZC_TYPE_CCM)
|
ci->ci_crypt_type != ZC_TYPE_CCM &&
|
||||||
|
ci->ci_crypt_type != ZC_TYPE_CHACHA20_POLY1305)
|
||||||
return (ENOTSUP);
|
return (ENOTSUP);
|
||||||
|
|
||||||
keydata_len = zio_crypt_table[crypt].ci_keylen;
|
keydata_len = zio_crypt_table[crypt].ci_keylen;
|
||||||
|
@ -278,7 +290,8 @@ zio_crypt_key_init(uint64_t crypt, zio_crypt_key_t *key)
|
||||||
|
|
||||||
ci = &zio_crypt_table[crypt];
|
ci = &zio_crypt_table[crypt];
|
||||||
if (ci->ci_crypt_type != ZC_TYPE_GCM &&
|
if (ci->ci_crypt_type != ZC_TYPE_GCM &&
|
||||||
ci->ci_crypt_type != ZC_TYPE_CCM)
|
ci->ci_crypt_type != ZC_TYPE_CCM &&
|
||||||
|
ci->ci_crypt_type != ZC_TYPE_CHACHA20_POLY1305)
|
||||||
return (ENOTSUP);
|
return (ENOTSUP);
|
||||||
|
|
||||||
ret = freebsd_crypt_newsession(&key->zk_session, ci,
|
ret = freebsd_crypt_newsession(&key->zk_session, ci,
|
||||||
|
@ -400,7 +413,8 @@ zio_do_crypt_uio_opencrypto(boolean_t encrypt, freebsd_crypt_session_t *sess,
|
||||||
{
|
{
|
||||||
const zio_crypt_info_t *ci = &zio_crypt_table[crypt];
|
const zio_crypt_info_t *ci = &zio_crypt_table[crypt];
|
||||||
if (ci->ci_crypt_type != ZC_TYPE_GCM &&
|
if (ci->ci_crypt_type != ZC_TYPE_GCM &&
|
||||||
ci->ci_crypt_type != ZC_TYPE_CCM)
|
ci->ci_crypt_type != ZC_TYPE_CCM &&
|
||||||
|
ci->ci_crypt_type != ZC_TYPE_CHACHA20_POLY1305)
|
||||||
return (ENOTSUP);
|
return (ENOTSUP);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -195,15 +195,26 @@ typedef struct blkptr_auth_buf {
|
||||||
} blkptr_auth_buf_t;
|
} blkptr_auth_buf_t;
|
||||||
|
|
||||||
const zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = {
|
const zio_crypt_info_t zio_crypt_table[ZIO_CRYPT_FUNCTIONS] = {
|
||||||
{"", ZC_TYPE_NONE, 0, "inherit"},
|
{"", ZC_TYPE_NONE,
|
||||||
{"", ZC_TYPE_NONE, 0, "on"},
|
0, "inherit"},
|
||||||
{"", ZC_TYPE_NONE, 0, "off"},
|
{"", ZC_TYPE_NONE,
|
||||||
{SUN_CKM_AES_CCM, ZC_TYPE_CCM, 16, "aes-128-ccm"},
|
0, "on"},
|
||||||
{SUN_CKM_AES_CCM, ZC_TYPE_CCM, 24, "aes-192-ccm"},
|
{"", ZC_TYPE_NONE,
|
||||||
{SUN_CKM_AES_CCM, ZC_TYPE_CCM, 32, "aes-256-ccm"},
|
0, "off"},
|
||||||
{SUN_CKM_AES_GCM, ZC_TYPE_GCM, 16, "aes-128-gcm"},
|
{SUN_CKM_AES_CCM, ZC_TYPE_CCM,
|
||||||
{SUN_CKM_AES_GCM, ZC_TYPE_GCM, 24, "aes-192-gcm"},
|
16, "aes-128-ccm"},
|
||||||
{SUN_CKM_AES_GCM, ZC_TYPE_GCM, 32, "aes-256-gcm"}
|
{SUN_CKM_AES_CCM, ZC_TYPE_CCM,
|
||||||
|
24, "aes-192-ccm"},
|
||||||
|
{SUN_CKM_AES_CCM, ZC_TYPE_CCM,
|
||||||
|
32, "aes-256-ccm"},
|
||||||
|
{SUN_CKM_AES_GCM, ZC_TYPE_GCM,
|
||||||
|
16, "aes-128-gcm"},
|
||||||
|
{SUN_CKM_AES_GCM, ZC_TYPE_GCM,
|
||||||
|
24, "aes-192-gcm"},
|
||||||
|
{SUN_CKM_AES_GCM, ZC_TYPE_GCM,
|
||||||
|
32, "aes-256-gcm"},
|
||||||
|
{SUN_CKM_CHACHA20_POLY1305, ZC_TYPE_CHACHA20_POLY1305,
|
||||||
|
32, "chacha20-poly1305"},
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -760,6 +760,19 @@ zpool_feature_init(void)
|
||||||
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
|
ZFEATURE_FLAG_READONLY_COMPAT, ZFEATURE_TYPE_BOOLEAN, NULL,
|
||||||
sfeatures);
|
sfeatures);
|
||||||
|
|
||||||
|
{
|
||||||
|
static const spa_feature_t chapoly_deps[] = {
|
||||||
|
SPA_FEATURE_EXTENSIBLE_DATASET,
|
||||||
|
SPA_FEATURE_ENCRYPTION,
|
||||||
|
SPA_FEATURE_NONE
|
||||||
|
};
|
||||||
|
zfeature_register(SPA_FEATURE_CHACHA20_POLY1305,
|
||||||
|
"com.despairlabs:chacha20_poly1305", "chacha20_poly1305",
|
||||||
|
"Chacha20-Poly1305 encryption suite.",
|
||||||
|
ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
|
||||||
|
chapoly_deps, sfeatures);
|
||||||
|
}
|
||||||
|
|
||||||
zfs_mod_list_supported_free(sfeatures);
|
zfs_mod_list_supported_free(sfeatures);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -223,6 +223,7 @@ zfs_prop_init(void)
|
||||||
{ "aes-128-gcm", ZIO_CRYPT_AES_128_GCM },
|
{ "aes-128-gcm", ZIO_CRYPT_AES_128_GCM },
|
||||||
{ "aes-192-gcm", ZIO_CRYPT_AES_192_GCM },
|
{ "aes-192-gcm", ZIO_CRYPT_AES_192_GCM },
|
||||||
{ "aes-256-gcm", ZIO_CRYPT_AES_256_GCM },
|
{ "aes-256-gcm", ZIO_CRYPT_AES_256_GCM },
|
||||||
|
{ "chacha20-poly1305", ZIO_CRYPT_CHACHA20_POLY1305 },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -552,8 +553,8 @@ zfs_prop_init(void)
|
||||||
zprop_register_index(ZFS_PROP_ENCRYPTION, "encryption",
|
zprop_register_index(ZFS_PROP_ENCRYPTION, "encryption",
|
||||||
ZIO_CRYPT_DEFAULT, PROP_ONETIME, ZFS_TYPE_DATASET,
|
ZIO_CRYPT_DEFAULT, PROP_ONETIME, ZFS_TYPE_DATASET,
|
||||||
"on | off | aes-128-ccm | aes-192-ccm | aes-256-ccm | "
|
"on | off | aes-128-ccm | aes-192-ccm | aes-256-ccm | "
|
||||||
"aes-128-gcm | aes-192-gcm | aes-256-gcm", "ENCRYPTION",
|
"aes-128-gcm | aes-192-gcm | aes-256-gcm | chacha20-poly1305",
|
||||||
crypto_table, sfeatures);
|
"ENCRYPTION", crypto_table, sfeatures);
|
||||||
|
|
||||||
/* set once index (boolean) properties */
|
/* set once index (boolean) properties */
|
||||||
zprop_register_index(ZFS_PROP_UTF8ONLY, "utf8only", 0, PROP_ONETIME,
|
zprop_register_index(ZFS_PROP_UTF8ONLY, "utf8only", 0, PROP_ONETIME,
|
||||||
|
|
|
@ -1853,6 +1853,12 @@ dmu_objset_create_crypt_check(dsl_dir_t *parentdd, dsl_crypto_params_t *dcp,
|
||||||
return (SET_ERROR(EOPNOTSUPP));
|
return (SET_ERROR(EOPNOTSUPP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (crypt == ZIO_CRYPT_CHACHA20_POLY1305 && parentdd != NULL &&
|
||||||
|
!spa_feature_is_enabled(parentdd->dd_pool->dp_spa,
|
||||||
|
SPA_FEATURE_CHACHA20_POLY1305)) {
|
||||||
|
return (SET_ERROR(EOPNOTSUPP));
|
||||||
|
}
|
||||||
|
|
||||||
/* handle inheritance */
|
/* handle inheritance */
|
||||||
if (dcp->cp_wkey == NULL) {
|
if (dcp->cp_wkey == NULL) {
|
||||||
ASSERT3P(parentdd, !=, NULL);
|
ASSERT3P(parentdd, !=, NULL);
|
||||||
|
@ -1971,6 +1977,9 @@ dsl_dataset_create_crypt_sync(uint64_t dsobj, dsl_dir_t *dd,
|
||||||
tx));
|
tx));
|
||||||
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION,
|
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION,
|
||||||
(void *)B_TRUE, tx);
|
(void *)B_TRUE, tx);
|
||||||
|
if (crypt == ZIO_CRYPT_CHACHA20_POLY1305)
|
||||||
|
dsl_dataset_activate_feature(dsobj,
|
||||||
|
SPA_FEATURE_CHACHA20_POLY1305, (void *)B_TRUE, tx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we inherited the wrapping key we release our reference now.
|
* If we inherited the wrapping key we release our reference now.
|
||||||
|
@ -2191,6 +2200,11 @@ dsl_crypto_recv_raw_key_check(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
|
||||||
if (intval >= ZIO_CRYPT_FUNCTIONS)
|
if (intval >= ZIO_CRYPT_FUNCTIONS)
|
||||||
return (SET_ERROR(ZFS_ERR_CRYPTO_NOTSUP));
|
return (SET_ERROR(ZFS_ERR_CRYPTO_NOTSUP));
|
||||||
|
|
||||||
|
if (intval == ZIO_CRYPT_CHACHA20_POLY1305 &&
|
||||||
|
!spa_feature_is_enabled(ds->ds_dir->dd_pool->dp_spa,
|
||||||
|
SPA_FEATURE_CHACHA20_POLY1305))
|
||||||
|
return (SET_ERROR(EOPNOTSUPP));
|
||||||
|
|
||||||
ret = nvlist_lookup_uint64(nvl, DSL_CRYPTO_KEY_GUID, &intval);
|
ret = nvlist_lookup_uint64(nvl, DSL_CRYPTO_KEY_GUID, &intval);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return (SET_ERROR(EINVAL));
|
return (SET_ERROR(EINVAL));
|
||||||
|
@ -2310,6 +2324,13 @@ dsl_crypto_recv_raw_key_sync(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
|
||||||
SPA_FEATURE_ENCRYPTION, (void *)B_TRUE, tx);
|
SPA_FEATURE_ENCRYPTION, (void *)B_TRUE, tx);
|
||||||
ds->ds_feature[SPA_FEATURE_ENCRYPTION] = (void *)B_TRUE;
|
ds->ds_feature[SPA_FEATURE_ENCRYPTION] = (void *)B_TRUE;
|
||||||
|
|
||||||
|
if (crypt == ZIO_CRYPT_CHACHA20_POLY1305) {
|
||||||
|
dsl_dataset_activate_feature(ds->ds_object,
|
||||||
|
SPA_FEATURE_CHACHA20_POLY1305, (void *)B_TRUE, tx);
|
||||||
|
ds->ds_feature[SPA_FEATURE_CHACHA20_POLY1305] =
|
||||||
|
(void *)B_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* save the dd_crypto_obj on disk */
|
/* save the dd_crypto_obj on disk */
|
||||||
VERIFY0(zap_add(mos, dd->dd_object, DD_FIELD_CRYPTO_KEY_OBJ,
|
VERIFY0(zap_add(mos, dd->dd_object, DD_FIELD_CRYPTO_KEY_OBJ,
|
||||||
sizeof (uint64_t), 1, &dd->dd_crypto_obj, tx));
|
sizeof (uint64_t), 1, &dd->dd_crypto_obj, tx));
|
||||||
|
|
|
@ -530,8 +530,12 @@ dsl_pool_create(spa_t *spa, nvlist_t *zplprops __attribute__((unused)),
|
||||||
spa_feature_create_zap_objects(spa, tx);
|
spa_feature_create_zap_objects(spa, tx);
|
||||||
|
|
||||||
if (dcp != NULL && dcp->cp_crypt != ZIO_CRYPT_OFF &&
|
if (dcp != NULL && dcp->cp_crypt != ZIO_CRYPT_OFF &&
|
||||||
dcp->cp_crypt != ZIO_CRYPT_INHERIT)
|
dcp->cp_crypt != ZIO_CRYPT_INHERIT) {
|
||||||
spa_feature_enable(spa, SPA_FEATURE_ENCRYPTION, tx);
|
spa_feature_enable(spa, SPA_FEATURE_ENCRYPTION, tx);
|
||||||
|
if (dcp->cp_crypt == ZIO_CRYPT_CHACHA20_POLY1305)
|
||||||
|
spa_feature_enable(spa,
|
||||||
|
SPA_FEATURE_CHACHA20_POLY1305, tx);
|
||||||
|
}
|
||||||
|
|
||||||
/* create the root dataset */
|
/* create the root dataset */
|
||||||
obj = dsl_dataset_create_sync_dd(dp->dp_root_dir, NULL, dcp, 0, tx);
|
obj = dsl_dataset_create_sync_dd(dp->dp_root_dir, NULL, dcp, 0, tx);
|
||||||
|
|
|
@ -290,7 +290,8 @@ tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
|
||||||
'zfs_receive_raw', 'zfs_receive_raw_incremental', 'zfs_receive_-e',
|
'zfs_receive_raw', 'zfs_receive_raw_incremental', 'zfs_receive_-e',
|
||||||
'zfs_receive_raw_-d', 'zfs_receive_from_zstd', 'zfs_receive_new_props',
|
'zfs_receive_raw_-d', 'zfs_receive_from_zstd', 'zfs_receive_new_props',
|
||||||
'zfs_receive_-wR-encrypted-mix', 'zfs_receive_corrective',
|
'zfs_receive_-wR-encrypted-mix', 'zfs_receive_corrective',
|
||||||
'zfs_receive_compressed_corrective', 'zfs_receive_large_block_corrective']
|
'zfs_receive_compressed_corrective', 'zfs_receive_large_block_corrective',
|
||||||
|
'zfs_receive_chapoly_feature']
|
||||||
tags = ['functional', 'cli_root', 'zfs_receive']
|
tags = ['functional', 'cli_root', 'zfs_receive']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_rename]
|
[tests/functional/cli_root/zfs_rename]
|
||||||
|
|
|
@ -178,7 +178,8 @@ tests = ['zfs_receive_001_pos', 'zfs_receive_002_pos', 'zfs_receive_003_pos',
|
||||||
'zfs_receive_016_pos', 'zfs_receive_from_encrypted',
|
'zfs_receive_016_pos', 'zfs_receive_from_encrypted',
|
||||||
'zfs_receive_to_encrypted', 'zfs_receive_raw',
|
'zfs_receive_to_encrypted', 'zfs_receive_raw',
|
||||||
'zfs_receive_raw_incremental', 'zfs_receive_-e',
|
'zfs_receive_raw_incremental', 'zfs_receive_-e',
|
||||||
'zfs_receive_raw_-d', 'zfs_receive_from_zstd', 'zfs_receive_new_props']
|
'zfs_receive_raw_-d', 'zfs_receive_from_zstd', 'zfs_receive_new_props',
|
||||||
|
'zfs_receive_chapoly_feature']
|
||||||
tags = ['functional', 'cli_root', 'zfs_receive']
|
tags = ['functional', 'cli_root', 'zfs_receive']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_rename]
|
[tests/functional/cli_root/zfs_rename]
|
||||||
|
|
|
@ -27,6 +27,11 @@ scripts_zfs_tests_functional_tmpfile_PROGRAMS = \
|
||||||
%D%/tests/functional/tmpfile/tmpfile_003_pos \
|
%D%/tests/functional/tmpfile/tmpfile_003_pos \
|
||||||
%D%/tests/functional/tmpfile/tmpfile_stat_mode \
|
%D%/tests/functional/tmpfile/tmpfile_stat_mode \
|
||||||
%D%/tests/functional/tmpfile/tmpfile_test
|
%D%/tests/functional/tmpfile/tmpfile_test
|
||||||
|
|
||||||
|
scripts_zfs_tests_functional_chapolydir = $(datadir)/$(PACKAGE)/zfs-tests/tests/functional/chapoly
|
||||||
|
scripts_zfs_tests_functional_chapoly_PROGRAMS = %D%/tests/functional/chapoly/chapoly_test
|
||||||
|
%C%_tests_functional_chapoly_chapoly_test_LDADD = \
|
||||||
|
libzpool.la
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -827,6 +827,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/cli_root/zfs_receive/zfs_receive_corrective.ksh \
|
functional/cli_root/zfs_receive/zfs_receive_corrective.ksh \
|
||||||
functional/cli_root/zfs_receive/zfs_receive_compressed_corrective.ksh \
|
functional/cli_root/zfs_receive/zfs_receive_compressed_corrective.ksh \
|
||||||
functional/cli_root/zfs_receive/zfs_receive_large_block_corrective.ksh \
|
functional/cli_root/zfs_receive/zfs_receive_large_block_corrective.ksh \
|
||||||
|
functional/cli_root/zfs_receive/zfs_receive_chapoly_feature.ksh \
|
||||||
functional/cli_root/zfs_rename/cleanup.ksh \
|
functional/cli_root/zfs_rename/cleanup.ksh \
|
||||||
functional/cli_root/zfs_rename/setup.ksh \
|
functional/cli_root/zfs_rename/setup.ksh \
|
||||||
functional/cli_root/zfs_rename/zfs_rename_001_pos.ksh \
|
functional/cli_root/zfs_rename/zfs_rename_001_pos.ksh \
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
chapoly_test
|
|
@ -0,0 +1,814 @@
|
||||||
|
/*
|
||||||
|
* 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 https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
* See the License for the specific language governing permissions
|
||||||
|
* and limitations under the License.
|
||||||
|
*
|
||||||
|
* When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
* If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
*
|
||||||
|
* CDDL HEADER END
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This program runs the test vectors from RFC 8439 to ensure the bundled
|
||||||
|
* implementations of Chacha20 and Poly1305 are hooked up properly, and then
|
||||||
|
* tests the Chacha20-Poly1305 ICP module to ensure it properly implements the
|
||||||
|
* AEAD.
|
||||||
|
*
|
||||||
|
* This is mostly useful to verify that alternate implementations of the
|
||||||
|
* algorithms (eg accelerated versions) do the right thing, as the
|
||||||
|
* implementations out there are highly variable in function and quality and
|
||||||
|
* its often very difficult to tell if they're producing the right results.
|
||||||
|
*
|
||||||
|
* That said, these tests passing doesn't say anything about the security
|
||||||
|
* characteristics of these algorithms as used in OpenZFS, only that the
|
||||||
|
* underlying implementations are probably not entirely broken.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/crypto/icp.h>
|
||||||
|
#include <sys/crypto/api.h>
|
||||||
|
#include <monocypher.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
hexdump(const char *str, const uint8_t *src, uint_t len)
|
||||||
|
{
|
||||||
|
printf("%12s:", str);
|
||||||
|
int i = 0;
|
||||||
|
while (i < len) {
|
||||||
|
if (i % 4 == 0)
|
||||||
|
printf(" ");
|
||||||
|
printf("%02x", src[i]);
|
||||||
|
i++;
|
||||||
|
if (i % 16 == 0 && i < len) {
|
||||||
|
printf("\n");
|
||||||
|
if (i < len)
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t PLAINTEXT_SUNSCREEN[] = {
|
||||||
|
0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, /* Ladies a */
|
||||||
|
0x6e, 0x64, 0x20, 0x47, 0x65, 0x6e, 0x74, 0x6c, /* nd Gentl */
|
||||||
|
0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, /* emen of */
|
||||||
|
0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, /* the clas */
|
||||||
|
0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39, 0x39, /* s of '99 */
|
||||||
|
0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, /* : If I c */
|
||||||
|
0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6f, 0x66, 0x66, /* ould off */
|
||||||
|
0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, /* er you o */
|
||||||
|
0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, /* nly one */
|
||||||
|
0x74, 0x69, 0x70, 0x20, 0x66, 0x6f, 0x72, 0x20, /* tip for */
|
||||||
|
0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, /* the futu */
|
||||||
|
0x72, 0x65, 0x2c, 0x20, 0x73, 0x75, 0x6e, 0x73, /* re, suns */
|
||||||
|
0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f, /* creen wo */
|
||||||
|
0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, /* uld be i */
|
||||||
|
0x74, 0x2e /* t. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t PLAINTEXT_IETF[] = {
|
||||||
|
0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, /* Any subm */
|
||||||
|
0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, /* ission t */
|
||||||
|
0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x49, 0x45, /* o the IE */
|
||||||
|
0x54, 0x46, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x6e, /* TF inten */
|
||||||
|
0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, /* ded by t */
|
||||||
|
0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, /* he Contr */
|
||||||
|
0x69, 0x62, 0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, /* ibutor f */
|
||||||
|
0x6f, 0x72, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, /* or publi */
|
||||||
|
0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, /* cation a */
|
||||||
|
0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72, /* s all or */
|
||||||
|
0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, /* part of */
|
||||||
|
0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, /* an IETF */
|
||||||
|
0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, /* Internet */
|
||||||
|
0x74, 0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x20, /* -Draft */
|
||||||
|
0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61, /* or RFC a */
|
||||||
|
0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, /* nd any s */
|
||||||
|
0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, /* tatement */
|
||||||
|
0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x77, 0x69, /* made wi */
|
||||||
|
0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, /* thin the */
|
||||||
|
0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, /* context */
|
||||||
|
0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, /* of an IE */
|
||||||
|
0x45, 0x54, 0x46, 0x20, 0x61, 0x63, 0x74, 0x69, /* TF acti */
|
||||||
|
0x76, 0x69, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20, /* vity is */
|
||||||
|
0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, /* consider */
|
||||||
|
0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49, /* ed an "I */
|
||||||
|
0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, /* ETF Cont */
|
||||||
|
0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, /* ribution */
|
||||||
|
0x22, 0x2e, 0x20, 0x53, 0x75, 0x63, 0x68, 0x20, /* ". Such */
|
||||||
|
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, /* statemen */
|
||||||
|
0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, /* ts inclu */
|
||||||
|
0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, /* de oral */
|
||||||
|
0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, /* statemen */
|
||||||
|
0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x49, 0x45, /* ts in IE */
|
||||||
|
0x54, 0x46, 0x20, 0x73, 0x65, 0x73, 0x73, 0x69, /* TF sessi */
|
||||||
|
0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20, /* ons, as */
|
||||||
|
0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, /* well as */
|
||||||
|
0x77, 0x72, 0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, /* written */
|
||||||
|
0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, /* and elec */
|
||||||
|
0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63, 0x20, 0x63, /* tronic c */
|
||||||
|
0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61, /* ommunica */
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, /* tions ma */
|
||||||
|
0x64, 0x65, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, /* de at an */
|
||||||
|
0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20, 0x6f, /* y time o */
|
||||||
|
0x72, 0x20, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x2c, /* r place, */
|
||||||
|
0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61, /* which ar */
|
||||||
|
0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, /* e addre */
|
||||||
|
0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x6f /* ssed to */
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t PLAINTEXT_IETF2[] = {
|
||||||
|
0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, /* Internet */
|
||||||
|
0x2d, 0x44, 0x72, 0x61, 0x66, 0x74, 0x73, 0x20, /* -Drafts */
|
||||||
|
0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, /* are draf */
|
||||||
|
0x74, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, /* t docume */
|
||||||
|
0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c, 0x69, /* nts vali */
|
||||||
|
0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, /* d for a */
|
||||||
|
0x6d, 0x61, 0x78, 0x69, 0x6d, 0x75, 0x6d, 0x20, /* maximum */
|
||||||
|
0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, /* of six m */
|
||||||
|
0x6f, 0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, /* onths an */
|
||||||
|
0x64, 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, /* d may be */
|
||||||
|
0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, /* updated */
|
||||||
|
0x2c, 0x20, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, /* , replac */
|
||||||
|
0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f, /* ed, or o */
|
||||||
|
0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, /* bsoleted */
|
||||||
|
0x20, 0x62, 0x79, 0x20, 0x6f, 0x74, 0x68, 0x65, /* by othe */
|
||||||
|
0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, /* r docume */
|
||||||
|
0x6e, 0x74, 0x73, 0x20, 0x61, 0x74, 0x20, 0x61, /* nts at a */
|
||||||
|
0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x2e, /* ny time. */
|
||||||
|
0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, /* It is i */
|
||||||
|
0x6e, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x70, 0x72, /* nappropr */
|
||||||
|
0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, /* iate to */
|
||||||
|
0x75, 0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, /* use Inte */
|
||||||
|
0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, /* rnet-Dra */
|
||||||
|
0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, /* fts as r */
|
||||||
|
0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, /* eference */
|
||||||
|
0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61, /* materia */
|
||||||
|
0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, /* l or to */
|
||||||
|
0x63, 0x69, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, /* cite the */
|
||||||
|
0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, /* m other */
|
||||||
|
0x74, 0x68, 0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, /* than as */
|
||||||
|
0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72, 0x6b, /* /...work */
|
||||||
|
0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, /* in prog */
|
||||||
|
0x72, 0x65, 0x73, 0x73, 0x2e, 0x2f, 0xe2, 0x80, /* ress./.. */
|
||||||
|
0x9d /* . */
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t PLAINTEXT_JABBERWOCKY[] = {
|
||||||
|
0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, /* 'Twas br */
|
||||||
|
0x69, 0x6c, 0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, /* illig, a */
|
||||||
|
0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, /* nd the s */
|
||||||
|
0x6c, 0x69, 0x74, 0x68, 0x79, 0x20, 0x74, 0x6f, /* lithy to */
|
||||||
|
0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20, /* ves.Did */
|
||||||
|
0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, /* gyre and */
|
||||||
|
0x20, 0x67, 0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, /* gimble */
|
||||||
|
0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x77, /* in the w */
|
||||||
|
0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41, 0x6c, 0x6c, /* abe:.All */
|
||||||
|
0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77, /* mimsy w */
|
||||||
|
0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, /* ere the */
|
||||||
|
0x62, 0x6f, 0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, /* borogove */
|
||||||
|
0x73, 0x2c, 0x0a, 0x41, 0x6e, 0x64, 0x20, 0x74, /* s,.And t */
|
||||||
|
0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d, 0x65, 0x20, /* he mome */
|
||||||
|
0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75, /* raths ou */
|
||||||
|
0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e /* tgrabe. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t PLAINTEXT_CFRG[] = {
|
||||||
|
0x43, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x67, 0x72, /* Cryptogr */
|
||||||
|
0x61, 0x70, 0x68, 0x69, 0x63, 0x20, 0x46, 0x6f, /* aphic Fo */
|
||||||
|
0x72, 0x75, 0x6d, 0x20, 0x52, 0x65, 0x73, 0x65, /* rum Rese */
|
||||||
|
0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6f, /* arch Gro */
|
||||||
|
0x75, 0x70 /* up */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const uint8_t key[32];
|
||||||
|
const uint8_t nonce[12];
|
||||||
|
uint32_t counter;
|
||||||
|
const uint8_t *plaintext;
|
||||||
|
const uint8_t *ciphertext;
|
||||||
|
size_t textlen;
|
||||||
|
} chacha_test_t;
|
||||||
|
|
||||||
|
static const chacha_test_t chacha_tests[] = {
|
||||||
|
{
|
||||||
|
.name = "RFC 8439 2.4.2",
|
||||||
|
.key = {
|
||||||
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||||
|
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||||
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||||
|
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
|
||||||
|
},
|
||||||
|
.nonce = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x4a,
|
||||||
|
0x00, 0x00, 0x00, 0x00
|
||||||
|
},
|
||||||
|
.counter = 1,
|
||||||
|
.plaintext = PLAINTEXT_SUNSCREEN,
|
||||||
|
.ciphertext = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80,
|
||||||
|
0x41, 0xba, 0x07, 0x28, 0xdd, 0x0d, 0x69, 0x81,
|
||||||
|
0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2,
|
||||||
|
0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b,
|
||||||
|
0xf9, 0x1b, 0x65, 0xc5, 0x52, 0x47, 0x33, 0xab,
|
||||||
|
0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
|
||||||
|
0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab,
|
||||||
|
0x8f, 0x53, 0x0c, 0x35, 0x9f, 0x08, 0x61, 0xd8,
|
||||||
|
0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61,
|
||||||
|
0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e,
|
||||||
|
0x52, 0xbc, 0x51, 0x4d, 0x16, 0xcc, 0xf8, 0x06,
|
||||||
|
0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36,
|
||||||
|
0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6,
|
||||||
|
0xb4, 0x0b, 0x8e, 0xed, 0xf2, 0x78, 0x5e, 0x42,
|
||||||
|
0x87, 0x4d
|
||||||
|
},
|
||||||
|
.textlen = sizeof (PLAINTEXT_SUNSCREEN),
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.2 #1",
|
||||||
|
.key = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
},
|
||||||
|
.nonce = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00
|
||||||
|
},
|
||||||
|
.counter = 0,
|
||||||
|
.plaintext = (uint8_t *)&(uint8_t[64]) { 0 },
|
||||||
|
.ciphertext = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90,
|
||||||
|
0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28,
|
||||||
|
0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a,
|
||||||
|
0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7,
|
||||||
|
0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
|
||||||
|
0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37,
|
||||||
|
0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c,
|
||||||
|
0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86
|
||||||
|
},
|
||||||
|
.textlen = 64,
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.2 #2",
|
||||||
|
.key = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||||
|
},
|
||||||
|
.nonce = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x02
|
||||||
|
},
|
||||||
|
.counter = 1,
|
||||||
|
.plaintext = PLAINTEXT_IETF,
|
||||||
|
.ciphertext = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde,
|
||||||
|
0x4f, 0x37, 0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70,
|
||||||
|
0x41, 0x60, 0x5d, 0x9f, 0x4f, 0x4f, 0x57, 0xbd,
|
||||||
|
0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79, 0x55, 0xec,
|
||||||
|
0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15,
|
||||||
|
0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05,
|
||||||
|
0x0e, 0x9e, 0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f,
|
||||||
|
0x56, 0xe0, 0x31, 0xca, 0x5e, 0xb6, 0x25, 0x0d,
|
||||||
|
0x40, 0x42, 0xe0, 0x27, 0x85, 0xec, 0xec, 0xfa,
|
||||||
|
0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e,
|
||||||
|
0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7,
|
||||||
|
0xc6, 0x13, 0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50,
|
||||||
|
0x42, 0xbd, 0xfa, 0x77, 0x73, 0xd8, 0xa9, 0x05,
|
||||||
|
0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1, 0x41, 0x1c,
|
||||||
|
0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05,
|
||||||
|
0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a,
|
||||||
|
0xd0, 0x0f, 0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0,
|
||||||
|
0xd6, 0x62, 0xab, 0x05, 0x26, 0x91, 0xca, 0x66,
|
||||||
|
0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8, 0x0e, 0xa4,
|
||||||
|
0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d,
|
||||||
|
0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91,
|
||||||
|
0x39, 0xdd, 0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28,
|
||||||
|
0xe6, 0x35, 0x55, 0x3b, 0xa7, 0x6c, 0x5c, 0x87,
|
||||||
|
0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2, 0xe6, 0x2b,
|
||||||
|
0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2,
|
||||||
|
0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f,
|
||||||
|
0xa8, 0xca, 0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76,
|
||||||
|
0x59, 0x89, 0xcb, 0xcf, 0x3d, 0xaa, 0x8b, 0x6c,
|
||||||
|
0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79, 0xc9, 0x2b,
|
||||||
|
0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84,
|
||||||
|
0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd,
|
||||||
|
0xa2, 0x36, 0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b,
|
||||||
|
0xc3, 0x9c, 0x1e, 0x87, 0x6b, 0x19, 0x3b, 0xfe,
|
||||||
|
0x55, 0x69, 0x75, 0x3f, 0x88, 0x12, 0x8c, 0xc0,
|
||||||
|
0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80,
|
||||||
|
0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f,
|
||||||
|
0x58, 0x69, 0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3,
|
||||||
|
0x6f, 0xf2, 0x16, 0xb9, 0xc1, 0xd3, 0x00, 0x62,
|
||||||
|
0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc, 0xe0, 0x91,
|
||||||
|
0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6,
|
||||||
|
0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64,
|
||||||
|
0x77, 0x33, 0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85,
|
||||||
|
0x14, 0xea, 0x99, 0x82, 0xcc, 0xaf, 0xb3, 0x41,
|
||||||
|
0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3, 0xd1, 0xab,
|
||||||
|
0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba,
|
||||||
|
0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd,
|
||||||
|
0xc4, 0xfd, 0x80, 0x6c, 0x22, 0xf2, 0x21
|
||||||
|
},
|
||||||
|
.textlen = sizeof (PLAINTEXT_IETF),
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.2 #3",
|
||||||
|
.key = {
|
||||||
|
0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
|
||||||
|
0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
|
||||||
|
0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
|
||||||
|
0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
|
||||||
|
},
|
||||||
|
.nonce = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x02
|
||||||
|
},
|
||||||
|
.counter = 42,
|
||||||
|
.plaintext = PLAINTEXT_JABBERWOCKY,
|
||||||
|
.ciphertext = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x62, 0xe6, 0x34, 0x7f, 0x95, 0xed, 0x87, 0xa4,
|
||||||
|
0x5f, 0xfa, 0xe7, 0x42, 0x6f, 0x27, 0xa1, 0xdf,
|
||||||
|
0x5f, 0xb6, 0x91, 0x10, 0x04, 0x4c, 0x0d, 0x73,
|
||||||
|
0x11, 0x8e, 0xff, 0xa9, 0x5b, 0x01, 0xe5, 0xcf,
|
||||||
|
0x16, 0x6d, 0x3d, 0xf2, 0xd7, 0x21, 0xca, 0xf9,
|
||||||
|
0xb2, 0x1e, 0x5f, 0xb1, 0x4c, 0x61, 0x68, 0x71,
|
||||||
|
0xfd, 0x84, 0xc5, 0x4f, 0x9d, 0x65, 0xb2, 0x83,
|
||||||
|
0x19, 0x6c, 0x7f, 0xe4, 0xf6, 0x05, 0x53, 0xeb,
|
||||||
|
0xf3, 0x9c, 0x64, 0x02, 0xc4, 0x22, 0x34, 0xe3,
|
||||||
|
0x2a, 0x35, 0x6b, 0x3e, 0x76, 0x43, 0x12, 0xa6,
|
||||||
|
0x1a, 0x55, 0x32, 0x05, 0x57, 0x16, 0xea, 0xd6,
|
||||||
|
0x96, 0x25, 0x68, 0xf8, 0x7d, 0x3f, 0x3f, 0x77,
|
||||||
|
0x04, 0xc6, 0xa8, 0xd1, 0xbc, 0xd1, 0xbf, 0x4d,
|
||||||
|
0x50, 0xd6, 0x15, 0x4b, 0x6d, 0xa7, 0x31, 0xb1,
|
||||||
|
0x87, 0xb5, 0x8d, 0xfd, 0x72, 0x8a, 0xfa, 0x36,
|
||||||
|
0x75, 0x7a, 0x79, 0x7a, 0xc1, 0x88, 0xd1
|
||||||
|
},
|
||||||
|
.textlen = sizeof (PLAINTEXT_JABBERWOCKY),
|
||||||
|
}, {
|
||||||
|
.name = NULL,
|
||||||
|
} };
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_chacha(void)
|
||||||
|
{
|
||||||
|
uint8_t outbuf[1024];
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
for (int testno = 0; chacha_tests[testno].name; testno++) {
|
||||||
|
const chacha_test_t *test = &chacha_tests[testno];
|
||||||
|
printf("chacha test: %s: ", test->name);
|
||||||
|
|
||||||
|
crypto_chacha20_ietf(
|
||||||
|
outbuf, test->plaintext, test->textlen,
|
||||||
|
test->key, test->nonce, test->counter);
|
||||||
|
|
||||||
|
if (memcmp(outbuf, test->ciphertext, test->textlen) != 0) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" ciphertexts don't match:\n");
|
||||||
|
hexdump("got", outbuf, test->textlen);
|
||||||
|
hexdump("expected", test->ciphertext, test->textlen);
|
||||||
|
failed |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
printf("SUCCESS\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const uint8_t key[32];
|
||||||
|
const uint8_t *text;
|
||||||
|
size_t textlen;
|
||||||
|
const uint8_t tag[16];
|
||||||
|
} poly_test_t;
|
||||||
|
|
||||||
|
static const poly_test_t poly_tests[] = {
|
||||||
|
{
|
||||||
|
.name = "RFC 8439 2.5.2",
|
||||||
|
.key = {
|
||||||
|
0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33,
|
||||||
|
0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06, 0xa8,
|
||||||
|
0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd,
|
||||||
|
0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49, 0xf5, 0x1b
|
||||||
|
},
|
||||||
|
.text = PLAINTEXT_CFRG,
|
||||||
|
.textlen = sizeof (PLAINTEXT_CFRG),
|
||||||
|
.tag = {
|
||||||
|
0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6,
|
||||||
|
0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27, 0xa9
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.3 #1",
|
||||||
|
.key = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
.text = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
},
|
||||||
|
.textlen = 64,
|
||||||
|
.tag = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.3 #2",
|
||||||
|
.key = {
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70,
|
||||||
|
0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e
|
||||||
|
},
|
||||||
|
.text = PLAINTEXT_IETF,
|
||||||
|
.textlen = sizeof (PLAINTEXT_IETF),
|
||||||
|
.tag = {
|
||||||
|
0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70,
|
||||||
|
0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.3 #3",
|
||||||
|
.key = {
|
||||||
|
0x36, 0xe5, 0xf6, 0xb5, 0xc5, 0xe0, 0x60, 0x70,
|
||||||
|
0xf0, 0xef, 0xca, 0x96, 0x22, 0x7a, 0x86, 0x3e,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||||
|
},
|
||||||
|
.text = PLAINTEXT_IETF,
|
||||||
|
.textlen = sizeof (PLAINTEXT_IETF),
|
||||||
|
.tag = {
|
||||||
|
0xf3, 0x47, 0x7e, 0x7c, 0xd9, 0x54, 0x17, 0xaf,
|
||||||
|
0x89, 0xa6, 0xb8, 0x79, 0x4c, 0x31, 0x0c, 0xf0
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.3 #4",
|
||||||
|
.key = {
|
||||||
|
0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
|
||||||
|
0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
|
||||||
|
0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
|
||||||
|
0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
|
||||||
|
},
|
||||||
|
.text = PLAINTEXT_JABBERWOCKY,
|
||||||
|
.textlen = sizeof (PLAINTEXT_JABBERWOCKY),
|
||||||
|
.tag = {
|
||||||
|
0x45, 0x41, 0x66, 0x9a, 0x7e, 0xaa, 0xee, 0x61,
|
||||||
|
0xe7, 0x08, 0xdc, 0x7c, 0xbc, 0xc5, 0xeb, 0x62
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
.name = NULL,
|
||||||
|
} };
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_poly(void)
|
||||||
|
{
|
||||||
|
uint8_t macbuf[16];
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
for (int testno = 0; poly_tests[testno].name; testno++) {
|
||||||
|
const poly_test_t *test = &poly_tests[testno];
|
||||||
|
printf("poly test: %s: ", test->name);
|
||||||
|
|
||||||
|
crypto_poly1305_ctx poly;
|
||||||
|
crypto_poly1305_init(&poly, test->key);
|
||||||
|
|
||||||
|
crypto_poly1305_update(&poly, test->text, test->textlen);
|
||||||
|
|
||||||
|
crypto_poly1305_final(&poly, macbuf);
|
||||||
|
|
||||||
|
if (memcmp(test->tag, macbuf, 16) != 0) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" tags don't match:\n");
|
||||||
|
hexdump("got", macbuf, 16);
|
||||||
|
hexdump("expected", test->tag, 16);
|
||||||
|
failed |= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
printf("SUCCESS\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const uint8_t key[32];
|
||||||
|
const uint8_t nonce[12];
|
||||||
|
const uint8_t *aad;
|
||||||
|
size_t aadlen;
|
||||||
|
const uint8_t *plaintext;
|
||||||
|
const uint8_t *ciphertext;
|
||||||
|
size_t textlen;
|
||||||
|
const uint8_t *tag;
|
||||||
|
size_t taglen;
|
||||||
|
} module_test_t;
|
||||||
|
|
||||||
|
static const module_test_t module_tests[] = {
|
||||||
|
{
|
||||||
|
.name = "RFC 8439 2.8.2",
|
||||||
|
.key = {
|
||||||
|
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||||
|
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||||
|
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||||
|
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
|
||||||
|
},
|
||||||
|
.nonce = {
|
||||||
|
0x07, 0x00, 0x00, 0x00,
|
||||||
|
0x40, 0x41, 0x42, 0x43,
|
||||||
|
0x44, 0x45, 0x46, 0x47
|
||||||
|
},
|
||||||
|
.aad = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x50, 0x51, 0x52, 0x53,
|
||||||
|
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7
|
||||||
|
},
|
||||||
|
.aadlen = 12,
|
||||||
|
.plaintext = PLAINTEXT_SUNSCREEN,
|
||||||
|
.ciphertext = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb,
|
||||||
|
0x7b, 0x86, 0xaf, 0xbc, 0x53, 0xef, 0x7e, 0xc2,
|
||||||
|
0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe,
|
||||||
|
0xa9, 0xe2, 0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6,
|
||||||
|
0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67, 0x12,
|
||||||
|
0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b,
|
||||||
|
0x1a, 0x71, 0xde, 0x0a, 0x9e, 0x06, 0x0b, 0x29,
|
||||||
|
0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36,
|
||||||
|
0x92, 0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c,
|
||||||
|
0x98, 0x03, 0xae, 0xe3, 0x28, 0x09, 0x1b, 0x58,
|
||||||
|
0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94,
|
||||||
|
0x55, 0x85, 0x80, 0x8b, 0x48, 0x31, 0xd7, 0xbc,
|
||||||
|
0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
|
||||||
|
0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b,
|
||||||
|
0x61, 0x16
|
||||||
|
},
|
||||||
|
.textlen = sizeof (PLAINTEXT_SUNSCREEN),
|
||||||
|
.tag = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a,
|
||||||
|
0x7e, 0x90, 0x2e, 0xcb, 0xd0, 0x60, 0x06, 0x91
|
||||||
|
},
|
||||||
|
.taglen = 16,
|
||||||
|
}, {
|
||||||
|
.name = "RFC 8439 A.5",
|
||||||
|
.key = {
|
||||||
|
0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a,
|
||||||
|
0xf3, 0x33, 0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0,
|
||||||
|
0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09,
|
||||||
|
0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0
|
||||||
|
},
|
||||||
|
.nonce = {
|
||||||
|
0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x02, 0x03, 0x04,
|
||||||
|
0x05, 0x06, 0x07, 0x08
|
||||||
|
},
|
||||||
|
.aad = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0xf3, 0x33, 0x88, 0x86,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x91
|
||||||
|
},
|
||||||
|
.aadlen = 12,
|
||||||
|
.plaintext = PLAINTEXT_IETF2,
|
||||||
|
.ciphertext = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4,
|
||||||
|
0x60, 0xf0, 0x62, 0xc7, 0x9b, 0xe6, 0x43, 0xbd,
|
||||||
|
0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89,
|
||||||
|
0xf1, 0x08, 0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2,
|
||||||
|
0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43, 0xee,
|
||||||
|
0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0,
|
||||||
|
0xbd, 0xb7, 0xb7, 0x3c, 0x32, 0x1b, 0x01, 0x00,
|
||||||
|
0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf,
|
||||||
|
0x33, 0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce,
|
||||||
|
0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b, 0x94, 0x81,
|
||||||
|
0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd,
|
||||||
|
0x60, 0xf9, 0x82, 0xb1, 0xff, 0x37, 0xc8, 0x55,
|
||||||
|
0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61,
|
||||||
|
0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38,
|
||||||
|
0x36, 0x06, 0x90, 0x7b, 0x6a, 0x7c, 0x02, 0xb0,
|
||||||
|
0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4,
|
||||||
|
0xb9, 0x16, 0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46,
|
||||||
|
0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4, 0xe9,
|
||||||
|
0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e,
|
||||||
|
0xe2, 0x82, 0xa1, 0xb0, 0xa0, 0x6c, 0x52, 0x3e,
|
||||||
|
0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15,
|
||||||
|
0x5b, 0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a,
|
||||||
|
0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56, 0x4e, 0xea,
|
||||||
|
0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a,
|
||||||
|
0x0b, 0xb2, 0x31, 0x60, 0x53, 0xfa, 0x76, 0x99,
|
||||||
|
0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e,
|
||||||
|
0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10,
|
||||||
|
0x73, 0xa6, 0x72, 0x76, 0x27, 0x09, 0x7a, 0x10,
|
||||||
|
0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94,
|
||||||
|
0xfa, 0x68, 0xf0, 0xff, 0x77, 0x98, 0x71, 0x30,
|
||||||
|
0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04, 0xdf,
|
||||||
|
0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29,
|
||||||
|
0xa6, 0xad, 0x5c, 0xb4, 0x02, 0x2b, 0x02, 0x70,
|
||||||
|
0x9b
|
||||||
|
},
|
||||||
|
.textlen = sizeof (PLAINTEXT_IETF2),
|
||||||
|
.tag = (uint8_t *)&(uint8_t[]) {
|
||||||
|
0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22,
|
||||||
|
0x39, 0x23, 0x36, 0xfe, 0xa1, 0x85, 0x1f, 0x38
|
||||||
|
},
|
||||||
|
.taglen = 16,
|
||||||
|
}, {
|
||||||
|
.name = NULL,
|
||||||
|
} };
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_module_encrypt(const module_test_t *test)
|
||||||
|
{
|
||||||
|
crypto_mechanism_t mech;
|
||||||
|
uint8_t outbuf[1024];
|
||||||
|
|
||||||
|
mech.cm_type = crypto_mech2id(SUN_CKM_CHACHA20_POLY1305);
|
||||||
|
|
||||||
|
printf("module test: %s [encrypt]: ", test->name);
|
||||||
|
|
||||||
|
CK_AES_GCM_PARAMS gcmp = {
|
||||||
|
.pIv = (uchar_t *)test->nonce,
|
||||||
|
.ulIvLen = sizeof (test->nonce),
|
||||||
|
.ulIvBits = CRYPTO_BYTES2BITS(sizeof (test->nonce)),
|
||||||
|
.pAAD = (uint8_t *)test->aad,
|
||||||
|
.ulAADLen = test->aadlen,
|
||||||
|
.ulTagBits = CRYPTO_BYTES2BITS(test->taglen),
|
||||||
|
};
|
||||||
|
|
||||||
|
mech.cm_param = (char *)&gcmp;
|
||||||
|
mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
|
||||||
|
|
||||||
|
crypto_key_t key = {
|
||||||
|
.ck_length = sizeof (test->key) << 3,
|
||||||
|
.ck_data = (uint8_t *)test->key,
|
||||||
|
};
|
||||||
|
|
||||||
|
crypto_data_t in = {
|
||||||
|
.cd_format = CRYPTO_DATA_RAW,
|
||||||
|
.cd_offset = 0,
|
||||||
|
.cd_length = test->textlen,
|
||||||
|
.cd_raw = {
|
||||||
|
.iov_base = (char *)test->plaintext,
|
||||||
|
.iov_len = test->textlen,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
crypto_data_t out = {
|
||||||
|
.cd_format = CRYPTO_DATA_RAW,
|
||||||
|
.cd_offset = 0,
|
||||||
|
.cd_length = test->textlen + test->taglen,
|
||||||
|
.cd_raw = {
|
||||||
|
.iov_base = (char *)outbuf,
|
||||||
|
.iov_len = sizeof (outbuf),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int rv = crypto_encrypt(&mech, &in, &key, NULL, &out);
|
||||||
|
if (rv != CRYPTO_SUCCESS) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" encrypt rv = 0x%02x\n", rv);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(outbuf, test->ciphertext, test->textlen) != 0) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" ciphertexts don't match:\n");
|
||||||
|
hexdump("got", outbuf, test->textlen);
|
||||||
|
hexdump("expected", test->ciphertext, test->textlen);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(outbuf + test->textlen, test->tag, test->taglen) != 0) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" tags don't match:\n");
|
||||||
|
hexdump("got", outbuf + test->textlen, test->taglen);
|
||||||
|
hexdump("expected", test->tag, test->taglen);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("SUCCESS\n");
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_module_decrypt(const module_test_t *test)
|
||||||
|
{
|
||||||
|
crypto_mechanism_t mech;
|
||||||
|
uint8_t inbuf[1024], outbuf[1024];
|
||||||
|
|
||||||
|
mech.cm_type = crypto_mech2id(SUN_CKM_CHACHA20_POLY1305);
|
||||||
|
|
||||||
|
printf("module test: %s [decrypt]: ", test->name);
|
||||||
|
|
||||||
|
CK_AES_GCM_PARAMS gcmp = {
|
||||||
|
.pIv = (uchar_t *)test->nonce,
|
||||||
|
.ulIvLen = sizeof (test->nonce),
|
||||||
|
.ulIvBits = CRYPTO_BYTES2BITS(sizeof (test->nonce)),
|
||||||
|
.pAAD = (uint8_t *)test->aad,
|
||||||
|
.ulAADLen = test->aadlen,
|
||||||
|
.ulTagBits = CRYPTO_BYTES2BITS(test->taglen),
|
||||||
|
};
|
||||||
|
|
||||||
|
mech.cm_param = (char *)&gcmp;
|
||||||
|
mech.cm_param_len = sizeof (CK_AES_GCM_PARAMS);
|
||||||
|
|
||||||
|
crypto_key_t key = {
|
||||||
|
.ck_length = sizeof (test->key) << 3,
|
||||||
|
.ck_data = (uint8_t *)test->key,
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(inbuf, test->ciphertext, test->textlen);
|
||||||
|
memcpy(inbuf + test->textlen, test->tag, test->taglen);
|
||||||
|
crypto_data_t in = {
|
||||||
|
.cd_format = CRYPTO_DATA_RAW,
|
||||||
|
.cd_offset = 0,
|
||||||
|
.cd_length = test->textlen + test->taglen,
|
||||||
|
.cd_raw = {
|
||||||
|
.iov_base = (char *)inbuf,
|
||||||
|
.iov_len = test->textlen + test->taglen,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
crypto_data_t out = {
|
||||||
|
.cd_format = CRYPTO_DATA_RAW,
|
||||||
|
.cd_offset = 0,
|
||||||
|
.cd_length = test->textlen,
|
||||||
|
.cd_raw = {
|
||||||
|
.iov_base = (char *)outbuf,
|
||||||
|
.iov_len = sizeof (outbuf),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
int rv = crypto_decrypt(&mech, &in, &key, NULL, &out);
|
||||||
|
if (rv != CRYPTO_SUCCESS) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" decrypt rv = 0x%02x\n", rv);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(outbuf, test->plaintext, test->textlen) != 0) {
|
||||||
|
printf("FAIL\n");
|
||||||
|
printf(" plaintexts don't match:\n");
|
||||||
|
hexdump("got", outbuf, test->textlen);
|
||||||
|
hexdump("expected", test->plaintext, test->textlen);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
printf("SUCCESS\n");
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_module(void)
|
||||||
|
{
|
||||||
|
int failed = 0;
|
||||||
|
|
||||||
|
icp_init();
|
||||||
|
|
||||||
|
for (int testno = 0; module_tests[testno].name; testno++) {
|
||||||
|
const module_test_t *test = &module_tests[testno];
|
||||||
|
failed |= test_module_encrypt(test);
|
||||||
|
failed |= test_module_decrypt(test);
|
||||||
|
}
|
||||||
|
|
||||||
|
icp_fini();
|
||||||
|
|
||||||
|
return (failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
int failed = 0;
|
||||||
|
failed |= test_chacha();
|
||||||
|
failed |= test_poly();
|
||||||
|
failed |= test_module();
|
||||||
|
return (failed);
|
||||||
|
}
|
|
@ -50,7 +50,8 @@ set -A ENCRYPTION_ALGS \
|
||||||
"encryption=aes-256-ccm" \
|
"encryption=aes-256-ccm" \
|
||||||
"encryption=aes-128-gcm" \
|
"encryption=aes-128-gcm" \
|
||||||
"encryption=aes-192-gcm" \
|
"encryption=aes-192-gcm" \
|
||||||
"encryption=aes-256-gcm"
|
"encryption=aes-256-gcm" \
|
||||||
|
"encryption=chacha20-poly1305"
|
||||||
|
|
||||||
set -A ENCRYPTION_PROPS \
|
set -A ENCRYPTION_PROPS \
|
||||||
"encryption=aes-256-gcm" \
|
"encryption=aes-256-gcm" \
|
||||||
|
@ -59,7 +60,8 @@ set -A ENCRYPTION_PROPS \
|
||||||
"encryption=aes-256-ccm" \
|
"encryption=aes-256-ccm" \
|
||||||
"encryption=aes-128-gcm" \
|
"encryption=aes-128-gcm" \
|
||||||
"encryption=aes-192-gcm" \
|
"encryption=aes-192-gcm" \
|
||||||
"encryption=aes-256-gcm"
|
"encryption=aes-256-gcm" \
|
||||||
|
"encryption=chacha20-poly1305"
|
||||||
|
|
||||||
set -A KEYFORMATS "keyformat=raw" \
|
set -A KEYFORMATS "keyformat=raw" \
|
||||||
"keyformat=hex" \
|
"keyformat=hex" \
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
#!/bin/ksh -p
|
||||||
|
#
|
||||||
|
# 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 https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
# See the License for the specific language governing permissions
|
||||||
|
# and limitations under the License.
|
||||||
|
#
|
||||||
|
# When distributing Covered Code, include this CDDL HEADER in each
|
||||||
|
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
||||||
|
# If applicable, add the following below this CDDL HEADER, with the
|
||||||
|
# fields enclosed by brackets "[]" replaced with your own identifying
|
||||||
|
# information: Portions Copyright [yyyy] [name of copyright owner]
|
||||||
|
#
|
||||||
|
# CDDL HEADER END
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2024, Rob Norris <robn@despairlabs.com>
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# A raw send with a dataset with Chacha20-Poly1305 encryption should only be
|
||||||
|
# received when the feature is enabled, otherwise rejected. An AES-GCM dataset
|
||||||
|
# however should always be received.
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "both"
|
||||||
|
|
||||||
|
log_assert "Raw sends with Chacha20-Poly1305 can only be" \
|
||||||
|
"recieved if feature available"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
poolexists srcpool && destroy_pool srcpool
|
||||||
|
poolexists dstpool && destroy_pool dstpool
|
||||||
|
log_must rm -f $TESTDIR/srcdev $TESTDIR/dstdev
|
||||||
|
}
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
# create a pool with the the chapoly feature enabled
|
||||||
|
truncate -s $MINVDEVSIZE $TESTDIR/srcdev
|
||||||
|
log_must zpool create -f -o feature@chacha20_poly1305=enabled \
|
||||||
|
srcpool $TESTDIR/srcdev
|
||||||
|
|
||||||
|
# created encrypted filesystems
|
||||||
|
echo 'password' | create_dataset srcpool/chapoly \
|
||||||
|
-o encryption=chacha20-poly1305 -o keyformat=passphrase
|
||||||
|
echo 'password' | create_dataset srcpool/aesgcm \
|
||||||
|
-o encryption=aes-256-gcm -o keyformat=passphrase
|
||||||
|
|
||||||
|
# snapshot everything
|
||||||
|
log_must zfs snapshot -r srcpool@snap
|
||||||
|
|
||||||
|
|
||||||
|
# create a pool with the chapoly feature enabled
|
||||||
|
truncate -s $MINVDEVSIZE $TESTDIR/dstdev
|
||||||
|
log_must zpool create -f -o feature@chacha20_poly1305=enabled \
|
||||||
|
dstpool $TESTDIR/dstdev
|
||||||
|
|
||||||
|
# send and receive both filesystems
|
||||||
|
log_must eval \
|
||||||
|
"zfs send -Rw srcpool/chapoly@snap | zfs receive -u dstpool/chapoly"
|
||||||
|
log_must eval \
|
||||||
|
"zfs send -Rw srcpool/aesgcm@snap | zfs receive -u dstpool/aesgcm"
|
||||||
|
|
||||||
|
# destroy received datasets
|
||||||
|
log_must zfs destroy -r dstpool/chapoly
|
||||||
|
log_must zfs destroy -r dstpool/aesgcm
|
||||||
|
|
||||||
|
# send and receive entire recursive stream
|
||||||
|
log_must eval "zfs send -Rw srcpool@snap | zfs receive -u dstpool/all"
|
||||||
|
|
||||||
|
|
||||||
|
# remake the dest pool with the chapoly feature disabled
|
||||||
|
destroy_pool dstpool
|
||||||
|
log_must zpool create -f -o feature@chacha20_poly1305=disabled \
|
||||||
|
dstpool $TESTDIR/dstdev
|
||||||
|
|
||||||
|
# send and receive both filesystems. chapoly shoud fail, but aesgcm should
|
||||||
|
# succeed
|
||||||
|
log_mustnot eval \
|
||||||
|
"zfs send -Rw srcpool/chapoly@snap | zfs receive -u dstpool/chapoly"
|
||||||
|
log_must eval \
|
||||||
|
"zfs send -Rw srcpool/aesgcm@snap | zfs receive -u dstpool/aesgcm"
|
||||||
|
|
||||||
|
# destroy received dataset
|
||||||
|
log_must zfs destroy -r dstpool/aesgcm
|
||||||
|
|
||||||
|
|
||||||
|
# send and receive entire recursive stream, which should fail
|
||||||
|
log_mustnot eval "zfs send -Rw srcpool@snap | zfs receive -u dstpool/all"
|
||||||
|
|
||||||
|
|
||||||
|
log_pass "Chacha20-Poly1305 datasets can only be recieved" \
|
||||||
|
"if the feature is enabled"
|
|
@ -46,7 +46,8 @@ set -A ENCRYPTION_ALGS "encryption=on" \
|
||||||
"encryption=aes-256-ccm" \
|
"encryption=aes-256-ccm" \
|
||||||
"encryption=aes-128-gcm" \
|
"encryption=aes-128-gcm" \
|
||||||
"encryption=aes-192-gcm" \
|
"encryption=aes-192-gcm" \
|
||||||
"encryption=aes-256-gcm"
|
"encryption=aes-256-gcm" \
|
||||||
|
"encryption=chacha20-poly1305"
|
||||||
|
|
||||||
set -A ENCRYPTION_PROPS "encryption=aes-256-gcm" \
|
set -A ENCRYPTION_PROPS "encryption=aes-256-gcm" \
|
||||||
"encryption=aes-128-ccm" \
|
"encryption=aes-128-ccm" \
|
||||||
|
@ -54,7 +55,8 @@ set -A ENCRYPTION_PROPS "encryption=aes-256-gcm" \
|
||||||
"encryption=aes-256-ccm" \
|
"encryption=aes-256-ccm" \
|
||||||
"encryption=aes-128-gcm" \
|
"encryption=aes-128-gcm" \
|
||||||
"encryption=aes-192-gcm" \
|
"encryption=aes-192-gcm" \
|
||||||
"encryption=aes-256-gcm"
|
"encryption=aes-256-gcm" \
|
||||||
|
"encryption=chacha20-poly1305"
|
||||||
|
|
||||||
set -A KEYFORMATS "keyformat=raw" \
|
set -A KEYFORMATS "keyformat=raw" \
|
||||||
"keyformat=hex" \
|
"keyformat=hex" \
|
||||||
|
|
|
@ -89,6 +89,7 @@ typeset -a properties=(
|
||||||
"feature@device_rebuild"
|
"feature@device_rebuild"
|
||||||
"feature@draid"
|
"feature@draid"
|
||||||
"feature@redaction_list_spill"
|
"feature@redaction_list_spill"
|
||||||
|
"feature@chacha20_poly1305"
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_linux || is_freebsd; then
|
if is_linux || is_freebsd; then
|
||||||
|
|
Loading…
Reference in New Issue