1package Digest::Perl::MD4;
2
3use strict;
4use Exporter;
5use warnings;
6use vars qw($VERSION @ISA @EXPORTER @EXPORT_OK);
7
8use integer;
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    no warnings;
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
35STDIN,$_,64;$r++,$_.="\x80"if$r<64&&!$p++;@W=unpack V16,$_."\0"x7;$W[14]=$l*8
36if$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[
3820+$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
40EOF
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
58sub new {
59	my $class = shift;
60	bless {}, ref($class) || $class;
61}
62
63sub reset {
64	my $self = shift;
65	delete $self->{data};
66	$self
67}
68
69sub add(@) {
70	my $self = shift;
71	$self->{data} .= join'', @_;
72	$self
73}
74
75sub addfile {
76  	my ($self,$fh) = @_;
77	if (!ref($fh) && ref(\$fh) ne "GLOB") {
78	    require Symbol;
79	    $fh = Symbol::qualify($fh, scalar caller);
80	}
81	$self->{data} .= do{local$/;<$fh>};
82	$self
83}
84
85sub digest {
86	md4(shift->{data})
87}
88
89sub hexdigest {
90	md4_hex(shift->{data})
91}
92
93sub b64digest {
94	md4_base64(shift->{data})
95}
96
97# This is the actual MD4 algorithm
98
99sub L # left-rotate
100{
101    my ($n, $x) = @_;
102    $x<<$n|2**$n-1&$x>>32-$n;
103}
104
105sub M # mod 2**32
106{
107    no integer;
108    my ($x) = @_;
109    my $m = 1+0xffffffff;
110    $x-$m*int$x/$m;
111}
112
113sub R # reverse two bit number
114{
115    my $n = pop;
116    ($n&1)*2 + ($n&2)/2;
117}
118
119sub md4(@)
120{
121    my @input = grep defined && length>0, split /(.{64})/s, join '', @_;
122    push @input, '' if !@input || length($input[$#input]) >= 56;
123    my @A = (0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476); # initial regs
124    my @L = qw(3 7 11 19 3 5 9 13 3 9 11 15); # left rotate counts
125    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    my @I = map {my $z=int $_/16;my $x=$_%4; my $y=int $_%16/4;
129		 $O[6+$z]&&(($x,$y)=(R($x),R($y)));
130		 $O[$z]*$x+$O[3+$z]*$y} 0..47;
131    my @T = (0, 0x5A827999, 0x6ED9EBA1);
132
133    my $l = 0;
134    my $p = 0;
135    my ($a,$b,$c,$d);
136    foreach (@input) {
137	my $r=length($_);
138	$l+=$r;
139	$r++,$_.="\x80" if $r<64&&!$p++;
140	my @W=unpack 'V16',$_."\0"x7;
141	push @W, (0)x16 if @W<16;
142	$W[14]=$l*8 if $r<57;		# add bit-length in low 32-bits
143	($a,$b,$c,$d) = @A;
144	for (0..47) {
145	    my $z = int $_/16;
146	    $a=L($L[4*($_>>4)+$_%4],
147		 M(&{(sub{$b&$c|~$b&$d}, 	# F
148		      sub{$b&$c|$b&$d|$c&$d},	# G
149		      sub{$b^$c^$d}		# H
150		     )[$z]}
151		   +$a+$W[$I[$_]]+$T[$z]));
152	    ($a,$b,$c,$d)=($d,$a,$b,$c);
153	}
154	my @v=($a, $b, $c, $d);
155	for (0..3) {
156	    $A[$_] = M($A[$_]+$v[$_]);
157	}
158    }
159    pack 'V4', @A;
160}
161
162sub md4_hex(@) {
163  unpack 'H*', &md4;
164}
165
166sub md4_base64(@) {
167  encode_base64(&md4);
168}
169
170
171sub encode_base64 ($) {
172    my $res;
173    while ($_[0] =~ /(.{1,45})/gs) {
174	$res .= substr pack('u', $1), 1;
175	chop $res;
176    }
177    $res =~ tr|` -_|AA-Za-z0-9+/|;#`
178    chop $res;chop $res;
179    $res;
180}
181
1821;
183
184=head1 NAME
185
186Digest::Perl::MD4 - Perl implementation of Ron Rivests MD4 Algorithm
187
188=head1 DISCLAIMER
189
190This is B<not> C-code interface (like C<Digest::MD5>) but a Perl-only
191implementation of MD4 (like C<Digest::Perl::MD5>).  Because of this, it is
192B<slow> but avoids platform specific complications.  For efficiency you should
193use C<Digest::MD4> 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
219This modules has the same interface as C<Digest::MD5>.  It should be compatible
220 with the Digest::MD4 module written by Mike McCauley <mikem@open.com.au>.
221
222=head1 EXAMPLES
223
224The simplest way to use this library is to import the md4_hex() function (or
225one of its cousins):
226
227    use Digest::Perl::MD4 'md4_hex';
228    print 'Digest is ', md4_hex('foobarbaz'), "\n";
229
230The above example would print out the message
231
232    Digest is b2b2b528f632f554ae9cb2c02c904eeb
233
234provided that the implementation is working correctly.  The same checksum can
235also 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
248This implementation of the MD4 algorithm has some limitations:
249
250=over 4
251
252=item
253
254It is slow, very slow, but still useful for encrypting small amounts of data
255like passwords.
256
257=item
258
259You can only encrypt up to 2^32 bits = 512 MB on 32bit archs.
260
261=item
262
263C<Digest::Perl::MD4> loads all data to encrypt into memory. This is a todo.
264
265=back
266
267=head1 SEE ALSO
268
269L<Digest::MD5>
270
271RFC 1320
272
273=head1 COPYRIGHT
274
275This library is free software; you can redistribute it and/or
276modify 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
284The MD4 algorithm is defined in RFC 1320. The basic C code
285implementing the algorithm is derived from that in the RFC and is
286covered by the following copyright:
287
288=over 4
289
290=item
291
292Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
293rights reserved.
294
295License to copy and use this software is granted provided that it
296is identified as the "RSA Data Security, Inc. MD4 Message-Digest
297Algorithm" in all material mentioning or referencing this software
298or this function.
299
300License is also granted to make and use derivative works provided
301that such works are identified as "derived from the RSA Data
302Security, Inc. MD4 Message-Digest Algorithm" in all material
303mentioning or referencing the derived work.
304
305RSA Data Security, Inc. makes no representations concerning either
306the merchantability of this software or the suitability of this
307software for any particular purpose. It is provided "as is"
308without express or implied warranty of any kind.
309
310These notices must be retained in any copies of any part of this
311documentation and/or software.
312
313=back
314
315This copyright does not prohibit distribution of any version of Perl
316containing this extension under the terms of the GNU or Artistic
317licenses.
318
319=head1 AUTHORS
320
321The original MD5 interface was written by Neil Winton
322<N.Winton@axion.bt.co.uk>.
323
324C<Digest::MD5> was made by Gisle Aas <gisle@aas.no>.
325
326C<Digest::Perl::MD5> was made by Christian Lackas <delta@clackas.de>.
327
328MD5 in 8 lines of perl5 implemented and optimized for size by John Allen[3] and
329collected by Adam Back[5] <adam@cypherspace.org>.  Conversion to MD4 algorithm
330by Ted Anderson <tedanderson@mindspring.com>.
331
332=head1 Footnotes
333
334=over 4
335
336=item [3]
337
338L<allen@grumman.com>
339
340=item [5]
341
342L<http://www.cypherspace.org/~adam/>
343
344=back
345
346=cut
347