1 package File
::KDBX
::Cipher
::Stream
;
2 # ABSTRACT: A cipher stream encrypter/decrypter
7 use Crypt
::Digest
qw(digest_data);
8 use File
::KDBX
::Constants
qw(:cipher :random_stream);
10 use File
::KDBX
::Util
qw(:class);
11 use Scalar
::Util
qw(blessed);
15 extends
'File::KDBX::Cipher';
17 our $VERSION = '999.999'; # VERSION
21 $counter = $cipher->counter;
23 Get the initial counter
/ block count into the keystream
.
27 $offset = $cipher->offset;
29 Get the initial byte offset into the keystream
. This
has precedence over L
</counter
> if both are set
.
33 has 'counter', is => 'ro', default => 0;
34 has 'offset', is => 'ro';
35 sub key_size
{ { Salsa20
=> 32, ChaCha
=> 32 }->{$_[0]->{algorithm
} || ''} // 0 }
36 sub iv_size
{ { Salsa20
=> 8, ChaCha
=> 12 }->{$_[0]->{algorithm
} || ''} // -1 }
43 if (my $uuid = $args{uuid
}) {
44 if ($uuid eq CIPHER_UUID_CHACHA20
&& length($args{iv
}) == 16) {
46 my $buf = substr($self->{iv
}, 0, 4, '');
47 $self->{counter
} = unpack('L<', $buf);
49 elsif ($uuid eq CIPHER_UUID_SALSA20
) {
50 # only need eight bytes...
51 $self->{iv
} = substr($args{iv
}, 8);
54 elsif (my $id = $args{stream_id
}) {
55 my $key_ref = ref $args{key
} ? $args{key
} : \
$args{key
};
56 if ($id == STREAM_ID_CHACHA20
) {
57 ($self->{key
}, $self->{iv
}) = unpack('a32 a12', digest_data
('SHA512', $$key_ref));
59 elsif ($id == STREAM_ID_SALSA20
) {
60 ($self->{key
}, $self->{iv
}) = (digest_data
('SHA256', $$key_ref), STREAM_SALSA20_IV
);
69 $ciphertext = $cipher->crypt($plaintext);
70 $plaintext = $cipher->crypt($ciphertext);
72 Encrypt
or decrypt some data
. These ciphers are symmetric
, so encryption
and decryption are the same
73 operation
. This
method is an alias
for both L
<File
::KDBX
::Cipher
/encrypt> and L<File::KDBX::Cipher/decrypt
>.
79 my $stream = $self->_stream;
80 return join('', map { $stream->crypt(ref $_ ? $$_ : $_) } grep { defined } @_);
85 $stream = $cipher->keystream;
93 return $self->_stream->keystream(@_);
98 $cipher_copy = $cipher->dup(%attributes);
100 Get a copy of an existing cipher with the counter
reset, optionally applying new attributes
.
106 my $class = blessed
($self);
108 my $dup = bless {%$self, @_}, $class;
109 delete $dup->{stream
};
116 $self->{stream
} //= do {
118 my $pkg = 'Crypt::Stream::'.$self->algorithm;
119 my $counter = $self->counter;
121 if (defined (my $offset = $self->offset)) {
122 $counter = int($offset / 64);
125 my $s = $pkg->new($self->key, $self->iv, $counter);
126 # seek to correct position within block
127 $s->keystream($pos) if $pos;
131 throw
'Failed to initialize stream cipher library',
133 algorithm
=> $self->{algorithm
},
134 key_length
=> length($self->key),
135 iv_length
=> length($self->iv),
136 iv
=> unpack('H*', $self->iv),
137 key
=> unpack('H*', $self->key);
143 sub encrypt
{ goto &crypt }
144 sub decrypt
{ goto &crypt }
146 sub finish
{ delete $_[0]->{stream
}; '' }
153 use File::KDBX::Cipher::Stream;
155 my $cipher = File::KDBX::Cipher::Stream->new(algorithm => $algorithm, key => $key, iv => $iv);
159 A subclass of L<File::KDBX::Cipher> for encrypting and decrypting data using a stream cipher.