File Coverage

blib/lib/Crypt/Passphrase/System.pm
Criterion Covered Total %
statement 39 46 84.7
branch 9 16 56.2
condition 10 27 37.0
subroutine 11 11 100.0
pod 5 6 83.3
total 74 106 69.8


line stmt bran cond sub pod time code
1             package Crypt::Passphrase::System;
2             $Crypt::Passphrase::System::VERSION = '0.023';
3 2     2   204958 use strict;
  2         4  
  2         76  
4 2     2   10 use warnings;
  2         3  
  2         129  
5              
6 2     2   17 use parent 'Crypt::Passphrase::Encoder';
  2         3  
  2         14  
7              
8 2     2   1015 use Crypt::Passphrase::Util::Crypt64 'encode_crypt64';
  2         6  
  2         164  
9              
10 2     2   12 use Carp 'croak';
  2         5  
  2         1905  
11              
12             my @possibilities = (
13             ['3' , '$3$' , 0, '$3$$8846f7eaee8fb117ad06bdd830b7586c'],
14             ['', '' , 2, 'abJnggxhB/yWI' , '%s%s'],
15             ['_', '_EQ0.' , 3, '_EQ0.jzhSVeUyoSqLupI', '%s%s'],
16             ['1' , '$1$' , 6, '$1$aaaaaa$FuYJ957Lgsw.eVsENqOok1' ],
17             ['md5', '$md5,rounds=5000$', 6, '$md5,rounds=5000$GUBv0xjJ$$PI9W.MLvhYh0hQMCkz1CH/', '%s%s$'],
18             ['sha1', '$sha1$40000$' , 6, '$sha1$40000$jtNX3nZ2$hBNaIXkt4wBI2o5rsi8KejSjNqIq'],
19             ['5' , '$5$rounds=535000$', 12, '$5$aaaaaa$9hHgJfCniK4.dU43ykArHVETrhKDDElbS.cioeCajw.' ],
20             ['6' , '$6$rounds=656000$', 12, '$6$aaaaaa$RgJSheuY/DBadaBm/5gQ.s3M9a/2n8gubwCE41kMiz1P4KcxORD6LxY2NUCuOQNZawfiD8tWWfRKg9v0CQjbH0'],
21             ['2x', '$2x$12$' , 16, '$2x$08$......................qrjEXaz4RUVmquy3IT5eLKXLB28ahI2' ],
22             ['2a', '$2a$12$' , 16, '$2a$08$......................qrjEXaz4RUVmquy3IT5eLKXLB28ahI2' ],
23             ['2y', '$2y$12$' , 16, '$2y$08$......................qrjEXaz4RUVmquy3IT5eLKXLB28ahI2' ],
24             ['2b', '$2b$12$' , 16, '$2b$08$......................qrjEXaz4RUVmquy3IT5eLKXLB28ahI2' ],
25             ['7' , '$7$DU..../....' , 16, '$7$AU..../....2Q9obwLhin8qvQl6sisAO/$E1HizYWxBmnIH4sdPkd1UOML9t62Gf.wvNTnt5XFzs8' ],
26             ['gy', '$gy$j8T$' , 16, '$gy$j9T$......................$5.2XCu2DhNfGzpifM7X8goEG2Wkio9cWIMtyWnX4tp2' ],
27             ['y' , '$y$j8T$' , 16, '$y$j9T$F5Jx5fExrKuPp53xLKQ..1$tnSYvahCwPBHKZUspmcxMfb0.WiB9W.zEaKlOBL35rC' ],
28             );
29              
30             my (%algorithm, $default);
31              
32             for my $row (@possibilities) {
33             my ($name, $setting, $salt_size, $value, $format) = @{$row};
34             my $hash = eval { crypt 'password', $value };
35             if (defined $hash and $hash eq $value) {
36             $algorithm{$name} = { settings => $setting, salt_size => $salt_size, format => $format };
37             $default = $name;
38             }
39             }
40              
41             sub new {
42 16     16 0 81 my ($class, %args) = @_;
43              
44 16         35 my ($settings, $salt_size, $format);
45 16 50       79 if (defined($settings = $args{settings})) {
46 0 0       0 if ($settings eq '') {
    0          
47 0         0 ($salt_size, $format) = (2, '%s%s');
48             } elsif ($settings eq '_') {
49 0         0 ($salt_size, $format) = (3, '%s%s');
50             } else {
51 0 0       0 my $type = $settings =~ /\A \$ ([^\$]+) \$ /x or croak "Invalid settings string '$settings'";
52 0   0     0 $salt_size = $args{salt_size} // $algorithm{$type}{salt_size} // 16;
      0        
53 0   0     0 $format = $args{format} // $algorithm{$type}{format} // '%s%s$';
      0        
54             }
55             }
56             else {
57 16   66     75 my $type = $args{type} // $default // croak 'No known crypt type found';
      33        
58 16   33     69 $settings = $algorithm{$type}{settings} // croak "No such crypt type '$type' known";
59 16   66     87 $salt_size = $args{salt_size} // $algorithm{$type}{salt_size};
60 16   66     105 $format = $args{format} // $algorithm{$type}{format} // '%s%s$';
      100        
61             }
62              
63 16         157 return bless {
64             settings => $settings,
65             salt_size => $salt_size,
66             format => $format,
67             }, $class;
68             }
69              
70             sub hash_password {
71 16     16 1 68 my ($self, $password) = @_;
72 16         104 my $salt = $self->random_bytes($self->{salt_size});
73 16         73 my $encoded_salt = encode_crypt64($salt);
74 16 100       58 substr $encoded_salt, 2, 1, '' if $self->{salt_size} == 2; # descrypt
75              
76 16         87 my $settings = sprintf $self->{format}, $self->{settings}, $encoded_salt;
77 16         3916015 return crypt $password, $settings;
78             }
79              
80             my $descrypt = qr{ \A [./0-9A-Za-z]{13} \z }x;
81              
82             my @formats;
83             push @formats, $descrypt if $algorithm{''};
84             push @formats, qr{ \A _[./0-9A-Za-z]{19} \z }x if $algorithm{'_'};
85              
86             sub accepts_hash {
87 20     20 1 59 my ($self, $hash) = @_;
88 20 100       125 return 1 if $self->SUPER::accepts_hash($hash);
89 3         11 for my $format (@formats) {
90 4 100       42 return 1 if $hash =~ $format;
91             }
92 0         0 return 0;
93             }
94              
95             sub crypt_subtypes {
96 18     18 1 322 return sort keys %algorithm;
97             }
98              
99             sub needs_rehash {
100 16     16 1 45 my ($self, $hash) = @_;
101 16 100       158 return length $self->{settings} ? substr($hash, 0, length $self->{settings}) ne $self->{settings} : $hash !~ $descrypt;
102             }
103              
104             sub verify_password {
105 20     20 1 113 my ($class, $password, $hash) = @_;
106 20         3911871 my $new_hash = crypt $password, $hash;
107 20         252 return $class->secure_compare($hash, $new_hash);
108             }
109              
110             #ABSTRACT: An system crypt() encoder for Crypt::Passphrase
111              
112             1;
113              
114             __END__