File Coverage

blib/lib/File/KDBX/KDF.pm
Criterion Covered Total %
statement 61 70 87.1
branch 9 14 64.2
condition 7 14 50.0
subroutine 15 19 78.9
pod 8 8 100.0
total 100 125 80.0


line stmt bran cond sub pod time code
1             package File::KDBX::KDF;
2             # ABSTRACT: A key derivation function
3              
4 11     11   181972 use warnings;
  11         20  
  11         397  
5 11     11   53 use strict;
  11         17  
  11         250  
6              
7 11     11   47 use Crypt::PRNG qw(random_bytes);
  11         51  
  11         878  
8 11     11   64 use File::KDBX::Constants qw(:version :kdf);
  11         19  
  11         2436  
9 11     11   72 use File::KDBX::Error;
  11         20  
  11         569  
10 11     11   80 use File::KDBX::Util qw(format_uuid);
  11         39  
  11         435  
11 11     11   58 use Module::Load;
  11         36  
  11         92  
12 11     11   569 use Scalar::Util qw(blessed);
  11         30  
  11         418  
13 11     11   68 use namespace::clean;
  11         25  
  11         64  
14              
15             our $VERSION = '0.905'; # VERSION
16              
17             my %KDFS;
18              
19              
20             sub new {
21 177     177 1 6510 my $class = shift;
22 177         451 my %args = @_;
23              
24 177 50 66     825 my $uuid = $args{+KDF_PARAM_UUID} //= delete $args{uuid} or throw 'Missing KDF UUID', args => \%args;
25 177         423 my $formatted_uuid = format_uuid($uuid);
26              
27 177 50       475 my $kdf = $KDFS{$uuid} or throw "Unsupported KDF ($formatted_uuid)", uuid => $uuid;
28 177         324 ($class, my %registration_args) = @$kdf;
29              
30 177         545 load $class;
31 177         9296 my $self = bless {KDF_PARAM_UUID() => $uuid}, $class;
32 177         653 return $self->init(%args, %registration_args);
33             }
34              
35              
36             sub init {
37 177     177 1 259 my $self = shift;
38 177         372 my %args = @_;
39              
40 177         552 @$self{keys %args} = values %args;
41              
42 177         1065 return $self;
43             }
44              
45              
46 182     182 1 620 sub uuid { $_[0]->{+KDF_PARAM_UUID} }
47              
48              
49 0     0 1 0 sub seed { die 'Not implemented' }
50              
51              
52             sub transform {
53 51     51 1 2980 my $self = shift;
54 51         82 my $key = shift;
55              
56 51 100 66     341 if (blessed $key && $key->can('raw_key')) {
57 45 100       107 return $self->_transform($key->raw_key) if $self->uuid eq KDF_UUID_AES;
58 21         48 return $self->_transform($key->raw_key($self->seed, @_));
59             }
60              
61 6         21 return $self->_transform($key);
62             }
63              
64 0     0   0 sub _transform { die 'Not implemented' }
65              
66              
67             sub randomize_seed {
68 0     0 1 0 my $self = shift;
69 0         0 $self->{+KDF_PARAM_AES_SEED} = random_bytes(length($self->seed));
70             }
71              
72              
73             sub register {
74 44     44 1 71 my $class = shift;
75 44         67 my $id = shift;
76 44         66 my $package = shift;
77 44         68 my @args = @_;
78              
79 44         102 my $formatted_id = format_uuid($id);
80 44 50 33     389 $package = "${class}::${package}" if $package !~ s/^\+// && $package !~ /^\Q${class}::\E/;
81              
82 44   50     191 my %blacklist = map { File::KDBX::Util::uuid($_) => 1 } split(/,/, $ENV{FILE_KDBX_KDF_BLACKLIST} // '');
  0         0  
83 44 50 33     152 if ($blacklist{$id} || $blacklist{$package}) {
84 0         0 alert "Ignoring blacklisted KDF ($formatted_id)", id => $id, package => $package;
85 0         0 return;
86             }
87              
88 44 50       81 if (defined $KDFS{$id}) {
89 0         0 alert "Overriding already-registered KDF ($formatted_id) with package $package",
90             id => $id,
91             package => $package;
92             }
93              
94 44         439 $KDFS{$id} = [$package, @args];
95             }
96              
97              
98             sub unregister {
99 0     0 1   delete $KDFS{$_} for @_;
100             }
101              
102             BEGIN {
103 11     11   12641 __PACKAGE__->register(KDF_UUID_AES, 'AES');
104 11         40 __PACKAGE__->register(KDF_UUID_AES_CHALLENGE_RESPONSE, 'AES');
105 11         41 __PACKAGE__->register(KDF_UUID_ARGON2D, 'Argon2');
106 11         39 __PACKAGE__->register(KDF_UUID_ARGON2ID, 'Argon2');
107             }
108              
109             1;
110              
111             __END__