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__ |