File Coverage

blib/lib/Net/ICQV5CD.pm
Criterion Covered Total %
statement 85 88 96.5
branch 7 10 70.0
condition n/a
subroutine 8 8 100.0
pod 5 5 100.0
total 105 111 94.5


line stmt bran cond sub pod time code
1             package Net::ICQV5CD;
2              
3             =head1 NAME
4              
5             C - Module to crypt/decrypt ICQ protocol V5 packets.
6              
7             =head1 SYNOPSIS
8              
9             use Net::ICQV5CD;
10              
11             $packet = "000102030405060708090A0B0C0D0E0F101112131415161718";
12             $packet = pack("H*",$packet);
13            
14             $packet = ICQV5_CRYPT_PACKET ($packet);
15             $packet = ICQV5_DECRYPT_PACKET ($packet);
16              
17             =head1 DESCRIPTION
18              
19             This module provides set of functions to crypt/decrypt ICQ V5 packets.
20              
21             =cut
22              
23 1     1   6302 use strict;
  1         2  
  1         43  
24 1     1   5 use vars qw($VERSION @ISA @EXPORT);
  1         2  
  1         113  
25              
26 1     1   6 use Exporter;
  1         6  
  1         896  
27              
28             @ISA = qw(Exporter);
29             @EXPORT = qw(@ICQV5_CRYPT_TABLE
30             &ICQV5_GET_PACKET_CHECKCODE
31             &ICQV5_SCRAMBLE_CHECKCODE
32             &ICQV5_DESCRAMBLE_CHECKCODE
33             &ICQV5_CRYPT_PACKET
34             &ICQV5_DECRYPT_PACKET);
35              
36             $VERSION = 1.02;
37              
38             ##############################################################################
39              
40             =head1 IMPORTED FUNCTIONS/VARS
41              
42             =head2 @ICQV5_CRYPT_TABLE
43              
44             ICQ V5 Crypt Table
45            
46             =cut
47              
48             my @ICQV5_CRYPT_TABLE = (
49             0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
50             0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
51             0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
52             0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
53             0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
54             0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
55             0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
56             0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
57             0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
58             0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
59             0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
60             0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
61             0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
62             0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
63             0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
64             0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00,
65             );
66             ###############################################################################
67              
68             =head2 $checkcode = ICQV5_GET_PACKET_CHECKCODE($packet)
69              
70             Function that will return packet checkcode.
71             If you don't know what is checkcode this fucntion will not be
72             useful for you.
73            
74             =cut
75              
76             sub ICQV5_GET_PACKET_CHECKCODE {
77 4     4 1 7 my $packet = shift ;
78              
79             # Packet length must be > 0x18
80              
81 4 50       10 if(length($packet) <= 0x18) {return undef;}
  0         0  
82            
83             # 1. Found NUMBER1 formed by:
84             #
85             # B8 = Byte at position 8 of the packet. (starting at position 0)
86             # B4 = Byte at position 4 of the packet.
87             # B2 = Byte at position 2 of the packet.
88             # B6 = Byte at position 6 of the packet.
89             #
90             # NUMBER1 = 0x B8 B4 B2 B6 (B8 = UPPER BYTE, B6 = LOWER BYTE)
91              
92 4         4 my ($number1);
93              
94 4         12 $number1 = unpack("c",substr($packet,0x08));
95 4         6 $number1 <<= 8;
96 4         8 $number1 += unpack("c",substr($packet,0x04));
97 4         6 $number1 <<= 8;
98 4         5 $number1 += unpack("c",substr($packet,0x02));
99 4         5 $number1 <<= 8;
100 4         9 $number1 += unpack("c",substr($packet,0x06));
101            
102             # 2. Calculate the following:
103             #
104             # PL = Packet length
105             # R1 = a random number beetween 0x18 and (0x18 + PL)
106             # R2 = another random number beetween 0 and 0xFF
107              
108 4         5 my ($r1,$r2);
109            
110 4         54 $r1 = rand(length($packet) - 0x18) + 0x18;
111 4         5 $r2 = rand(0xFF);
112              
113             # $r1 = 0x18; # For Test
114             # $r2 = 0x7F; # For Test
115              
116             # 3. Found NUMBER2:
117             #
118             # X4 = R1
119             # X3 = NOT (BYTE at pos X4 in the packet)
120             # X2 = R2
121             # X1 = NOT (BYTE at pos X2 in the TABLE) (see TABLE section)
122             #
123             # NUMBER2 = 0x X4 X3 X2 X1 (X4 = UPPER BYTE, X1 = LOWER BYTE)
124              
125 4         5 my ($number2);
126              
127 4         825 $number2 = $r1;
128 4         5 $number2 <<= 8;
129 4         10 $number2 += unpack("c",substr($packet,$r1));
130 4         6 $number2 <<= 8;
131 4         5 $number2 += $r2;
132 4         5 $number2 <<= 8;
133 4         6 $number2 += $ICQV5_CRYPT_TABLE[$r2];
134 4         5 $number2 ^= 0x00FF00FF;
135            
136             # 4. You can now calculate the checkcode:
137             #
138             # CHECKCODE = NUMBER1 XOR NUMBER2
139            
140 4         10 return $number1 ^ $number2;
141             }
142             #############################################################################
143              
144             =head2 $scheckcode = ICQV5_SCRAMBLE_CHECKCODE($checkcode)
145              
146             Function that will return packet scrabmled checkcode.
147             If you don't know what is checkcode this fucntion will not be
148             useful for you.
149            
150             =cut
151              
152             sub ICQV5_SCRAMBLE_CHECKCODE {
153 4     4 1 5 my $checkcode = shift;
154              
155 4         6 my $a1 = $checkcode & 0x0000001F;
156 4         5 my $a2 = $checkcode & 0x03E003E0;
157 4         5 my $a3 = $checkcode & 0xF8000400;
158 4         5 my $a4 = $checkcode & 0x0000F800;
159 4         4 my $a5 = $checkcode & 0x041F0000;
160              
161 4         5 $a1 <<= 0x0C;
162 4         4 $a2 <<= 0x01;
163 4         5 $a3 >>= 0x0A;
164 4         4 $a4 <<= 0x10;
165 4         5 $a5 >>= 0x0F;
166              
167 4         29 return $a1 + $a2 + $a3 + $a4 + $a5;
168             }
169             #############################################################################
170              
171             =head2 $dscheckcode = ICQV5_DESCRAMBLE_CHECKCODE($checkcode)
172              
173             Function that will return packet descrabmled checkcode.
174             If you don't know what is checkcode this fucntion will not be
175             useful for you.
176            
177             =cut
178              
179              
180             sub ICQV5_DESCRAMBLE_CHECKCODE {
181 4     4 1 18 my $checkcode = shift;
182              
183 4         7 my $a1 = $checkcode & 0x0001F000;
184 4         5 my $a2 = $checkcode & 0x07C007C0;
185 4         5 my $a3 = $checkcode & 0x003E0001;
186 4         6 my $a4 = $checkcode & 0xF8000000;
187 4         5 my $a5 = $checkcode & 0x0000083E;
188              
189 4         7 $a1 >>= 0x0C;
190 4         5 $a2 >>= 0x01;
191 4         5 $a3 <<= 0x0A;
192 4         4 $a4 >>= 0x10;
193 4         5 $a5 <<= 0x0F;
194              
195 4         10 return $a1 + $a2 + $a3 + $a4 + $a5;
196             }
197             #############################################################################
198              
199             =head2 $crypted_packet = ICQV5_CRYPT_PACKET($packet)
200              
201             Function that crypt incoming packet by ICQ V5 algorithm.
202             This is most usable function.
203             Packet must coming as string.
204            
205             =cut
206              
207              
208             sub ICQV5_CRYPT_PACKET {
209 8     8 1 363 my $packet = shift;
210 8         12 my $decryptpacket = shift;
211              
212             # Packet length must be > 0x18
213 8         10 my $pl = length($packet);
214            
215 8 50       21 if($pl<=0x18) {return $packet;}
  0         0  
216              
217             # If you want to encrypt or decrypt a packet, use the following algorithm:
218             # (the algorithm is the same for the ecryption AND decryption)
219              
220             # 1. Calculate the following:
221             #
222             # Calculate the CHECKCODE
223            
224 8         9 my $checkcode;
225              
226 8 100       17 if(!$decryptpacket)
227             {
228 4         7 $checkcode = ICQV5_GET_PACKET_CHECKCODE($packet);
229             }
230             else
231             {
232 4         7 $checkcode = unpack("V",substr($packet,0x14));
233 4         10 $checkcode = ICQV5_DESCRAMBLE_CHECKCODE($checkcode);
234             }
235              
236             # CODE1 = (DWORD) (PL * 0x68656C6C) (flush the overflow)
237             # CODE2 = (DWORD) (CODE1 + CHECKCODE) (flush the overflow)
238              
239 8         9 my ($code1,$code2);
240            
241 8         9 $code1 = $pl * 0x68656C6C;
242 8         17 while ($code1 > 0xFFFFFFFF) { $code1 = $code1 - 0xFFFFFFFF - 1; }
  84         152  
243            
244 8         10 $code2 = $code1 + $checkcode;
245 8 50       15 if($code2 > 0xFFFFFFFF) { $code2 = $code2 - 0xFFFFFFFF - 1; }
  0         0  
246              
247             # 2. Do the following loop:
248            
249 8         7 my ($data,$code3);
250 8         13 $packet = $packet . "000";
251              
252             # POS = 0x0A
253            
254 8         21 for(my $pos=0x0A;$pos<$pl;$pos+=4)
255             {
256             # T = POS MOD 0x0100
257             # CODE3 = CODE2 + TABLE[T] (see TABLE section)
258            
259 36         49 $code3 = $code2 + $ICQV5_CRYPT_TABLE[$pos & 0xFF];
260            
261             # DATA = DWORD at position POS in the packet
262             # (don't forget to reverse the byte order)
263             # DATA = DATA XOR CODE3
264              
265 36         52 $data = unpack("V",substr($packet,$pos));
266 36         37 $data ^= $code3;
267 36         120 $packet = substr($packet,0,$pos) . pack("V",$data) . substr($packet,$pos+0x04);
268             }
269            
270 8 100       18 if(!$decryptpacket)
271             {
272 4         13 $checkcode = ICQV5_SCRAMBLE_CHECKCODE($checkcode);
273 4         13 $packet = substr($packet,0,0x14) . pack("V",$checkcode) . substr($packet,0x18);
274             }
275              
276 8         12 $packet = substr($packet,0,$pl);
277            
278 8         23 return $packet;
279             }
280             #############################################################################
281              
282             =head2 $decrypted_packet = ICQV5_DECRYPT_PACKET($packet)
283              
284             Function that decrypt incoming packet by ICQ V5 algorithm.
285             This is most usable function.
286             Packet must coming as string.
287            
288             =cut
289              
290             sub ICQV5_DECRYPT_PACKET {
291 4     4 1 12 my $packet = shift;
292              
293 4         9 return ICQV5_CRYPT_PACKET($packet,1);
294             }
295             #############################################################################
296             1;
297              
298             =head1 DISCLAIMERS
299              
300             I am in no way affiliated with Mirabilis!
301              
302             This module was made without any help from Mirabilis or their
303             consent. No reverse engineering or decompilation of any Mirabilis
304             code took place to make this program.
305              
306             =head1 COPYRIGHT
307              
308             Copyright (c) 2000-2001 Sergei A. Nemarov (admin@tapor.com). All rights reserved.
309             This program is free software; you can redistribute it and/or modify
310             it under the same terms as Perl itself.
311              
312             http://www.tapor.com/NetICQ/
313              
314             =cut