File Coverage

blib/lib/Crypt/OICQ.pm
Criterion Covered Total %
statement 73 77 94.8
branch 4 6 66.6
condition 1 3 33.3
subroutine 10 11 90.9
pod 0 6 0.0
total 88 103 85.4


line stmt bran cond sub pod time code
1             package Crypt::OICQ;
2              
3             # $Id: OICQ.pm,v 1.4 2006/01/20 21:31:27 tans Exp $
4              
5             # Copyright (c) 2002-2006 Shufeng Tan. All rights reserved.
6             #
7             # This package is free software and is provided "as is" without express
8             # or implied warranty. It may be used, redistributed and/or modified
9             # under the terms of the Perl Artistic License (see
10             # http://www.perl.com/perl/misc/Artistic.html)
11              
12 1     1   27903 use 5.008;
  1         4  
  1         159  
13 1     1   7 use strict;
  1         2  
  1         48  
14 1     1   7 use warnings;
  1         7  
  1         174  
15              
16             our $VERSION = '1.1';
17              
18             our @ISA = qw(Exporter);
19             our @EXPORT_OK = qw(encrypt decrypt);
20              
21             sub new {
22 0     0 0 0 my ($class) = @_;
23 0         0 bless {}, $class;
24             }
25              
26             my $TEA_ROUNDS = 0x10;
27             my $TEA_DELTA = 0x9E3779B9;
28             my $TEA_SUM = 0xE3779B90;
29              
30             sub tea_decrypt {
31 1     1   1053 use integer;
  1         11  
  1         6  
32 1077498     1077498 0 1991682 my ($c_block, $key) = @_;
33 1077498         2316640 my ($y, $z) = unpack("NN", $c_block);
34 1077498         2647621 my ($a, $b, $c, $d) = unpack("NNNN", $key);
35 1077498         1475940 my $sum = $TEA_SUM;
36 1077498         1365143 my $n = $TEA_ROUNDS;
37 1077498         2627426 while ($n-- > 0) {
38 17239968         29407848 $z -= ($y<<4)+$c ^ $y+$sum ^ (0x07ffffff & ($y>>5))+$d;
39 17239968         28372815 $y -= ($z<<4)+$a ^ $z+$sum ^ (0x07ffffff & ($z>>5))+$b;
40 17239968         38392354 $sum -= $TEA_DELTA;
41             }
42 1077498         4093057 pack("NN", $y, $z);
43             }
44              
45             sub decrypt {
46 16441     16441 0 103197 my ($self, $crypt, $key) = @_;
47              
48 16441         30960 my $crypt_len = length($crypt);
49 16441 50 33     147998 if (($crypt_len % 8) || ($crypt_len < 16)) {
50 0         0 die "Crypt::OICQ::decrypt error: invalid input length $crypt_len\n";
51             }
52              
53 16441         41974 my $c_buf = substr($crypt, 0, 8);
54 16441         46678 my $p_buf = tea_decrypt($c_buf, $key);
55 16441         80895 my $pad_len = ord(substr($p_buf, 0, 1) & "\007");
56 16441         38957 my $plain_len = $crypt_len - $pad_len - 10;
57 16441         32822 my $plain = $p_buf;
58 16441         26166 my $pre_plain = $p_buf;
59 16441         40553 my $pre_crypt = $c_buf;
60              
61 16441         60628 for (my $i = 8; $i < $crypt_len; $i += 8) {
62 1061057         1839930 $c_buf = substr($crypt, $i, 8);
63 1061057         2724090 $p_buf = tea_decrypt($c_buf ^ $pre_plain, $key);
64 1061057         1994537 $pre_plain = $p_buf;
65 1061057         1572343 $p_buf ^= $pre_crypt;
66 1061057         1500597 $plain .= $p_buf;
67 1061057         3281381 $pre_crypt = $c_buf;
68             }
69 16441 50       75346 if (substr($plain, -7, 7) ne "\0\0\0\0\0\0\0") {
70 0         0 die "Crypt::OICQ::decrypt error: data dumped\n",
71             "crypt: ", unpack("H*", $crypt), "\n",
72             "key: ", unpack("H*", $key), "\n",
73             "plain: ", unpack("H*", $plain), "\n";
74             }
75 16441         186891 return substr($plain, -7-$plain_len, $plain_len);
76             }
77              
78             sub tea_encrypt {
79 1     1   508 use integer;
  1         2  
  1         5  
80 1077412     1077412 0 1755836 my ($p_block, $key) = @_;
81 1077412         2331846 my ($y, $z) = unpack("NN", $p_block);
82 1077412         2570178 my ($a, $b, $c, $d) = unpack("NNNN", $key);
83 1077412         1518779 my $sum = 0;
84 1077412         1363671 my $n = $TEA_ROUNDS;
85 1077412         2855006 while ($n-- > 0) {
86 17238592         20767225 $sum += $TEA_DELTA;
87 17238592         29308756 $y += ($z<<4)+$a ^ $z+$sum ^ (0x07ffffff & ($z>>5))+$b;
88 17238592         46945233 $z += ($y<<4)+$c ^ $y+$sum ^ (0x07ffffff & ($y>>5))+$d;
89             }
90 1077412         3715105 pack("NN", $y, $z);
91             }
92              
93             sub encrypt {
94 16429     16429 0 148626 my ($self, $plain, $key) = @_;
95 16429         44323 my $plain_len = length($plain);
96 16429         47419 my $head_pad_len = ($plain_len + 10) % 8;
97 16429 100       53607 $head_pad_len = 8 - $head_pad_len if $head_pad_len;
98 16429         71423 my $padded_plain = chr(0xa8 + $head_pad_len) .
99             rand_str(2+$head_pad_len) .
100             #(chr(0xad) x (2 + $head_pad_len)) .
101             $plain . ("\0" x 7);
102 16429         46094 my $padded_plain_len = length($padded_plain);
103 16429         25773 my $crypt = "";
104 16429         37326 my $pre_plain = "\0" x 8;
105 16429         26986 my $pre_crypt = $pre_plain;
106 16429         52833 for (my $i = 0; $i < $padded_plain_len; $i += 8) {
107 1077412         2140581 my $p_buf = substr($padded_plain, $i, 8) ^ $pre_crypt;
108 1077412         2221115 my $c_buf = tea_encrypt($p_buf, $key);
109 1077412         1871475 $c_buf ^= $pre_plain;
110 1077412         1525583 $crypt .= $c_buf;
111 1077412         1511677 $pre_crypt = $c_buf;
112 1077412         3217615 $pre_plain = $p_buf;
113             }
114 16429         158325 return $crypt;
115             }
116              
117             sub rand_str {
118 32829     32829 0 2077281 my $len = pop;
119 32829         7017403 join('', map(pack("C", rand(0xff)), 1..$len));
120             }
121              
122             1;
123              
124             __END__