File Coverage

blib/lib/Crypt/Passphrase/Linux.pm
Criterion Covered Total %
statement 39 39 100.0
branch 2 4 50.0
condition 7 13 53.8
subroutine 12 12 100.0
pod 6 6 100.0
total 66 74 89.1


line stmt bran cond sub pod time code
1             package Crypt::Passphrase::Linux;
2             $Crypt::Passphrase::Linux::VERSION = '0.003';
3 1     1   679 use strict;
  1         3  
  1         33  
4 1     1   6 use warnings;
  1         2  
  1         45  
5              
6 1     1   7 use Crypt::Passphrase 0.010 -encoder;
  1         26  
  1         8  
7              
8 1     1   6293 use Carp 'croak';
  1         3  
  1         59  
9 1     1   6 use Crypt::Passwd::XS 'crypt';
  1         2  
  1         27  
10 1     1   504 use MIME::Base64 qw/encode_base64/;
  1         651  
  1         622  
11              
12             my %identifier_for = (
13             md5 => '1',
14             apache_md5 => 'apr1',
15             sha256 => '5',
16             sha512 => '6',
17             );
18              
19             my %salt_size = (
20             md5 => 6,
21             apache_md5 => 6,
22             sha256 => 12,
23             sha512 => 12,
24             );
25              
26             sub new {
27 1     1 1 18 my ($class, %args) = @_;
28 1   50     5 my $type_name = $args{type} // 'sha512';
29 1   33     3 my $type = $identifier_for{$type_name} // croak "No such crypt type $type_name";
30 1         3 my $salt_size = $salt_size{$type_name};
31 1   50     3 my $rounds = $args{rounds} // 656_000;
32              
33 1         8 return bless {
34             type => $type,
35             rounds => $rounds + 0,
36             salt_size => $salt_size,
37             }, $class;
38             }
39              
40             sub hash_password {
41 1     1 1 145 my ($self, $password) = @_;
42 1         14 my $salt = $self->random_bytes($self->{salt_size});
43 1         10615 (my $encoded_salt = encode_base64($salt, "")) =~ tr{A-Za-z0-9+/=}{./A-Za-z0-9}d;
44 1         10 my $settings = sprintf '$%s$rounds=%d$%s', $self->{type}, $self->{rounds}, $encoded_salt;
45 1         7 return Crypt::Passwd::XS::crypt($password, $settings);
46             }
47              
48             sub accepts_hash {
49 5     5 1 239228 my ($self, $hash) = @_;
50 5   66     78 return $hash =~ / \A [.\/A-Za-z0-9]{13} \z /x || $self->SUPER::accepts_hash($hash);
51             }
52              
53             sub crypt_subtypes {
54 1     1 1 20 return values %identifier_for;
55             }
56              
57             my $regex = qr/ ^ \$ (1|5|6|apr1) \$ (?: rounds= ([0-9]+) \$ )? ([^\$]*) \$ [^\$]+ $ /x;
58              
59             sub needs_rehash {
60 4     4 1 2343 my ($self, $hash) = @_;
61 4 50       67 my ($type, $rounds, $salt) = $hash =~ $regex or return 1;
62 4 50       20 $rounds = 5000 if $rounds eq '';
63 4   66     60 return $type ne $self->{type} || $rounds != $self->{rounds} || length $salt != $self->{salt_size} * 4 / 3;
64             }
65              
66             sub verify_password {
67 5     5 1 616 my ($class, $password, $hash) = @_;
68 5         26 my $new_hash = Crypt::Passwd::XS::crypt($password, $hash);
69 5         350121 return $class->secure_compare($hash, $new_hash);
70             }
71              
72             #ABSTRACT: An linux crypt encoder for Crypt::Passphrase
73              
74             1;
75              
76             __END__