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 Scalar
::Util
qw(blessed);
14 use parent
'File::KDBX::Cipher';
16 our $VERSION = '999.999'; # VERSION
22 if (my $uuid = $args{uuid
}) {
23 if ($uuid eq CIPHER_UUID_CHACHA20
&& length($args{iv
}) == 16) {
25 my $buf = substr($self->{iv
}, 0, 4, '');
26 $self->{counter
} = unpack('L<', $buf);
28 elsif ($uuid eq CIPHER_UUID_SALSA20
) {
29 # only need eight bytes...
30 $self->{iv
} = substr($args{iv
}, 8);
33 elsif (my $id = $args{stream_id
}) {
34 my $key_ref = ref $args{key
} ? $args{key
} : \
$args{key
};
35 if ($id == STREAM_ID_CHACHA20
) {
36 ($self->{key
}, $self->{iv
}) = unpack('a32 a12', digest_data
('SHA512', $$key_ref));
38 elsif ($id == STREAM_ID_SALSA20
) {
39 ($self->{key
}, $self->{iv
}) = (digest_data
('SHA256', $$key_ref), STREAM_SALSA20_IV
);
48 $ciphertext = $cipher->crypt($plaintext);
49 $plaintext = $cipher->crypt($ciphertext);
51 Encrypt
or decrypt some data
. These ciphers are symmetric
, so encryption
and decryption are the same
52 operation
. This
method is an alias
for both L
<File
::KDBX
::Cipher
/encrypt> and L<File::KDBX::Cipher/decrypt
>.
58 my $stream = $self->_stream;
59 return join('', map { $stream->crypt(ref $_ ? $$_ : $_) } grep { defined } @_);
64 $stream = $cipher->keystream;
72 return $self->_stream->keystream(@_);
77 $cipher_copy = $cipher->dup(%attributes);
79 Get a copy of an existing cipher with the counter
reset, optionally applying new attributes
.
85 my $class = blessed
($self);
87 my $dup = bless {%$self, @_}, $class;
88 delete $dup->{stream
};
95 $self->{stream
} //= do {
97 my $pkg = 'Crypt::Stream::'.$self->algorithm;
98 my $counter = $self->counter;
100 if (defined (my $offset = $self->offset)) {
101 $counter = int($offset / 64);
104 my $s = $pkg->new($self->key, $self->iv, $counter);
105 # seek to correct position within block
106 $s->keystream($pos) if $pos;
110 throw
'Failed to initialize stream cipher library',
112 algorithm
=> $self->algorithm,
113 key_length
=> length($self->key),
114 iv_length
=> length($self->iv),
115 iv
=> unpack('H*', $self->iv),
116 key
=> unpack('H*', $self->key);
122 sub encrypt
{ goto &crypt }
123 sub decrypt
{ goto &crypt }
125 sub finish
{ delete $_[0]->{stream
}; '' }
129 $algorithm = $cipher->algorithm;
131 Get the stream cipher algorithm
. Can be one of C
<Salsa20
> and C
<ChaCha
>.
135 $counter = $cipher->counter;
137 Get the initial counter
/ block count into the keystream
.
141 $offset = $cipher->offset;
143 Get the initial byte offset into the keystream
. This
has precedence over L
</counter
> if both are set
.
147 sub algorithm
{ $_[0]->{algorithm
} or throw
'Stream cipher algorithm is not set' }
148 sub counter
{ $_[0]->{counter
} // 0 }
149 sub offset
{ $_[0]->{offset
} }
150 sub key_size
{ { Salsa20
=> 32, ChaCha
=> 32 }->{$_[0]->{algorithm
} || ''} // 0 }
151 sub iv_size
{ { Salsa20
=> 8, ChaCha
=> 12 }->{$_[0]->{algorithm
} || ''} // -1 }
159 use File::KDBX::Cipher::Stream;
161 my $cipher = File::KDBX::Cipher::Stream->new(algorithm => $algorithm, key => $key, iv => $iv);
165 A subclass of L<File::KDBX::Cipher> for encrypting and decrypting data using a stream cipher.