File Coverage

blib/lib/Crypt/Passphrase/Argon2/AES.pm
Criterion Covered Total %
statement 49 53 92.4
branch 10 24 41.6
condition 6 17 35.2
subroutine 11 11 100.0
pod 1 4 25.0
total 77 109 70.6


line stmt bran cond sub pod time code
1             package Crypt::Passphrase::Argon2::AES;
2              
3 1     1   385279 use strict;
  1         3  
  1         45  
4 1     1   7 use warnings;
  1         2  
  1         103  
5              
6             our $VERSION = '0.008';
7              
8 1     1   8 use parent 'Crypt::Passphrase::Argon2::Encrypted';
  1         2  
  1         10  
9 1     1   13276 use Crypt::Passphrase 0.019 -encoder;
  1         26  
  1         10  
10              
11 1     1   71 use Carp 'croak';
  1         2  
  1         67  
12 1     1   627 use Crypt::Rijndael 1.16;
  1         675  
  1         130  
13              
14             my %mode = (
15             'aes-cbc' => Crypt::Rijndael::MODE_CBC,
16             'aes-ecb' => Crypt::Rijndael::MODE_ECB,
17             'aes-cfb' => Crypt::Rijndael::MODE_CFB,
18             'aes-ofb' => Crypt::Rijndael::MODE_OFB,
19             'aes-ctr' => Crypt::Rijndael::MODE_CTR,
20              
21             'aes-cbc-pad' => Crypt::Rijndael::MODE_CBC,
22             'aes-ecb-pad' => Crypt::Rijndael::MODE_ECB,
23             );
24              
25             sub new {
26 1     1 1 22 my ($class, %args) = @_;
27 1 50       6 my $peppers = $args{peppers} or croak('No peppers given');
28 1 50 33 1   9 $args{active} //= (sort {; no warnings 'numeric'; $b <=> $a || $b cmp $a } keys %{ $peppers })[0];
  1         3  
  1         911  
  1         5  
  1         9  
  1         9  
29 1   50     6 my $mode = delete $args{mode} // 'cbc';
30 1         3 my $cipher = "aes-$mode";
31 1 50       3 croak "No such mode $mode" if not exists $mode{$cipher};
32 1         13 my $self = $class->SUPER::new(%args, cipher => $cipher, salt_size => 16);
33 1 50 33     75 croak "Output size must be a double of 16 for CBC and ECB" if ($mode eq 'cbc' || $mode eq 'ecb') && $self->{output_size} % 16;
      33        
34 1         2 for my $key (keys %{$peppers}) {
  1         4  
35 2         5 my $length = length $peppers->{$key};
36 2 0 33     7 croak "Pepper $key has invalid length $length" if $length != 16 && $length != 24 && $length != 32;
      33        
37 2         7 $self->{peppers}{$key} = $peppers->{$key};
38             }
39 1         8 return $self;
40             }
41              
42             sub encrypt_hash {
43 2     2 0 57405 my ($self, $cipher, $id, $iv, $raw) = @_;
44 2 50       14 if ($cipher =~ /-pad$/) {
45 0         0 my $pad_length = 16 - length($raw) % 16;
46 0         0 $raw .= chr($pad_length) x $pad_length;
47             }
48 2 50       19 my $mode = $mode{$cipher} or croak "No such cipher $cipher";
49 2 50       11 my $secret = $self->{peppers}{$id} or croak "No such pepper $id";
50 2         64 return Crypt::Rijndael->new($secret, $mode)->encrypt($raw, $iv);
51             }
52              
53             sub decrypt_hash {
54 3     3 0 137717 my ($self, $cipher, $id, $iv, $raw) = @_;
55 3 50       21 my $mode = $mode{$cipher} or croak "No such cipher $cipher";
56 3 50       31 my $secret = $self->{peppers}{$id} or croak "No such pepper $id";
57 3         57 my $plaintext = Crypt::Rijndael->new($secret, $mode)->decrypt($raw, $iv);
58 3 50       26 if ($cipher =~ /-pad$/) {
59 0         0 my $pad_length = ord substr $plaintext, -1;
60 0 0       0 substr($plaintext, -$pad_length, $pad_length, '') eq chr($pad_length) x $pad_length or croak 'Incorrectly padded';
61             }
62 3         15 return $plaintext;
63             }
64              
65             sub supported_ciphers {
66 1     1 0 129 return keys %mode;
67             }
68              
69             1;
70              
71             __END__