zfs icon indicating copy to clipboard operation
zfs copied to clipboard

Add ZFS_PROP_PASSPHRASE_KDF (passphrasekdf) property and argon2id13

Open nabijaczleweli opened this issue 1 year ago • 5 comments

Motivation and Context

Rowe told me to update and post the diff from #14762.

Description

id ZFS_PROP_PASSPHRASE_KDF name "passphrasekdf" enum of either ZFS_PASSPHRASE_KDF_PBKDF2 ("pbkdf2", PBKDF2), which is the default (and no changes there), or ZFS_PASSPHRASE_KDF_ARGON2ID13 ("argon2id13", Argon2id version 13, 18MB, single lane) in which case derive the key with Argon2id instead ~~(but divide pbkdf2iters by 10 (maybe this factor can be reduced so it takes a similar amount of time, but no factor + the default 350000 took multiple seconds which is unacceptable; this does make the default be 35000 Argon2id rounds, so an Argon2 enjoyer should opine if this is "secure", but it takes >500ms in my test VM, so))~~, the default is 40000 rounds and the min is 10000 rounds.

Do we want to add a "kdfiters" alias for pbkdf2iters?

The initial methodology was "find everywhere where ZFS_PROP_KEYFORMAT is mentioned and add it there as well". Clearly a good approach.

How Has This Been Tested?

(pool/datasets created on unpatched master):

# ./zfs load-key -a
Enter passphrase for 'loop':
derive_key: kdf=PBKDF2 iters=350000
b2f63b61549fc7457631807bd79a3dfa9dc798b9f782425557578e76bbb7582f
Enter passphrase for 'loop/iters':
derive_key: kdf=PBKDF2 iters=200000
5ca66d14b61f8b6df11bb281c409b67645665e9f25c7f284d0781dcdc63739ec
2 / 2 key(s) successfully loaded
# ./zfs change-key -o passphrasekdf=argon2id loop
Enter new passphrase for 'loop':
Re-enter new passphrase for 'loop':
derive_key: kdf=ARGON2ID iters=40000
d8c6249a74fe2db5f20c82a4fd383cb0a7b63435e329f0520b102b28eb6ba97c
# ./zfs change-key -o passphrasekdf=argon2id -o pbkdf2iters=5 loop/iters
Key change error: minimum KDF iterations is 10000
Key change error: encryption failure
# ./zfs change-key -o passphrasekdf=argon2id -o pbkdf2iters=10000 loop/iters
Enter new passphrase for 'loop/iters':
Re-enter new passphrase for 'loop/iters':
derive_key: kdf=ARGON2ID iters=10000
e42b7ca3130920ed0521c2b1cbaf662d13287d58be04d6ec439e36a435987865
# ./zfs unload-key -a
2 / 2 key(s) successfully unloaded
# ./zfs load-key -a
Enter passphrase for 'loop':
derive_key: kdf=ARGON2ID iters=40000
d8c6249a74fe2db5f20c82a4fd383cb0a7b63435e329f0520b102b28eb6ba97c
Enter passphrase for 'loop/iters':
derive_key: kdf=ARGON2ID iters=10000
e42b7ca3130920ed0521c2b1cbaf662d13287d58be04d6ec439e36a435987865
2 / 2 key(s) successfully loaded
# ./zdb -e -K itersiters -dddd loop/iters 2
Unlocked encryption root: loop/iters
Dataset loop/iters [ZPL], ID 389, cr_txg 34, 98.5K, 7 objects, rootbp DVA[0]=<0:26800:1000> DVA[1]=<0:10026600:1000> [L0 DMU objset] fletcher4 uncompressed authenticated Le

    Object  lvl   iblk   dblk  dsize  dnsize  lsize   %full  type
         2    1   128K    512    512     512    512  100.00  ZFS plain file
                                               176   bonus  System attributes
        dnode flags: USED_BYTES USERUSED_ACCOUNTED USEROBJUSED_ACCOUNTED
        dnode maxblkid: 0
        uid     0
        gid     0
        atime   Mon Dec 18 00:02:31 2023
        mtime   Mon Dec 18 00:02:31 2023
        ctime   Mon Dec 18 00:02:31 2023
        crtime  Mon Dec 18 00:02:31 2023
        gen     157
        mode    100644
        size    198
        parent  34
        links   1
        pflags  840800000004



(other system: # zfs send -vw tarta-zoot/enctest@snap > enctest@snap)
(other system: full send of tarta-zoot/enctest@snap estimated size is 71.1K)
(other system: total estimated size is 71.1K)
# ./zfs recv -ev loop < enctest@snap
receiving full stream of tarta-zoot/enctest@snap into loop/enctest@snap
received 27.1K stream in 0.18 seconds (148K/sec)
$ ./zfs get passphrasekdf
NAME               PROPERTY       VALUE     SOURCE
loop               passphrasekdf  argon2id  -
loop/enctest       passphrasekdf  pbkdf2    default
loop/enctest@snap  passphrasekdf  -         -
loop/iters         passphrasekdf  argon2id  -
# ./zfs load-key -a
Enter passphrase for 'loop/enctest':
derive_key: kdf=PBKDF2 iters=350000
2ac2a4f1b3ae791aa326bdbf6fdc8e704ecbd55795bd928efaccfa3fbd99c262
1 / 1 key(s) successfully loaded

# ./zfs send -vw loop/iters@snap > iters@snap
full send of loop/iters@snap estimated size is 50.1K
total estimated size is 50.1K
TIME        SENT   SNAPSHOT loop/iters@snap
# ./zfs recv -v loop/reiters < iters@snap
receiving full stream of loop/iters@snap into loop/reiters@snap
received 18.4K stream in 0.18 seconds (104K/sec)
$ ./zfs get passphrasekdf
NAME               PROPERTY       VALUE     SOURCE
loop               passphrasekdf  argon2id  -
loop/enctest       passphrasekdf  pbkdf2    default
loop/enctest@snap  passphrasekdf  -         -
loop/iters         passphrasekdf  argon2id  -
loop/iters@snap    passphrasekdf  -         -
loop/reiters       passphrasekdf  argon2id  -
loop/reiters@snap  passphrasekdf  -         -
# ./zfs load-key -a
Enter passphrase for 'loop/reiters':
derive_key: kdf=ARGON2ID iters=10000
e42b7ca3130920ed0521c2b1cbaf662d13287d58be04d6ec439e36a435987865
1 / 1 key(s) successfully loaded

(other system: # zfs recv -ev zest < iters@snap)
(other system: receiving full stream of loop/iters@snap into zest/iters@snap)
(other system: received 18.4K stream in 1 seconds (18.4K/sec))
(other system: # zfs load-key -a)
(other system: Enter passphrase for 'zest/iters':)
(other system: Key load error: Incorrect key provided for 'zest/iters'.)
(other system: # ...)
(other system: 0 / 1 key(s) successfully loaded)

# ./zfs create -o encryption=on -o keylocation=prompt -o keyformat=passphrase loop/create
Enter new passphrase:
Re-enter new passphrase:
derive_key: kdf=PBKDF2 iters=350000
04ce5829081d13d5b525ef4c927e4f7a33de7c73501b815d89372b3c347c7c13
# ./zfs create -o encryption=on -o keylocation=prompt -o keyformat=passphrase -o passphrasekdf=argon2id loop/create2
Enter new passphrase:
Re-enter new passphrase:
derive_key: kdf=ARGON2ID iters=40000
730c5e6deacc386f2dd0aa7af12c00f80e730ad1b8b0f2eb98d154508513bd71

~~What doesn't work rn: zfs change-key will revert to pbkdf2. idk why. probably easy~~

What I don't know if works (but should): ~~receiving encrypted datasets (every codepath in dsl_crypt that isn't trodden by change-key/load-key, really)~~, ~~zdb~~, pam_zfs_key

Types of changes

  • [ ] Bug fix (non-breaking change which fixes an issue)
  • [x] New feature (non-breaking change which adds functionality)
  • [ ] Performance enhancement (non-breaking change which improves efficiency)
  • [x] Code cleanup (non-breaking change which makes code smaller or more readable)
  • [ ] Breaking change (fix or feature that would cause existing functionality to change)
  • [x] Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv) – only because the DEFAULT_PBKDF2_ITERATIONS and MIN_PBKDF2_ITERATIONS macros were removed
  • [x] Documentation (a change to man pages or other documentation)

Checklist:

  • [x] My code follows the OpenZFS code style requirements.
  • [x] I have updated the documentation accordingly.
  • [x] I have read the contributing document.
  • [ ] I have added tests to cover my changes.
  • [ ] I have run the ZFS Test Suite with this change applied. – CI take my hand
  • [x] All commit messages are properly formatted and contain Signed-off-by.

nabijaczleweli avatar Dec 17 '23 05:12 nabijaczleweli

https://github.com/openzfs/zfs-buildbot/pull/280

nabijaczleweli avatar Dec 17 '23 05:12 nabijaczleweli

checkout #14836 as well

oromenahar avatar Dec 20 '23 21:12 oromenahar

I read through your PR. I think more parameters for argon2 need to configurable. Argon2 provides the options for this. I think 18MB with one CPU is not enough compute resource in my opinion. But I guess for other people it's enough or even to much, for that reason it should be configurable in my opinion.

But all in all it does not look that bad. You had the same Ideas like me. And I have the same points I don't like on my code and Ideas. Like what about adding a third KDF and more.

BTW: I'm working on a multi key slot variant for ZFS and wanna stop the PR #14836 if I finish it. But don't know when I can finish this work. I have the multislot already finished, but the user space tools don't handle it at the current point of time. Maybe wanna contact @tcaputi for some more information about the crypto key handling. I understand the most things, but not shure about everything.

oromenahar avatar Dec 20 '23 21:12 oromenahar

This could be done quite easily by packing more parameters into pbkdf2iters.

nabijaczleweli avatar Jan 02 '24 20:01 nabijaczleweli

Updated, now the following is possible:

# ./zpool create -O encryption=on -O passphrasekdf=argon2id -O pbkdf2iters=$((0x000100120001)) loop2 /dev/loop0  -f -O keyformat=passphrase

# ./zfs load-key  -a
Enter passphrase for 'loop2':
derive_key: kdf=1 iters=4296146945
argon2: t=1 m=18 p=1
3493dc0b9a5036bfd2c3fcd63887ba093f3eb5a95ea76fa303bb40b09c0df73e
1 / 1 key(s) successfully loaded

# ./zfs change-key -o pbkdf2iters=$((0x0002001500021)) loop2
2001500021
Enter new passphrase for 'loop2':
Re-enter new passphrase for 'loop2':
derive_key: kdf=1 iters=137460973601
argon2: t=32 m=336 p=33
d56b152a00ebe11c1687495a726aebf39c594c6c84d795b87a502e53d905fdcc

# ./zfs change-key -o kdfparams=$((0x0002001300021)) loop2
Enter new passphrase for 'loop2':
Re-enter new passphrase for 'loop2':
derive_key: kdf=1 iters=137458876449
argon2: t=32 m=304 p=33
23e2ade2b600d6bd226e0a9f9caf03395b894af0cbbace48b80d05e5a9cdbfbf

nabijaczleweli avatar Feb 08 '24 17:02 nabijaczleweli