File Coverage

blib/lib/Digest/Perl/MD4.pm
Criterion Covered Total %
statement 64 92 69.5
branch 10 12 83.3
condition 8 15 53.3
subroutine 15 24 62.5
pod 0 14 0.0
total 97 157 61.7


line stmt bran cond sub pod time code
1             package Digest::Perl::MD4;
2              
3 1     1   707 use strict;
  1         2  
  1         40  
4 1     1   6 use Exporter;
  1         1  
  1         39  
5 1     1   6 use warnings;
  1         13  
  1         35  
6 1     1   5 use vars qw($VERSION @ISA @EXPORTER @EXPORT_OK);
  1         2  
  1         85  
7              
8 1     1   980 use integer;
  1         11  
  1         5  
9              
10             @EXPORT_OK = qw(md4 md4_hex md4_base64);
11              
12             @ISA = 'Exporter';
13             $VERSION = '1.4';
14              
15             # Module logic and interface adapted from Digest::Perl::MD5 v1.5 from CPAN.
16             # See author information below.
17              
18             # The MD4 logic Perl code has these origins:
19             # MD5[0] in 8 lines of perl5
20             #
21             # The MD5 algorithm (Message Digest 5) is a cryptographic message digest
22             # algorithm. It is the message digest algorithm used by PGP 2.x.
23             #
24             # MD5 was designed by Ron Rivest[1], who is also the `R' in `RSA'. MD5 is
25             # described in rfc1321[2]. C source code is included with the RFC.
26             #
27             # John Allen[3] wrote this implementation of MD5 optimised for size, in 8
28             # lines of perl5:
29             {
30 1     1   63 no warnings;
  1         3  
  1         513  
31             <<'EOF'; # quote this stuff
32             #!/bin/perl -iH9T4C`>_-JXF8NMS^$#)4=@<,$18%"0X4!`L0%P8*#Q4``04``04#!P`` ~JLA
33             @A=unpack N4C24,unpack u,$^I;@K=map{int abs 2**32*sin$_}1..64;sub L{($x=pop)
34             <<($n=pop)|2**$n-1&$x>>32-$n}sub M{($x=pop)-($m=1+~0)*int$x/$m}do{$l+=$r=read
35             STDIN,$_,64;$r++,$_.="\x80"if$r<64&&!$p++;@W=unpack V16,$_."\0"x7;$W[14]=$l*8
36             if$r<57;($a,$b,$c,$d)=@A;for(0..63){$a=M$b+L$A[4+4*($_>>4)+$_%4],M&{(sub{$b&$c
37             |$d&~$b},sub{$b&$d|$c&~$d},sub{$b^$c^$d},sub{$c^($b|~$d)})[$z=$_/16]}+$W[($A[
38             20+$z]+$A[24+$z]*($_%16))%16]+$K[$_]+$a;($a,$b,$c,$d)=($d,$a,$b,$c)}$v=a;for(
39             @A[0..3]){$_=M$_+${$v++}}}while$r>56;print unpack H32,pack V4,@A # RSA's MD5
40             EOF
41             }
42              
43             # Comments, html bugs to Adam Back[5] at adam@cypherspace.org.
44              
45             # My MD4 modifications are based on reading rfc1320.txt[6]. While some
46             # remnants of the the highly concise nature of the orginal remain, I've made
47             # numerous typographical adjustments. -ota
48              
49             # [0] http://www.cypherspace.org/~adam/rsa/md5.html
50             # [1] http://theory.lcs.mit.edu/~rivest/homepage.html
51             # [2] http://www.ietf.org/rfc/rfc1321.txt
52             # [3] mailto:allen@grumman.com
53             # [4] http://www.cypherspace.org/~adam/rsa/sha.html
54             # [5] http://www.cypherspace.org/~adam/
55             # [6] http://www.ietf.org/rfc/rfc1320.txt
56              
57             # object part of this module
58             sub new {
59 0     0 0 0 my $class = shift;
60 0   0     0 bless {}, ref($class) || $class;
61             }
62              
63             sub reset {
64 0     0 0 0 my $self = shift;
65 0         0 delete $self->{data};
66 0         0 $self
67             }
68              
69             sub add(@) {
70 0     0 0 0 my $self = shift;
71 0         0 $self->{data} .= join'', @_;
72 0         0 $self
73             }
74              
75             sub addfile {
76 0     0 0 0 my ($self,$fh) = @_;
77 0 0 0     0 if (!ref($fh) && ref(\$fh) ne "GLOB") {
78 0         0 require Symbol;
79 0         0 $fh = Symbol::qualify($fh, scalar caller);
80             }
81 0         0 $self->{data} .= do{local$/;<$fh>};
  0         0  
  0         0  
82 0         0 $self
83             }
84              
85             sub digest {
86 0     0 0 0 md4(shift->{data})
87             }
88              
89             sub hexdigest {
90 0     0 0 0 md4_hex(shift->{data})
91             }
92              
93             sub b64digest {
94 0     0 0 0 md4_base64(shift->{data})
95             }
96              
97             # This is the actual MD4 algorithm
98              
99             sub L # left-rotate
100             {
101 624     624 0 677 my ($n, $x) = @_;
102 624         1293 $x<<$n|2**$n-1&$x>>32-$n;
103             }
104              
105             sub M # mod 2**32
106             {
107 1     1   6 no integer;
  1         9  
  1         5  
108 676     676 0 756 my ($x) = @_;
109 676         604 my $m = 1+0xffffffff;
110 676         1425 $x-$m*int$x/$m;
111             }
112              
113             sub R # reverse two bit number
114             {
115 320     320 0 282 my $n = pop;
116 320         497 ($n&1)*2 + ($n&2)/2;
117             }
118              
119             sub md4(@)
120             {
121 10   66 10 0 88 my @input = grep defined && length>0, split /(.{64})/s, join '', @_;
122 10 100 100     52 push @input, '' if !@input || length($input[$#input]) >= 56;
123 10         20 my @A = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476); # initial regs
124 10         26 my @L = qw(3 7 11 19 3 5 9 13 3 9 11 15); # left rotate counts
125 10         20 my @O = (1, 4, 4, # x stride for input index
126             4, 1, 1, # y stride for input index
127             0, 0, 1); # bitwise reverse both indexes
128 10         17 my @I = map {my $z=int $_/16;my $x=$_%4; my $y=int $_%16/4;
  480         509  
  480         482  
  480         460  
129 480 100       858 $O[6+$z]&&(($x,$y)=(R($x),R($y)));
130 480         805 $O[$z]*$x+$O[3+$z]*$y} 0..47;
131 10         23 my @T = (0, 0x5A827999, 0x6ED9EBA1);
132              
133 10         13 my $l = 0;
134 10         11 my $p = 0;
135 10         7 my ($a,$b,$c,$d);
136 10         17 foreach (@input) {
137 13         15 my $r=length($_);
138 13         11 $l+=$r;
139 13 100 100     59 $r++,$_.="\x80" if $r<64&&!$p++;
140 13         42 my @W=unpack 'V16',$_."\0"x7;
141 13 100       43 push @W, (0)x16 if @W<16;
142 13 100       25 $W[14]=$l*8 if $r<57; # add bit-length in low 32-bits
143 13         18 ($a,$b,$c,$d) = @A;
144 13         18 for (0..47) {
145 624         738 my $z = int $_/16;
146 208     208   515 $a=L($L[4*($_>>4)+$_%4],
147 624         812 M(&{(sub{$b&$c|~$b&$d}, # F
148 208     208   533 sub{$b&$c|$b&$d|$c&$d}, # G
149 208     208   473 sub{$b^$c^$d} # H
150 624         3180 )[$z]}
151             +$a+$W[$I[$_]]+$T[$z]));
152 624         2658 ($a,$b,$c,$d)=($d,$a,$b,$c);
153             }
154 13         30 my @v=($a, $b, $c, $d);
155 13         17 for (0..3) {
156 52         78 $A[$_] = M($A[$_]+$v[$_]);
157             }
158             }
159 10         83 pack 'V4', @A;
160             }
161              
162             sub md4_hex(@) {
163 10     10 0 770 unpack 'H*', &md4;
164             }
165              
166             sub md4_base64(@) {
167 0     0 0   encode_base64(&md4);
168             }
169              
170              
171             sub encode_base64 ($) {
172 0     0 0   my $res;
173 0           while ($_[0] =~ /(.{1,45})/gs) {
174 0           $res .= substr pack('u', $1), 1;
175 0           chop $res;
176             }
177 0           $res =~ tr|` -_|AA-Za-z0-9+/|;#`
178 0           chop $res;chop $res;
  0            
179 0           $res;
180             }
181              
182             1;
183              
184             =head1 NAME
185              
186             Digest::Perl::MD4 - Perl implementation of Ron Rivests MD4 Algorithm
187              
188             =head1 DISCLAIMER
189              
190             This is B C-code interface (like C) but a Perl-only
191             implementation of MD4 (like C). Because of this, it is
192             B but avoids platform specific complications. For efficiency you should
193             use C instead of this module if it is available.
194              
195             =head1 SYNOPSIS
196              
197             # Functional style
198             use Digest::Perl::MD4 qw(md4 md4_hex md4_base64);
199              
200             $hash = md4 $data;
201             $hash = md4_hex $data;
202             $hash = md4_base64 $data;
203              
204              
205             # OO style
206             use Digest::Perl::MD4;
207              
208             $ctx = Digest::Perl::MD4->new;
209              
210             $ctx->add($data);
211             $ctx->addfile(*FILE);
212              
213             $digest = $ctx->digest;
214             $digest = $ctx->hexdigest;
215             $digest = $ctx->b64digest;
216              
217             =head1 DESCRIPTION
218              
219             This modules has the same interface as C. It should be compatible
220             with the Digest::MD4 module written by Mike McCauley .
221              
222             =head1 EXAMPLES
223              
224             The simplest way to use this library is to import the md4_hex() function (or
225             one of its cousins):
226              
227             use Digest::Perl::MD4 'md4_hex';
228             print 'Digest is ', md4_hex('foobarbaz'), "\n";
229              
230             The above example would print out the message
231              
232             Digest is b2b2b528f632f554ae9cb2c02c904eeb
233              
234             provided that the implementation is working correctly. The same checksum can
235             also be calculated in OO style:
236              
237             use Digest::Perl::MD4;
238              
239             $md4 = Digest::Perl::MD4->new;
240             $md4->add('foo', 'bar');
241             $md4->add('baz');
242             $digest = $md4->hexdigest;
243              
244             print "Digest is $digest\n";
245              
246             =head1 LIMITATIONS
247              
248             This implementation of the MD4 algorithm has some limitations:
249              
250             =over 4
251              
252             =item
253              
254             It is slow, very slow, but still useful for encrypting small amounts of data
255             like passwords.
256              
257             =item
258              
259             You can only encrypt up to 2^32 bits = 512 MB on 32bit archs.
260              
261             =item
262              
263             C loads all data to encrypt into memory. This is a todo.
264              
265             =back
266              
267             =head1 SEE ALSO
268              
269             L
270              
271             RFC 1320
272              
273             =head1 COPYRIGHT
274              
275             This library is free software; you can redistribute it and/or
276             modify it under the same terms as Perl itself.
277              
278             Copyright 2002 Ted Anderson.
279             Copyright 2000 Christian Lackas, Imperia Software Solutions.
280             Copyright 1998-1999 Gisle Aas.
281             Copyright 1995-1996 Neil Winton.
282             Copyright 1991-1992 RSA Data Security, Inc.
283              
284             The MD4 algorithm is defined in RFC 1320. The basic C code
285             implementing the algorithm is derived from that in the RFC and is
286             covered by the following copyright:
287              
288             =over 4
289              
290             =item
291              
292             Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
293             rights reserved.
294              
295             License to copy and use this software is granted provided that it
296             is identified as the "RSA Data Security, Inc. MD4 Message-Digest
297             Algorithm" in all material mentioning or referencing this software
298             or this function.
299              
300             License is also granted to make and use derivative works provided
301             that such works are identified as "derived from the RSA Data
302             Security, Inc. MD4 Message-Digest Algorithm" in all material
303             mentioning or referencing the derived work.
304              
305             RSA Data Security, Inc. makes no representations concerning either
306             the merchantability of this software or the suitability of this
307             software for any particular purpose. It is provided "as is"
308             without express or implied warranty of any kind.
309              
310             These notices must be retained in any copies of any part of this
311             documentation and/or software.
312              
313             =back
314              
315             This copyright does not prohibit distribution of any version of Perl
316             containing this extension under the terms of the GNU or Artistic
317             licenses.
318              
319             =head1 AUTHORS
320              
321             The original MD5 interface was written by Neil Winton
322             .
323              
324             C was made by Gisle Aas .
325              
326             C was made by Christian Lackas .
327              
328             MD5 in 8 lines of perl5 implemented and optimized for size by John Allen[3] and
329             collected by Adam Back[5] . Conversion to MD4 algorithm
330             by Ted Anderson .
331              
332             =head1 Footnotes
333              
334             =over 4
335              
336             =item [3]
337              
338             L
339              
340             =item [5]
341              
342             L
343              
344             =back
345              
346             =cut