line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::YMSG::CRAM; |
2
|
|
|
|
|
|
|
|
3
|
2
|
|
|
2
|
|
8222
|
use Digest::MD5 qw(md5); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1074
|
|
4
|
2
|
|
|
2
|
|
12
|
use vars qw($VERSION); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
110
|
|
5
|
|
|
|
|
|
|
$VERSION = '0.02'; |
6
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
75
|
|
7
|
|
|
|
|
|
|
|
8
|
2
|
|
|
2
|
|
11
|
use constant MD5_CRYPT_MAGIC_STRING => '$1$'; |
|
2
|
|
|
|
|
40
|
|
|
2
|
|
|
|
|
380
|
|
9
|
2
|
|
|
2
|
|
11
|
use constant I_TO_A64 => './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
3913
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
sub new |
13
|
|
|
|
|
|
|
{ |
14
|
1
|
|
|
1
|
0
|
492
|
my $class = shift; |
15
|
1
|
|
|
|
|
10
|
bless { |
16
|
|
|
|
|
|
|
challenge_string => '', |
17
|
|
|
|
|
|
|
id => '', |
18
|
|
|
|
|
|
|
password => '', |
19
|
|
|
|
|
|
|
}, $class; |
20
|
|
|
|
|
|
|
} |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub set_challenge_string |
24
|
|
|
|
|
|
|
{ |
25
|
2
|
|
|
2
|
0
|
798
|
my $self = shift; |
26
|
2
|
|
|
|
|
13
|
$self->{challenge_string} = shift; |
27
|
|
|
|
|
|
|
} |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub set_id |
31
|
|
|
|
|
|
|
{ |
32
|
2
|
|
|
2
|
0
|
9
|
my $self = shift; |
33
|
2
|
|
|
|
|
7
|
$self->{id} = shift; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
sub set_password |
38
|
|
|
|
|
|
|
{ |
39
|
2
|
|
|
2
|
0
|
8
|
my $self = shift; |
40
|
2
|
|
|
|
|
7
|
$self->{password} = shift; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub get_response_strings |
45
|
|
|
|
|
|
|
{ |
46
|
2
|
|
|
2
|
0
|
10
|
my $self = shift; |
47
|
2
|
|
|
|
|
5
|
my $id = $self->{id}; |
48
|
2
|
|
|
|
|
4
|
my $password = $self->{password}; |
49
|
2
|
|
|
|
|
20
|
my @challenge_string = split //, $self->{challenge_string}; |
50
|
|
|
|
|
|
|
|
51
|
2
|
50
|
|
|
|
11
|
return undef unless scalar @challenge_string; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
|
54
|
2
|
|
|
|
|
18
|
my $password_hash = _to_yahoo_base64(md5($password)); |
55
|
2
|
|
|
|
|
9
|
my $crypt_hash = _to_yahoo_base64(md5(_md5_crypt($password, '_2S43d5f'))); |
56
|
|
|
|
|
|
|
|
57
|
2
|
|
|
|
|
5
|
my $hash_string_p; |
58
|
|
|
|
|
|
|
my $hash_string_c; |
59
|
|
|
|
|
|
|
|
60
|
2
|
|
|
|
|
8
|
my $sv = ord($challenge_string[15]) % 8; |
61
|
2
|
100
|
66
|
|
|
71
|
if ($sv == 1 || $sv == 6) { |
|
|
50
|
33
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
62
|
1
|
|
|
|
|
5
|
my $checksum = $challenge_string[ord($challenge_string[9]) % 16]; |
63
|
1
|
|
|
|
|
13
|
$hash_string_p = sprintf '%s%s%s%s', |
64
|
|
|
|
|
|
|
$checksum, $id, join('', @challenge_string), $password_hash; |
65
|
1
|
|
|
|
|
6
|
$hash_string_c = sprintf '%s%s%s%s', |
66
|
|
|
|
|
|
|
$checksum, $id, join('', @challenge_string), $crypt_hash; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
elsif ($sv == 2 || $sv == 7) { |
69
|
1
|
|
|
|
|
4
|
my $checksum = $challenge_string[ord($challenge_string[15]) % 16]; |
70
|
1
|
|
|
|
|
13
|
$hash_string_p = sprintf '%s%s%s%s', |
71
|
|
|
|
|
|
|
$checksum, join('', @challenge_string), $password_hash, $id; |
72
|
1
|
|
|
|
|
6
|
$hash_string_c = sprintf '%s%s%s%s', |
73
|
|
|
|
|
|
|
$checksum, join('', @challenge_string), $crypt_hash, $id; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
elsif ($sv == 3) { |
76
|
0
|
|
|
|
|
0
|
my $checksum = $challenge_string[ord($challenge_string[1]) % 16]; |
77
|
0
|
|
|
|
|
0
|
$hash_string_p = sprintf '%s%s%s%s', |
78
|
|
|
|
|
|
|
$checksum, $id, $password_hash, join('', @challenge_string); |
79
|
0
|
|
|
|
|
0
|
$hash_string_c = sprintf '%s%s%s%s', |
80
|
|
|
|
|
|
|
$checksum, $id, $crypt_hash, join('', @challenge_string); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
elsif ($sv == 4) { |
83
|
0
|
|
|
|
|
0
|
my $checksum = $challenge_string[ord($challenge_string[3]) % 16]; |
84
|
0
|
|
|
|
|
0
|
$hash_string_p = sprintf '%s%s%s%s', |
85
|
|
|
|
|
|
|
$checksum, $password_hash, join('', @challenge_string), $id; |
86
|
0
|
|
|
|
|
0
|
$hash_string_c = sprintf '%s%s%s%s', |
87
|
|
|
|
|
|
|
$checksum, $crypt_hash, join('', @challenge_string), $id; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
elsif ($sv == 0 || $sv == 5) { |
90
|
0
|
|
|
|
|
0
|
my $checksum = $challenge_string[ord($challenge_string[7]) % 16]; |
91
|
0
|
|
|
|
|
0
|
$hash_string_p = sprintf '%s%s%s%s', |
92
|
|
|
|
|
|
|
$checksum, $password_hash, $id, join('', @challenge_string); |
93
|
0
|
|
|
|
|
0
|
$hash_string_c = sprintf '%s%s%s%s', |
94
|
|
|
|
|
|
|
$checksum, $crypt_hash, $id, join('', @challenge_string); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
2
|
|
|
|
|
11
|
my $result6 = _to_yahoo_base64(md5($hash_string_p)); |
98
|
2
|
|
|
|
|
11
|
my $result96 = _to_yahoo_base64(md5($hash_string_c)); |
99
|
2
|
|
|
|
|
24
|
return ($result6, $result96); |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub _to_yahoo_base64 |
104
|
|
|
|
|
|
|
{ |
105
|
8
|
|
|
8
|
|
33
|
pos($_[0]) = 0; |
106
|
|
|
|
|
|
|
|
107
|
8
|
|
|
|
|
98
|
my $res = join '', map( pack('u',$_)=~ /^.(\S*)/, ($_[0]=~/(.{1,45})/gs)); |
108
|
8
|
|
|
|
|
17
|
$res =~ tr{` -_}{AA-Za-z0-9\._}; |
109
|
|
|
|
|
|
|
|
110
|
8
|
|
|
|
|
22
|
my $padding = (3 - length($_[0]) % 3) % 3; |
111
|
8
|
50
|
|
|
|
94
|
$res =~ s/.{$padding}$/'-' x $padding/e if $padding; |
|
8
|
|
|
|
|
27
|
|
112
|
8
|
|
|
|
|
27
|
return $res; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub _to64 |
117
|
|
|
|
|
|
|
{ |
118
|
12
|
|
|
12
|
|
19
|
my ($v, $n) = @_; |
119
|
12
|
|
|
|
|
14
|
my $ret = ''; |
120
|
12
|
|
|
|
|
29
|
while (--$n >= 0) { |
121
|
44
|
|
|
|
|
56
|
$ret .= substr(I_TO_A64, $v & 0x3f, 1); |
122
|
44
|
|
|
|
|
85
|
$v >>= 6; |
123
|
|
|
|
|
|
|
} |
124
|
12
|
|
|
|
|
27
|
$ret; |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub _md5_crypt |
129
|
|
|
|
|
|
|
{ |
130
|
2
|
|
|
2
|
|
3
|
my $pw = shift; |
131
|
2
|
|
|
|
|
4
|
my $salt = shift; |
132
|
|
|
|
|
|
|
|
133
|
2
|
|
|
|
|
3
|
my $Magic = MD5_CRYPT_MAGIC_STRING; |
134
|
2
|
|
|
|
|
18
|
$salt =~ s/^\Q$Magic//; |
135
|
2
|
|
|
|
|
6
|
$salt =~ s/^(.*)\$.*$/$1/; |
136
|
2
|
|
|
|
|
4
|
$salt = substr $salt, 0, 8; |
137
|
|
|
|
|
|
|
|
138
|
2
|
|
|
|
|
15
|
my $ctx = new Digest::MD5; |
139
|
2
|
|
|
|
|
8
|
$ctx->add($pw); |
140
|
2
|
|
|
|
|
7
|
$ctx->add($Magic); |
141
|
2
|
|
|
|
|
6
|
$ctx->add($salt); |
142
|
|
|
|
|
|
|
|
143
|
2
|
|
|
|
|
9
|
my $final = new Digest::MD5; |
144
|
2
|
|
|
|
|
6
|
$final->add($pw); |
145
|
2
|
|
|
|
|
7
|
$final->add($salt); |
146
|
2
|
|
|
|
|
5
|
$final->add($pw); |
147
|
2
|
|
|
|
|
20
|
$final = $final->digest; |
148
|
|
|
|
|
|
|
|
149
|
2
|
|
|
|
|
26
|
for (my $pl = length($pw); $pl > 0; $pl -= 16) { |
150
|
2
|
50
|
|
|
|
20
|
$ctx->add(substr($final, 0, $pl > 16 ? 16 : $pl)); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
154
|
2
|
|
|
|
|
7
|
for (my $i = length($pw); $i; $i >>= 1) { |
155
|
7
|
100
|
|
|
|
13
|
if ($i & 1) { |
156
|
3
|
|
|
|
|
38
|
$ctx->add(pack("C", 0)); |
157
|
|
|
|
|
|
|
} else { |
158
|
4
|
|
|
|
|
20
|
$ctx->add(substr($pw, 0, 1)); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
2
|
|
|
|
|
8
|
$final = $ctx->digest; |
163
|
|
|
|
|
|
|
|
164
|
2
|
|
|
|
|
8
|
for (my $i = 0; $i < 1000; $i++) { |
165
|
2000
|
|
|
|
|
7275
|
my $ctx1 = new Digest::MD5; |
166
|
2000
|
100
|
|
|
|
4351
|
if ($i & 1) { |
167
|
1000
|
|
|
|
|
2442
|
$ctx1->add($pw); |
168
|
|
|
|
|
|
|
} else { |
169
|
1000
|
|
|
|
|
3279
|
$ctx1->add(substr($final, 0, 16)); |
170
|
|
|
|
|
|
|
} |
171
|
2000
|
100
|
|
|
|
4361
|
if ($i % 3) { |
172
|
1332
|
|
|
|
|
2567
|
$ctx1->add($salt); |
173
|
|
|
|
|
|
|
} |
174
|
2000
|
100
|
|
|
|
3609
|
if ($i % 7) { |
175
|
1714
|
|
|
|
|
3491
|
$ctx1->add($pw); |
176
|
|
|
|
|
|
|
} |
177
|
2000
|
100
|
|
|
|
3278
|
if ($i & 1) { |
178
|
1000
|
|
|
|
|
4392
|
$ctx1->add(substr($final, 0, 16)); |
179
|
|
|
|
|
|
|
} else { |
180
|
1000
|
|
|
|
|
2083
|
$ctx1->add($pw); |
181
|
|
|
|
|
|
|
} |
182
|
2000
|
|
|
|
|
13705
|
$final = $ctx1->digest; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
2
|
|
|
|
|
6
|
my $passwd = ''; |
186
|
2
|
|
|
|
|
29
|
$passwd .= _to64(int(unpack("C", (substr($final, 0, 1))) << 16) |
187
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 6, 1))) << 8) |
188
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 12, 1)))), 4); |
189
|
2
|
|
|
|
|
16
|
$passwd .= _to64(int(unpack("C", (substr($final, 1, 1))) << 16) |
190
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 7, 1))) << 8) |
191
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 13, 1)))), 4); |
192
|
2
|
|
|
|
|
55
|
$passwd .= _to64(int(unpack("C", (substr($final, 2, 1))) << 16) |
193
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 8, 1))) << 8) |
194
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 14, 1)))), 4); |
195
|
2
|
|
|
|
|
14
|
$passwd .= _to64(int(unpack("C", (substr($final, 3, 1))) << 16) |
196
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 9, 1))) << 8) |
197
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 15, 1)))), 4); |
198
|
2
|
|
|
|
|
16
|
$passwd .= _to64(int(unpack("C", (substr($final, 4, 1))) << 16) |
199
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 10, 1))) << 8) |
200
|
|
|
|
|
|
|
| int(unpack("C", (substr($final, 5, 1)))), 4); |
201
|
2
|
|
|
|
|
7
|
$passwd .= _to64(int(unpack("C", substr($final, 11, 1))), 2); |
202
|
|
|
|
|
|
|
|
203
|
2
|
|
|
|
|
30
|
return $Magic. $salt. '$'. $passwd; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
1; |
208
|
|
|
|
|
|
|
__END__ |