| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Webqq::Encryption::TEA::Perl; |
|
2
|
1
|
|
|
1
|
|
4
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
39
|
|
|
3
|
|
|
|
|
|
|
#源码参考cpan模块Crypt::OICQ,感谢作者Shufeng Tan |
|
4
|
|
|
|
|
|
|
my $TEA_ROUNDS = 0x10; |
|
5
|
|
|
|
|
|
|
my $TEA_DELTA = 0x9E3779B9; |
|
6
|
|
|
|
|
|
|
my $TEA_SUM = 0xE3779B90; |
|
7
|
|
|
|
|
|
|
sub tea_decrypt { |
|
8
|
1
|
|
|
1
|
|
714
|
use integer; |
|
|
1
|
|
|
|
|
8
|
|
|
|
1
|
|
|
|
|
6
|
|
|
9
|
0
|
|
|
0
|
0
|
|
my ($c_block, $key) = @_; |
|
10
|
0
|
|
|
|
|
|
my ($y, $z) = unpack("NN", $c_block); |
|
11
|
0
|
|
|
|
|
|
my ($a, $b, $c, $d) = unpack("NNNN", $key); |
|
12
|
0
|
|
|
|
|
|
my $sum = $TEA_SUM; |
|
13
|
0
|
|
|
|
|
|
my $n = $TEA_ROUNDS; |
|
14
|
0
|
|
|
|
|
|
while ($n-- > 0) { |
|
15
|
0
|
|
|
|
|
|
$z -= ($y<<4)+$c ^ $y+$sum ^ (0x07ffffff & ($y>>5))+$d; |
|
16
|
0
|
|
|
|
|
|
$y -= ($z<<4)+$a ^ $z+$sum ^ (0x07ffffff & ($z>>5))+$b; |
|
17
|
0
|
|
|
|
|
|
$sum -= $TEA_DELTA; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
0
|
|
|
|
|
|
pack("NN", $y, $z); |
|
20
|
|
|
|
|
|
|
} |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub decrypt { |
|
23
|
0
|
|
|
0
|
0
|
|
my ($crypt, $key) = @_; |
|
24
|
0
|
|
|
|
|
|
my $crypt_len = length($crypt); |
|
25
|
0
|
0
|
0
|
|
|
|
if (($crypt_len % 8) || ($crypt_len < 16)) { |
|
26
|
0
|
|
|
|
|
|
warn "Webqq::Encryption::TEA::Perl::decrypt error: invalid input length $crypt_len\n"; |
|
27
|
0
|
|
|
|
|
|
return undef; |
|
28
|
|
|
|
|
|
|
} |
|
29
|
0
|
|
|
|
|
|
my $c_buf = substr($crypt, 0, 8); |
|
30
|
0
|
|
|
|
|
|
my $p_buf = tea_decrypt($c_buf, $key); |
|
31
|
0
|
|
|
|
|
|
my $pad_len = ord(substr($p_buf, 0, 1) & "\007"); |
|
32
|
0
|
|
|
|
|
|
my $plain_len = $crypt_len - $pad_len - 10; |
|
33
|
0
|
|
|
|
|
|
my $plain = $p_buf; |
|
34
|
0
|
|
|
|
|
|
my $pre_plain = $p_buf; |
|
35
|
0
|
|
|
|
|
|
my $pre_crypt = $c_buf; |
|
36
|
|
|
|
|
|
|
|
|
37
|
0
|
|
|
|
|
|
for (my $i = 8; $i < $crypt_len; $i += 8) { |
|
38
|
0
|
|
|
|
|
|
$c_buf = substr($crypt, $i, 8); |
|
39
|
0
|
|
|
|
|
|
$p_buf = tea_decrypt($c_buf ^ $pre_plain, $key); |
|
40
|
0
|
|
|
|
|
|
$pre_plain = $p_buf; |
|
41
|
0
|
|
|
|
|
|
$p_buf ^= $pre_crypt; |
|
42
|
0
|
|
|
|
|
|
$plain .= $p_buf; |
|
43
|
0
|
|
|
|
|
|
$pre_crypt = $c_buf; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
0
|
0
|
|
|
|
|
if (substr($plain, -7, 7) ne "\0\0\0\0\0\0\0") { |
|
46
|
0
|
|
|
|
|
|
warn "Webqq::Encryption::TEA::Perl::decrypt error: bad decrypt data\n", |
|
47
|
|
|
|
|
|
|
"crypt: ", unpack("H*", $crypt), "\n", |
|
48
|
|
|
|
|
|
|
"key: ", unpack("H*", $key), "\n", |
|
49
|
|
|
|
|
|
|
"plain: ", unpack("H*", $plain), "\n"; |
|
50
|
0
|
|
|
|
|
|
return undef; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
0
|
|
|
|
|
|
return substr($plain, -7-$plain_len, $plain_len); |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub tea_encrypt { |
|
56
|
1
|
|
|
1
|
|
408
|
use integer; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
3
|
|
|
57
|
0
|
|
|
0
|
0
|
|
my ($p_block, $key) = @_; |
|
58
|
0
|
|
|
|
|
|
my ($y, $z) = unpack("NN", $p_block); |
|
59
|
0
|
|
|
|
|
|
my ($a, $b, $c, $d) = unpack("NNNN", $key); |
|
60
|
0
|
|
|
|
|
|
my $sum = 0; |
|
61
|
0
|
|
|
|
|
|
my $n = $TEA_ROUNDS; |
|
62
|
0
|
|
|
|
|
|
while ($n-- > 0) { |
|
63
|
0
|
|
|
|
|
|
$sum += $TEA_DELTA; |
|
64
|
0
|
|
|
|
|
|
$y += ($z<<4)+$a ^ $z+$sum ^ (0x07ffffff & ($z>>5))+$b; |
|
65
|
0
|
|
|
|
|
|
$z += ($y<<4)+$c ^ $y+$sum ^ (0x07ffffff & ($y>>5))+$d; |
|
66
|
|
|
|
|
|
|
} |
|
67
|
0
|
|
|
|
|
|
pack("NN", $y, $z); |
|
68
|
|
|
|
|
|
|
} |
|
69
|
|
|
|
|
|
|
sub encrypt { |
|
70
|
0
|
|
|
0
|
0
|
|
my ($plain, $key) = @_; |
|
71
|
0
|
|
|
|
|
|
my $plain_len = length($plain); |
|
72
|
0
|
|
|
|
|
|
my $head_pad_len = ($plain_len + 10) % 8; |
|
73
|
0
|
0
|
|
|
|
|
$head_pad_len = 8 - $head_pad_len if $head_pad_len; |
|
74
|
0
|
|
|
|
|
|
my $padded_plain = chr(0xa8 + $head_pad_len) . |
|
75
|
|
|
|
|
|
|
rand_str(2+$head_pad_len) . |
|
76
|
|
|
|
|
|
|
#(chr(0xad) x (2 + $head_pad_len)) . |
|
77
|
|
|
|
|
|
|
$plain . ("\0" x 7); |
|
78
|
0
|
|
|
|
|
|
my $padded_plain_len = length($padded_plain); |
|
79
|
0
|
|
|
|
|
|
my $crypt = ""; |
|
80
|
0
|
|
|
|
|
|
my $pre_plain = "\0" x 8; |
|
81
|
0
|
|
|
|
|
|
my $pre_crypt = $pre_plain; |
|
82
|
0
|
|
|
|
|
|
for (my $i = 0; $i < $padded_plain_len; $i += 8) { |
|
83
|
0
|
|
|
|
|
|
my $p_buf = substr($padded_plain, $i, 8) ^ $pre_crypt; |
|
84
|
0
|
|
|
|
|
|
my $c_buf = tea_encrypt($p_buf, $key); |
|
85
|
0
|
|
|
|
|
|
$c_buf ^= $pre_plain; |
|
86
|
0
|
|
|
|
|
|
$crypt .= $c_buf; |
|
87
|
0
|
|
|
|
|
|
$pre_crypt = $c_buf; |
|
88
|
0
|
|
|
|
|
|
$pre_plain = $p_buf; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
0
|
|
|
|
|
|
return $crypt; |
|
91
|
|
|
|
|
|
|
} |
|
92
|
|
|
|
|
|
|
sub rand_str { |
|
93
|
0
|
|
|
0
|
0
|
|
my $len = pop; |
|
94
|
0
|
|
|
|
|
|
join('', map(pack("C", rand(0xff)), 1..$len)); |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
1; |