1 package File
::KDBX
::Cipher
;
2 # ABSTRACT: A block cipher mode or cipher stream
7 use Devel
::GlobalDestruction
;
8 use File
::KDBX
::Constants
qw(:cipher :random_stream);
10 use File
::KDBX
::Util
qw(erase format_uuid);
12 use Scalar
::Util
qw(looks_like_number);
15 our $VERSION = '999.999'; # VERSION
23 =method new_from_stream_id
25 $cipher = File
::KDBX
::Cipher-
>new(uuid
=> $uuid, key
=> $key, iv
=> $iv);
27 $cipher = File
::KDBX
::Cipher-
>new_from_uuid($uuid, key
=> $key, iv
=> $iv);
29 $cipher = File
::KDBX
::Cipher-
>new(stream_id
=> $id, key
=> $key);
31 $cipher = File
::KDBX
::Cipher-
>new_from_stream_id($id, key
=> $key);
33 Construct a new L
<File
::KDBX
::Cipher
>.
35 This
is a factory
method which returns a subclass
.
43 return $class->new_from_uuid(delete $args{uuid
}, %args) if defined $args{uuid
};
44 return $class->new_from_stream_id(delete $args{stream_id
}, %args) if defined $args{stream_id
};
46 throw
'Must pass uuid or stream_id';
54 $args{key
} or throw
'Missing encryption key';
55 $args{iv
} or throw
'Missing encryption IV';
57 my $formatted_uuid = format_uuid
($uuid);
59 my $cipher = $CIPHERS{$uuid} or throw
"Unsupported cipher ($formatted_uuid)", uuid
=> $uuid;
60 ($class, my %registration_args) = @$cipher;
62 my @args = (%args, %registration_args, uuid
=> $uuid);
64 my $self = bless {@args}, $class;
65 return $self->init(@args);
68 sub new_from_stream_id
{
73 $args{key
} or throw
'Missing encryption key';
75 my $cipher = $CIPHERS{$id} or throw
"Unsupported stream cipher ($id)", id
=> $id;
76 ($class, my %registration_args) = @$cipher;
78 my @args = (%args, %registration_args, stream_id
=> $id);
80 my $self = bless {@args}, $class;
81 return $self->init(@args);
88 Initialize the cipher
. Called by
</new
>.
94 sub DESTROY
{ !in_global_destruction
and erase \
$_[0]->{key
} }
98 $uuid = $cipher->uuid;
100 Get the UUID
if the cipher was constructed with one
.
104 sub uuid
{ $_[0]->{uuid
} }
108 $stream_id = $cipher->stream_id;
110 Get the stream ID
if the cipher was constructed with one
.
114 sub stream_id
{ $_[0]->{stream_id
} }
120 Get the raw encryption key
.
124 sub key
{ $_[0]->{key
} }
130 Get the initialization vector
.
134 sub iv
{ $_[0]->{iv
} }
136 =attr default_iv_size
138 $size = $cipher->default_iv_size;
140 Get the
default size of the initialization vector
, in bytes
.
148 $size = $cipher->key_size;
150 Get the size the mode expects the key to be
, in bytes
.
158 $size = $cipher->block_size;
160 Get the block size
, in bytes
.
168 $ciphertext = $cipher->encrypt($plaintext, ...);
174 sub encrypt
{ die "Not implemented" }
178 $plaintext = $cipher->decrypt($ciphertext, ...);
184 sub decrypt
{ die "Not implemented" }
188 $ciphertext .= $cipher->finish; # if encrypting
189 $plaintext .= $cipher->finish; # if decrypting
197 =method encrypt_finish
199 $ciphertext = $cipher->encrypt_finish($plaintext, ...);
201 Encrypt
and finish a stream
in one call
.
207 my $out = $self->encrypt(@_);
208 $out .= $self->finish;
212 =method decrypt_finish
214 $plaintext = $cipher->decrypt_finish($ciphertext, ...);
216 Decrypt
and finish a stream
in one call
.
222 my $out = $self->decrypt(@_);
223 $out .= $self->finish;
229 File
::KDBX
::Cipher-
>register($uuid => $package, %args);
231 Register a cipher
. Registered ciphers can be used to encrypt
and decrypt KDBX databases
. A cipher
's UUID
232 B<must> be unique and B<musn't change
>. A cipher UUID
is written into
each KDBX file
and the associated cipher
233 must be registered with the same UUID
in order to decrypt the KDBX file
.
235 C
<$package> should be a Perl
package relative to C
<File
::KDBX
::Cipher
::> or prefixed with a C
<+> if it
is
236 a fully-qualified
package. C
<%args> are passed as-is to the cipher
's L</init> method.
246 my $formatted_id = looks_like_number($id) ? $id : format_uuid($id);
247 $package = "${class}::${package}" if $package !~ s/^\+// && $package !~ /^\Q${class}::\E/;
249 my %blacklist = map { (looks_like_number($_) ? $_ : File::KDBX::Util::uuid($_)) => 1 }
250 split(/,/, $ENV{FILE_KDBX_CIPHER_BLACKLIST} // '');
251 if ($blacklist{$id} || $blacklist{$package}) {
252 alert "Ignoring blacklisted cipher ($formatted_id)", id => $id, package => $package;
256 if (defined $CIPHERS{$id}) {
257 alert "Overriding already-registered cipher ($formatted_id) with package $package",
262 $CIPHERS{$id} = [$package, @args];
267 File::KDBX::Cipher->unregister($uuid);
269 Unregister a cipher. Unregistered ciphers can no longer be used to encrypt and decrypt KDBX databases, until
270 reregistered (see L</register>).
275 delete $CIPHERS{$_} for @_;
279 __PACKAGE__->register(CIPHER_UUID_AES128, 'CBC
', algorithm => 'AES
', key_size => 16);
280 __PACKAGE__->register(CIPHER_UUID_AES256, 'CBC
', algorithm => 'AES
', key_size => 32);
281 __PACKAGE__->register(CIPHER_UUID_SERPENT, 'CBC
', algorithm => 'Serpent
', key_size => 32);
282 __PACKAGE__->register(CIPHER_UUID_TWOFISH, 'CBC
', algorithm => 'Twofish
', key_size => 32);
283 __PACKAGE__->register(CIPHER_UUID_CHACHA20, 'Stream
', algorithm => 'ChaCha
');
284 __PACKAGE__->register(CIPHER_UUID_SALSA20, 'Stream
', algorithm => 'Salsa20
');
285 __PACKAGE__->register(STREAM_ID_CHACHA20, 'Stream
', algorithm => 'ChaCha
');
286 __PACKAGE__->register(STREAM_ID_SALSA20, 'Stream
', algorithm => 'Salsa20
');
294 use File::KDBX::Cipher;
296 my $cipher = File::KDBX::Cipher->new(uuid => $uuid, key => $key, iv => $iv);
298 my $ciphertext = $cipher->encrypt('data
');
299 $ciphertext .= $cipher->encrypt('more data
');
300 $ciphertext .= $cipher->finish;
302 my $plaintext = $cipher->decrypt('data
');
303 $plaintext .= $cipher->decrypt('more data
');
304 $plaintext .= $cipher->finish;
308 A cipher is used to encrypt and decrypt KDBX files. The L<File::KDBX> distribution comes with several
309 pre-registered ciphers ready to go:
312 * C<61AB05A1-9464-41C3-8D74-3A563DF8DD35> - AES128 (legacy)
313 * C<31C1F2E6-BF71-4350-BE58-05216AFC5AFF> - AES256
314 * C<D6038A2B-8B6F-4CB5-A524-339A31DBB59A> - ChaCha20
315 * C<716E1C8A-EE17-4BDC-93AE-A977B882833A> - Salsa20
316 * C<098563FF-DDF7-4F98-8619-8079F6DB897A> - Serpent
317 * C<AD68F29F-576F-4BB9-A36A-D47AF965346C> - Twofish
319 B<NOTE:> If you want your KDBX file to be readable by other KeePass implementations, you must use a UUID and
320 algorithm that they support. From the list above, AES256 and ChaCha20 are well-supported. You should avoid
321 AES128 for new databases.
323 You can also L</register> your own cipher. Here is a skeleton:
325 package File::KDBX::Cipher::MyCipher;
327 use parent 'File
::KDBX
::Cipher
';
329 File::KDBX::Cipher->register(
330 # $uuid, $package, %args
331 "\x12\x34\x56\x78\x9a\xbc\xde\xfg\x12\x34\x56\x78\x9a\xbc\xde\xfg" => __PACKAGE__,
334 sub init { ... } # optional
342 sub block_size { ... }