This commit is contained in:
наб 2024-07-17 07:16:25 +08:00 committed by GitHub
commit 34d4266afd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 400 additions and 114 deletions

View File

@ -28,6 +28,7 @@ libmount-dev
libpam0g-dev libpam0g-dev
libselinux1-dev libselinux1-dev
libssl-dev libssl-dev
libargon2-dev
libtool libtool
libudev-dev libudev-dev
linux-headers-generic linux-headers-generic

View File

@ -42,6 +42,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
#include <getopt.h> #include <getopt.h>
#include <argon2.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <sys/zfs_context.h> #include <sys/zfs_context.h>
#include <sys/spa.h> #include <sys/spa.h>
@ -3053,7 +3054,7 @@ static char *key_material = NULL;
static boolean_t static boolean_t
zdb_derive_key(dsl_dir_t *dd, uint8_t *key_out) zdb_derive_key(dsl_dir_t *dd, uint8_t *key_out)
{ {
uint64_t keyformat, salt, iters; uint64_t keyformat, kdf = ZFS_PASSPHRASE_KDF_PBKDF2, salt, iters;
int i; int i;
unsigned char c; unsigned char c;
@ -3081,10 +3082,35 @@ zdb_derive_key(dsl_dir_t *dd, uint8_t *key_out)
dd->dd_crypto_obj, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), dd->dd_crypto_obj, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS),
sizeof (uint64_t), 1, &iters)); sizeof (uint64_t), 1, &iters));
if (PKCS5_PBKDF2_HMAC_SHA1(key_material, strlen(key_material), int err = zap_lookup(dd->dd_pool->dp_meta_objset,
((uint8_t *)&salt), sizeof (uint64_t), iters, dd->dd_crypto_obj,
WRAPPING_KEY_LEN, key_out) != 1) zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF),
return (B_FALSE); sizeof (uint64_t), 1, &kdf);
VERIFY(err == 0 || err == ENOENT);
switch (kdf) {
case ZFS_PASSPHRASE_KDF_PBKDF2:
if (PKCS5_PBKDF2_HMAC_SHA1(key_material,
strlen(key_material), ((uint8_t *)&salt),
sizeof (uint64_t), iters,
WRAPPING_KEY_LEN, key_out) != 1)
return (B_FALSE);
break;
case ZFS_PASSPHRASE_KDF_ARGON2ID:
zfs_passphrase_kdf_argon2id_params_t params =
zfs_passphrase_kdf_argon2id_params(iters);
if (argon2_hash(params.t_cost, params.m_cost,
params.parallelism,
key_material, strlen(key_material),
&salt, sizeof (uint64_t), key_out, WRAPPING_KEY_LEN,
NULL, 0, Argon2_id, ARGON2_VERSION_13)
!= ARGON2_OK)
return (B_FALSE);
break;
default:
fatal("no support for KDF %u\n",
(unsigned int) kdf);
}
break; break;

View File

@ -416,8 +416,9 @@ get_usage(zfs_help_t idx)
"<-a | filesystem|volume>\n")); "<-a | filesystem|volume>\n"));
case HELP_CHANGE_KEY: case HELP_CHANGE_KEY:
return (gettext("\tchange-key [-l] [-o keyformat=<value>]\n" return (gettext("\tchange-key [-l] [-o keyformat=<value>]\n"
"\t [-o keylocation=<value>] [-o pbkdf2iters=<value>]\n" "\t [-o keylocation=<value>] "
"\t <filesystem|volume>\n" "[-o passphrasekdf=<value>] \n"
"\t [-o pbkdf2iters=<value>] <filesystem|volume>\n"
"\tchange-key -i [-l] <filesystem|volume>\n")); "\tchange-key -i [-l] <filesystem|volume>\n"));
case HELP_VERSION: case HELP_VERSION:
return (gettext("\tversion\n")); return (gettext("\tversion\n"));

View File

@ -4545,6 +4545,9 @@ ztest_dataset_create(char *dsname)
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), ZFS_KEYFORMAT_RAW); zfs_prop_to_name(ZFS_PROP_KEYFORMAT), ZFS_KEYFORMAT_RAW);
fnvlist_add_string(props, fnvlist_add_string(props,
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt"); zfs_prop_to_name(ZFS_PROP_KEYLOCATION), "prompt");
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF),
ztest_random(ZFS_PASSPHRASE_KDF_KDFS));
fnvlist_add_uint64(props, fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 0ULL); zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 0ULL);
fnvlist_add_uint64(props, fnvlist_add_uint64(props,

View File

@ -1,8 +1,16 @@
dnl # dnl #
dnl # Check for libcrypto. Used for userspace password derivation via PBKDF2. dnl # Check for libcrypto and libargon. Used for userspace password derivation via PBKDF2 and argon2id.
dnl # dnl #
AC_DEFUN([ZFS_AC_CONFIG_USER_LIBCRYPTO], [ AC_DEFUN([ZFS_AC_CONFIG_USER_LIBCRYPTO], [
ZFS_AC_FIND_SYSTEM_LIBRARY(LIBCRYPTO, [libcrypto], [openssl/evp.h], [], [crypto], [PKCS5_PBKDF2_HMAC_SHA1], [], [ ZFS_AC_FIND_SYSTEM_LIBRARY(LIBCRYPTO_SSL, [libcrypto], [openssl/evp.h], [], [crypto], [PKCS5_PBKDF2_HMAC_SHA1], [], [
AC_MSG_FAILURE([ AC_MSG_FAILURE([*** evp.h missing, libssl-devel package required])])
*** evp.h missing, libssl-devel package required])])
# ARGON2 is included in openssl 3.2: once this is widely distributed, we should detect it and drop the libargon2 dep
ZFS_AC_FIND_SYSTEM_LIBRARY(LIBCRYPTO_ARGON2, [libargon2], [argon2.h], [], [argon2], [argon2id_hash_raw], [], [
AC_MSG_FAILURE([*** libargon2-dev package required])])
LIBCRYPTO_CFLAGS="$LIBCRYPTO_SSL_CFLAGS $LIBCRYPTO_ARGON2_CFLAGS"
LIBCRYPTO_LIBS="$LIBCRYPTO_SSL_LIBS $LIBCRYPTO_ARGON2_LIBS"
AC_SUBST(LIBCRYPTO_CFLAGS, [])
AC_SUBST(LIBCRYPTO_LIBS, [])
]) ])

View File

@ -33,6 +33,7 @@
#include <sys/zio_crypt.h> #include <sys/zio_crypt.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <argon2.h>
#define PAM_SM_AUTH #define PAM_SM_AUTH
#define PAM_SM_PASSWORD #define PAM_SM_PASSWORD
@ -250,17 +251,24 @@ static pw_password_t *
prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds, prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds,
const char *passphrase, nvlist_t *nvlist) const char *passphrase, nvlist_t *nvlist)
{ {
const char *errstr = NULL;
pw_password_t *key = alloc_pw_size(WRAPPING_KEY_LEN); pw_password_t *key = alloc_pw_size(WRAPPING_KEY_LEN);
if (!key) { if (!key) {
return (NULL); return (NULL);
} }
uint64_t salt; uint64_t kdf, salt, iters;
uint64_t iters;
if (nvlist != NULL) { if (nvlist != NULL) {
kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
if (nvlist_add_uint64(nvlist,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), kdf)) {
errstr = "failed to add KDF to nvlist";
goto err;
}
int fd = open("/dev/urandom", O_RDONLY); int fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) { if (fd < 0) {
pw_free(key); errstr = "/dev/urandom";
return (NULL); goto err;
} }
int bytes_read = 0; int bytes_read = 0;
char *buf = (char *)&salt; char *buf = (char *)&salt;
@ -270,8 +278,8 @@ prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds,
- bytes_read); - bytes_read);
if (len < 0) { if (len < 0) {
close(fd); close(fd);
pw_free(key); errstr = "failed to read salt";
return (NULL); goto err;
} }
bytes_read += len; bytes_read += len;
} }
@ -279,34 +287,54 @@ prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds,
if (nvlist_add_uint64(nvlist, if (nvlist_add_uint64(nvlist,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt)) { zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt)) {
pam_syslog(pamh, LOG_ERR, errstr = "failed to add salt to nvlist";
"failed to add salt to nvlist"); goto err;
pw_free(key);
return (NULL);
} }
iters = DEFAULT_PBKDF2_ITERATIONS; iters = zfs_passphrase_kdf_default_parameters[kdf];
if (nvlist_add_uint64(nvlist, zfs_prop_to_name( if (nvlist_add_uint64(nvlist, zfs_prop_to_name(
ZFS_PROP_PBKDF2_ITERS), iters)) { ZFS_PROP_PBKDF2_ITERS), iters)) {
pam_syslog(pamh, LOG_ERR, errstr = "failed to add iters to nvlist";
"failed to add iters to nvlist"); goto err;
pw_free(key);
return (NULL);
} }
} else { } else {
kdf = zfs_prop_get_int(ds, ZFS_PROP_PASSPHRASE_KDF);
salt = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_SALT); salt = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_SALT);
iters = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_ITERS); iters = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_ITERS);
} }
salt = LE_64(salt); salt = LE_64(salt);
if (!PKCS5_PBKDF2_HMAC_SHA1((char *)passphrase,
strlen(passphrase), (uint8_t *)&salt, switch (kdf) {
sizeof (uint64_t), iters, WRAPPING_KEY_LEN, case ZFS_PASSPHRASE_KDF_PBKDF2:
(uint8_t *)key->value)) { if (PKCS5_PBKDF2_HMAC_SHA1((char *)passphrase,
pam_syslog(pamh, LOG_ERR, "pbkdf failed"); strlen(passphrase), ((uint8_t *)&salt),
pw_free(key); sizeof (uint64_t), iters, WRAPPING_KEY_LEN,
return (NULL); (uint8_t *)key->value) != 1)
errstr = "PBKDF2 failed";
break;
case ZFS_PASSPHRASE_KDF_ARGON2ID:
zfs_passphrase_kdf_argon2id_params_t params =
zfs_passphrase_kdf_argon2id_params(iters);
if (argon2_hash(params.t_cost, params.m_cost,
params.parallelism,
passphrase, strlen((char *)passphrase),
&salt, sizeof (uint64_t), (uint8_t *)key->value,
WRAPPING_KEY_LEN, NULL, 0, Argon2_id, ARGON2_VERSION_13)
!= ARGON2_OK)
errstr = "ARGON2ID13 failed";
break;
default:
errstr = "unknown KDF";
break;
} }
if (errstr)
goto err;
return (key); return (key);
err:
pam_syslog(pamh, LOG_ERR, "%s", errstr);
pw_free(key);
return (NULL);
} }
static int static int

View File

@ -836,8 +836,8 @@ def lzc_change_key(fsname, crypt_cmd, props=None, key=None):
supported values are "new_key", "inherit", "force_new_key" and supported values are "new_key", "inherit", "force_new_key" and
"force_inherit". "force_inherit".
:param props: a `dict` of encryption-related property name-value pairs; :param props: a `dict` of encryption-related property name-value pairs;
only "keyformat", "keylocation" and "pbkdf2iters" are supported only "keyformat", "keylocation", "passphrasepkdf", and "pbkdf2iters"
(empty by default). are supported (empty by default).
:type props: dict of bytes:Any :type props: dict of bytes:Any
:param key: dataset encryption key data (empty by default). :param key: dataset encryption key data (empty by default).
:type key: bytes :type key: bytes

View File

@ -28,8 +28,9 @@
/* /*
* ZAP entry keys for DSL Crypto Keys stored on disk. In addition, * ZAP entry keys for DSL Crypto Keys stored on disk. In addition,
* ZFS_PROP_KEYFORMAT, ZFS_PROP_PBKDF2_SALT, and ZFS_PROP_PBKDF2_ITERS are * ZFS_PROP_KEYFORMAT, ZFS_PROP_PBKDF2_SALT, ZFS_PROP_PBKDF2_ITERS,
* also maintained here using their respective property names. * and ZFS_PROP_PASSPHRASE_KDF are also maintained here using their
* respective property names.
*/ */
#define DSL_CRYPTO_KEY_CRYPTO_SUITE "DSL_CRYPTO_SUITE" #define DSL_CRYPTO_KEY_CRYPTO_SUITE "DSL_CRYPTO_SUITE"
#define DSL_CRYPTO_KEY_GUID "DSL_CRYPTO_GUID" #define DSL_CRYPTO_KEY_GUID "DSL_CRYPTO_GUID"
@ -52,10 +53,13 @@ typedef struct dsl_wrapping_key {
/* keyformat property enum */ /* keyformat property enum */
zfs_keyformat_t wk_keyformat; zfs_keyformat_t wk_keyformat;
/* the pbkdf2 salt, if the keyformat is of type passphrase */ /* the KDF to use, if the keyformat is of type passphrase */
zfs_passphrase_kdf_t wk_kdf;
/* the KDF salt, if the keyformat is of type passphrase */
uint64_t wk_salt; uint64_t wk_salt;
/* the pbkdf2 iterations, if the keyformat is of type passphrase */ /* the KDF iterations, if the keyformat is of type passphrase */
uint64_t wk_iters; uint64_t wk_iters;
/* actual wrapping key */ /* actual wrapping key */

View File

@ -193,6 +193,7 @@ typedef enum {
ZFS_PROP_SNAPSHOTS_CHANGED, ZFS_PROP_SNAPSHOTS_CHANGED,
ZFS_PROP_PREFETCH, ZFS_PROP_PREFETCH,
ZFS_PROP_VOLTHREADING, ZFS_PROP_VOLTHREADING,
ZFS_PROP_PASSPHRASE_KDF,
ZFS_NUM_PROPS ZFS_NUM_PROPS
} zfs_prop_t; } zfs_prop_t;
@ -541,6 +542,52 @@ typedef enum zfs_keyformat {
ZFS_KEYFORMAT_FORMATS ZFS_KEYFORMAT_FORMATS
} zfs_keyformat_t; } zfs_keyformat_t;
typedef enum zfs_passphrase_kdf {
ZFS_PASSPHRASE_KDF_PBKDF2 = 0,
ZFS_PASSPHRASE_KDF_ARGON2ID,
ZFS_PASSPHRASE_KDF_KDFS
} zfs_passphrase_kdf_t;
typedef struct zfs_passphrase_kdf_argon2id_params {
uint32_t t_cost;
uint32_t m_cost;
uint32_t parallelism;
} zfs_passphrase_kdf_argon2id_params_t;
static zfs_passphrase_kdf_argon2id_params_t
zfs_passphrase_kdf_argon2id_params(uint64_t iters)
{
struct zfs_passphrase_kdf_argon2id_params ret = {
.t_cost = (iters >> (16 * 2)) & 0xFFFF,
.m_cost = (iters >> (16 * 1)) & 0xFFFF,
.parallelism = (iters >> (16 * 0)) & 0xFFFF,
};
return (ret);
}
static boolean_t
zfs_passphrase_kdf_pbkdf2_min_validate(uint64_t iters)
{
return (iters >= 100000);
}
static boolean_t
zfs_passphrase_kdf_argon2id_min_validate(uint64_t iters)
{
zfs_passphrase_kdf_argon2id_params_t p =
zfs_passphrase_kdf_argon2id_params(iters);
return (!(iters & 0xFFFF000000000000ull) &&
p.t_cost >= 1 && p.m_cost >= 12 && p.parallelism >= 1);
}
static const uint64_t zfs_passphrase_kdf_default_parameters[
ZFS_PASSPHRASE_KDF_KDFS] = {350000, 0x000100110001ull /* m=17 */};
static boolean_t(*const zfs_passphrase_kdf_min_parameters[
ZFS_PASSPHRASE_KDF_KDFS])(uint64_t) = {
zfs_passphrase_kdf_pbkdf2_min_validate,
zfs_passphrase_kdf_argon2id_min_validate};
static const char * const zfs_passphrase_kdf_min_parameters_str[
ZFS_PASSPHRASE_KDF_KDFS] = {"100000", "0x0001000C0001"};
typedef enum zfs_key_location { typedef enum zfs_key_location {
ZFS_KEYLOCATION_NONE = 0, ZFS_KEYLOCATION_NONE = 0,
ZFS_KEYLOCATION_PROMPT, ZFS_KEYLOCATION_PROMPT,
@ -554,9 +601,6 @@ typedef enum {
ZFS_PREFETCH_ALL = 2 ZFS_PREFETCH_ALL = 2
} zfs_prefetch_type_t; } zfs_prefetch_type_t;
#define DEFAULT_PBKDF2_ITERATIONS 350000
#define MIN_PBKDF2_ITERATIONS 100000
/* /*
* On-disk version number. * On-disk version number.
*/ */

View File

@ -1847,7 +1847,8 @@
<enumerator name='ZFS_PROP_SNAPSHOTS_CHANGED' value='95'/> <enumerator name='ZFS_PROP_SNAPSHOTS_CHANGED' value='95'/>
<enumerator name='ZFS_PROP_PREFETCH' value='96'/> <enumerator name='ZFS_PROP_PREFETCH' value='96'/>
<enumerator name='ZFS_PROP_VOLTHREADING' value='97'/> <enumerator name='ZFS_PROP_VOLTHREADING' value='97'/>
<enumerator name='ZFS_NUM_PROPS' value='98'/> <enumerator name='ZFS_PROP_PASSPHRASE_KDF' value='98'/>
<enumerator name='ZFS_NUM_PROPS' value='99'/>
</enum-decl> </enum-decl>
<typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/> <typedef-decl name='zfs_prop_t' type-id='4b000d60' id='58603c44'/>
<enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'> <enum-decl name='zprop_source_t' naming-typedef-id='a2256d42' id='5903f80e'>

View File

@ -26,6 +26,7 @@
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <argon2.h>
#if LIBFETCH_DYNAMIC #if LIBFETCH_DYNAMIC
#include <dlfcn.h> #include <dlfcn.h>
#endif #endif
@ -774,12 +775,14 @@ error:
} }
static int static int
derive_key(libzfs_handle_t *hdl, zfs_keyformat_t format, uint64_t iters, derive_key(libzfs_handle_t *hdl, zfs_keyformat_t format,
uint8_t *key_material, uint64_t salt, zfs_passphrase_kdf_t kdf, uint64_t iters, uint8_t *key_material,
uint8_t **key_out) uint64_t salt, uint8_t **key_out)
{ {
int ret; int ret;
uint8_t *key; uint8_t *key;
boolean_t err;
zfs_passphrase_kdf_argon2id_params_t params;
*key_out = NULL; *key_out = NULL;
@ -801,10 +804,28 @@ derive_key(libzfs_handle_t *hdl, zfs_keyformat_t format, uint64_t iters,
case ZFS_KEYFORMAT_PASSPHRASE: case ZFS_KEYFORMAT_PASSPHRASE:
salt = LE_64(salt); salt = LE_64(salt);
ret = PKCS5_PBKDF2_HMAC_SHA1((char *)key_material, ret = 0;
strlen((char *)key_material), ((uint8_t *)&salt), switch (kdf) {
sizeof (uint64_t), iters, WRAPPING_KEY_LEN, key); case ZFS_PASSPHRASE_KDF_PBKDF2:
if (ret != 1) { err = PKCS5_PBKDF2_HMAC_SHA1((char *)key_material,
strlen((char *)key_material), ((uint8_t *)&salt),
sizeof (uint64_t), iters, WRAPPING_KEY_LEN, key)
!= 1;
break;
case ZFS_PASSPHRASE_KDF_ARGON2ID:
params = zfs_passphrase_kdf_argon2id_params(iters);
err = argon2_hash(params.t_cost, params.m_cost,
params.parallelism,
key_material, strlen((char *)key_material),
&salt, sizeof (uint64_t), key, WRAPPING_KEY_LEN,
NULL, 0, Argon2_id, ARGON2_VERSION_13)
!= ARGON2_OK;
break;
default:
ret = EINVAL;
goto error;
}
if (err) {
ret = EIO; ret = EIO;
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"Failed to generate key from passphrase.")); "Failed to generate key from passphrase."));
@ -850,8 +871,8 @@ encryption_feature_is_enabled(zpool_handle_t *zph)
static int static int
populate_create_encryption_params_nvlists(libzfs_handle_t *hdl, populate_create_encryption_params_nvlists(libzfs_handle_t *hdl,
zfs_handle_t *zhp, boolean_t newkey, zfs_keyformat_t keyformat, zfs_handle_t *zhp, boolean_t newkey, zfs_keyformat_t keyformat,
const char *keylocation, nvlist_t *props, uint8_t **wkeydata, const char *keylocation, zfs_passphrase_kdf_t kdf, nvlist_t *props,
uint_t *wkeylen) uint8_t **wkeydata, uint_t *wkeylen)
{ {
int ret; int ret;
uint64_t iters = 0, salt = 0; uint64_t iters = 0, salt = 0;
@ -893,7 +914,7 @@ populate_create_encryption_params_nvlists(libzfs_handle_t *hdl,
ret = nvlist_lookup_uint64(props, ret = nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &iters); zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &iters);
if (ret == ENOENT) { if (ret == ENOENT) {
iters = DEFAULT_PBKDF2_ITERATIONS; iters = zfs_passphrase_kdf_default_parameters[kdf];
ret = nvlist_add_uint64(props, ret = nvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), iters); zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), iters);
if (ret != 0) if (ret != 0)
@ -917,7 +938,8 @@ populate_create_encryption_params_nvlists(libzfs_handle_t *hdl,
} }
/* derive a key from the key material */ /* derive a key from the key material */
ret = derive_key(hdl, keyformat, iters, key_material, salt, &key_data); ret = derive_key(hdl, keyformat, kdf, iters, key_material, salt,
&key_data);
if (ret != 0) if (ret != 0)
goto error; goto error;
@ -955,15 +977,14 @@ proplist_has_encryption_props(nvlist_t *props)
if (ret == 0 && strcmp(strval, "none") != 0) if (ret == 0 && strcmp(strval, "none") != 0)
return (B_TRUE); return (B_TRUE);
ret = nvlist_lookup_uint64(props, zfs_prop_t exist_props[] = {
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &intval); ZFS_PROP_KEYFORMAT, ZFS_PROP_PASSPHRASE_KDF, ZFS_PROP_PBKDF2_ITERS};
if (ret == 0) for (size_t i = 0; i < ARRAY_SIZE(exist_props); ++i) {
return (B_TRUE); ret = nvlist_lookup_uint64(props,
zfs_prop_to_name(exist_props[i]), &intval);
ret = nvlist_lookup_uint64(props, if (ret == 0)
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), &intval); return (B_TRUE);
if (ret == 0) }
return (B_TRUE);
return (B_FALSE); return (B_FALSE);
} }
@ -1008,6 +1029,7 @@ zfs_crypto_create(libzfs_handle_t *hdl, char *parent_name, nvlist_t *props,
char errbuf[ERRBUFLEN]; char errbuf[ERRBUFLEN];
uint64_t crypt = ZIO_CRYPT_INHERIT, pcrypt = ZIO_CRYPT_INHERIT; uint64_t crypt = ZIO_CRYPT_INHERIT, pcrypt = ZIO_CRYPT_INHERIT;
uint64_t keyformat = ZFS_KEYFORMAT_NONE; uint64_t keyformat = ZFS_KEYFORMAT_NONE;
uint64_t kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
const char *keylocation = NULL; const char *keylocation = NULL;
zfs_handle_t *pzhp = NULL; zfs_handle_t *pzhp = NULL;
uint8_t *wkeydata = NULL; uint8_t *wkeydata = NULL;
@ -1026,6 +1048,8 @@ zfs_crypto_create(libzfs_handle_t *hdl, char *parent_name, nvlist_t *props,
/* lookup key location and format from props */ /* lookup key location and format from props */
(void) nvlist_lookup_uint64(props, (void) nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat); zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat);
(void) nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), &kdf);
(void) nvlist_lookup_string(props, (void) nvlist_lookup_string(props,
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation); zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);
@ -1147,7 +1171,7 @@ zfs_crypto_create(libzfs_handle_t *hdl, char *parent_name, nvlist_t *props,
} }
ret = populate_create_encryption_params_nvlists(hdl, NULL, ret = populate_create_encryption_params_nvlists(hdl, NULL,
B_TRUE, keyformat, keylocation, props, &wkeydata, B_TRUE, keyformat, keylocation, kdf, props, &wkeydata,
&wkeylen); &wkeylen);
if (ret != 0) if (ret != 0)
goto out; goto out;
@ -1186,6 +1210,7 @@ zfs_crypto_clone_check(libzfs_handle_t *hdl, zfs_handle_t *origin_zhp,
* inherited from the origin dataset. * inherited from the origin dataset.
*/ */
if (nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYFORMAT)) || if (nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYFORMAT)) ||
nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF)) ||
nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION)) || nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_KEYLOCATION)) ||
nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION)) || nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION)) ||
nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS))) { nvlist_exists(props, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS))) {
@ -1280,6 +1305,7 @@ zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop,
int ret, attempts = 0; int ret, attempts = 0;
char errbuf[ERRBUFLEN]; char errbuf[ERRBUFLEN];
uint64_t keystatus, iters = 0, salt = 0; uint64_t keystatus, iters = 0, salt = 0;
uint64_t kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
uint64_t keyformat = ZFS_KEYFORMAT_NONE; uint64_t keyformat = ZFS_KEYFORMAT_NONE;
char prop_keylocation[MAXNAMELEN]; char prop_keylocation[MAXNAMELEN];
char prop_encroot[MAXNAMELEN]; char prop_encroot[MAXNAMELEN];
@ -1356,8 +1382,9 @@ zfs_crypto_load_key(zfs_handle_t *zhp, boolean_t noop,
} }
} }
/* passphrase formats require a salt and pbkdf2_iters property */ /* passphrase formats require a kdf, salt, and pbkdf2_iters property */
if (keyformat == ZFS_KEYFORMAT_PASSPHRASE) { if (keyformat == ZFS_KEYFORMAT_PASSPHRASE) {
kdf = zfs_prop_get_int(zhp, ZFS_PROP_PASSPHRASE_KDF);
salt = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_SALT); salt = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_SALT);
iters = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_ITERS); iters = zfs_prop_get_int(zhp, ZFS_PROP_PBKDF2_ITERS);
} }
@ -1374,8 +1401,8 @@ try_again:
goto error; goto error;
/* derive a key from the key material */ /* derive a key from the key material */
ret = derive_key(zhp->zfs_hdl, keyformat, iters, key_material, salt, ret = derive_key(zhp->zfs_hdl, keyformat, kdf, iters, key_material,
&key_data); salt, &key_data);
if (ret != 0) if (ret != 0)
goto error; goto error;
@ -1556,12 +1583,13 @@ zfs_crypto_verify_rewrap_nvlist(zfs_handle_t *zhp, nvlist_t *props,
case ZFS_PROP_PBKDF2_ITERS: case ZFS_PROP_PBKDF2_ITERS:
case ZFS_PROP_KEYFORMAT: case ZFS_PROP_KEYFORMAT:
case ZFS_PROP_KEYLOCATION: case ZFS_PROP_KEYLOCATION:
case ZFS_PROP_PASSPHRASE_KDF:
break; break;
default: default:
ret = EINVAL; ret = EINVAL;
zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN, zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
"Only keyformat, keylocation and pbkdf2iters may " "Only keyformat, keylocation, passphrasekdf and "
"be set with this command.")); "pbkdf2iters may be set with this command."));
goto error; goto error;
} }
} }
@ -1588,13 +1616,14 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
{ {
int ret; int ret;
char errbuf[ERRBUFLEN]; char errbuf[ERRBUFLEN];
boolean_t is_encroot; boolean_t is_encroot, explicit_kdf;
nvlist_t *props = NULL; nvlist_t *props = NULL;
uint8_t *wkeydata = NULL; uint8_t *wkeydata = NULL;
uint_t wkeylen = 0; uint_t wkeylen = 0;
dcp_cmd_t cmd = (inheritkey) ? DCP_CMD_INHERIT : DCP_CMD_NEW_KEY; dcp_cmd_t cmd = (inheritkey) ? DCP_CMD_INHERIT : DCP_CMD_NEW_KEY;
uint64_t crypt, pcrypt, keystatus, pkeystatus; uint64_t crypt, pcrypt, keystatus, pkeystatus;
uint64_t keyformat = ZFS_KEYFORMAT_NONE; uint64_t keyformat = ZFS_KEYFORMAT_NONE;
uint64_t kdf;
zfs_handle_t *pzhp = NULL; zfs_handle_t *pzhp = NULL;
const char *keylocation = NULL; const char *keylocation = NULL;
char origin_name[MAXNAMELEN]; char origin_name[MAXNAMELEN];
@ -1659,6 +1688,8 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat); zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat);
(void) nvlist_lookup_string(props, (void) nvlist_lookup_string(props,
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation); zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);
explicit_kdf = nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), &kdf) == 0;
if (is_encroot) { if (is_encroot) {
/* /*
@ -1694,6 +1725,21 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
keylocation = prop_keylocation; keylocation = prop_keylocation;
} }
if (!explicit_kdf) {
kdf = zfs_prop_get_int(zhp,
ZFS_PROP_PASSPHRASE_KDF);
ret = nvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF),
kdf);
if (ret != 0) {
zfs_error_aux(zhp->zfs_hdl,
dgettext(TEXT_DOMAIN, "Failed to "
"get existing passphrasekdf "
"property."));
goto error;
}
}
} else { } else {
/* need a new key for non-encryption roots */ /* need a new key for non-encryption roots */
if (keyformat == ZFS_KEYFORMAT_NONE) { if (keyformat == ZFS_KEYFORMAT_NONE) {
@ -1713,11 +1759,13 @@ zfs_crypto_rewrap(zfs_handle_t *zhp, nvlist_t *raw_props, boolean_t inheritkey)
if (ret != 0) if (ret != 0)
goto error; goto error;
} }
kdf = zfs_prop_get_int(zhp, ZFS_PROP_PASSPHRASE_KDF);
} }
/* fetch the new wrapping key and associated properties */ /* fetch the new wrapping key and associated properties */
ret = populate_create_encryption_params_nvlists(zhp->zfs_hdl, ret = populate_create_encryption_params_nvlists(zhp->zfs_hdl,
zhp, B_TRUE, keyformat, keylocation, props, &wkeydata, zhp, B_TRUE, keyformat, keylocation, kdf, props, &wkeydata,
&wkeylen); &wkeylen);
if (ret != 0) if (ret != 0)
goto error; goto error;

View File

@ -1039,6 +1039,9 @@ zfs_valid_proplist(libzfs_handle_t *hdl, zfs_type_t type, nvlist_t *nvl,
int chosen_normal = -1; int chosen_normal = -1;
int chosen_utf = -1; int chosen_utf = -1;
int set_maxbs = 0; int set_maxbs = 0;
zfs_passphrase_kdf_t chosen_kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
uint64_t chosen_iters;
boolean_t have_chosen_iters = B_FALSE;
if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) { if (nvlist_alloc(&ret, NV_UNIQUE_NAME, 0) != 0) {
(void) no_memory(hdl); (void) no_memory(hdl);
@ -1507,14 +1510,13 @@ badlabel:
} }
break; break;
case ZFS_PROP_PASSPHRASE_KDF:
chosen_kdf = intval;
break;
case ZFS_PROP_PBKDF2_ITERS: case ZFS_PROP_PBKDF2_ITERS:
if (intval < MIN_PBKDF2_ITERATIONS) { chosen_iters = intval;
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, have_chosen_iters = B_TRUE;
"minimum pbkdf2 iterations is %u"),
MIN_PBKDF2_ITERATIONS);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
break; break;
case ZFS_PROP_UTF8ONLY: case ZFS_PROP_UTF8ONLY:
@ -1589,6 +1591,15 @@ badlabel:
} }
} }
if (have_chosen_iters &&
!zfs_passphrase_kdf_min_parameters[chosen_kdf](chosen_iters)) {
zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
"minimum KDF iterations is %s"),
zfs_passphrase_kdf_min_parameters_str[chosen_kdf]);
(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
goto error;
}
/* /*
* If normalization was chosen, but no UTF8 choice was made, * If normalization was chosen, but no UTF8 choice was made,
* enforce rejection of non-UTF8 names. * enforce rejection of non-UTF8 names.

View File

@ -38,7 +38,7 @@
.\" 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.
.\" .\"
.Dd August 8, 2023 .Dd February 8, 2024
.Dt ZFSPROPS 7 .Dt ZFSPROPS 7
.Os .Os
. .
@ -1110,7 +1110,7 @@ A raw key can be generated with the following command:
.Dl # Nm dd Sy if=/dev/urandom bs=32 count=1 Sy of= Ns Pa /path/to/output/key .Dl # Nm dd Sy if=/dev/urandom bs=32 count=1 Sy of= Ns Pa /path/to/output/key
.Pp .Pp
Passphrases must be between 8 and 512 bytes long and will be processed through Passphrases must be between 8 and 512 bytes long and will be processed through
PBKDF2 before being used (see the a KDF before being used (see the
.Sy pbkdf2iters .Sy pbkdf2iters
property). property).
Even though the encryption suite cannot be changed after dataset creation, Even though the encryption suite cannot be changed after dataset creation,
@ -1163,14 +1163,27 @@ and
.Sy SSL_CLIENT_KEY_FILE .Sy SSL_CLIENT_KEY_FILE
environment variables can be set to configure the path environment variables can be set to configure the path
to the client certificate and its key. to the client certificate and its key.
.It Sy pbkdf2iters Ns = Ns Ar iterations .It Sy passphrasekdf Ns = Ns Sy pbkdf2 Ns | Ns Sy argon2id
Controls the number of PBKDF2 iterations that a If keyformat is
.Sy passphrase ,
this variable governs which key derivation function will be used (see below).
The default value is
.Sy pbkdf2
(PBKDF2).
Datasets using
.Sy argon2id
(Argon2id version 13)
cannot be unlocked with OpenZFS <2.2.3.
This property may be changed with
.Nm zfs Cm change-key .
.It Sy pbkdf2iters Ns = Ns Ar parameters Pq Sy kdfparams Ns = Ns Ar parameters
Controls KDF parameters that a
.Sy passphrase .Sy passphrase
encryption key should be run through when processing it into an encryption key. encryption key should be run through when processing it into an encryption key.
This property is only defined when encryption is enabled and a keyformat of This property is only defined when encryption is enabled and a keyformat of
.Sy passphrase .Sy passphrase
is selected. is selected.
The goal of PBKDF2 is to significantly increase the The goal of a KDF is to significantly increase the
computational difficulty needed to brute force a user's passphrase. computational difficulty needed to brute force a user's passphrase.
This is accomplished by forcing the attacker to run each passphrase through a This is accomplished by forcing the attacker to run each passphrase through a
computationally expensive hashing function many times before they arrive at the computationally expensive hashing function many times before they arrive at the
@ -1178,12 +1191,24 @@ resulting key.
A user who actually knows the passphrase will only have to pay this cost once. A user who actually knows the passphrase will only have to pay this cost once.
As CPUs become better at processing, this number should be As CPUs become better at processing, this number should be
raised to ensure that a brute force attack is still not possible. raised to ensure that a brute force attack is still not possible.
The current default is
.Sy 350000
and the minimum is
.Sy 100000 .
This property may be changed with This property may be changed with
.Nm zfs Cm change-key . .Nm zfs Cm change-key .
.Pp
For PBKDF2, the only parameter is the iteration count (default
.Sy 350000 ,
minimum
.Sy 10000 ) .
.br
For Argon2id, this parameter is a bitfield of three 16-bit integers:
the most significant is the iteration count,
then the memory cost (log2 kilobytes),
and the least significant is the parallelism.
The default is
.Sy 0x000100110001
.Pq Va t Ns = Ns Sy 1 , Va m Ns = Ns Sy 17 Po 128M Pc , Va p Ns = Ns Sy 1 ,
the minimum \(en
.Sy 0x0001000C0001
.Pq Va t Ns = Ns Sy 1 , Va m Ns = Ns Sy 12 Po 4M Pc , Va p Ns = Ns Sy 1 .
.It Sy exec Ns = Ns Sy on Ns | Ns Sy off .It Sy exec Ns = Ns Sy on Ns | Ns Sy off
Controls whether processes can be executed from within this file system. Controls whether processes can be executed from within this file system.
The default value is The default value is
@ -1267,10 +1292,10 @@ location.
When the When the
.Sy mountpoint .Sy mountpoint
property is set with property is set with
.Nm zfs Cm set Fl u .Nm zfs Cm set Fl u ,
, the the
.Sy mountpoint .Sy mountpoint
property is updated but dataset is not mounted or unmounted and remains property is updated but the dataset is neither mounted nor unmounted and remains
as it was before. as it was before.
.It Sy nbmand Ns = Ns Sy on Ns | Ns Sy off .It Sy nbmand Ns = Ns Sy on Ns | Ns Sy off
Controls whether the file system should be mounted with Controls whether the file system should be mounted with

View File

@ -29,7 +29,7 @@
.\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2018 Nexenta Systems, Inc.
.\" Copyright 2019 Joyent, Inc. .\" Copyright 2019 Joyent, Inc.
.\" .\"
.Dd March 16, 2022 .Dd December 17, 2023
.Dt ZFS-ALLOW 8 .Dt ZFS-ALLOW 8
.Os .Os
. .
@ -249,6 +249,7 @@ filesystem_limit property
fscontext property fscontext property
keyformat property keyformat property
keylocation property keylocation property
passphrasekdf property
logbias property logbias property
mlslabel property mlslabel property
mountpoint property mountpoint property

View File

@ -29,7 +29,7 @@
.\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2018 Nexenta Systems, Inc.
.\" Copyright 2019 Joyent, Inc. .\" Copyright 2019 Joyent, Inc.
.\" .\"
.Dd January 13, 2020 .Dd December 17, 2023
.Dt ZFS-LOAD-KEY 8 .Dt ZFS-LOAD-KEY 8
.Os .Os
. .
@ -51,6 +51,7 @@
.Op Fl l .Op Fl l
.Op Fl o Ar keylocation Ns = Ns Ar value .Op Fl o Ar keylocation Ns = Ns Ar value
.Op Fl o Ar keyformat Ns = Ns Ar value .Op Fl o Ar keyformat Ns = Ns Ar value
.Op Fl o Ar passphrasekdf Ns = Ns Ar value
.Op Fl o Ar pbkdf2iters Ns = Ns Ar value .Op Fl o Ar pbkdf2iters Ns = Ns Ar value
.Ar filesystem .Ar filesystem
.Nm zfs .Nm zfs
@ -83,6 +84,9 @@ Note that if the
is set to is set to
.Sy prompt .Sy prompt
the terminal will interactively wait for the key to be entered. the terminal will interactively wait for the key to be entered.
If
.Sy passphrasekdf
isn't specified, the current value is preserved.
Loading a key will not automatically mount the dataset. Loading a key will not automatically mount the dataset.
If that functionality is desired, If that functionality is desired,
.Nm zfs Cm mount Fl l .Nm zfs Cm mount Fl l
@ -152,6 +156,7 @@ Unloads the keys for all encryption roots in all imported pools.
.Op Fl l .Op Fl l
.Op Fl o Ar keylocation Ns = Ns Ar value .Op Fl o Ar keylocation Ns = Ns Ar value
.Op Fl o Ar keyformat Ns = Ns Ar value .Op Fl o Ar keyformat Ns = Ns Ar value
.Op Fl o Ar passphrasekdf Ns = Ns Ar value
.Op Fl o Ar pbkdf2iters Ns = Ns Ar value .Op Fl o Ar pbkdf2iters Ns = Ns Ar value
.Ar filesystem .Ar filesystem
.Xc .Xc
@ -167,6 +172,7 @@ This command requires that the existing key for the dataset is already loaded.
This command may also be used to change the This command may also be used to change the
.Sy keylocation , .Sy keylocation ,
.Sy keyformat , .Sy keyformat ,
.Sy passphrasekdf ,
and and
.Sy pbkdf2iters .Sy pbkdf2iters
properties as needed. properties as needed.
@ -204,10 +210,11 @@ This is effectively equivalent to running
.Nm zfs Cm load-key Ar filesystem ; Nm zfs Cm change-key Ar filesystem .Nm zfs Cm load-key Ar filesystem ; Nm zfs Cm change-key Ar filesystem
.It Fl o Ar property Ns = Ns Ar value .It Fl o Ar property Ns = Ns Ar value
Allows the user to set encryption key properties Allows the user to set encryption key properties
.Pq Sy keyformat , keylocation , No and Sy pbkdf2iters .Pq Sy keyformat , keylocation , passphrasekdf , No and Sy pbkdf2iters
while changing the key. while changing the key.
This is the only way to alter This is the only way to alter
.Sy keyformat .Sy keyformat ,
.Sy passphrasekdf ,
and and
.Sy pbkdf2iters .Sy pbkdf2iters
after the dataset has been created. after the dataset has been created.
@ -244,7 +251,7 @@ subcommand for more info on key loading).
Creating an encrypted dataset requires specifying the Creating an encrypted dataset requires specifying the
.Sy encryption No and Sy keyformat .Sy encryption No and Sy keyformat
properties at creation time, along with an optional properties at creation time, along with an optional
.Sy keylocation No and Sy pbkdf2iters . .Sy keylocation , passphrasekdf , No and Sy pbkdf2iters .
After entering an encryption key, the After entering an encryption key, the
created dataset will become an encryption root. created dataset will become an encryption root.
Any descendant datasets will Any descendant datasets will
@ -265,7 +272,7 @@ property alone does not create a new encryption root; this would simply use a
different cipher suite with the same key as its encryption root. different cipher suite with the same key as its encryption root.
The one exception is that clones will always use their origin's encryption key. The one exception is that clones will always use their origin's encryption key.
As a result of this exception, some encryption-related properties As a result of this exception, some encryption-related properties
.Pq namely Sy keystatus , keyformat , keylocation , No and Sy pbkdf2iters .Pq namely Sy keystatus , keyformat , passphrasekdf , keylocation , No and Sy pbkdf2iters
do not inherit like other ZFS properties and instead use the value determined do not inherit like other ZFS properties and instead use the value determined
by their encryption root. by their encryption root.
Encryption root inheritance can be tracked via the read-only Encryption root inheritance can be tracked via the read-only

View File

@ -234,6 +234,12 @@ zfs_prop_init(void)
{ NULL } { NULL }
}; };
static const zprop_index_t passphrase_kdf_table[] = {
{ "pbkdf2", ZFS_PASSPHRASE_KDF_PBKDF2 },
{ "argon2id", ZFS_PASSPHRASE_KDF_ARGON2ID },
{ NULL }
};
static const zprop_index_t snapdir_table[] = { static const zprop_index_t snapdir_table[] = {
{ "hidden", ZFS_SNAPDIR_HIDDEN }, { "hidden", ZFS_SNAPDIR_HIDDEN },
{ "visible", ZFS_SNAPDIR_VISIBLE }, { "visible", ZFS_SNAPDIR_VISIBLE },
@ -554,6 +560,11 @@ zfs_prop_init(void)
"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", "ENCRYPTION",
crypto_table, sfeatures); crypto_table, sfeatures);
zprop_register_index(ZFS_PROP_PASSPHRASE_KDF, "passphrasekdf",
ZFS_PASSPHRASE_KDF_PBKDF2, PROP_ONETIME_DEFAULT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"pbkdf2 | argon2id", "KDF", passphrase_kdf_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,
@ -668,7 +679,7 @@ zfs_prop_init(void)
B_TRUE, sfeatures); B_TRUE, sfeatures);
zprop_register_number(ZFS_PROP_PBKDF2_ITERS, "pbkdf2iters", zprop_register_number(ZFS_PROP_PBKDF2_ITERS, "pbkdf2iters",
0, PROP_ONETIME_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, 0, PROP_ONETIME_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
"<iters>", "PBKDF2ITERS", B_TRUE, sfeatures); "<iters>", "KDFPARAMS", B_TRUE, sfeatures);
zprop_register_number(ZFS_PROP_OBJSETID, "objsetid", 0, zprop_register_number(ZFS_PROP_OBJSETID, "objsetid", 0,
PROP_READONLY, ZFS_TYPE_DATASET, "<uint64>", "OBJSETID", B_TRUE, PROP_READONLY, ZFS_TYPE_DATASET, "<uint64>", "OBJSETID", B_TRUE,
sfeatures); sfeatures);
@ -838,10 +849,10 @@ zfs_prop_userquota(const char *name)
boolean_t boolean_t
zfs_prop_written(const char *name) zfs_prop_written(const char *name)
{ {
static const char *prop_prefix = "written@"; static const char prop_prefix[] = "written@";
static const char *book_prefix = "written#"; static const char book_prefix[] = "written#";
return (strncmp(name, prop_prefix, strlen(prop_prefix)) == 0 || return (strncmp(name, prop_prefix, sizeof (prop_prefix) - 1) == 0 ||
strncmp(name, book_prefix, strlen(book_prefix)) == 0); strncmp(name, book_prefix, sizeof (book_prefix) - 1) == 0);
} }
/* /*
@ -972,7 +983,7 @@ zfs_prop_encryption_key_param(zfs_prop_t prop)
* changed at will without needing the master keys. * changed at will without needing the master keys.
*/ */
return (prop == ZFS_PROP_PBKDF2_SALT || prop == ZFS_PROP_PBKDF2_ITERS || return (prop == ZFS_PROP_PBKDF2_SALT || prop == ZFS_PROP_PBKDF2_ITERS ||
prop == ZFS_PROP_KEYFORMAT); prop == ZFS_PROP_KEYFORMAT || prop == ZFS_PROP_PASSPHRASE_KDF);
} }
/* /*

View File

@ -109,7 +109,8 @@ dsl_wrapping_key_free(dsl_wrapping_key_t *wkey)
static void static void
dsl_wrapping_key_create(uint8_t *wkeydata, zfs_keyformat_t keyformat, dsl_wrapping_key_create(uint8_t *wkeydata, zfs_keyformat_t keyformat,
uint64_t salt, uint64_t iters, dsl_wrapping_key_t **wkey_out) zfs_passphrase_kdf_t kdf, uint64_t salt, uint64_t iters,
dsl_wrapping_key_t **wkey_out)
{ {
dsl_wrapping_key_t *wkey; dsl_wrapping_key_t *wkey;
@ -125,6 +126,7 @@ dsl_wrapping_key_create(uint8_t *wkeydata, zfs_keyformat_t keyformat,
/* initialize the rest of the struct */ /* initialize the rest of the struct */
zfs_refcount_create(&wkey->wk_refcnt); zfs_refcount_create(&wkey->wk_refcnt);
wkey->wk_keyformat = keyformat; wkey->wk_keyformat = keyformat;
wkey->wk_kdf = kdf;
wkey->wk_salt = salt; wkey->wk_salt = salt;
wkey->wk_iters = iters; wkey->wk_iters = iters;
@ -138,6 +140,7 @@ dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
int ret; int ret;
uint64_t crypt = ZIO_CRYPT_INHERIT; uint64_t crypt = ZIO_CRYPT_INHERIT;
uint64_t keyformat = ZFS_KEYFORMAT_NONE; uint64_t keyformat = ZFS_KEYFORMAT_NONE;
uint64_t kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
uint64_t salt = 0, iters = 0; uint64_t salt = 0, iters = 0;
dsl_crypto_params_t *dcp = NULL; dsl_crypto_params_t *dcp = NULL;
dsl_wrapping_key_t *wkey = NULL; dsl_wrapping_key_t *wkey = NULL;
@ -156,6 +159,8 @@ dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat); zfs_prop_to_name(ZFS_PROP_KEYFORMAT), &keyformat);
(void) nvlist_lookup_string(props, (void) nvlist_lookup_string(props,
zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation); zfs_prop_to_name(ZFS_PROP_KEYLOCATION), &keylocation);
(void) nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), &kdf);
(void) nvlist_lookup_uint64(props, (void) nvlist_lookup_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), &salt); zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), &salt);
(void) nvlist_lookup_uint64(props, (void) nvlist_lookup_uint64(props,
@ -191,6 +196,12 @@ dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
goto error; goto error;
} }
/* check for valid kdf */
if (kdf >= ZFS_PASSPHRASE_KDF_KDFS) {
ret = SET_ERROR(EINVAL);
goto error;
}
/* check for a valid keylocation (of any kind) and copy it in */ /* check for a valid keylocation (of any kind) and copy it in */
if (keylocation != NULL) { if (keylocation != NULL) {
if (!zfs_prop_valid_keylocation(keylocation, B_FALSE)) { if (!zfs_prop_valid_keylocation(keylocation, B_FALSE)) {
@ -214,7 +225,7 @@ dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
/* create the wrapping key from the raw data */ /* create the wrapping key from the raw data */
if (wkeydata != NULL) { if (wkeydata != NULL) {
/* create the wrapping key with the verified parameters */ /* create the wrapping key with the verified parameters */
dsl_wrapping_key_create(wkeydata, keyformat, salt, dsl_wrapping_key_create(wkeydata, keyformat, kdf, salt,
iters, &wkey); iters, &wkey);
dcp->cp_wkey = wkey; dcp->cp_wkey = wkey;
} }
@ -225,6 +236,8 @@ dsl_crypto_params_create_nvlist(dcp_cmd_t cmd, nvlist_t *props,
*/ */
(void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION)); (void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_ENCRYPTION));
(void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_KEYFORMAT)); (void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_KEYFORMAT));
(void) nvlist_remove_all(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF));
(void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT)); (void) nvlist_remove_all(props, zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT));
(void) nvlist_remove_all(props, (void) nvlist_remove_all(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS)); zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS));
@ -776,7 +789,7 @@ spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp,
dsl_crypto_key_t *dck = NULL; dsl_crypto_key_t *dck = NULL;
dsl_wrapping_key_t *wkey = dcp->cp_wkey; dsl_wrapping_key_t *wkey = dcp->cp_wkey;
dsl_pool_t *dp = NULL; dsl_pool_t *dp = NULL;
uint64_t rddobj, keyformat, salt, iters; uint64_t rddobj, keyformat, kdf, salt, iters;
/* /*
* We don't validate the wrapping key's keyformat, salt, or iters * We don't validate the wrapping key's keyformat, salt, or iters
@ -826,6 +839,13 @@ spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp,
if (ret != 0) if (ret != 0)
goto error; goto error;
ret = zap_lookup(dp->dp_meta_objset, dd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), 8, 1, &kdf);
if (ret == ENOENT)
kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
else if (ret != 0)
goto error;
ret = zap_lookup(dp->dp_meta_objset, dd->dd_crypto_obj, ret = zap_lookup(dp->dp_meta_objset, dd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 8, 1, &salt); zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 8, 1, &salt);
if (ret != 0) if (ret != 0)
@ -838,6 +858,7 @@ spa_keystore_load_wkey(const char *dsname, dsl_crypto_params_t *dcp,
ASSERT3U(keyformat, <, ZFS_KEYFORMAT_FORMATS); ASSERT3U(keyformat, <, ZFS_KEYFORMAT_FORMATS);
ASSERT3U(keyformat, !=, ZFS_KEYFORMAT_NONE); ASSERT3U(keyformat, !=, ZFS_KEYFORMAT_NONE);
ASSERT3U(kdf, <, ZFS_PASSPHRASE_KDF_KDFS);
IMPLY(keyformat == ZFS_KEYFORMAT_PASSPHRASE, iters != 0); IMPLY(keyformat == ZFS_KEYFORMAT_PASSPHRASE, iters != 0);
IMPLY(keyformat == ZFS_KEYFORMAT_PASSPHRASE, salt != 0); IMPLY(keyformat == ZFS_KEYFORMAT_PASSPHRASE, salt != 0);
IMPLY(keyformat != ZFS_KEYFORMAT_PASSPHRASE, iters == 0); IMPLY(keyformat != ZFS_KEYFORMAT_PASSPHRASE, iters == 0);
@ -1204,7 +1225,7 @@ static void
dsl_crypto_key_sync_impl(objset_t *mos, uint64_t dckobj, uint64_t crypt, dsl_crypto_key_sync_impl(objset_t *mos, uint64_t dckobj, uint64_t crypt,
uint64_t root_ddobj, uint64_t guid, uint8_t *iv, uint8_t *mac, uint64_t root_ddobj, uint64_t guid, uint8_t *iv, uint8_t *mac,
uint8_t *keydata, uint8_t *hmac_keydata, uint64_t keyformat, uint8_t *keydata, uint8_t *hmac_keydata, uint64_t keyformat,
uint64_t salt, uint64_t iters, dmu_tx_t *tx) uint64_t kdf, uint64_t salt, uint64_t iters, dmu_tx_t *tx)
{ {
VERIFY0(zap_update(mos, dckobj, DSL_CRYPTO_KEY_CRYPTO_SUITE, 8, 1, VERIFY0(zap_update(mos, dckobj, DSL_CRYPTO_KEY_CRYPTO_SUITE, 8, 1,
&crypt, tx)); &crypt, tx));
@ -1222,6 +1243,9 @@ dsl_crypto_key_sync_impl(objset_t *mos, uint64_t dckobj, uint64_t crypt,
SHA512_HMAC_KEYLEN, hmac_keydata, tx)); SHA512_HMAC_KEYLEN, hmac_keydata, tx));
VERIFY0(zap_update(mos, dckobj, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), VERIFY0(zap_update(mos, dckobj, zfs_prop_to_name(ZFS_PROP_KEYFORMAT),
8, 1, &keyformat, tx)); 8, 1, &keyformat, tx));
VERIFY0(zap_update(mos, dckobj,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF),
8, 1, &kdf, tx));
VERIFY0(zap_update(mos, dckobj, zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), VERIFY0(zap_update(mos, dckobj, zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT),
8, 1, &salt, tx)); 8, 1, &salt, tx));
VERIFY0(zap_update(mos, dckobj, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), VERIFY0(zap_update(mos, dckobj, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS),
@ -1248,8 +1272,8 @@ dsl_crypto_key_sync(dsl_crypto_key_t *dck, dmu_tx_t *tx)
/* update the ZAP with the obtained values */ /* update the ZAP with the obtained values */
dsl_crypto_key_sync_impl(tx->tx_pool->dp_meta_objset, dck->dck_obj, dsl_crypto_key_sync_impl(tx->tx_pool->dp_meta_objset, dck->dck_obj,
key->zk_crypt, wkey->wk_ddobj, key->zk_guid, iv, mac, keydata, key->zk_crypt, wkey->wk_ddobj, key->zk_guid, iv, mac, keydata,
hmac_keydata, wkey->wk_keyformat, wkey->wk_salt, wkey->wk_iters, hmac_keydata, wkey->wk_keyformat, wkey->wk_kdf, wkey->wk_salt,
tx); wkey->wk_iters, tx);
} }
typedef struct spa_keystore_change_key_args { typedef struct spa_keystore_change_key_args {
@ -1403,7 +1427,8 @@ spa_keystore_change_key_check(void *arg, dmu_tx_t *tx)
/* passphrases require pbkdf2 salt and iters */ /* passphrases require pbkdf2 salt and iters */
if (dcp->cp_wkey->wk_keyformat == ZFS_KEYFORMAT_PASSPHRASE) { if (dcp->cp_wkey->wk_keyformat == ZFS_KEYFORMAT_PASSPHRASE) {
if (dcp->cp_wkey->wk_salt == 0 || if (dcp->cp_wkey->wk_salt == 0 ||
dcp->cp_wkey->wk_iters < MIN_PBKDF2_ITERATIONS) { !zfs_passphrase_kdf_min_parameters[
dcp->cp_wkey->wk_kdf](dcp->cp_wkey->wk_iters)) {
ret = SET_ERROR(EINVAL); ret = SET_ERROR(EINVAL);
goto error; goto error;
} }
@ -1889,7 +1914,8 @@ dmu_objset_create_crypt_check(dsl_dir_t *parentdd, dsl_crypto_params_t *dcp,
case ZFS_KEYFORMAT_PASSPHRASE: case ZFS_KEYFORMAT_PASSPHRASE:
/* requires pbkdf2 iters and salt */ /* requires pbkdf2 iters and salt */
if (dcp->cp_wkey->wk_salt == 0 || if (dcp->cp_wkey->wk_salt == 0 ||
dcp->cp_wkey->wk_iters < MIN_PBKDF2_ITERATIONS) !zfs_passphrase_kdf_min_parameters[
dcp->cp_wkey->wk_kdf](dcp->cp_wkey->wk_iters))
return (SET_ERROR(EINVAL)); return (SET_ERROR(EINVAL));
break; break;
case ZFS_KEYFORMAT_NONE: case ZFS_KEYFORMAT_NONE:
@ -2244,6 +2270,13 @@ dsl_crypto_recv_raw_key_check(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
is_passphrase = (intval == ZFS_KEYFORMAT_PASSPHRASE); is_passphrase = (intval == ZFS_KEYFORMAT_PASSPHRASE);
ret = nvlist_lookup_uint64(nvl,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), &intval);
if (ret == ENOENT)
;
else if (ret != 0 || intval >= ZFS_PASSPHRASE_KDF_KDFS)
return (SET_ERROR(EINVAL));
/* /*
* for raw receives we allow any number of pbkdf2iters since there * for raw receives we allow any number of pbkdf2iters since there
* won't be a chance for the user to change it. * won't be a chance for the user to change it.
@ -2271,6 +2304,7 @@ dsl_crypto_recv_raw_key_sync(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
uint64_t rddobj, one = 1; uint64_t rddobj, one = 1;
uint8_t *keydata, *hmac_keydata, *iv, *mac; uint8_t *keydata, *hmac_keydata, *iv, *mac;
uint64_t crypt, key_guid, keyformat, iters, salt; uint64_t crypt, key_guid, keyformat, iters, salt;
uint64_t kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
uint64_t version = ZIO_CRYPT_KEY_CURRENT_VERSION; uint64_t version = ZIO_CRYPT_KEY_CURRENT_VERSION;
const char *keylocation = "prompt"; const char *keylocation = "prompt";
@ -2279,6 +2313,8 @@ dsl_crypto_recv_raw_key_sync(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
key_guid = fnvlist_lookup_uint64(nvl, DSL_CRYPTO_KEY_GUID); key_guid = fnvlist_lookup_uint64(nvl, DSL_CRYPTO_KEY_GUID);
keyformat = fnvlist_lookup_uint64(nvl, keyformat = fnvlist_lookup_uint64(nvl,
zfs_prop_to_name(ZFS_PROP_KEYFORMAT)); zfs_prop_to_name(ZFS_PROP_KEYFORMAT));
(void) nvlist_lookup_uint64(nvl,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), &kdf);
iters = fnvlist_lookup_uint64(nvl, iters = fnvlist_lookup_uint64(nvl,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS)); zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS));
salt = fnvlist_lookup_uint64(nvl, salt = fnvlist_lookup_uint64(nvl,
@ -2331,8 +2367,8 @@ dsl_crypto_recv_raw_key_sync(dsl_dataset_t *ds, nvlist_t *nvl, dmu_tx_t *tx)
/* sync the key data to the ZAP object on disk */ /* sync the key data to the ZAP object on disk */
dsl_crypto_key_sync_impl(mos, dd->dd_crypto_obj, crypt, dsl_crypto_key_sync_impl(mos, dd->dd_crypto_obj, crypt,
rddobj, key_guid, iv, mac, keydata, hmac_keydata, keyformat, salt, rddobj, key_guid, iv, mac, keydata, hmac_keydata, keyformat, kdf,
iters, tx); salt, iters, tx);
} }
static int static int
@ -2426,6 +2462,7 @@ dsl_crypto_populate_key_nvlist(objset_t *os, uint64_t from_ivset_guid,
dsl_pool_t *dp = ds->ds_dir->dd_pool; dsl_pool_t *dp = ds->ds_dir->dd_pool;
objset_t *mos = dp->dp_meta_objset; objset_t *mos = dp->dp_meta_objset;
uint64_t crypt = 0, key_guid = 0, format = 0; uint64_t crypt = 0, key_guid = 0, format = 0;
uint64_t kdf = ZFS_PASSPHRASE_KDF_PBKDF2;
uint64_t iters = 0, salt = 0, version = 0; uint64_t iters = 0, salt = 0, version = 0;
uint64_t to_ivset_guid = 0; uint64_t to_ivset_guid = 0;
uint8_t raw_keydata[MASTER_KEY_MAX_LEN]; uint8_t raw_keydata[MASTER_KEY_MAX_LEN];
@ -2508,6 +2545,11 @@ dsl_crypto_populate_key_nvlist(objset_t *os, uint64_t from_ivset_guid,
if (ret != 0) if (ret != 0)
goto error_unlock; goto error_unlock;
ret = zap_lookup(dp->dp_meta_objset, rdd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), 8, 1, &kdf);
if (ret != 0 && ret != ENOENT)
goto error_unlock;
if (format == ZFS_KEYFORMAT_PASSPHRASE) { if (format == ZFS_KEYFORMAT_PASSPHRASE) {
ret = zap_lookup(dp->dp_meta_objset, rdd->dd_crypto_obj, ret = zap_lookup(dp->dp_meta_objset, rdd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), 8, 1, &iters); zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), 8, 1, &iters);
@ -2537,6 +2579,7 @@ dsl_crypto_populate_key_nvlist(objset_t *os, uint64_t from_ivset_guid,
VERIFY0(nvlist_add_uint8_array(nvl, "portable_mac", VERIFY0(nvlist_add_uint8_array(nvl, "portable_mac",
os->os_phys->os_portable_mac, ZIO_OBJSET_MAC_LEN)); os->os_phys->os_portable_mac, ZIO_OBJSET_MAC_LEN));
fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), format); fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_KEYFORMAT), format);
fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), kdf);
fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), iters); fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), iters);
fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt); fnvlist_add_uint64(nvl, zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt);
fnvlist_add_uint64(nvl, "mdn_checksum", mdn->dn_checksum); fnvlist_add_uint64(nvl, "mdn_checksum", mdn->dn_checksum);
@ -2650,6 +2693,10 @@ dsl_dataset_crypt_stats(dsl_dataset_t *ds, nvlist_t *nv)
zfs_prop_to_name(ZFS_PROP_KEYFORMAT), 8, 1, &intval) == 0) { zfs_prop_to_name(ZFS_PROP_KEYFORMAT), 8, 1, &intval) == 0) {
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_KEYFORMAT, intval); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_KEYFORMAT, intval);
} }
if (zap_lookup(dd->dd_pool->dp_meta_objset, dd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), 8, 1, &intval) == 0) {
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_PASSPHRASE_KDF, intval);
}
if (zap_lookup(dd->dd_pool->dp_meta_objset, dd->dd_crypto_obj, if (zap_lookup(dd->dd_pool->dp_meta_objset, dd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 8, 1, &intval) == 0) { zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 8, 1, &intval) == 0) {
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_PBKDF2_SALT, intval); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_PBKDF2_SALT, intval);

View File

@ -378,13 +378,16 @@ get_special_prop(lua_State *state, dsl_dataset_t *ds, const char *dsname,
} }
case ZFS_PROP_KEYSTATUS: case ZFS_PROP_KEYSTATUS:
case ZFS_PROP_KEYFORMAT: { case ZFS_PROP_KEYFORMAT:
case ZFS_PROP_PASSPHRASE_KDF: {
/* provide defaults in case no crypto obj exists */ /* provide defaults in case no crypto obj exists */
setpoint[0] = '\0'; setpoint[0] = '\0';
if (zfs_prop == ZFS_PROP_KEYSTATUS) if (zfs_prop == ZFS_PROP_KEYSTATUS)
numval = ZFS_KEYSTATUS_NONE; numval = ZFS_KEYSTATUS_NONE;
else else if (zfs_prop == ZFS_PROP_KEYFORMAT)
numval = ZFS_KEYFORMAT_NONE; numval = ZFS_KEYFORMAT_NONE;
else
numval = ZFS_PASSPHRASE_KDF_PBKDF2;
nvlist_t *nvl, *propval; nvlist_t *nvl, *propval;
nvl = fnvlist_alloc(); nvl = fnvlist_alloc();

View File

@ -33,6 +33,8 @@
# 5. Unload the dataset's key # 5. Unload the dataset's key
# 6. Attempt to load the dataset's key # 6. Attempt to load the dataset's key
# #
# Do the same with Argon2id
#
verify_runnable "both" verify_runnable "both"
@ -58,6 +60,7 @@ log_onexit cleanup
log_assert "'zfs change-key -o' should change the pbkdf2 iterations" log_assert "'zfs change-key -o' should change the pbkdf2 iterations"
log_must eval "echo $PASSPHRASE > /$TESTPOOL/pkey" log_must eval "echo $PASSPHRASE > /$TESTPOOL/pkey"
log_must zfs create -o encryption=on -o keyformat=passphrase \ log_must zfs create -o encryption=on -o keyformat=passphrase \
-o keylocation=file:///$TESTPOOL/pkey -o pbkdf2iters=200000 \ -o keylocation=file:///$TESTPOOL/pkey -o pbkdf2iters=200000 \
@ -72,4 +75,18 @@ log_must verify_pbkdf2iters $TESTPOOL/$TESTFS1 "150000"
log_must zfs unload-key $TESTPOOL/$TESTFS1 log_must zfs unload-key $TESTPOOL/$TESTFS1
log_must zfs load-key $TESTPOOL/$TESTFS1 log_must zfs load-key $TESTPOOL/$TESTFS1
log_must zfs change-key -o passphrasekdf=argon2id $TESTPOOL/$TESTFS1
log_must verify_pbkdf2iters $TESTPOOL/$TESTFS1 "40000"
log_must zfs unload-key $TESTPOOL/$TESTFS1
log_must zfs load-key $TESTPOOL/$TESTFS1
log_must zfs change-key -o pbkdf2iters=10000 $TESTPOOL/$TESTFS1
log_must verify_pbkdf2iters $TESTPOOL/$TESTFS1 "10000"
log_must zfs unload-key $TESTPOOL/$TESTFS1
log_must zfs load-key $TESTPOOL/$TESTFS1
log_pass "'zfs change-key -o' changes the pbkdf2 iterations" log_pass "'zfs change-key -o' changes the pbkdf2 iterations"