1 package PerlIO
::via
::File
::KDBX
::Crypt
;
2 # ABSTRACT: Encrypter/decrypter PerlIO layer
11 our $VERSION = '999.999'; # VERSION
12 our $BUFFER_SIZE = 8192;
17 PerlIO
::via
::File
::KDBX
::Crypt-
>push($fh, cipher
=> $cipher);
19 Push an encryption
or decryption layer onto a filehandle
. C
<$cipher> must be compatible with
20 L
<File
::KDBX
::Cipher
>.
22 You mustn
't push this layer using C<binmode> directly because the layer needs to be initialized with the
23 required cipher object.
25 B<WARNING:> When writing, you mustn't
close the filehandle before popping this layer
(using
26 C
<binmode($fh, ':pop')>) or the stream will be truncated
. The layer needs to know
when there
is no more data
27 before the filehandle closes so it can finish the encryption correctly
, and the way to indicate that
is by
34 %PUSHED_ARGS and throw
'Pushing Crypt layer would stomp existing arguments';
37 my %args = @_ % 2 == 0 ? @_ : (cipher
=> @_);
38 $args{cipher
} or throw
'Must pass a cipher';
39 $args{cipher
}->finish if defined $args{finish
} && !$args{finish
};
42 binmode($fh, ':via(' . __PACKAGE__
. ')');
46 my ($class, $mode) = @_;
48 $ENV{DEBUG_STREAM
} and print STDERR
"PUSHED\t$class\n";
49 %PUSHED_ARGS or throw
'Programmer error: Use PerlIO::via::File::KDBX::Crypt->push instead of binmode';
54 cipher
=> $PUSHED_ARGS{cipher
},
64 $ENV{DEBUG_STREAM
} and print STDERR
"FILL\t$self\n";
65 return if $self->EOF($fh);
67 $fh->read(my $buf, $BUFFER_SIZE);
68 if (0 < length($buf)) {
69 my $plaintext = eval { $self->cipher->decrypt($buf) };
71 $self->_set_error($err);
78 my $plaintext = eval { $self->cipher->finish };
80 $self->_set_error($err);
83 delete $self->{cipher
};
88 my ($self, $buf, $fh) = @_;
90 $ENV{DEBUG_STREAM
} and print STDERR
"WRITE\t$self\n";
91 return 0 if $self->EOF($fh);
93 ${$self->buffer} .= eval { $self->cipher->encrypt($buf) } || '';
95 $self->_set_error($err);
102 my ($self, $fh) = @_;
104 $ENV{DEBUG_STREAM
} and print STDERR
"POPPED\t$self\n";
105 return if $self->EOF($fh) || $self->mode !~ /^w/;
107 ${$self->buffer} .= eval { $self->cipher->finish } || '';
109 $self->_set_error($err);
113 delete $self->{cipher
};
118 my ($self, $fh) = @_;
120 $ENV{DEBUG_STREAM
} and print STDERR
"FLUSH\t$self\n";
121 return 0 if !ref $self;
123 my $buf = $self->buffer;
124 print $fh $$buf or return -1 if 0 < length($$buf);
129 # sub EOF { !$_[0]->cipher || $_[0]->ERROR($_[1]) }
130 # sub ERROR { $_[0]->{error} ? 1 : 0 }
131 # sub CLEARERR { delete $_[0]->{error}; 0 }
134 $ENV{DEBUG_STREAM
} and print STDERR
"EOF\t$_[0]\n";
135 !$_[0]->cipher || $_[0]->ERROR($_[1]);
138 $ENV{DEBUG_STREAM
} and print STDERR
"ERROR\t$_[0] : ", $_[0]->{error
} // 'ok', "\n";
139 $_[0]->{error
} ? 1 : 0;
142 $ENV{DEBUG_STREAM
} and print STDERR
"CLEARERR\t$_[0]\n";
143 # delete $_[0]->{error};
146 sub cipher
{ $_[0]->{cipher
} }
147 sub mode
{ $_[0]->{mode
} }
148 sub buffer
{ $_[0]->{buffer
} }
152 $ENV{DEBUG_STREAM
} and print STDERR
"err\t$self\n";
153 delete $self->{cipher
};
154 if (exists &Errno
::EPROTO
) {
157 elsif (exists &Errno
::EIO
) {
160 $self->{error
} = $ERROR = File
::KDBX
::Error-
>new(@_);
168 use PerlIO::via::File::KDBX::Crypt;
169 use File::KDBX::Cipher;
171 my $cipher = File::KDBX::Cipher->new(...);
173 open(my $out_fh, '>:raw', 'ciphertext.bin');
174 PerlIO::via::File::KDBX::Crypt->push($out_fh, cipher => $cipher);
176 print $out_fh $plaintext;
178 binmode($out_fh, ':pop'); # <-- This is required.
181 open(my $in_fh, '<:raw', 'ciphertext.bin');
182 PerlIO::via::File::KDBX::Crypt->push($in_fh, cipher => $cipher);
184 my $plaintext = do { local $/; <$in_fh> );