File Coverage

blib/lib/Authen/NTLM/MD4.pm
Criterion Covered Total %
statement 121 133 90.9
branch 3 4 75.0
condition n/a
subroutine 12 12 100.0
pod 0 11 0.0
total 136 160 85.0


line stmt bran cond sub pod time code
1             #!/usr/local/bin/perl
2             #
3             # This is a partial implentation of the MD4 checksum code.
4             #
5             # NOTE
6             #
7             # The function &add() in this module is required as we need to be
8             # able to add 32bit integers ignoring overflow. The C code this is
9             # based on does this because it uses the underlying hardware to
10             # perform the required addition however we need to be more careful
11             # as Perl will overflow an int and produce a result of 0xffffffff
12             # which is not very useful. The &add() function splits its arguments
13             # into two shorts and adds these carrying overflow from the low short
14             # to the high short and ignoring carry from the high short. Not
15             # exactly efficient, but it works and is fast enough for the purposes
16             # of this implementation
17             #
18              
19             package Authen::NTLM::MD4;
20              
21 4     4   28 use vars qw($VERSION @ISA @EXPORT);
  4         40  
  4         12243  
22             require Exporter;
23              
24             $VERSION = "1.02";
25             @ISA = qw(Exporter);
26             @EXPORT = qw(mdfour);
27              
28             my ($A, $B, $C, $D);
29             my (@X, $M);
30              
31             sub mdfour
32             {
33 4     4 0 10 my ($in) = @_;
34              
35 4         8 my ($i, $pos);
36 4         11 my $len = length($in);
37 4         10 my $b = $len * 8;
38 4         12 $in .= "\0"x128;
39 4         6 $A = 0x67452301;
40 4         8 $B = 0xefcdab89;
41 4         9 $C = 0x98badcfe;
42 4         6 $D = 0x10325476;
43 4         7 $pos = 0;
44 4         18 while ($len > 64)
45             {
46 0         0 ©64(substr($in, $pos, 64));
47 0         0 &mdfour64;
48 0         0 $pos += 64;
49 0         0 $len -= 64;
50             }
51 4         19 my $buf = substr($in, $pos, $len);
52 4         10 $buf .= sprintf "%c", 0x80;
53 4 50       15 if ($len <= 55)
54             {
55 4         18 $buf .= "\0"x(55-$len);
56 4         13 $buf .= pack("V", $b);
57 4         8 $buf .= "\0"x4;
58 4         17 ©64($buf);
59 4         22 &mdfour64;
60             }
61             else
62             {
63 0         0 $buf .= "\0"x(120-$len);
64 0         0 $buf .= pack("V", $b);
65 0         0 $buf .= "\0"x4;
66 0         0 ©64(substr($buf, 0, 64));
67 0         0 &mdfour64;
68 0         0 ©64(substr($buf, 64, 64));
69 0         0 &mdfour64;
70             }
71 4         23 my $out = pack("VVVV", $A, $B, $C, $D);
72 4         34 return $out;
73             }
74              
75             sub F
76             {
77 64     64 0 82 my ($X, $Y, $Z) = @_;
78 64         96 my $res = ($X&$Y) | ((~$X)&$Z);
79 64         133 return $res;
80             }
81              
82             sub G
83             {
84 64     64 0 73 my ($X, $Y, $Z) = @_;
85              
86 64         156 return ($X&$Y) | ($X&$Z) | ($Y&$Z);
87             }
88              
89             sub H
90             {
91 64     64 0 229 my ($X, $Y, $Z) = @_;
92              
93 64         197 return $X^$Y^$Z;
94             }
95              
96             sub lshift
97             {
98 192     192 0 241 my ($x, $s) = @_;
99              
100 192         198 $x &= 0xffffffff;
101 192         481 return (($x<<$s)&0xffffffff) | ($x>>(32-$s));
102             }
103              
104             sub ROUND1
105             {
106 64     64 0 90 my ($a, $b, $c, $d, $k, $s) = @_;
107 64         113 my $e = &add($a, &F($b, $c, $d), $X[$k]);
108 64         115 return &lshift($e, $s);
109             }
110              
111             sub ROUND2
112             {
113 64     64 0 91 my ($a, $b, $c, $d, $k, $s) = @_;
114              
115 64         133 my $e = &add($a, &G($b, $c, $d), $X[$k], 0x5a827999);
116 64         127 return &lshift($e, $s);
117             }
118              
119             sub ROUND3
120             {
121 64     64 0 101 my ($a, $b, $c, $d, $k, $s) = @_;
122              
123 64         111 my $e = &add($a, &H($b, $c, $d), $X[$k], 0x6ed9eba1);
124 64         1018 return &lshift($e, $s);
125             }
126              
127             sub mdfour64
128             {
129 4     4 0 10 my ($i, $AA, $BB, $CC, $DD);
130 4         21 @X = unpack("N16", $M);
131 4         24 $AA = $A;
132 4         7 $BB = $B;
133 4         12 $CC = $C;
134 4         6 $DD = $D;
135              
136 4         25 $A = &ROUND1($A,$B,$C,$D, 0, 3); $D = &ROUND1($D,$A,$B,$C, 1, 7);
  4         13  
137 4         12 $C = &ROUND1($C,$D,$A,$B, 2,11); $B = &ROUND1($B,$C,$D,$A, 3,19);
  4         12  
138 4         13 $A = &ROUND1($A,$B,$C,$D, 4, 3); $D = &ROUND1($D,$A,$B,$C, 5, 7);
  4         14  
139 4         90 $C = &ROUND1($C,$D,$A,$B, 6,11); $B = &ROUND1($B,$C,$D,$A, 7,19);
  4         13  
140 4         11 $A = &ROUND1($A,$B,$C,$D, 8, 3); $D = &ROUND1($D,$A,$B,$C, 9, 7);
  4         17  
141 4         11 $C = &ROUND1($C,$D,$A,$B,10,11); $B = &ROUND1($B,$C,$D,$A,11,19);
  4         13  
142 4         14 $A = &ROUND1($A,$B,$C,$D,12, 3); $D = &ROUND1($D,$A,$B,$C,13, 7);
  4         12  
143 4         13 $C = &ROUND1($C,$D,$A,$B,14,11); $B = &ROUND1($B,$C,$D,$A,15,19);
  4         12  
144              
145 4         17 $A = &ROUND2($A,$B,$C,$D, 0, 3); $D = &ROUND2($D,$A,$B,$C, 4, 5);
  4         10  
146 4         11 $C = &ROUND2($C,$D,$A,$B, 8, 9); $B = &ROUND2($B,$C,$D,$A,12,13);
  4         13  
147 4         13 $A = &ROUND2($A,$B,$C,$D, 1, 3); $D = &ROUND2($D,$A,$B,$C, 5, 5);
  4         29  
148 4         12 $C = &ROUND2($C,$D,$A,$B, 9, 9); $B = &ROUND2($B,$C,$D,$A,13,13);
  4         10  
149 4         13 $A = &ROUND2($A,$B,$C,$D, 2, 3); $D = &ROUND2($D,$A,$B,$C, 6, 5);
  4         21  
150 4         10 $C = &ROUND2($C,$D,$A,$B,10, 9); $B = &ROUND2($B,$C,$D,$A,14,13);
  4         14  
151 4         19 $A = &ROUND2($A,$B,$C,$D, 3, 3); $D = &ROUND2($D,$A,$B,$C, 7, 5);
  4         11  
152 4         12 $C = &ROUND2($C,$D,$A,$B,11, 9); $B = &ROUND2($B,$C,$D,$A,15,13);
  4         14  
153              
154 4         21 $A = &ROUND3($A,$B,$C,$D, 0, 3); $D = &ROUND3($D,$A,$B,$C, 8, 9);
  4         13  
155 4         18 $C = &ROUND3($C,$D,$A,$B, 4,11); $B = &ROUND3($B,$C,$D,$A,12,15);
  4         12  
156 4         23 $A = &ROUND3($A,$B,$C,$D, 2, 3); $D = &ROUND3($D,$A,$B,$C,10, 9);
  4         15  
157 4         13 $C = &ROUND3($C,$D,$A,$B, 6,11); $B = &ROUND3($B,$C,$D,$A,14,15);
  4         14  
158 4         14 $A = &ROUND3($A,$B,$C,$D, 1, 3); $D = &ROUND3($D,$A,$B,$C, 9, 9);
  4         14  
159 4         12 $C = &ROUND3($C,$D,$A,$B, 5,11); $B = &ROUND3($B,$C,$D,$A,13,15);
  4         13  
160 4         13 $A = &ROUND3($A,$B,$C,$D, 3, 3); $D = &ROUND3($D,$A,$B,$C,11, 9);
  4         14  
161 4         21 $C = &ROUND3($C,$D,$A,$B, 7,11); $B = &ROUND3($B,$C,$D,$A,15,15);
  4         13  
162              
163 4         12 $A = &add($A, $AA); $B = &add($B, $BB);
  4         11  
164 4         14 $C = &add($C, $CC); $D = &add($D, $DD);
  4         12  
165 4         8 $A &= 0xffffffff; $B &= 0xffffffff;
  4         9  
166 4         17 $C &= 0xffffffff; $D &= 0xffffffff;
  4         8  
167 4         12 map {$_ = 0} @X;
  64         88  
168             }
169              
170             sub copy64
171             {
172 4     4 0 10 my ($in) = @_;
173              
174 4         28 $M = pack("V16", unpack("N16", $in));
175             }
176              
177             # see note at top of this file about this function
178             sub add
179             {
180 208     208 0 490 my (@nums) = @_;
181 208         215 my ($r_low, $r_high, $n_low, $l_high);
182 0         0 my $num;
183 208         245 $r_low = $r_high = 0;
184 208         390 foreach $num (@nums)
185             {
186 736         749 $n_low = $num & 0xffff;
187 736         1043 $n_high = ($num&0xffff0000)>>16;
188 736         1157 $r_low += $n_low;
189 736 100       1728 ($r_low&0xf0000) && $r_high++;
190 736         802 $r_low &= 0xffff;
191 736         818 $r_high += $n_high;
192 736         1546 $r_high &= 0xffff;
193             }
194 208         471 return ($r_high<<16)|$r_low;
195             }
196              
197             1;