diff --git a/include/zfeature_common.h b/include/zfeature_common.h
index 1025c44738ba..cfde1c76d7c6 100644
--- a/include/zfeature_common.h
+++ b/include/zfeature_common.h
@@ -81,6 +81,7 @@ typedef enum spa_feature {
SPA_FEATURE_BLOCK_CLONING,
SPA_FEATURE_AVZ_V2,
SPA_FEATURE_REDACTION_LIST_SPILL,
+ SPA_FEATURE_CHACHA20_POLY1305,
SPA_FEATURES
} spa_feature_t;
diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi
index 0a8e9bcbd74d..af55f4fb91da 100644
--- a/lib/libzfs/libzfs.abi
+++ b/lib/libzfs/libzfs.abi
@@ -5810,7 +5810,8 @@
-
+
+
diff --git a/man/man7/zpool-features.7 b/man/man7/zpool-features.7
index 3c7b0b345d96..af3dc5e8f490 100644
--- a/man/man7/zpool-features.7
+++ b/man/man7/zpool-features.7
@@ -18,7 +18,7 @@
.\" Copyright (c) 2019, Allan Jude
.\" Copyright (c) 2021, Colm Buckley
.\"
-.Dd June 23, 2022
+.Dd May 21, 2023
.Dt ZPOOL-FEATURES 7
.Os
.
@@ -398,6 +398,21 @@ returned to the
.Sy enabled
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 lackng 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
This feature enables the ability for the
.Nm zpool Cm attach
diff --git a/module/zcommon/zfeature_common.c b/module/zcommon/zfeature_common.c
index 2c74d10f43ff..0977006c990b 100644
--- a/module/zcommon/zfeature_common.c
+++ b/module/zcommon/zfeature_common.c
@@ -749,6 +749,19 @@ zpool_feature_init(void)
redact_list_spill_deps, sfeatures);
}
+ {
+ static const spa_feature_t chapoly_deps[] = {
+ SPA_FEATURE_EXTENSIBLE_DATASET,
+ SPA_FEATURE_ENCRYPTION,
+ SPA_FEATURE_NONE
+ };
+ zfeature_register(SPA_FEATURE_CHACHA20_POLY1305,
+ "org.openzfs:chacha20_poly1305", "chacha20_poly1305",
+ "Chacha20-Poly1305 encryption suite.",
+ ZFEATURE_FLAG_PER_DATASET, ZFEATURE_TYPE_BOOLEAN,
+ chapoly_deps, sfeatures);
+ }
+
zfs_mod_list_supported_free(sfeatures);
}
diff --git a/module/zfs/dsl_crypt.c b/module/zfs/dsl_crypt.c
index 5e6e4e3d6c39..9393bd4f45ea 100644
--- a/module/zfs/dsl_crypt.c
+++ b/module/zfs/dsl_crypt.c
@@ -1819,6 +1819,12 @@ dmu_objset_create_crypt_check(dsl_dir_t *parentdd, dsl_crypto_params_t *dcp,
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 */
if (dcp->cp_wkey == NULL) {
ASSERT3P(parentdd, !=, NULL);
@@ -1937,6 +1943,9 @@ dsl_dataset_create_crypt_sync(uint64_t dsobj, dsl_dir_t *dd,
tx));
dsl_dataset_activate_feature(dsobj, SPA_FEATURE_ENCRYPTION,
(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.
@@ -2157,6 +2166,11 @@ dsl_crypto_recv_raw_key_check(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
if (intval >= ZIO_CRYPT_FUNCTIONS)
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);
if (ret != 0)
return (SET_ERROR(EINVAL));
@@ -2276,6 +2290,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);
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 */
VERIFY0(zap_add(mos, dd->dd_object, DD_FIELD_CRYPTO_KEY_OBJ,
sizeof (uint64_t), 1, &dd->dd_crypto_obj, tx));
diff --git a/module/zfs/dsl_pool.c b/module/zfs/dsl_pool.c
index 9120fef93c74..0ef2ad30f17d 100644
--- a/module/zfs/dsl_pool.c
+++ b/module/zfs/dsl_pool.c
@@ -537,8 +537,12 @@ dsl_pool_create(spa_t *spa, nvlist_t *zplprops __attribute__((unused)),
spa_feature_create_zap_objects(spa, tx);
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);
+ if (dcp->cp_crypt == ZIO_CRYPT_CHACHA20_POLY1305)
+ spa_feature_enable(spa,
+ SPA_FEATURE_CHACHA20_POLY1305, tx);
+ }
/* create the root dataset */
obj = dsl_dataset_create_sync_dd(dp->dp_root_dir, NULL, dcp, 0, tx);
diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
index 4248578cde16..ba58aff8e899 100644
--- a/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
+++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/zpool_get.cfg
@@ -87,6 +87,7 @@ typeset -a properties=(
"feature@device_rebuild"
"feature@draid"
"feature@redaction_list_spill"
+ "feature@chacha20_poly1305"
)
if is_linux || is_freebsd; then