]>
Dogcows Code - chaz/p5-File-KDBX/blob - lib/File/KDBX/IO/HashBlock.pm
f7e200d82280f0120f8b418f9800e07173530074
1 package File
::KDBX
::IO
::HashBlock
;
2 # ABSTRACT: Hash block stream IO handle
7 use Crypt
::Digest
qw(digest_data);
10 use File
::KDBX
::Util
qw(:class :io);
14 extends
'File::KDBX::IO';
16 our $VERSION = '0.904'; # VERSION
17 our $ALGORITHM = 'SHA256';
18 our $BLOCK_SIZE = 1048576; # 1MiB
24 _buffer
=> sub { \
(my $buf = '') },
26 algorithm
=> sub { $ALGORITHM },
27 block_size
=> sub { $BLOCK_SIZE },
29 while (my ($attr, $default) = each %ATTRS) {
30 no strict
'refs'; ## no critic (ProhibitNoStrict)
33 *$self->{$attr} = shift if @_;
34 *$self->{$attr} //= (ref $default eq 'CODE') ? $default->($self) : $default;
41 my %args = @_ % 2 == 1 ? (fh
=> shift, @_) : @_;
42 my $self = $class->SUPER::new
;
43 $self->_fh($args{fh
}) or throw
'IO handle required';
44 $self->algorithm($args{algorithm
});
45 $self->block_size($args{block_size
});
53 $ENV{DEBUG_STREAM
} and print STDERR
"FILL\t$self\n";
54 return if $self->_finished;
56 my $block = eval { $self->_read_hash_block($fh) };
58 $self->_set_error($err);
61 return $$block if defined $block;
65 my ($self, $buf, $fh) = @_;
67 $ENV{DEBUG_STREAM
} and print STDERR
"WRITE\t$self\n";
68 return 0 if $self->_finished;
70 ${$self->_buffer} .= $buf;
80 $ENV{DEBUG_STREAM
} and print STDERR
"POPPED\t$self\n";
81 return if $self->_mode ne 'w';
85 $self->_write_next_hash_block($fh); # partial block with remaining content
86 $self->_write_final_hash_block($fh); # terminating block
88 $self->_set_error($@) if $@;
94 $ENV{DEBUG_STREAM
} and print STDERR
"FLUSH\t$self\n";
95 return if $self->_mode ne 'w';
98 while ($self->block_size <= length(${*$self->{_buffer
}})) {
99 $self->_write_next_hash_block($fh);
103 $self->_set_error($err);
110 ##############################################################################
112 sub _read_hash_block
{
116 read_all
$fh, my $buf, 4 or throw
'Failed to read hash block index';
117 my ($index) = unpack('L<', $buf);
119 $index == $self->_block_index or throw
'Invalid block index', index => $index;
121 read_all
$fh, my $hash, 32 or throw
'Failed to read hash';
123 read_all
$fh, $buf, 4 or throw
'Failed to read hash block size';
124 my ($size) = unpack('L<', $buf);
127 $hash eq ("\0" x
32) or throw
'Invalid final block hash', hash
=> $hash;
132 read_all
$fh, my $block, $size or throw
'Failed to read hash block', index => $index, size
=> $size;
134 my $got_hash = digest_data
($self->algorithm, $block);
136 or throw
'Hash mismatch', index => $index, size
=> $size, got
=> $got_hash, expected
=> $hash;
138 *$self->{_block_index
}++;
142 sub _write_next_hash_block
{
146 my $size = length(${$self->_buffer});
147 $size = $self->block_size if $self->block_size < $size;
148 return 0 if $size == 0;
150 my $block = substr(${$self->_buffer}, 0, $size, '');
152 my $buf = pack('L<', $self->_block_index);
153 print $fh $buf or throw
'Failed to write hash block index';
155 my $hash = digest_data
($self->algorithm, $block);
156 print $fh $hash or throw
'Failed to write hash';
158 $buf = pack('L<', length($block));
159 print $fh $buf or throw
'Failed to write hash block size';
161 # $fh->write($block, $size) or throw 'Failed to hash write block';
162 print $fh $block or throw
'Failed to hash write block';
164 *$self->{_block_index
}++;
168 sub _write_final_hash_block
{
172 my $buf = pack('L<', $self->_block_index);
173 print $fh $buf or throw
'Failed to write hash block index';
175 my $hash = "\0" x
32;
176 print $fh $hash or throw
'Failed to write hash';
178 $buf = pack('L<', 0);
179 print $fh $buf or throw
'Failed to write hash block size';
187 $ENV{DEBUG_STREAM
} and print STDERR
"err\t$self\n";
188 if (exists &Errno
::EPROTO
) {
191 elsif (exists &Errno
::EIO
) {
194 $self->_error($ERROR = error
(@_));
207 File::KDBX::IO::HashBlock - Hash block stream IO handle
215 Writing to a hash-block handle will transform the data into a series of blocks. Each block is hashed, and the
216 hash is included with the block in the stream.
218 Reading from a handle, each hash block will be verified as the blocks are disassembled back into a data
221 This format helps ensure data integrity of KDBX3 files.
223 Each block is encoded thusly:
229 Block index - Little-endian unsigned 32-bit integer, increments starting with 0
237 Block size - Little-endian unsigned 32-bit (counting only the data)
241 Data - String of bytes
245 The terminating block is an empty block where hash is 32 null bytes, block size is 0 and there is no data.
251 Digest algorithm in hash-blocking the stream (default: C<SHA-256>)
255 Desired block size when writing (default: C<$File::KDBX::IO::HashBlock::BLOCK_SIZE> or 1,048,576 bytes)
261 $fh = File::KDBX::IO::HashBlock->new(%attributes);
262 $fh = File::KDBX::IO::HashBlock->new($fh, %attributes);
264 Construct a new hash-block stream IO handle.
268 Please report any bugs or feature requests on the bugtracker website
269 L<https://github.com/chazmcgarvey/File-KDBX/issues>
271 When submitting a bug or request, please include a test-file or a
272 patch to an existing test-file that illustrates the bug or desired
277 Charles McGarvey <ccm@cpan.org>
279 =head1 COPYRIGHT AND LICENSE
281 This software is copyright (c) 2022 by Charles McGarvey.
283 This is free software; you can redistribute it and/or modify it under
284 the same terms as the Perl 5 programming language system itself.
This page took 0.053648 seconds and 3 git commands to generate.