File-KDBX
view release on metacpan or search on metacpan
lib/File/KDBX/Safe.pm view on Meta::CPAN
package File::KDBX::Safe;
# ABSTRACT: Keep strings encrypted while in memory
use warnings;
use strict;
use Crypt::PRNG qw(random_bytes);
use Devel::GlobalDestruction;
use Encode qw(encode decode);
use File::KDBX::Constants qw(:random_stream);
use File::KDBX::Error;
use File::KDBX::Util qw(erase erase_scoped);
use Ref::Util qw(is_arrayref is_coderef is_hashref is_scalarref);
use Scalar::Util qw(refaddr);
use namespace::clean;
our $VERSION = '0.906'; # VERSION
sub new {
my $class = shift;
my %args = @_ % 2 == 0 ? @_ : (strings => shift, @_);
if (!$args{cipher} && $args{key}) {
require File::KDBX::Cipher;
$args{cipher} = File::KDBX::Cipher->new(stream_id => STREAM_ID_CHACHA20, key => $args{key});
}
my $self = bless \%args, $class;
$self->cipher->finish;
$self->{counter} = 0;
my $strings = delete $args{strings};
$self->{items} = [];
$self->{index} = {};
$self->add($strings) if $strings;
return $self;
}
sub DESTROY { local ($., $@, $!, $^E, $?); !in_global_destruction and $_[0]->unlock }
sub clear {
my $self = shift;
$self->{items} = [];
$self->{index} = {};
$self->{counter} = 0;
return $self;
}
sub lock { shift->add(@_) }
sub add {
my $self = shift;
my @strings = map { is_arrayref($_) ? @$_ : $_ } @_;
@strings or throw 'Must provide strings to lock';
my $cipher = $self->cipher;
for my $string (@strings) {
my $item = {str => $string, off => $self->{counter}};
if (is_scalarref($string)) {
next if !defined $$string;
$item->{enc} = 'UTF-8' if utf8::is_utf8($$string);
if (my $encoding = $item->{enc}) {
my $encoded = encode($encoding, $$string);
$item->{val} = $cipher->crypt(\$encoded);
erase $encoded;
}
else {
( run in 0.794 second using v1.01-cache-2.11-cpan-39bf76dae61 )