File Coverage

blib/lib/Webqq/Encryption/TEA/Perl.pm
Criterion Covered Total %
statement 9 71 12.6
branch 0 6 0.0
condition 0 3 0.0
subroutine 3 8 37.5
pod 0 5 0.0
total 12 93 12.9


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;