File Coverage

blib/lib/Crypt/AuthEnc/XChaCha20Poly1305.pm
Criterion Covered Total %
statement 42 43 97.6
branch 12 16 75.0
condition 5 9 55.5
subroutine 12 13 92.3
pod 5 5 100.0
total 76 86 88.3


line stmt bran cond sub pod time code
1             package Crypt::AuthEnc::XChaCha20Poly1305;
2              
3 2     2   129647 use strict;
  2         2  
  2         55  
4 2     2   7 use warnings;
  2         2  
  2         237  
5             our $VERSION = '0.089';
6              
7             require Exporter; our @ISA = qw(Exporter Crypt::AuthEnc::ChaCha20Poly1305); ### use Exporter 5.57 'import';
8             our %EXPORT_TAGS = ( all => [qw( xchacha20poly1305_encrypt_authenticate xchacha20poly1305_decrypt_verify )] );
9             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
10             our @EXPORT = qw();
11              
12 2     2   14 use Carp;
  2         3  
  2         118  
13             $Carp::Internal{(__PACKAGE__)}++;
14 2     2   349 use Crypt::AuthEnc::ChaCha20Poly1305 ();
  2         7  
  2         74  
15 2     2   969 use overload ();
  2         4229  
  2         714  
16              
17             sub _check_nonce {
18 11     11   24 my ($nonce) = @_;
19 11 50       26 croak "FATAL: undefined nonce" unless defined $nonce;
20 11 50 66     34 croak "FATAL: nonce must be string/buffer scalar"
21             if ref($nonce) && !overload::Method($nonce, q{""});
22 11 100       378 croak "FATAL: XChaCha20Poly1305 nonce length must be 24 bytes" unless length($nonce) == 24;
23             }
24              
25             sub _check_key {
26 12     12   32 my ($key) = @_;
27 12 50       38 croak "FATAL: undefined key" unless defined $key;
28 12 50 66     47 croak "FATAL: key must be string/buffer scalar"
29             if ref($key) && !overload::Method($key, q{""});
30 12 100       521 croak "FATAL: XChaCha20Poly1305 key length must be 32 bytes" unless length($key) == 32;
31             }
32              
33             sub new {
34 6     6 1 200871 my ($class, $key, $nonce) = @_;
35 6         21 _check_key($key);
36 5 100       23 _check_nonce($nonce) if @_ > 2;
37 4 100       101 my $self = @_ > 2
38             ? Crypt::AuthEnc::ChaCha20Poly1305->new($key, $nonce)
39             : Crypt::AuthEnc::ChaCha20Poly1305->new($key);
40 4         18 return bless $self, $class;
41             }
42              
43             sub clone {
44 1     1 1 16 my ($self) = @_;
45 1   33     9 return bless Crypt::AuthEnc::ChaCha20Poly1305::clone($self), ref($self) || $self;
46             }
47              
48             sub set_iv {
49 1     1 1 4 my ($self, $nonce) = @_;
50 1         5 _check_nonce($nonce);
51 1         8 Crypt::AuthEnc::ChaCha20Poly1305::set_iv($self, $nonce);
52 1         3 return $self;
53             }
54              
55             sub xchacha20poly1305_encrypt_authenticate {
56 3     3 1 2975 my ($key, $nonce, $adata, $plaintext) = @_;
57 3         11 _check_key($key);
58 3         15 _check_nonce($nonce);
59 3         57 return Crypt::AuthEnc::ChaCha20Poly1305::chacha20poly1305_encrypt_authenticate($key, $nonce, $adata, $plaintext);
60             }
61              
62             sub xchacha20poly1305_decrypt_verify {
63 3     3 1 4602 my ($key, $nonce, $adata, $ciphertext, $tag) = @_;
64 3         25 _check_key($key);
65 3         14 _check_nonce($nonce);
66 3         35 return Crypt::AuthEnc::ChaCha20Poly1305::chacha20poly1305_decrypt_verify($key, $nonce, $adata, $ciphertext, $tag);
67             }
68              
69 0     0     sub CLONE_SKIP { 1 } # prevent cloning
70              
71             1;
72              
73             =pod
74              
75             =head1 NAME
76              
77             Crypt::AuthEnc::XChaCha20Poly1305 - Authenticated encryption in XChaCha20-Poly1305 mode
78              
79             =head1 SYNOPSIS
80              
81             ### OO interface
82             use Crypt::AuthEnc::XChaCha20Poly1305;
83              
84             my $key = '...';
85             my $nonce = '...';
86             my $expected_tag = '...';
87              
88             # encrypt and authenticate
89             my $ae_enc = Crypt::AuthEnc::XChaCha20Poly1305->new($key, $nonce);
90             $ae_enc->adata_add('additional_authenticated_data1');
91             $ae_enc->adata_add('additional_authenticated_data2');
92             my $ct = $ae_enc->encrypt_add('data1');
93             $ct .= $ae_enc->encrypt_add('data2');
94             my $tag = $ae_enc->encrypt_done();
95              
96             # decrypt and verify
97             my $ae_dec = Crypt::AuthEnc::XChaCha20Poly1305->new($key, $nonce);
98             $ae_dec->adata_add('additional_authenticated_data1');
99             my $pt = $ae_dec->decrypt_add($ct);
100             die "decrypt failed" unless $ae_dec->decrypt_done($tag);
101              
102             ### functional interface
103             use Crypt::AuthEnc::XChaCha20Poly1305 qw(
104             xchacha20poly1305_encrypt_authenticate
105             xchacha20poly1305_decrypt_verify
106             );
107              
108             my $key = '...';
109             my $nonce = '...';
110             my $adata = '...';
111             my $plaintext = '...';
112              
113             my ($ciphertext, $tag) = xchacha20poly1305_encrypt_authenticate($key, $nonce, $adata, $plaintext);
114             my $decrypted = xchacha20poly1305_decrypt_verify($key, $nonce, $adata, $ciphertext, $tag);
115              
116             =head1 DESCRIPTION
117              
118             I
119              
120             Provides encryption and authentication based on XChaCha20 + Poly1305 using
121             the extended 192-bit (24-byte) nonce variant of ChaCha20-Poly1305.
122              
123             This is a stateful API. Build one message by calling, in order:
124             C or C, optional C, zero or more C or
125             C calls, then C or C.
126              
127             Use a fresh object per message. If you construct with C you must
128             call C before adding AAD or processing plaintext/ciphertext.
129             When verifying, C is the safer one-step form;
130             C without arguments only returns the calculated tag.
131             The first C / C call finalizes the object. After that,
132             further C, C, C, C,
133             C, and C calls croak.
134              
135             =head1 EXPORT
136              
137             Nothing is exported by default.
138              
139             You can export selected functions:
140              
141             use Crypt::AuthEnc::XChaCha20Poly1305 qw(
142             xchacha20poly1305_encrypt_authenticate
143             xchacha20poly1305_decrypt_verify
144             );
145              
146             =head1 FUNCTIONS
147              
148             =head2 xchacha20poly1305_encrypt_authenticate
149              
150             my ($ciphertext, $tag) = xchacha20poly1305_encrypt_authenticate($key, $nonce, $adata, $plaintext);
151              
152             # $key ..... [binary string] encryption key (256 bits / 32 bytes)
153             # $nonce ... [binary string] extended nonce (192 bits / 24 bytes)
154             # $adata ... [binary string] additional authenticated data (optional)
155              
156             Invalid key or nonce lengths croak.
157             String-overloaded objects are accepted for C<$key> and C<$nonce>.
158              
159             =head2 xchacha20poly1305_decrypt_verify
160              
161             my $plaintext = xchacha20poly1305_decrypt_verify($key, $nonce, $adata, $ciphertext, $tag);
162             # on error returns undef
163              
164             Invalid key or nonce lengths croak.
165             String-overloaded objects are accepted for C<$key> and C<$nonce>.
166              
167             =head1 METHODS
168              
169             Unless noted otherwise, assume C<$ae> is an existing AEAD object created via
170             C, for example:
171              
172             my $ae = Crypt::AuthEnc::XChaCha20Poly1305->new($key, $nonce);
173              
174             =head2 new
175              
176             my $ae = Crypt::AuthEnc::XChaCha20Poly1305->new($key, $nonce);
177             my $ae = Crypt::AuthEnc::XChaCha20Poly1305->new($key);
178              
179             # $key ..... [binary string] encryption key (256 bits / 32 bytes)
180             # $nonce ... [binary string] extended nonce (192 bits / 24 bytes)
181              
182             =head2 adata_add
183              
184             Add B.
185             Can be called only before the first C or C.
186             Returns the object itself (for chaining).
187              
188             $ae->adata_add($aad_data); # can be called multiple times
189              
190             =head2 encrypt_add
191              
192             Returns a binary string of ciphertext (raw bytes).
193              
194             my $ciphertext = $ae->encrypt_add($data); # can be called multiple times
195              
196             =head2 encrypt_done
197              
198             Returns the authentication tag as a binary string (raw bytes).
199             This call finalizes the current message.
200              
201             my $tag = $ae->encrypt_done(); # returns $tag value
202              
203             =head2 decrypt_add
204              
205             Returns a binary string of plaintext (raw bytes).
206              
207             my $plaintext = $ae->decrypt_add($ciphertext); # can be called multiple times
208              
209             =head2 decrypt_done
210              
211             Without argument returns the computed tag as a binary string. With C<$tag> argument returns C<1> (success) or C<0> (failure).
212             This call finalizes the current message.
213              
214             my $tag = $ae->decrypt_done; # returns $tag value
215             #or
216             my $result = $ae->decrypt_done($tag); # returns 1 (success) or 0 (failure)
217              
218             =head2 set_iv
219              
220             my $ae = Crypt::AuthEnc::XChaCha20Poly1305->new($key)->set_iv($nonce);
221             # $nonce ... [binary string] extended nonce (192 bits / 24 bytes)
222              
223             Call C before the first C, C, or C
224             for a message.
225              
226             =head2 clone
227              
228             Returns a copy of the AEAD object in its current state.
229              
230             my $ae_new = $ae->clone;
231              
232             =head1 SEE ALSO
233              
234             =over
235              
236             =item * L, L, L
237              
238             =item * L
239              
240             =back
241              
242             =cut