line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Crypt::Password::StretchedHash; |
2
|
4
|
|
|
4
|
|
78594
|
use 5.008005; |
|
4
|
|
|
|
|
16
|
|
|
4
|
|
|
|
|
206
|
|
3
|
4
|
|
|
4
|
|
24
|
use strict; |
|
4
|
|
|
|
|
12
|
|
|
4
|
|
|
|
|
235
|
|
4
|
4
|
|
|
4
|
|
36
|
use warnings; |
|
4
|
|
|
|
|
16
|
|
|
4
|
|
|
|
|
16036
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = "0.05"; |
7
|
|
|
|
|
|
|
|
8
|
4
|
|
|
|
|
215
|
use Exporter qw( |
9
|
|
|
|
|
|
|
import |
10
|
4
|
|
|
4
|
|
37
|
); |
|
4
|
|
|
|
|
7
|
|
11
|
4
|
|
|
|
|
370
|
use Carp qw( |
12
|
|
|
|
|
|
|
croak |
13
|
4
|
|
|
4
|
|
28
|
); |
|
4
|
|
|
|
|
9
|
|
14
|
4
|
|
|
|
|
307
|
use MIME::Base64 qw( |
15
|
|
|
|
|
|
|
encode_base64 |
16
|
|
|
|
|
|
|
decode_base64 |
17
|
4
|
|
|
4
|
|
4150
|
); |
|
4
|
|
|
|
|
3516
|
|
18
|
4
|
|
|
|
|
4761
|
use Params::Validate qw( |
19
|
|
|
|
|
|
|
SCALAR |
20
|
4
|
|
|
4
|
|
4489
|
); |
|
4
|
|
|
|
|
52662
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
23
|
|
|
|
|
|
|
crypt |
24
|
|
|
|
|
|
|
verify |
25
|
|
|
|
|
|
|
crypt_with_hashinfo |
26
|
|
|
|
|
|
|
verify_with_hashinfo |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
sub crypt { |
30
|
|
|
|
|
|
|
|
31
|
37
|
|
|
37
|
1
|
26204
|
my %params = Params::Validate::validate(@_, { |
32
|
|
|
|
|
|
|
password => { type => SCALAR }, |
33
|
|
|
|
|
|
|
hash => 1, |
34
|
|
|
|
|
|
|
salt => { type => SCALAR }, |
35
|
|
|
|
|
|
|
stretch_count => { type => SCALAR, regex => qr/\A[0-9]+\z/,}, |
36
|
|
|
|
|
|
|
format => { type => SCALAR, optional => 1 }, |
37
|
|
|
|
|
|
|
}); |
38
|
|
|
|
|
|
|
|
39
|
29
|
|
|
|
|
893
|
my $salt = $params{salt}; |
40
|
29
|
100
|
100
|
|
|
1577
|
croak "\$params{hash} must be Digest::SHAx Object" |
41
|
|
|
|
|
|
|
unless ( $params{hash}->isa("Digest::SHA") || |
42
|
|
|
|
|
|
|
$params{hash}->isa("Digest::SHA3")); |
43
|
|
|
|
|
|
|
|
44
|
28
|
|
|
|
|
58
|
my $hash = $params{hash}; |
45
|
|
|
|
|
|
|
|
46
|
28
|
100
|
|
|
|
204
|
croak "\$params{stretch_count} must be more than 1" |
47
|
|
|
|
|
|
|
unless ($params{stretch_count} > 0); |
48
|
|
|
|
|
|
|
|
49
|
27
|
|
|
|
|
76
|
my $pwhash = q{}; |
50
|
27
|
|
|
|
|
109
|
for (1..$params{stretch_count}) { |
51
|
131000
|
|
|
|
|
311245
|
$hash->add( $pwhash, $params{password}, $salt ); |
52
|
131000
|
|
|
|
|
629037
|
$pwhash = $hash->digest; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
27
|
100
|
100
|
|
|
434
|
if ( exists $params{format} && $params{format} eq q{hex} ){ |
|
|
100
|
66
|
|
|
|
|
56
|
4
|
|
|
|
|
43
|
$pwhash = unpack("H*", $pwhash); |
57
|
|
|
|
|
|
|
}elsif( exists $params{format} && $params{format} eq q{base64} ){ |
58
|
14
|
|
|
|
|
104
|
$pwhash = encode_base64 $pwhash; |
59
|
14
|
|
|
|
|
116
|
$pwhash =~ s/\n//; |
60
|
14
|
|
|
|
|
127
|
chomp($pwhash); |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
27
|
|
|
|
|
277
|
return $pwhash; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub verify { |
67
|
|
|
|
|
|
|
|
68
|
9
|
|
|
9
|
1
|
29880
|
my %params = Params::Validate::validate(@_, { |
69
|
|
|
|
|
|
|
password => { type => SCALAR }, |
70
|
|
|
|
|
|
|
password_hash => { type => SCALAR }, |
71
|
|
|
|
|
|
|
hash => 1, |
72
|
|
|
|
|
|
|
salt => { type => SCALAR }, |
73
|
|
|
|
|
|
|
stretch_count => { type => SCALAR, regex => qr/\A[0-9]+\z/,}, |
74
|
|
|
|
|
|
|
format => { type => SCALAR, optional => 1 }, |
75
|
|
|
|
|
|
|
}); |
76
|
|
|
|
|
|
|
|
77
|
9
|
|
|
|
|
599
|
my $pwhash = $params{password_hash}; |
78
|
9
|
|
|
|
|
32
|
delete $params{password_hash}; |
79
|
9
|
|
|
|
|
92
|
my $calculated_pwhash = Crypt::Password::StretchedHash::crypt( %params ); |
80
|
9
|
|
|
|
|
132
|
return ( $calculated_pwhash eq $pwhash ); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub crypt_with_hashinfo { |
84
|
|
|
|
|
|
|
|
85
|
7
|
|
|
7
|
1
|
8081
|
my %params = Params::Validate::validate(@_, { |
86
|
|
|
|
|
|
|
password => { type => SCALAR }, |
87
|
|
|
|
|
|
|
hash_info => 1, |
88
|
|
|
|
|
|
|
}); |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# validate hashinfo object |
91
|
7
|
|
|
|
|
45
|
my $hash_info = $params{hash_info}; |
92
|
7
|
50
|
|
|
|
53
|
croak "\$params{hash_info} must be Crypt::Password::StretchedHash::HashInfo Object" |
93
|
|
|
|
|
|
|
unless ( $hash_info->isa("Crypt::Password::StretchedHash::HashInfo") ); |
94
|
|
|
|
|
|
|
|
95
|
7
|
|
|
|
|
29
|
my $salt = $hash_info->salt; |
96
|
|
|
|
|
|
|
|
97
|
7
|
|
|
|
|
58
|
my $pwhash = Crypt::Password::StretchedHash::crypt( |
98
|
|
|
|
|
|
|
password => $params{password}, |
99
|
|
|
|
|
|
|
hash => $hash_info->hash, |
100
|
|
|
|
|
|
|
salt => $salt, |
101
|
|
|
|
|
|
|
stretch_count => $hash_info->stretch_count, |
102
|
|
|
|
|
|
|
format => $hash_info->format, |
103
|
|
|
|
|
|
|
); |
104
|
|
|
|
|
|
|
|
105
|
7
|
100
|
|
|
|
69
|
if ( $hash_info->format eq q{hex} ){ |
|
|
50
|
|
|
|
|
|
106
|
1
|
|
|
|
|
44
|
$salt = unpack("H*", $salt); |
107
|
|
|
|
|
|
|
}elsif( $hash_info->format eq q{base64} ){ |
108
|
6
|
|
|
|
|
102
|
$salt = encode_base64 $salt; |
109
|
6
|
|
|
|
|
15
|
chomp($salt); |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
7
|
|
|
|
|
41
|
return $hash_info->delimiter . |
113
|
|
|
|
|
|
|
$hash_info->identifier. |
114
|
|
|
|
|
|
|
$hash_info->delimiter. |
115
|
|
|
|
|
|
|
$salt. |
116
|
|
|
|
|
|
|
$hash_info->delimiter. |
117
|
|
|
|
|
|
|
$pwhash; |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub verify_with_hashinfo { |
122
|
|
|
|
|
|
|
|
123
|
11
|
|
|
11
|
1
|
6050
|
my %params = Params::Validate::validate(@_, { |
124
|
|
|
|
|
|
|
password => { type => SCALAR }, |
125
|
|
|
|
|
|
|
password_hash => { type => SCALAR }, |
126
|
|
|
|
|
|
|
hash_info => 1, |
127
|
|
|
|
|
|
|
}); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# validate hashinfo object |
130
|
11
|
|
|
|
|
75
|
my $hash_info = $params{hash_info}; |
131
|
11
|
50
|
|
|
|
62
|
croak "\$params{hash_info} must be Crypt::Password::StretchedHash::HashInfo Object" |
132
|
|
|
|
|
|
|
unless ( $hash_info->isa("Crypt::Password::StretchedHash::HashInfo") ); |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
# split password hash |
135
|
11
|
|
|
|
|
36
|
my $delimiter = quotemeta($hash_info->delimiter); |
136
|
11
|
|
|
|
|
74
|
my $identifier = $hash_info->identifier; |
137
|
11
|
|
|
|
|
49
|
my ( $pwhash, $salt ); |
138
|
|
|
|
|
|
|
|
139
|
11
|
|
|
|
|
124
|
my @split_password_hash = split( /$delimiter/, $params{password_hash} ); |
140
|
11
|
100
|
100
|
|
|
163
|
if ($params{password_hash} =~ /\A$delimiter/ && |
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
141
|
|
|
|
|
|
|
scalar @split_password_hash == 4 && |
142
|
|
|
|
|
|
|
$split_password_hash[0] eq q{} && |
143
|
|
|
|
|
|
|
$identifier eq $split_password_hash[1] ){ |
144
|
6
|
|
|
|
|
11
|
$salt = $split_password_hash[2]; |
145
|
6
|
|
|
|
|
11
|
$pwhash = $split_password_hash[3]; |
146
|
|
|
|
|
|
|
} else { |
147
|
5
|
|
|
|
|
24
|
return; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# obtain law_salt string |
151
|
6
|
100
|
|
|
|
25
|
if ( $hash_info->format eq q{hex} ){ |
|
|
50
|
|
|
|
|
|
152
|
1
|
|
|
|
|
14
|
$salt = pack("H*", $salt); |
153
|
|
|
|
|
|
|
}elsif( $hash_info->format eq q{base64} ){ |
154
|
5
|
|
|
|
|
87
|
$salt = decode_base64 $salt; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# generate hashed password |
158
|
6
|
|
|
|
|
29
|
my $expected_pwhash = Crypt::Password::StretchedHash::crypt( |
159
|
|
|
|
|
|
|
password => $params{password}, |
160
|
|
|
|
|
|
|
hash => $hash_info->hash, |
161
|
|
|
|
|
|
|
salt => $salt, |
162
|
|
|
|
|
|
|
stretch_count => $hash_info->stretch_count, |
163
|
|
|
|
|
|
|
format => $hash_info->format, |
164
|
|
|
|
|
|
|
); |
165
|
6
|
|
|
|
|
68
|
return ( $expected_pwhash eq $pwhash ); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
} |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
1; |
170
|
|
|
|
|
|
|
__END__ |