]> Dogcows Code - chaz/p5-File-KDBX/blob - lib/File/KDBX/Cipher/Stream.pm
Fix CryptX 0.062 functionality change
[chaz/p5-File-KDBX] / lib / File / KDBX / Cipher / Stream.pm
1 package File::KDBX::Cipher::Stream;
2 # ABSTRACT: A cipher stream encrypter/decrypter
3
4 use warnings;
5 use strict;
6
7 use Crypt::Digest qw(digest_data);
8 use File::KDBX::Constants qw(:cipher :random_stream);
9 use File::KDBX::Error;
10 use File::KDBX::Util qw(:class);
11 use Scalar::Util qw(blessed);
12 use Module::Load;
13 use namespace::clean;
14
15 extends 'File::KDBX::Cipher';
16
17 our $VERSION = '999.999'; # VERSION
18
19 =attr counter
20
21 $counter = $cipher->counter;
22
23 Get the initial counter / block count into the keystream.
24
25 =attr offset
26
27 $offset = $cipher->offset;
28
29 Get the initial byte offset into the keystream. This has precedence over L</counter> if both are set.
30
31 =cut
32
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 }
37 sub block_size { 1 }
38
39 sub init {
40 my $self = shift;
41 my %args = @_;
42
43 if (my $uuid = $args{uuid}) {
44 if ($uuid eq CIPHER_UUID_CHACHA20 && length($args{iv}) == 16) {
45 # extract the counter
46 my $buf = substr($self->{iv}, 0, 4, '');
47 $self->{counter} = unpack('L<', $buf);
48 }
49 elsif ($uuid eq CIPHER_UUID_SALSA20) {
50 # only need eight bytes...
51 $self->{iv} = substr($args{iv}, 8);
52 }
53 }
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));
58 }
59 elsif ($id == STREAM_ID_SALSA20) {
60 ($self->{key}, $self->{iv}) = (digest_data('SHA256', $$key_ref), STREAM_SALSA20_IV);
61 }
62 }
63
64 return $self;
65 }
66
67 =method crypt
68
69 $ciphertext = $cipher->crypt($plaintext);
70 $plaintext = $cipher->crypt($ciphertext);
71
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>.
74
75 =cut
76
77 sub crypt {
78 my $self = shift;
79 my $stream = $self->_stream;
80 return join('', map { $stream->crypt(ref $_ ? $$_ : $_) } grep { defined } @_);
81 }
82
83 =method keystream
84
85 $stream = $cipher->keystream;
86
87 Access the keystream.
88
89 =cut
90
91 sub keystream {
92 my $self = shift;
93 return $self->_stream->keystream(@_);
94 }
95
96 =method dup
97
98 $cipher_copy = $cipher->dup(%attributes);
99
100 Get a copy of an existing cipher with the counter reset, optionally applying new attributes.
101
102 =cut
103
104 sub dup {
105 my $self = shift;
106 my $class = blessed($self);
107
108 my $dup = bless {%$self, @_}, $class;
109 delete $dup->{stream};
110 return $dup;
111 }
112
113 sub _stream {
114 my $self = shift;
115
116 $self->{stream} //= do {
117 my $s = eval {
118 my $pkg = 'Crypt::Stream::'.$self->algorithm;
119 my $counter = $self->counter;
120 my $pos = 0;
121 if (defined (my $offset = $self->offset)) {
122 $counter = int($offset / 64);
123 $pos = $offset % 64;
124 }
125 load $pkg;
126 my $s = $pkg->new($self->key, $self->iv, $counter);
127 # seek to correct position within block
128 $s->keystream($pos) if $pos;
129 $s;
130 };
131 if (my $err = $@) {
132 throw 'Failed to initialize stream cipher library',
133 error => $err,
134 algorithm => $self->{algorithm},
135 key_length => length($self->key),
136 iv_length => length($self->iv),
137 iv => unpack('H*', $self->iv),
138 key => unpack('H*', $self->key);
139 }
140 $s;
141 };
142 }
143
144 sub encrypt { goto &crypt }
145 sub decrypt { goto &crypt }
146
147 sub finish { delete $_[0]->{stream}; '' }
148
149 1;
150 __END__
151
152 =head1 SYNOPSIS
153
154 use File::KDBX::Cipher::Stream;
155
156 my $cipher = File::KDBX::Cipher::Stream->new(algorithm => $algorithm, key => $key, iv => $iv);
157
158 =head1 DESCRIPTION
159
160 A subclass of L<File::KDBX::Cipher> for encrypting and decrypting data using a stream cipher.
161
162 =cut
This page took 0.043754 seconds and 4 git commands to generate.