Skip to content

Commit

Permalink
Add ZFS_PROP_PASSPHRASE_KDF (passphrasekdf) property and argon2id13
Browse files Browse the repository at this point in the history
Signed-off-by: Ahelenia Ziemiańska <[email protected]>
  • Loading branch information
nabijaczleweli committed Dec 17, 2023
1 parent b06259a commit 8cdd4e7
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 73 deletions.
1 change: 1 addition & 0 deletions .github/workflows/build-dependencies.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ libmount-dev
libpam0g-dev
libselinux1-dev
libssl-dev
libargon2-dev
libtool
libudev-dev
linux-headers-generic
Expand Down
33 changes: 28 additions & 5 deletions cmd/zdb/zdb.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <getopt.h>
#include <argon2.h>
#include <openssl/evp.h>
#include <sys/zfs_context.h>
#include <sys/spa.h>
Expand Down Expand Up @@ -3123,7 +3124,7 @@ static char *key_material = NULL;
static boolean_t
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;
unsigned char c;

Expand Down Expand Up @@ -3151,10 +3152,32 @@ zdb_derive_key(dsl_dir_t *dd, uint8_t *key_out)
dd->dd_crypto_obj, zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS),
sizeof (uint64_t), 1, &iters));

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);
int err = zap_lookup(dd->dd_pool->dp_meta_objset,
dd->dd_crypto_obj,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF),
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_ARGON2ID13:
if (argon2_hash(iters / 10, 18, 1,
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;

Expand Down
2 changes: 2 additions & 0 deletions cmd/ztest.c
Original file line number Diff line number Diff line change
Expand Up @@ -4557,6 +4557,8 @@ ztest_dataset_create(char *dsname)
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), 0ULL);
fnvlist_add_uint64(props,
zfs_prop_to_name(ZFS_PROP_PBKDF2_ITERS), 0ULL);
fnvlist_add_string(props,
zfs_prop_to_name(ZFS_PROP_PASSPHRASE_KDF), "pbkdf2");

VERIFY0(dsl_crypto_params_create_nvlist(DCP_CMD_NONE, props,
crypto_args, &dcp));
Expand Down
16 changes: 12 additions & 4 deletions config/user-libcrypto.m4
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
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 #
AC_DEFUN([ZFS_AC_CONFIG_USER_LIBCRYPTO], [
ZFS_AC_FIND_SYSTEM_LIBRARY(LIBCRYPTO, [libcrypto], [openssl/evp.h], [], [crypto], [PKCS5_PBKDF2_HMAC_SHA1], [], [
AC_MSG_FAILURE([
*** evp.h missing, libssl-devel package required])])
ZFS_AC_FIND_SYSTEM_LIBRARY(LIBCRYPTO_SSL, [libcrypto], [openssl/evp.h], [], [crypto], [PKCS5_PBKDF2_HMAC_SHA1], [], [
AC_MSG_FAILURE([*** 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, [])
])
69 changes: 47 additions & 22 deletions contrib/pam_zfs_key/pam_zfs_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

#include <sys/zio_crypt.h>
#include <openssl/evp.h>
#include <argon2.h>

#define PAM_SM_AUTH
#define PAM_SM_PASSWORD
Expand Down Expand Up @@ -250,17 +251,24 @@ static pw_password_t *
prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds,
const char *passphrase, nvlist_t *nvlist)
{
const char *errstr = NULL;
pw_password_t *key = alloc_pw_size(WRAPPING_KEY_LEN);
if (!key) {
return (NULL);
}
uint64_t salt;
uint64_t iters;
uint64_t kdf, salt, iters;
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);
if (fd < 0) {
pw_free(key);
return (NULL);
errstr = "/dev/urandom";
goto err;
}
int bytes_read = 0;
char *buf = (char *)&salt;
Expand All @@ -270,43 +278,60 @@ prepare_passphrase(pam_handle_t *pamh, zfs_handle_t *ds,
- bytes_read);
if (len < 0) {
close(fd);
pw_free(key);
return (NULL);
errstr = "failed to read salt";
goto err;
}
bytes_read += len;
}
close(fd);

if (nvlist_add_uint64(nvlist,
zfs_prop_to_name(ZFS_PROP_PBKDF2_SALT), salt)) {
pam_syslog(pamh, LOG_ERR,
"failed to add salt to nvlist");
pw_free(key);
return (NULL);
errstr = "failed to add salt to nvlist";
goto err;
}
iters = DEFAULT_PBKDF2_ITERATIONS;
if (nvlist_add_uint64(nvlist, zfs_prop_to_name(
ZFS_PROP_PBKDF2_ITERS), iters)) {
pam_syslog(pamh, LOG_ERR,
"failed to add iters to nvlist");
pw_free(key);
return (NULL);
errstr = "failed to add iters to nvlist";
goto err;
}
} else {
kdf = zfs_prop_get_int(ds, ZFS_PROP_PASSPHRASE_KDF);
salt = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_SALT);
iters = zfs_prop_get_int(ds, ZFS_PROP_PBKDF2_ITERS);
}

salt = LE_64(salt);
if (!PKCS5_PBKDF2_HMAC_SHA1((char *)passphrase,
strlen(passphrase), (uint8_t *)&salt,
sizeof (uint64_t), iters, WRAPPING_KEY_LEN,
(uint8_t *)key->value)) {
pam_syslog(pamh, LOG_ERR, "pbkdf failed");
pw_free(key);
return (NULL);
}

switch (kdf) {
case ZFS_PASSPHRASE_KDF_PBKDF2:
if (PKCS5_PBKDF2_HMAC_SHA1((char *)passphrase,
strlen(passphrase), ((uint8_t *)&salt),
sizeof (uint64_t), iters, WRAPPING_KEY_LEN,
(uint8_t *)key->value) != 1)
errstr = "PBKDF2 failed";
break;
case ZFS_PASSPHRASE_KDF_ARGON2ID13:
if (argon2_hash(iters / 10, 18, 1,
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);

err:
pam_syslog(pamh, LOG_ERR, "%s", errstr);
pw_free(key);
return (NULL);
}

static int
Expand Down
12 changes: 8 additions & 4 deletions include/sys/dsl_crypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@

/*
* 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
* also maintained here using their respective property names.
* ZFS_PROP_KEYFORMAT, ZFS_PROP_PBKDF2_SALT, ZFS_PROP_PBKDF2_ITERS,
* 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_GUID "DSL_CRYPTO_GUID"
Expand All @@ -52,10 +53,13 @@ typedef struct dsl_wrapping_key {
/* keyformat property enum */
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;

/* the pbkdf2 iterations, if the keyformat is of type passphrase */
/* the KDF iterations, if the keyformat is of type passphrase */
uint64_t wk_iters;

/* actual wrapping key */
Expand Down
7 changes: 7 additions & 0 deletions include/sys/fs/zfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ typedef enum {
ZFS_PROP_SNAPSHOTS_CHANGED,
ZFS_PROP_PREFETCH,
ZFS_PROP_VOLTHREADING,
ZFS_PROP_PASSPHRASE_KDF,
ZFS_NUM_PROPS
} zfs_prop_t;

Expand Down Expand Up @@ -539,6 +540,12 @@ typedef enum zfs_keyformat {
ZFS_KEYFORMAT_FORMATS
} zfs_keyformat_t;

typedef enum zfs_passphrase_kdf {
ZFS_PASSPHRASE_KDF_PBKDF2 = 0,
ZFS_PASSPHRASE_KDF_ARGON2ID13,
ZFS_PASSPHRASE_KDF_KDFS
} zfs_passphrase_kdf_t;

typedef enum zfs_key_location {
ZFS_KEYLOCATION_NONE = 0,
ZFS_KEYLOCATION_PROMPT,
Expand Down
Loading

0 comments on commit 8cdd4e7

Please sign in to comment.