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