From: Charles McGarvey Date: Tue, 16 Aug 2022 21:52:51 +0000 (-0600) Subject: Make transform_rounds work with Argon KDF X-Git-Tag: v0.906~3 X-Git-Url: https://git.dogcows.com/gitweb?a=commitdiff_plain;h=a88318ecb7f38a65fa1d6e68de001f4385d34fa7;p=chaz%2Fp5-File-KDBX Make transform_rounds work with Argon KDF --- diff --git a/Changes b/Changes index 1b27a06..dcce162 100644 --- a/Changes +++ b/Changes @@ -1,10 +1,11 @@ Revision history for File-KDBX. {{$NEXT}} + * Fixed transform_rounds method to work with Argon KDF. Thanks HIGHTOWE. 0.905 2022-08-06 12:12:42-0600 - * Declare Time::Local 1.19 as a required dependency. - * Declare CryptX 0.055 as a required dependency. Thanks HIGHTOWE. + * Declared Time::Local 1.19 as a required dependency. + * Declared CryptX 0.055 as a required dependency. Thanks HIGHTOWE. * Fixed minor documentation errors. 0.904 2022-07-07 21:51:17-0600 diff --git a/lib/File/KDBX.pm b/lib/File/KDBX.pm index 680c252..db40366 100644 --- a/lib/File/KDBX.pm +++ b/lib/File/KDBX.pm @@ -1482,7 +1482,6 @@ sub kdf { my %args = @_ % 2 == 1 ? (params => shift, @_) : @_; my $params = $args{params}; - my $compat = $args{compatible} // 1; $params //= $self->kdf_parameters; $params = {%{$params || {}}}; @@ -1508,18 +1507,22 @@ sub kdf { sub transform_seed { my $self = shift; + my $param = KDF_PARAM_AES_SEED; # Short cut: Argon2 uses the same parameter name ("S") $self->headers->{+HEADER_TRANSFORM_SEED} = - $self->headers->{+HEADER_KDF_PARAMETERS}{+KDF_PARAM_AES_SEED} = shift if @_; + $self->headers->{+HEADER_KDF_PARAMETERS}{$param} = shift if @_; $self->headers->{+HEADER_TRANSFORM_SEED} = - $self->headers->{+HEADER_KDF_PARAMETERS}{+KDF_PARAM_AES_SEED} //= random_bytes(32); + $self->headers->{+HEADER_KDF_PARAMETERS}{$param} //= random_bytes(32); } sub transform_rounds { my $self = shift; + require File::KDBX::KDF; + my $info = $File::KDBX::KDF::ROUNDS_INFO{$self->kdf_parameters->{+KDF_PARAM_UUID} // ''} // + $File::KDBX::KDF::DEFAULT_ROUNDS_INFO; $self->headers->{+HEADER_TRANSFORM_ROUNDS} = - $self->headers->{+HEADER_KDF_PARAMETERS}{+KDF_PARAM_AES_ROUNDS} = shift if @_; + $self->headers->{+HEADER_KDF_PARAMETERS}{$info->{p}} = shift if @_; $self->headers->{+HEADER_TRANSFORM_ROUNDS} = - $self->headers->{+HEADER_KDF_PARAMETERS}{+KDF_PARAM_AES_ROUNDS} //= 100_000; + $self->headers->{+HEADER_KDF_PARAMETERS}{$info->{p}} //= $info->{d}; } =method cipher @@ -1712,7 +1715,7 @@ L. =attr comment -A text string associated with the database. Often unset. +A text string associated with the database stored unencrypted in the file header. Often unset. =attr cipher_id @@ -1743,7 +1746,7 @@ The transform seed I be changed each time the database is saved to file. =attr transform_rounds The number of rounds or iterations used in the key derivation function. Increasing this number makes loading -and saving the database slower by design in order to make dictionary and brute force attacks more costly. +and saving the database slower in order to make dictionary and brute force attacks more costly. =attr encryption_iv diff --git a/lib/File/KDBX/Cipher.pm b/lib/File/KDBX/Cipher.pm index 655f8fb..04be271 100644 --- a/lib/File/KDBX/Cipher.pm +++ b/lib/File/KDBX/Cipher.pm @@ -142,7 +142,8 @@ sub new_from_stream_id { $self->init; -Initialize the cipher. Called by . +Called by L to set attributes. You normally shouldn't call this. Returns itself to allow method +chaining. =cut diff --git a/lib/File/KDBX/KDF.pm b/lib/File/KDBX/KDF.pm index ce32945..60b4acf 100644 --- a/lib/File/KDBX/KDF.pm +++ b/lib/File/KDBX/KDF.pm @@ -16,6 +16,15 @@ our $VERSION = '999.999'; # VERSION my %KDFS; +our %ROUNDS_INFO = ( + KDF_UUID_ARGON2D() => {p => KDF_PARAM_ARGON2_ITERATIONS, d => KDF_DEFAULT_ARGON2_ITERATIONS}, + KDF_UUID_ARGON2ID() => {p => KDF_PARAM_ARGON2_ITERATIONS, d => KDF_DEFAULT_ARGON2_ITERATIONS}, +); +our $DEFAULT_ROUNDS_INFO = { + p => KDF_PARAM_AES_ROUNDS, + d => KDF_DEFAULT_AES_ROUNDS, +}; + =method new $kdf = File::KDBX::KDF->new(parameters => \%params); @@ -43,7 +52,8 @@ sub new { $kdf = $kdf->init(%attributes); -Called by method to set attributes. You normally shouldn't call this. +Called by L to set attributes. You normally shouldn't call this. Returns itself to allow method +chaining. =cut @@ -109,7 +119,7 @@ sub _transform { die 'Not implemented' } $kdf->randomize_seed; -Generate a new random seed/salt. +Generate and set a new random seed/salt. =cut diff --git a/t/kdbx4.t b/t/kdbx4.t index ff48700..b14ddcf 100644 --- a/t/kdbx4.t +++ b/t/kdbx4.t @@ -34,6 +34,11 @@ subtest 'Verify Format400' => sub { master_seed => ";\372y\300yS%\3331\177\231\364u\265Y\361\225\3273h\332R,\22\240a\240\302\271\357\313\23", }, 'Extract headers' or diag explain $kdbx->headers; + is $kdbx->transform_seed, + "V\254\6m-\206*\260\305\f\0\366\24:4\235\364A\362\346\221\13)}\250\217P\303\303\2\331\245", + 'Get the correct transform seed'; + cmp_ok $kdbx->transform_rounds, '==', 2, 'Get the correct transform rounds'; + is $kdbx->meta->{database_name}, 'Format400', 'Extract database name from meta'; is $kdbx->root->name, 'Format400', 'Extract name of root group'; @@ -132,10 +137,10 @@ sub test_upgrade_master_key_integrity { plan tests => $expected_version >= KDBX_VERSION_4_0 ? 6 : 5; my $kdbx = File::KDBX->new; - $kdbx->kdf_parameters(fast_kdf); - is $kdbx->kdf->uuid, KDF_UUID_AES, 'Default KDF is AES'; + $kdbx->kdf_parameters(fast_kdf); + { local $_ = $kdbx; $modifier->($kdbx); @@ -216,4 +221,28 @@ subtest 'Custom data' => sub { is_deeply $entry2->custom_data_value('bool'), '0', 'Store a boolean in entry custom data'; }; +subtest 'KDF parameters' => sub { + my $kdbx = File::KDBX->new; + $kdbx->version(KDBX_VERSION_4_0); + + is $kdbx->kdf_parameters->{+KDF_PARAM_UUID}, KDF_UUID_AES, 'Default KDF type is correct'; + cmp_ok $kdbx->transform_rounds, '==', 100_000, 'Default transform rounds is correct'; + + $kdbx->transform_rounds(17); + cmp_deeply $kdbx->kdf_parameters, { + "\$UUID" => "\311\331\363\232b\212D`\277t\r\b\301\212O\352", + R => num(17), + S => ignore(), + }, 'Set transform rounds for AES KDF'; + + $kdbx->kdf_parameters({KDF_PARAM_UUID() => KDF_UUID_ARGON2D}); + cmp_ok $kdbx->transform_rounds, '==', 10, 'Default Argon2D transform rounds is correct'; + + $kdbx->transform_rounds(17); + cmp_deeply $kdbx->kdf_parameters, { + "\$UUID" => "\357cm\337\214)DK\221\367\251\244\3\343\n\f", + I => num(17), + }, 'Set transform rounds for Argon KDF'; +}; + done_testing; diff --git a/t/lib/TestCommon.pm b/t/lib/TestCommon.pm index 33438d3..195b76c 100644 --- a/t/lib/TestCommon.pm +++ b/t/lib/TestCommon.pm @@ -80,6 +80,7 @@ sub ok_magic { ], $note // 'KDBX magic numbers are correct'; } +# Returns parameters for a fast KDF so that running tests isn't pointlessly slow. sub fast_kdf { my $uuid = shift // KDF_UUID_AES; my $params = {