File Coverage

blib/lib/Crypt/Passphrase/Linux.pm
Criterion Covered Total %
statement 33 34 97.0
branch 2 4 50.0
condition 5 9 55.5
subroutine 9 10 90.0
pod 5 5 100.0
total 54 62 87.1


line stmt bran cond sub pod time code
1             package Crypt::Passphrase::Linux;
2             $Crypt::Passphrase::Linux::VERSION = '0.001';
3 1     1   67282 use strict;
  1         13  
  1         29  
4 1     1   5 use warnings;
  1         2  
  1         31  
5              
6 1     1   410 use parent 'Crypt::Passphrase::Encoder';
  1         321  
  1         5  
7              
8 1     1   7796 use Crypt::Passwd::XS 'crypt';
  1         3  
  1         26  
9 1     1   500 use MIME::Base64 qw/encode_base64 decode_base64/;
  1         1065  
  1         540  
10              
11             my %identifier_for = (
12             md5 => '1',
13             apache_md5 => 'apr1',
14             sha256 => '5',
15             sha512 => '6',
16             );
17              
18             my %salt_size = (
19             md5 => 6,
20             apache_md5 => 6,
21             sha256 => 12,
22             sha512 => 12,
23             );
24              
25             sub new {
26 1     1 1 102 my ($class, %args) = @_;
27 1   50     5 my $type_name = $args{type} // 'sha512';
28 1   50     5 my $type = $identifier_for{$type_name} // die "No such crypt type $type_name";
29 1         3 my $salt_size = $salt_size{$type_name};
30 1   50     4 my $rounds = $args{rounds} // 656_000;
31              
32 1         17 return bless {
33             type => $type,
34             rounds => $rounds + 0,
35             salt_size => $salt_size,
36             }, $class;
37             }
38              
39             sub hash_password {
40 1     1 1 9 my ($self, $password) = @_;
41 1         18 my $salt = $self->random_bytes($self->{salt_size});
42 1         10907 my $settings = sprintf '$%s$rounds=%d$%s', $self->{type}, $self->{rounds}, encode_base64($salt);
43 1         11 return Crypt::Passwd::XS::crypt($password, $settings);
44             }
45              
46             sub crypt_subtypes {
47 0     0 1 0 return values %identifier_for;
48             }
49              
50             my $regex = qr/ ^ \$ (1|5|6|apr1) \$ (?: rounds= ([0-9]+) \$ )? ([^\$]*) \$ [^\$]+ $ /x;
51              
52             sub needs_rehash {
53 4     4 1 2284 my ($self, $hash) = @_;
54 4 50       99 my ($type, $rounds, $salt) = $hash =~ $regex or return 0;
55 4 50       17 $rounds = 5000 if $rounds eq '';
56 4   66     67 return $type ne $self->{type} || $rounds != $self->{rounds} || length $salt != $self->{salt_size} * 4 / 3;
57             }
58              
59             sub verify_password {
60 4     4 1 239120 my ($class, $password, $hash) = @_;
61 4         57 my ($settings) = $hash =~ /^(.*)\$[^\$]*/;
62 4         21 my $new_hash = Crypt::Passwd::XS::crypt($password, $settings);
63 4         347504 return $class->secure_compare($hash, $new_hash);
64             }
65              
66             #ABSTRACT: An linux crypt encoder for Crypt::Passphrase
67              
68             1;
69              
70             __END__