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
my %args = @_ % 2 == 1 ? (params => shift, @_) : @_;
my $params = $args{params};
- my $compat = $args{compatible} // 1;
$params //= $self->kdf_parameters;
$params = {%{$params || {}}};
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
=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
=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
$self->init;
-Initialize the cipher. Called by </new>.
+Called by L</new> to set attributes. You normally shouldn't call this. Returns itself to allow method
+chaining.
=cut
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);
$kdf = $kdf->init(%attributes);
-Called by method to set attributes. You normally shouldn't call this.
+Called by L</new> to set attributes. You normally shouldn't call this. Returns itself to allow method
+chaining.
=cut
$kdf->randomize_seed;
-Generate a new random seed/salt.
+Generate and set a new random seed/salt.
=cut
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';
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);
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;
], $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 = {