1 package File
::KDBX
::KDF
::AES
;
2 # ABSTRACT: Using the AES cipher as a key derivation function
8 use Crypt
::Digest
qw(digest_data);
9 use File
::KDBX
::Constants
qw(:kdf);
10 use File
::KDBX
::Error
;
11 use File
::KDBX
::Util
qw(:load can_fork);
14 use parent
'File::KDBX::KDF';
16 our $VERSION = '999.999'; # VERSION
18 # Rounds higher than this are eligible for forking:
19 my $FORK_OPTIMIZATION_THRESHOLD = 100_000;
25 $use_fork = 0 if $ENV{NO_FORK
} || !can_fork
;
26 *USE_FORK
= $use_fork ? sub() { 1 } : sub() { 0 };
32 return $self->SUPER::init
(
33 KDF_PARAM_AES_ROUNDS
() => $args{+KDF_PARAM_AES_ROUNDS
} // $args{rounds
},
34 KDF_PARAM_AES_SEED
() => $args{+KDF_PARAM_AES_SEED
} // $args{seed
},
40 $rounds = $kdf->rounds;
42 Get the number of
times to run the function during transformation
.
46 sub rounds
{ $_[0]->{+KDF_PARAM_AES_ROUNDS
} || KDF_DEFAULT_AES_ROUNDS
}
47 sub seed
{ $_[0]->{+KDF_PARAM_AES_SEED
} }
53 my $seed = $self->seed;
54 my $rounds = $self->rounds;
56 length($key) == 32 or throw
'Raw key must be 32 bytes', size
=> length($key);
57 length($seed) == 32 or throw
'Invalid seed length', size
=> length($seed);
59 my ($key_l, $key_r) = unpack('(a16)2', $key);
61 goto NO_FORK
if !USE_FORK
|| $rounds < $FORK_OPTIMIZATION_THRESHOLD;
63 my $pid = open(my $read, '-|') // do { alert
"fork failed: $!"; goto NO_FORK
};
64 if ($pid == 0) { # child
65 my $l = _transform_half
($seed, $key_l, $rounds);
67 print $l or POSIX
::_exit
(1);
70 my $r = _transform_half
($seed, $key_r, $rounds);
71 read($read, my $l, length($key_l)) == length($key_l) or do { alert
"read failed: $!", goto NO_FORK
};
72 close($read) or do { alert
"worker thread exited abnormally", status
=> $?; goto NO_FORK
};
73 return digest_data
('SHA256', $l, $r);
76 # FIXME: This used to work but now it crashes frequently. threads are discouraged anyway
77 # if ($ENV{THREADS} && eval 'use threads; 1') {
78 # my $l = threads->create(\&_transform_half, $key_l, $seed, $rounds);
79 # my $r = _transform_half($key_r, $seed, $rounds);
80 # return digest_data('SHA256', $l->join, $r);
84 my $l = _transform_half
($seed, $key_l, $rounds);
85 my $r = _transform_half
($seed, $key_r, $rounds);
86 return digest_data
('SHA256', $l, $r);
90 my $xs = __PACKAGE__-
>can('_transform_half_xs');
97 my $c = Crypt
::Cipher-
>new('AES', $seed);
100 for (my $i = 0; $i < $rounds; ++$i) {
101 $result = $c->encrypt($result);
112 An AES-256-based key derivation function. This is a L<File::KDBX::KDF> subclass.
114 This KDF has a long, solid track record. It is supported in both KDBX3 and KDBX4.
118 This module can be pretty slow when the number of rounds is high. If you have L<File::KDBX::XS>, that will
119 help. If your perl has C<fork>, that will also help. If you need to turn off one or both of these
120 optimizations for some reason, set the C<PERL_ONLY> (to prevent Loading C<File::KDBX::XS>) and C<NO_FORK>
121 environment variables.