diff --git a/include/zfeature_common.h b/include/zfeature_common.h
index 7066c699e203..fa186bb90bf9 100644
--- a/include/zfeature_common.h
+++ b/include/zfeature_common.h
@@ -80,6 +80,7 @@ typedef enum spa_feature {
SPA_FEATURE_BLAKE3,
SPA_FEATURE_BLOCK_CLONING,
SPA_FEATURE_AVZ_V2,
+ SPA_FEATURE_CHACHA20_POLY1305,
SPA_FEATURES
} spa_feature_t;
diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi
index 6e53bcb41a87..b87516d23daf 100644
--- a/lib/libzfs/libzfs.abi
+++ b/lib/libzfs/libzfs.abi
@@ -596,7 +596,7 @@
-
+
@@ -5809,7 +5809,8 @@
-
+
+
@@ -8706,8 +8707,8 @@
-
-
+
+
diff --git a/man/man7/zpool-features.7 b/man/man7/zpool-features.7
index 2b7dcb63829c..8f52cb8ade3f 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
.
@@ -396,6 +396,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 4c9b7ed72a0f..7266261e3f69 100644
--- a/module/zcommon/zfeature_common.c
+++ b/module/zcommon/zfeature_common.c
@@ -737,6 +737,19 @@ zpool_feature_init(void)
ZFEATURE_FLAG_MOS, ZFEATURE_TYPE_BOOLEAN, NULL,
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);