| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
2
|
|
|
2
|
|
7
|
use warnings; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
60
|
|
|
2
|
2
|
|
|
2
|
|
8
|
use strict; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
69
|
|
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Net::OAuth2::Scheme::HmacUtil; |
|
5
|
|
|
|
|
|
|
BEGIN { |
|
6
|
2
|
|
|
2
|
|
23
|
$Net::OAuth2::Scheme::HmacUtil::VERSION = '0.020002_099'; |
|
7
|
|
|
|
|
|
|
} |
|
8
|
|
|
|
|
|
|
# ABSTRACT: hash functions and encodings |
|
9
|
|
|
|
|
|
|
|
|
10
|
2
|
|
|
2
|
|
918
|
use Digest::SHA (); |
|
|
2
|
|
|
|
|
5098
|
|
|
|
2
|
|
|
|
|
50
|
|
|
11
|
|
|
|
|
|
|
# use MIME::Base64 qw(encode_base64 decode_base64); |
|
12
|
|
|
|
|
|
|
|
|
13
|
2
|
|
|
2
|
|
11
|
use parent qw(Exporter); |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
11
|
|
|
14
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
|
15
|
|
|
|
|
|
|
hmac_name_to_len_fn |
|
16
|
|
|
|
|
|
|
sign_binary unsign_binary |
|
17
|
|
|
|
|
|
|
encode_base64url decode_base64url |
|
18
|
|
|
|
|
|
|
encode_plainstring decode_plainstring |
|
19
|
|
|
|
|
|
|
timing_indep_eq |
|
20
|
|
|
|
|
|
|
); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our @Known_HMACs = |
|
23
|
|
|
|
|
|
|
# list of [id, key_length, underscored_name, dashed-name, hmac_function] |
|
24
|
|
|
|
|
|
|
( |
|
25
|
|
|
|
|
|
|
# NIST's HMAC-SHA functions |
|
26
|
|
|
|
|
|
|
map {[$_->[0], $_->[1], "hmac_sha$_->[2]", "hmac-sha$_->[2]"]} |
|
27
|
|
|
|
|
|
|
map {[$_%107, $_/8, ($_ == 160 ? 1 : $_)]} |
|
28
|
|
|
|
|
|
|
160,224,256,384,512, |
|
29
|
|
|
|
|
|
|
# add more keylengths here as NIST adds new ones |
|
30
|
|
|
|
|
|
|
), |
|
31
|
|
|
|
|
|
|
( |
|
32
|
|
|
|
|
|
|
# more families |
|
33
|
|
|
|
|
|
|
); |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# Why 107? |
|
36
|
|
|
|
|
|
|
# Short answer: |
|
37
|
|
|
|
|
|
|
# Why not? Really all that matters is that no id get used twice |
|
38
|
|
|
|
|
|
|
# and whatever we do to achieve that, nobody should care. |
|
39
|
|
|
|
|
|
|
# Long answer: |
|
40
|
|
|
|
|
|
|
# 107 is THE prime smaller than 128 for which the sequence 2^n mod p |
|
41
|
|
|
|
|
|
|
# whose subsequences starting with 8 (= 256/32) and 12 (= 384/32) |
|
42
|
|
|
|
|
|
|
# that do not contain either each other or 5 (=160/32) or 7 (=224/32) |
|
43
|
|
|
|
|
|
|
# are of maximal length. The idea being that we can keep adding new |
|
44
|
|
|
|
|
|
|
# SHA functions of lengths 256*2^n, 384*2^n and not run into |
|
45
|
|
|
|
|
|
|
# previously used ids for a VERY long time... |
|
46
|
|
|
|
|
|
|
# OR (more likely) we'll be able to intersperse other families of |
|
47
|
|
|
|
|
|
|
# secure hash functions (i.e., once SHA turns out to be inadequate |
|
48
|
|
|
|
|
|
|
# for whatever reason) and likewise have plenty of room for those to |
|
49
|
|
|
|
|
|
|
# grow, too, assuming those, too, start with key lengths of 256 and |
|
50
|
|
|
|
|
|
|
# 384. E.g., for the next family, you could do |
|
51
|
|
|
|
|
|
|
# |
|
52
|
|
|
|
|
|
|
# map {[($_*13)%107, $_/8, "hmac_xxx$_", "hmac-xxx$_", \&whatever]} |
|
53
|
|
|
|
|
|
|
# |
|
54
|
|
|
|
|
|
|
# Note that all internal id numbers will thus be 106 or smaller, so |
|
55
|
|
|
|
|
|
|
# if all else fails you can uses id bytes with the high-bit set to |
|
56
|
|
|
|
|
|
|
# indicate some jackass extension scheme, though, hopefully, by that |
|
57
|
|
|
|
|
|
|
# point we will have burned through so many families of secure hash |
|
58
|
|
|
|
|
|
|
# functions that I will be safely dead and won't care anymore. |
|
59
|
|
|
|
|
|
|
# Actually, I already don't care, so... --rfc |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
our %Known_HMACs_by_name = ( map {$_->[2],$_,$_->[3],$_} @Known_HMACs ); |
|
63
|
|
|
|
|
|
|
our %Known_HMACs_by_id = ( map {$_->[0],$_} @Known_HMACs ); |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
die "looks like we used an id number twice" |
|
66
|
|
|
|
|
|
|
if 2 * keys %Known_HMACs_by_id != keys %Known_HMACs_by_name; |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
our $Default_HMAC = 'hmac_sha256'; |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
sub hmac_name_to_len_fn { |
|
71
|
0
|
|
|
0
|
0
|
|
my ($aname) = @_; |
|
72
|
0
|
0
|
|
|
|
|
my $a = $Known_HMACs_by_name{$aname} or return (); |
|
73
|
0
|
|
|
|
|
|
return ($a->[1], _hmac_fn($a)); |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _hmac_fn { |
|
77
|
0
|
|
|
0
|
|
|
my $a = shift; |
|
78
|
0
|
|
0
|
|
|
|
return ($a->[4] ||= \&{"Digest::SHA::$a->[2]"}); |
|
|
0
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub _hmac_name_to_id_fn { |
|
82
|
0
|
|
|
0
|
|
|
my ($aname) = @_; |
|
83
|
0
|
0
|
|
|
|
|
my $a = $Known_HMACs_by_name{$aname} or |
|
84
|
|
|
|
|
|
|
Carp::croak("unknown hmac function: $aname"); |
|
85
|
0
|
|
|
|
|
|
return ($a->[0], _hmac_fn($a)); |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub _hmac_id_to_len_fn { |
|
89
|
0
|
|
|
0
|
|
|
my ($id) = @_; |
|
90
|
0
|
0
|
|
|
|
|
my $a = $Known_HMACs_by_id{$id} or return (); |
|
91
|
0
|
|
|
|
|
|
return ($a->[1], _hmac_fn($a)); |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub timing_indep_eq { |
|
95
|
2
|
|
|
2
|
|
702
|
no warnings 'uninitialized'; |
|
|
2
|
|
|
|
|
7
|
|
|
|
2
|
|
|
|
|
1071
|
|
|
96
|
0
|
|
|
0
|
0
|
|
my ($x, $y, $len)=@_; |
|
97
|
0
|
0
|
0
|
|
|
|
warnings::warn('uninitialized','Use of uninitialized value in timing_indep_eq') |
|
|
|
|
0
|
|
|
|
|
|
98
|
|
|
|
|
|
|
if (warnings::enabled('uninitialized') && !(defined($x) && defined($y))); |
|
99
|
|
|
|
|
|
|
|
|
100
|
0
|
|
|
|
|
|
my $result=0; |
|
101
|
0
|
|
|
|
|
|
for (my $i=0; $i<$len; $i++) { |
|
102
|
0
|
|
|
|
|
|
$result |= ord(substr($x, $i, 1)) ^ ord(substr($y, $i, 1)); |
|
103
|
|
|
|
|
|
|
} |
|
104
|
|
|
|
|
|
|
|
|
105
|
0
|
|
|
|
|
|
return !$result; |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub sign_binary { |
|
109
|
0
|
|
|
0
|
0
|
|
my ($secret, $value, %o) = @_; |
|
110
|
0
|
|
0
|
|
|
|
my $aname = $o{hmac} || $Default_HMAC; |
|
111
|
0
|
|
|
|
|
|
my ($id, $fn) = _hmac_name_to_id_fn($aname); |
|
112
|
0
|
|
|
|
|
|
my $extra = $o{extra}; |
|
113
|
0
|
0
|
|
|
|
|
$extra = '' unless defined $extra; |
|
114
|
0
|
|
|
|
|
|
return pack 'ww/a*a*', $id, $fn->($secret, $value . $extra), $value; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub unsign_binary { |
|
118
|
0
|
|
|
0
|
0
|
|
my ($secret, $bin, $extra) = @_; |
|
119
|
0
|
|
|
|
|
|
my ($id, $hash, $value) = unpack 'ww/a*a*', $bin; |
|
120
|
0
|
0
|
|
|
|
|
my ($keylen, $fn) = _hmac_id_to_len_fn($id) or |
|
121
|
|
|
|
|
|
|
return (undef, "unknown hash function id: $id"); |
|
122
|
0
|
0
|
|
|
|
|
$extra = '' unless defined $extra; |
|
123
|
0
|
0
|
0
|
|
|
|
return ($value) |
|
124
|
|
|
|
|
|
|
if length($hash) == $keylen && |
|
125
|
|
|
|
|
|
|
timing_indep_eq($hash, $fn->($secret, $value . $extra), $keylen); |
|
126
|
|
|
|
|
|
|
# implement extensions here but for now, just fail |
|
127
|
0
|
|
|
|
|
|
return (undef, 'bad hash value'); |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# base64url is described in RFC 4648: use - and _ in place of + and / |
|
131
|
|
|
|
|
|
|
# and we leave off trailing =s, all so as not to use characters that |
|
132
|
|
|
|
|
|
|
# are meaningful in URLs |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
sub encode_base64url { |
|
135
|
0
|
|
|
0
|
0
|
|
local $_ = join '' , map {pack 'B6',$_} ((unpack 'B*',shift).'0000') =~ m/(.{6})/gs; |
|
|
0
|
|
|
|
|
|
|
|
136
|
0
|
|
|
|
|
|
y(\0\4\10\14\20\24\30\34\40\44\50\54\60\64\70\74\100\104\110\114\120\124\130\134\140\144\150\154\160\164\170\174\200\204\210\214\220\224\230\234\240\244\250\254\260\264\270\274\300\304\310\314\320\324\330\334\340\344\350\354\360\364\370\374)(A-Za-z0-9\-_); |
|
137
|
|
|
|
|
|
|
# local $_ = encode_base64(shift,''); |
|
138
|
|
|
|
|
|
|
# y|+/=|-_|d; |
|
139
|
0
|
|
|
|
|
|
return $_; |
|
140
|
|
|
|
|
|
|
} |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub decode_base64url { |
|
143
|
0
|
|
|
0
|
0
|
|
local $_ = shift; |
|
144
|
0
|
|
|
|
|
|
y(A-Za-z0-9\-_)(\0\4\10\14\20\24\30\34\40\44\50\54\60\64\70\74\100\104\110\114\120\124\130\134\140\144\150\154\160\164\170\174\200\204\210\214\220\224\230\234\240\244\250\254\260\264\270\274\300\304\310\314\320\324\330\334\340\344\350\354\360\364\370\374)d; |
|
145
|
0
|
|
|
|
|
|
return pack 'B'. (((3*length)>>2)<<3) , join '', unpack 'B6'x(length), $_; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# # for some reason this is way faster than: |
|
148
|
|
|
|
|
|
|
# y|-_=|+/|d; |
|
149
|
|
|
|
|
|
|
# return decode_base64($_ . substr('===',(3+length)>>2)) |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# plainstring is printable ascii excluding whitespace, backslash, |
|
153
|
|
|
|
|
|
|
# and double quote (- 128 32 1 1 1 1) |
|
154
|
|
|
|
|
|
|
sub encode_plainstring { |
|
155
|
0
|
|
|
0
|
0
|
|
my @ords = (); |
|
156
|
0
|
|
|
|
|
|
my $m = (length($_[0])+2) % 3 + 1; |
|
157
|
0
|
|
|
|
|
|
for my $c (split '', $_[0]) { |
|
158
|
0
|
|
|
|
|
|
my @ords2 = (ord($c), (map {$_*2} @ords)); |
|
|
0
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
|
for my $i (0 .. $#ords) { |
|
160
|
0
|
|
|
|
|
|
$ords[$i] = 72*$ords[$i] + $ords2[$i]; |
|
161
|
|
|
|
|
|
|
} |
|
162
|
0
|
|
|
|
|
|
push @ords, $ords2[$#ords2]; |
|
163
|
0
|
|
|
|
|
|
my $rc = 0; |
|
164
|
0
|
0
|
|
|
|
|
unless (--$m) { |
|
165
|
0
|
|
|
|
|
|
$m = 3; |
|
166
|
0
|
|
|
|
|
|
for my $i (0 .. $#ords) { |
|
167
|
2
|
|
|
2
|
|
10
|
use integer; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
9
|
|
|
168
|
0
|
|
|
|
|
|
$ords[$i] += $rc; |
|
169
|
0
|
|
|
|
|
|
$rc = $ords[$i]/92; |
|
170
|
0
|
|
|
|
|
|
$ords[$i] %= 92; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
0
|
|
|
|
|
|
while ($rc > 0) { |
|
173
|
2
|
|
|
2
|
|
72
|
use integer; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
4
|
|
|
174
|
0
|
|
|
|
|
|
push @ords, $rc % 92; |
|
175
|
0
|
|
|
|
|
|
$rc /= 92; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
} |
|
179
|
0
|
0
|
|
|
|
|
return join '', map {$_ >= 58 ? chr($_+35) : ($_ >= 1 ? chr($_+34) : '!')} @ords; |
|
|
0
|
0
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# 33, 35..91 93..126 |
|
183
|
|
|
|
|
|
|
# 0 1..57 58..92 |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub decode_plainstring { |
|
186
|
0
|
|
|
0
|
0
|
|
my @ords = (); |
|
187
|
0
|
|
|
|
|
|
for my $c (reverse split '', $_[0]) { |
|
188
|
0
|
|
|
|
|
|
@ords = map {$_*92} @ords; |
|
|
0
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
my $o = ord($c); |
|
190
|
0
|
0
|
|
|
|
|
$ords[0] += ($o >= 93 ? $o-35 : $o >= 35 ? $o-34 : 0); |
|
|
|
0
|
|
|
|
|
|
|
191
|
0
|
|
|
|
|
|
my $rc = 0; |
|
192
|
0
|
|
|
|
|
|
for my $i (0 .. $#ords) { |
|
193
|
2
|
|
|
2
|
|
274
|
use integer; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
5
|
|
|
194
|
0
|
|
|
|
|
|
$ords[$i] += $rc; |
|
195
|
0
|
|
|
|
|
|
$rc = $ords[$i]>>8; |
|
196
|
0
|
|
|
|
|
|
$ords[$i] &= 255; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
0
|
|
|
|
|
|
while ($rc > 0) { |
|
199
|
2
|
|
|
2
|
|
67
|
use integer; |
|
|
2
|
|
|
|
|
3
|
|
|
|
2
|
|
|
|
|
5
|
|
|
200
|
0
|
|
|
|
|
|
push @ords, $rc & 255; |
|
201
|
0
|
|
|
|
|
|
$rc >>= 8; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
} |
|
204
|
0
|
|
|
|
|
|
return join '', map {chr($_)} reverse @ords; |
|
|
0
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
1; |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
__END__ |