| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Crypt::ScryptKDF; |
|
2
|
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
22948
|
use strict; |
|
|
4
|
|
|
|
|
8
|
|
|
|
4
|
|
|
|
|
105
|
|
|
4
|
4
|
|
|
4
|
|
20
|
use warnings ; |
|
|
4
|
|
|
|
|
5
|
|
|
|
4
|
|
|
|
|
187
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.010'; |
|
7
|
|
|
|
|
|
|
|
|
8
|
4
|
|
|
4
|
|
2969
|
use MIME::Base64 qw(decode_base64 encode_base64); |
|
|
4
|
|
|
|
|
5117
|
|
|
|
4
|
|
|
|
|
477
|
|
|
9
|
4
|
|
|
4
|
|
36
|
use Exporter 'import'; |
|
|
4
|
|
|
|
|
9
|
|
|
|
4
|
|
|
|
|
6317
|
|
|
10
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( all => [qw(scrypt_raw scrypt_hex scrypt_b64 scrypt_hash scrypt_hash_verify random_bytes)] ); |
|
11
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
|
12
|
|
|
|
|
|
|
our @EXPORT = qw(); |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
require XSLoader; |
|
15
|
|
|
|
|
|
|
XSLoader::load('Crypt::ScryptKDF', $VERSION); |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub random_bytes { |
|
18
|
7
|
|
50
|
7
|
1
|
23
|
my $length = shift || 32; |
|
19
|
7
|
|
|
|
|
10
|
my $rv; |
|
20
|
|
|
|
|
|
|
|
|
21
|
7
|
50
|
|
|
|
14
|
if (eval {require Crypt::PRNG}) { |
|
|
7
|
50
|
|
|
|
2787
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
22
|
0
|
|
|
|
|
0
|
$rv = Crypt::PRNG::random_bytes($length); |
|
23
|
|
|
|
|
|
|
} |
|
24
|
7
|
|
|
|
|
2287
|
elsif (eval {require Crypt::OpenSSL::Random}) { |
|
25
|
0
|
0
|
|
|
|
0
|
if (Crypt::OpenSSL::Random::random_status()) { |
|
26
|
0
|
|
|
|
|
0
|
$rv = Crypt::OpenSSL::Random::random_bytes($length); |
|
27
|
|
|
|
|
|
|
} |
|
28
|
|
|
|
|
|
|
} |
|
29
|
7
|
|
|
|
|
40919
|
elsif (eval {require Net::SSLeay}) { |
|
30
|
0
|
0
|
|
|
|
0
|
if (Net::SSLeay::RAND_status() == 1) { |
|
31
|
0
|
0
|
|
|
|
0
|
if (Net::SSLeay::RAND_bytes($rv, $length) != 1) { |
|
32
|
0
|
|
|
|
|
0
|
$rv = undef; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
} |
|
36
|
7
|
|
|
|
|
2473
|
elsif (eval {require Crypt::Random}) { |
|
37
|
0
|
|
|
|
|
0
|
$rv = Crypt::Random::makerandom_octet(Length=>$length); |
|
38
|
|
|
|
|
|
|
} |
|
39
|
7
|
|
|
|
|
2507
|
elsif (eval {require Bytes::Random::Secure}) { |
|
40
|
0
|
|
|
|
|
0
|
$rv = Bytes::Random::Secure::random_bytes(32); |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
7
|
50
|
|
|
|
73
|
if (!defined $rv) { |
|
44
|
7
|
|
|
|
|
474
|
warn "WARNING: Generating random bytes via insecure rand()\n"; |
|
45
|
7
|
|
|
|
|
261
|
$rv = pack('C*', map(int(rand(256)), 1..$length)); |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
7
|
|
|
|
|
46
|
return $rv |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub scrypt_raw { |
|
52
|
2
|
50
|
0
|
2
|
1
|
15
|
warn "scrypt_raw: 2 or 6 parameters required\n" and return undef unless @_ == 2 || @_ == 6; |
|
|
|
|
66
|
|
|
|
|
|
53
|
2
|
|
|
|
|
8
|
my $key = _scrypt_extra(@_); |
|
54
|
2
|
|
|
|
|
21
|
return $key; |
|
55
|
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub scrypt_b64 { |
|
58
|
3
|
50
|
0
|
3
|
1
|
29
|
warn "scrypt_b64: 2 or 6 parameters required\n" and return undef unless @_ == 2 || @_ == 6; |
|
|
|
|
66
|
|
|
|
|
|
59
|
3
|
|
|
|
|
9
|
my $key = _scrypt_extra(@_); |
|
60
|
3
|
50
|
|
|
|
13
|
return undef unless defined $key; |
|
61
|
3
|
|
|
|
|
81
|
return encode_base64($key, ''); |
|
62
|
|
|
|
|
|
|
} |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
sub scrypt_hex { |
|
65
|
5
|
50
|
0
|
5
|
1
|
47
|
warn "scrypt_hex: 2 or 6 parameters required\n" and return undef unless @_ == 2 || @_ == 6; |
|
|
|
|
66
|
|
|
|
|
|
66
|
5
|
|
|
|
|
34
|
my $key = _scrypt_extra(@_); |
|
67
|
5
|
50
|
|
|
|
30
|
return undef unless defined $key; |
|
68
|
5
|
|
|
|
|
75
|
return unpack("H*", $key); |
|
69
|
|
|
|
|
|
|
} |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub scrypt_hash { |
|
72
|
9
|
|
|
9
|
1
|
37
|
my ($key, $salt, $N, $r, $p) = _scrypt_extra(@_); |
|
73
|
9
|
50
|
33
|
|
|
179
|
return undef unless defined $key && defined $salt && defined $N && defined $r && defined $p; |
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
74
|
9
|
|
|
|
|
250
|
return "SCRYPT:$N:$r:$p:" . MIME::Base64::encode($salt, "") . ":" . MIME::Base64::encode($key, ""); |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub scrypt_hash_verify { |
|
78
|
1
|
|
|
1
|
1
|
9
|
my ($passwd, $string) = @_; |
|
79
|
1
|
50
|
|
|
|
8
|
return 0 unless $string; |
|
80
|
1
|
50
|
|
|
|
5
|
return 0 unless defined $passwd; |
|
81
|
1
|
|
|
|
|
19
|
my ($alg, $N, $r, $p, $salt, $hash) = ($string =~ /^(SCRYPT):(\d+):(\d+):(\d+):([^\:]+):([^\:]+)$/); |
|
82
|
1
|
50
|
33
|
|
|
10
|
return 0 unless defined $salt && defined $hash; |
|
83
|
1
|
|
|
|
|
6
|
$salt = MIME::Base64::decode($salt); |
|
84
|
1
|
|
|
|
|
4
|
$hash = MIME::Base64::decode($hash); |
|
85
|
1
|
50
|
33
|
|
|
9
|
return 0 unless defined $salt && defined $hash; |
|
86
|
1
|
50
|
|
|
|
4
|
return 0 unless length($hash) > 0; |
|
87
|
1
|
50
|
33
|
|
|
14
|
return 0 unless $N > 0 && $r >= 0 && $p >= 0; |
|
|
|
|
33
|
|
|
|
|
|
88
|
|
|
|
|
|
|
#XXX-TODO utf8::encode($passwd) if utf8::is_utf8($passwd); |
|
89
|
1
|
|
|
|
|
176604
|
my $key = _scrypt($passwd, $salt, $N, $r, $p, length($hash)); |
|
90
|
1
|
50
|
|
|
|
13
|
return 0 unless defined $key; |
|
91
|
1
|
50
|
|
|
|
6
|
return 0 unless _slow_eq($key, $hash); |
|
92
|
1
|
|
|
|
|
11
|
return 1; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub _get_scrypt_defaults { |
|
96
|
|
|
|
|
|
|
# (N=2^14, r=8, p=1, len=32) |
|
97
|
10
|
|
|
10
|
|
45
|
return (16384, 8, 1, 32); |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub _scrypt_extra { |
|
101
|
19
|
|
|
19
|
|
35
|
my $salt; |
|
102
|
|
|
|
|
|
|
my @args; |
|
103
|
19
|
100
|
|
|
|
99
|
if (@_ == 1) { # ... ($passwd) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
104
|
2
|
|
|
|
|
10
|
($salt, @args) = (random_bytes(32), _get_scrypt_defaults); |
|
105
|
|
|
|
|
|
|
} |
|
106
|
|
|
|
|
|
|
elsif (@_ == 2) { # ... ($passwd, $salt) |
|
107
|
8
|
|
|
|
|
27
|
($salt, @args) = ($_[1], _get_scrypt_defaults); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
elsif (@_ == 5) { # ... ($passwd, $N, $r, $p, $dklen) |
|
110
|
1
|
|
|
|
|
5
|
($salt, @args) = (random_bytes(32), $_[1], $_[2], $_[3], $_[4]); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
elsif (@_ == 6) { # ... ($passwd, $salt, $N, $r, $p, $dklen) |
|
113
|
8
|
|
|
|
|
26
|
(undef, $salt, @args) = @_; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
else { |
|
116
|
0
|
|
|
|
|
0
|
warn "ERROR: scrypt() invalid number of arguments\n"; |
|
117
|
0
|
|
|
|
|
0
|
return; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
#check @args |
|
120
|
19
|
|
|
|
|
99
|
my $N = $args[0]; |
|
121
|
19
|
50
|
33
|
|
|
174
|
if ( ($N <= 0) || (($N&($N-1)) != 0) ) { warn "ERROR: invalid 'N'\n"; return } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
122
|
19
|
50
|
|
|
|
58
|
if ($args[1] < 1) { warn "ERROR: invalid 'r'\n"; return } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
123
|
19
|
50
|
|
|
|
47
|
if ($args[2] < 1) { warn "ERROR: invalid 'p'\n"; return } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
124
|
19
|
50
|
|
|
|
49
|
if ($args[3] < 1) { warn "ERROR: invalid 'len'\n"; return } |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
125
|
|
|
|
|
|
|
#XXX-TODO utf8::encode($_[0]) if utf8::is_utf8($_[0]); |
|
126
|
19
|
100
|
66
|
|
|
106
|
$salt = random_bytes($$salt) if ref $salt eq 'SCALAR' && $$salt =~ /^\d+$/; |
|
127
|
19
|
|
|
|
|
2223015
|
my $key = _scrypt($_[0], $salt, @args); |
|
128
|
19
|
100
|
|
|
|
257
|
return wantarray ? ($key, $salt, $args[0], $args[1], $args[2]) : $key; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub _slow_eq { |
|
132
|
19
|
|
|
19
|
|
48
|
my ($a, $b) = @_; |
|
133
|
19
|
100
|
100
|
|
|
117
|
return unless defined $a && defined $b; |
|
134
|
14
|
|
|
|
|
27
|
my $diff = length $a ^ length $b; |
|
135
|
14
|
|
100
|
|
|
80
|
for(my $i = 0; $i < length $a && $i < length $b; $i++) { |
|
136
|
125
|
|
|
|
|
583
|
$diff |= ord(substr $a, $i) ^ ord(substr $b, $i); |
|
137
|
|
|
|
|
|
|
} |
|
138
|
14
|
|
|
|
|
70
|
return $diff == 0; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
1; |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
__END__ |