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