File Coverage

blib/lib/App/Raps2/Password.pm
Criterion Covered Total %
statement 60 60 100.0
branch 12 12 100.0
condition 13 17 76.4
subroutine 14 14 100.0
pod 7 7 100.0
total 106 110 96.3


line stmt bran cond sub pod time code
1             package App::Raps2::Password;
2              
3 2     2   837 use strict;
  2         3  
  2         49  
4 2     2   9 use warnings;
  2         2  
  2         49  
5 2     2   39 use 5.010;
  2         6  
6              
7 2     2   10 use Carp 'confess';
  2         2  
  2         108  
8 2     2   1798 use Crypt::CBC;
  2         8418  
  2         56  
9 2     2   1292 use Crypt::Eksblowfish;
  2         4873  
  2         69  
10 2     2   1551 use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash en_base64 de_base64);
  2         4094  
  2         1127  
11              
12             our $VERSION = '0.54';
13              
14             sub new {
15 8     8 1 3026 my ( $obj, %conf ) = @_;
16              
17 8   100     35 $conf{cost} //= 12;
18              
19 8 100       19 if ( not defined $conf{salt} ) {
20 2         9 $conf{salt} = create_salt();
21             }
22              
23 8 100       29 if ( length( $conf{salt} ) != 16 ) {
24 2         462 confess('incorrect salt length');
25             }
26              
27 6 100 100     34 if ( not( defined $conf{passphrase} and length $conf{passphrase} ) ) {
28 2         519 confess('no passphrase given');
29             }
30              
31 4         7 my $ref = \%conf;
32              
33 4         15 return bless( $ref, $obj );
34             }
35              
36             sub create_salt {
37 4     4 1 7 my ($self) = @_;
38 4         10 my $salt = q{};
39              
40 4         15 for ( 1 .. 16 ) {
41 64         181 $salt .= chr( 0x21 + int( rand(90) ) );
42             }
43              
44 4         19 return $salt;
45             }
46              
47             sub salt {
48 6     6 1 1996 my ( $self, $salt ) = @_;
49              
50 6 100       22 if ( defined $salt ) {
51 4 100       12 if ( length($salt) != 16 ) {
52 3         365 confess('incorrect salt length');
53             }
54              
55 1         4 $self->{salt} = $salt;
56             }
57              
58 3         14 return $self->{salt};
59             }
60              
61             sub encrypt {
62 4     4 1 691 my ( $self, %opt ) = @_;
63              
64 4   66     20 $opt{salt} //= $self->{salt};
65 4   66     14 $opt{cost} //= $self->{cost};
66              
67             my $eksblowfish
68 4         1409974 = Crypt::Eksblowfish->new( $opt{cost}, $opt{salt}, $self->{passphrase}, );
69 4         103 my $cbc = Crypt::CBC->new( -cipher => $eksblowfish );
70              
71 4         848 return $cbc->encrypt_hex( $opt{data} );
72             }
73              
74             sub decrypt {
75 7     7 1 1492 my ( $self, %opt ) = @_;
76              
77 7   66     79 $opt{cost} //= $self->{cost};
78 7   66     26 $opt{salt} //= $self->{salt};
79              
80             my $eksblowfish
81 7         2357648 = Crypt::Eksblowfish->new( $opt{cost}, $opt{salt}, $self->{passphrase}, );
82 7         196 my $cbc = Crypt::CBC->new( -cipher => $eksblowfish );
83              
84 7         1312 return $cbc->decrypt_hex( $opt{data} );
85             }
86              
87             sub bcrypt {
88 6     6 1 710 my ($self) = @_;
89              
90             return en_base64(
91             bcrypt_hash(
92             {
93             key_nul => 1,
94             cost => $self->{cost},
95             salt => $self->{salt},
96             },
97             $self->{passphrase},
98             )
99 6         47 );
100             }
101              
102             sub verify {
103 4     4 1 30010 my ( $self, $testhash ) = @_;
104              
105 4         14 my $myhash = $self->bcrypt();
106              
107 4 100       549916 if ( $testhash eq $myhash ) {
108 3         23 return 1;
109             }
110 1         211 confess('Passwords did not match');
111             }
112              
113             1;
114              
115             __END__