md4.tcl

Go to the documentation of this file.
00001 /*  md4.tcl - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00002 /* */
00003 /*  This is a Tcl-only implementation of the MD4 hash algorithm as described in */
00004 /*  RFC 1320 ( http://www.ietf.org/rfc/rfc1320.txt )*/
00005 /* */
00006 /*  -------------------------------------------------------------------------*/
00007 /*  See the file "license.terms" for information on usage and redistribution*/
00008 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00009 /*  -------------------------------------------------------------------------*/
00010 /* */
00011 /*  $Id: md4.tcl,v 1.19 2006/09/19 23:36:17 andreas_kupries Exp $*/
00012 
00013 package require Tcl 8.2;                /*  tcl minimum version*/
00014 catch {package require md4c 1.0};       /*  tcllib critcl alternative*/
00015 
00016 /*  @mdgen EXCLUDE: md4c.tcl*/
00017 
00018 namespace ::md4 {
00019     variable version 1.0.4
00020     variable rcsid {$Id: md4.tcl,v 1.19 2006/09/19 23:36:17 andreas_kupries Exp $}
00021     variable accel
00022     array  accel =  {critcl 0 cryptkit 0}
00023 
00024     namespace export md4 hmac MD4Init MD4Update MD4Final
00025 
00026     variable uid
00027     if {![info exists uid]} {
00028          uid =  0
00029     }
00030 }
00031 
00032 /*  -------------------------------------------------------------------------*/
00033 
00034 /*  MD4Init - create and initialize an MD4 state variable. This will be*/
00035 /*  cleaned up when we call MD4Final*/
00036 /* */
00037 ret  ::md4::MD4Init () {
00038     variable uid
00039     variable accel
00040     set token [namespace current]::[incr uid]
00041     upvar #0 $token state
00042 
00043     # RFC1320:3.3 - Initialize MD4 state structure
00044     array set state \
00045         [list \
00046              A [expr {0x67452301}] \
00047              B [expr {0xefcdab89}] \
00048              C [expr {0x98badcfe}] \
00049              D [expr {0x10325476}] \
00050              n 0 i "" ]
00051     if {$accel(cryptkit)} {
00052         cryptkit::cryptCreateContext state(ckctx) CRYPT_UNUSED CRYPT_ALGO_MD4
00053     }
00054     return $token
00055 }
00056 
00057 ret  ::md4::MD4Update (type token , type data) {
00058     variable accel
00059     upvar #0 $token state
00060 
00061     if {$accel(critcl)} {
00062         if {[info exists state(md4c)]} {
00063             set state(md4c) [md4c $data $state(md4c)]
00064         } else {
00065             set state(md4c) [md4c $data]
00066         }
00067         return
00068     } elseif {[info exists state(ckctx)]} {
00069         if {[string length $data] > 0} {
00070             cryptkit::cryptEncrypt $state(ckctx) $data
00071         }
00072         return
00073     }
00074 
00075     # Update the state values
00076     incr state(n) [string length $data]
00077     append state(i) $data
00078 
00079     # Calculate the hash for any complete blocks
00080     set len [string length $state(i)]
00081     for {set n 0} {($n + 64) <= $len} {} {
00082         MD4Hash $token [string range $state(i) $n [incr n 64]]
00083     }
00084 
00085     # Adjust the state for the blocks completed.
00086     set state(i) [string range $state(i) $n end]
00087     return
00088 }
00089 
00090 ret  ::md4::MD4Final (type token) {
00091     upvar #0 $token state
00092 
00093     if {[info exists state(md4c)]} {
00094         set r $state(md4c)
00095         unset state
00096         return $r
00097     } elseif {[info exists state(ckctx)]} {
00098         cryptkit::cryptEncrypt $state(ckctx) ""
00099         cryptkit::cryptGetAttributeString $state(ckctx) \
00100             CRYPT_CTXINFO_HASHVALUE r 16
00101         cryptkit::cryptDestroyContext $state(ckctx)
00102         # If nothing was hashed, we get no r variable set!
00103         if {[info exists r]} {
00104             unset state
00105             return $r
00106         }
00107     }
00108 
00109     # RFC1320:3.1 - Padding
00110     #
00111     set len [string length $state(i)]
00112     set pad [expr {56 - ($len % 64)}]
00113     if {$len % 64 > 56} {
00114         incr pad 64
00115     }
00116     if {$pad == 0} {
00117         incr pad 64
00118     }
00119     append state(i) [binary format a$pad \x80]
00120 
00121     # RFC1320:3.2 - Append length in bits as little-endian wide int.
00122     append state(i) [binary format ii [expr {8 * $state(n)}] 0]
00123 
00124     # Calculate the hash for the remaining block.
00125     set len [string length $state(i)]
00126     for {set n 0} {($n + 64) <= $len} {} {
00127         MD4Hash $token [string range $state(i) $n [incr n 64]]
00128     }
00129 
00130     # RFC1320:3.5 - Output
00131     set r [bytes $state(A)][bytes $state(B)][bytes $state(C)][bytes $state(D)]
00132     unset state
00133     return $r
00134 }
00135 
00136 /*  -------------------------------------------------------------------------*/
00137 /*  HMAC Hashed Message Authentication (RFC 2104)*/
00138 /* */
00139 /*  hmac = H(K xor opad, H(K xor ipad, text))*/
00140 /* */
00141 ret  ::md4::HMACInit (type K) {
00142 
00143     # Key K is adjusted to be 64 bytes long. If K is larger, then use
00144     # the MD4 digest of K and pad this instead.
00145     set len [string length $K]
00146     if {$len > 64} {
00147         set tok [MD4Init]
00148         MD4Update $tok $K
00149         set K [MD4Final $tok]
00150         set len [string length $K]
00151     }
00152     set pad [expr {64 - $len}]
00153     append K [string repeat \0 $pad]
00154 
00155     # Cacluate the padding buffers.
00156     set Ki {}
00157     set Ko {}
00158     binary scan $K i16 Ks
00159     foreach k $Ks {
00160         append Ki [binary format i [expr {$k ^ 0x36363636}]]
00161         append Ko [binary format i [expr {$k ^ 0x5c5c5c5c}]]
00162     }
00163 
00164     set tok [MD4Init]
00165     MD4Update $tok $Ki;                 # initialize with the inner pad
00166     
00167     # preserve the Ko value for the final stage.
00168     # FRINK: nocheck
00169     set [subst $tok](Ko) $Ko
00170 
00171     return $tok
00172 }
00173 
00174 ret  ::md4::HMACUpdate (type token , type data) {
00175     MD4Update $token $data
00176     return
00177 }
00178 
00179 ret  ::md4::HMACFinal (type token) {
00180     # FRINK: nocheck
00181     variable $token
00182     upvar 0 $token state
00183 
00184     set tok [MD4Init];                  # init the outer hashing function
00185     MD4Update $tok $state(Ko);          # prepare with the outer pad.
00186     MD4Update $tok [MD4Final $token];   # hash the inner result
00187     return [MD4Final $tok]
00188 }
00189 
00190 /*  -------------------------------------------------------------------------*/
00191 
00192  ::md4 = ::MD4Hash_body {
00193     variable $token
00194     upvar 0 $token state
00195 
00196     /*  RFC1320:3.4 - Process Message in 16-Word Blocks*/
00197     binary scan $msg i* blocks
00198     foreach {X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15} $blocks {
00199          A =  $state(A)
00200          B =  $state(B)
00201          C =  $state(C)
00202          D =  $state(D)
00203 
00204         /*  Round 1*/
00205         /*  Let [abcd k s] denote the operation*/
00206         /*    a = (a + F(b,c,d) + X[k]) <<< s.*/
00207         /*  Do the following 16 operations.*/
00208         /*  [ABCD  0  3]  [DABC  1  7]  [CDAB  2 11]  [BCDA  3 19]*/
00209          A =  [expr {($A + [F $B $C $D] + $X0) <<< 3}]
00210          D =  [expr {($D + [F $A $B $C] + $X1) <<< 7}]
00211          C =  [expr {($C + [F $D $A $B] + $X2) <<< 11}]
00212          B =  [expr {($B + [F $C $D $A] + $X3) <<< 19}]
00213         /*  [ABCD  4  3]  [DABC  5  7]  [CDAB  6 11]  [BCDA  7 19]*/
00214          A =  [expr {($A + [F $B $C $D] + $X4) <<< 3}]
00215          D =  [expr {($D + [F $A $B $C] + $X5) <<< 7}]
00216          C =  [expr {($C + [F $D $A $B] + $X6) <<< 11}]
00217          B =  [expr {($B + [F $C $D $A] + $X7) <<< 19}]
00218         /*  [ABCD  8  3]  [DABC  9  7]  [CDAB 10 11]  [BCDA 11 19]*/
00219          A =  [expr {($A + [F $B $C $D] + $X8) <<< 3}]
00220          D =  [expr {($D + [F $A $B $C] + $X9) <<< 7}]
00221          C =  [expr {($C + [F $D $A $B] + $X10) <<< 11}]
00222          B =  [expr {($B + [F $C $D $A] + $X11) <<< 19}]
00223         /*  [ABCD 12  3]  [DABC 13  7]  [CDAB 14 11]  [BCDA 15 19]*/
00224          A =  [expr {($A + [F $B $C $D] + $X12) <<< 3}]
00225          D =  [expr {($D + [F $A $B $C] + $X13) <<< 7}]
00226          C =  [expr {($C + [F $D $A $B] + $X14) <<< 11}]
00227          B =  [expr {($B + [F $C $D $A] + $X15) <<< 19}]
00228 
00229         /*  Round 2.*/
00230         /*  Let [abcd k s] denote the operation*/
00231         /*    a = (a + G(b,c,d) + X[k] + 5A827999) <<< s*/
00232         /*  Do the following 16 operations.*/
00233         /*  [ABCD  0  3]  [DABC  4  5]  [CDAB  8  9]  [BCDA 12 13]*/
00234          A =  [expr {($A + [G $B $C $D] + $X0  + 0x5a827999) <<< 3}]
00235          D =  [expr {($D + [G $A $B $C] + $X4  + 0x5a827999) <<< 5}]
00236          C =  [expr {($C + [G $D $A $B] + $X8  + 0x5a827999) <<< 9}]
00237          B =  [expr {($B + [G $C $D $A] + $X12 + 0x5a827999) <<< 13}]
00238         /*  [ABCD  1  3]  [DABC  5  5]  [CDAB  9  9]  [BCDA 13 13]*/
00239          A =  [expr {($A + [G $B $C $D] + $X1  + 0x5a827999) <<< 3}]
00240          D =  [expr {($D + [G $A $B $C] + $X5  + 0x5a827999) <<< 5}]
00241          C =  [expr {($C + [G $D $A $B] + $X9  + 0x5a827999) <<< 9}]
00242          B =  [expr {($B + [G $C $D $A] + $X13 + 0x5a827999) <<< 13}]
00243         /*  [ABCD  2  3]  [DABC  6  5]  [CDAB 10  9]  [BCDA 14 13]*/
00244          A =  [expr {($A + [G $B $C $D] + $X2  + 0x5a827999) <<< 3}]
00245          D =  [expr {($D + [G $A $B $C] + $X6  + 0x5a827999) <<< 5}]
00246          C =  [expr {($C + [G $D $A $B] + $X10 + 0x5a827999) <<< 9}]
00247          B =  [expr {($B + [G $C $D $A] + $X14 + 0x5a827999) <<< 13}]
00248         /*  [ABCD  3  3]  [DABC  7  5]  [CDAB 11  9]  [BCDA 15 13]*/
00249          A =  [expr {($A + [G $B $C $D] + $X3  + 0x5a827999) <<< 3}]
00250          D =  [expr {($D + [G $A $B $C] + $X7  + 0x5a827999) <<< 5}]
00251          C =  [expr {($C + [G $D $A $B] + $X11 + 0x5a827999) <<< 9}]
00252          B =  [expr {($B + [G $C $D $A] + $X15 + 0x5a827999) <<< 13}]
00253         
00254         /*  Round 3.*/
00255         /*  Let [abcd k s] denote the operation*/
00256         /*    a = (a + H(b,c,d) + X[k] + 6ED9EBA1) <<< s.*/
00257         /*  Do the following 16 operations.*/
00258         /*  [ABCD  0  3]  [DABC  8  9]  [CDAB  4 11]  [BCDA 12 15]*/
00259          A =  [expr {($A + [H $B $C $D] + $X0  + 0x6ed9eba1) <<< 3}]
00260          D =  [expr {($D + [H $A $B $C] + $X8  + 0x6ed9eba1) <<< 9}]
00261          C =  [expr {($C + [H $D $A $B] + $X4  + 0x6ed9eba1) <<< 11}]
00262          B =  [expr {($B + [H $C $D $A] + $X12 + 0x6ed9eba1) <<< 15}]
00263         /*  [ABCD  2  3]  [DABC 10  9]  [CDAB  6 11]  [BCDA 14 15]*/
00264          A =  [expr {($A + [H $B $C $D] + $X2  + 0x6ed9eba1) <<< 3}]
00265          D =  [expr {($D + [H $A $B $C] + $X10 + 0x6ed9eba1) <<< 9}]
00266          C =  [expr {($C + [H $D $A $B] + $X6  + 0x6ed9eba1) <<< 11}]
00267          B =  [expr {($B + [H $C $D $A] + $X14 + 0x6ed9eba1) <<< 15}]
00268         /*  [ABCD  1  3]  [DABC  9  9]  [CDAB  5 11]  [BCDA 13 15]*/
00269          A =  [expr {($A + [H $B $C $D] + $X1  + 0x6ed9eba1) <<< 3}]
00270          D =  [expr {($D + [H $A $B $C] + $X9  + 0x6ed9eba1) <<< 9}]
00271          C =  [expr {($C + [H $D $A $B] + $X5  + 0x6ed9eba1) <<< 11}]
00272          B =  [expr {($B + [H $C $D $A] + $X13 + 0x6ed9eba1) <<< 15}]
00273         /*  [ABCD  3  3]  [DABC 11  9]  [CDAB  7 11]  [BCDA 15 15]*/
00274          A =  [expr {($A + [H $B $C $D] + $X3  + 0x6ed9eba1) <<< 3}]
00275          D =  [expr {($D + [H $A $B $C] + $X11 + 0x6ed9eba1) <<< 9}]
00276          C =  [expr {($C + [H $D $A $B] + $X7  + 0x6ed9eba1) <<< 11}]
00277          B =  [expr {($B + [H $C $D $A] + $X15 + 0x6ed9eba1) <<< 15}]
00278 
00279         /*  Then perform the following additions. (That is, increment each*/
00280         /*  of the four registers by the value it had before this block*/
00281         /*  was started.)*/
00282         incr state(A) $A
00283         incr state(B) $B
00284         incr state(C) $C
00285         incr state(D) $D
00286     }
00287 
00288     return
00289 }
00290 
00291 ret  ::md4::byte (type n , type v) {expr {((0xFF << (8 * $n)) & $v) >> (8 * $n)}}
00292 ret  ::md4::bytes (type v) { 
00293     #format %c%c%c%c [byte 0 $v] [byte 1 $v] [byte 2 $v] [byte 3 $v]
00294     format %c%c%c%c \
00295         [expr {0xFF & $v}] \
00296         [expr {(0xFF00 & $v) >> 8}] \
00297         [expr {(0xFF0000 & $v) >> 16}] \
00298         [expr {((0xFF000000 & $v) >> 24) & 0xFF}]
00299 }
00300 
00301 /*  32bit rotate-left*/
00302 ret  ::md4::<<< (type v , type n) {
00303     return [expr {((($v << $n) \
00304                         | (($v >> (32 - $n)) \
00305                                & (0x7FFFFFFF >> (31 - $n))))) \
00306                       & 0xFFFFFFFF}]
00307 }
00308 
00309 /*  Convert our <<< pseudo-operator into a procedure call.*/
00310 regsub -all -line \
00311     {\[expr {(.*) <<< (\d+)}\]} \
00312     $::md4::MD4Hash_body \
00313     {[<<< [expr {\1}] \2]} \
00314     ::md4::MD4Hash_body
00315 
00316 /*  RFC1320:3.4 - function F*/
00317 ret  ::md4::F (type X , type Y , type Z) {
00318     return [expr {($X & $Y) | ((~$X) & $Z)}]
00319 }
00320 
00321 /*  Inline the F function*/
00322 regsub -all -line \
00323     {\[F (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00324     $::md4::MD4Hash_body \
00325     {( (\1 \& \2) | ((~\1) \& \3) )} \
00326     ::md4::MD4Hash_body
00327     
00328 /*  RFC1320:3.4 - function G*/
00329 ret  ::md4::G (type X , type Y , type Z) {
00330     return [expr {($X & $Y) | ($X & $Z) | ($Y & $Z)}]
00331 }
00332 
00333 /*  Inline the G function*/
00334 regsub -all -line \
00335     {\[G (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00336     $::md4::MD4Hash_body \
00337     {((\1 \& \2) | (\1 \& \3) | (\2 \& \3))} \
00338     ::md4::MD4Hash_body
00339 
00340 /*  RFC1320:3.4 - function H*/
00341 ret  ::md4::H (type X , type Y , type Z) {
00342     return [expr {$X ^ $Y ^ $Z}]
00343 }
00344 
00345 /*  Inline the H function*/
00346 regsub -all -line \
00347     {\[H (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00348     $::md4::MD4Hash_body \
00349     {(\1 ^ \2 ^ \3)} \
00350     ::md4::MD4Hash_body
00351 
00352 /*  Define the MD4 hashing procedure with inline functions.*/
00353 ret  ::md4::MD4Hash (type token , type msg) $::md4::MD4Hash_body
00354 
00355 # -------------------------------------------------------------------------
00356 
00357 if {[package provide Trf] != {}} {
00358     interp alias {} ::md4::Hex {} ::hex -mode encode --
00359 } else {
00360     ret  ::md4::Hex (type data) {
00361         binary scan $data H* result
00362         return [string toupper $result]
00363     }
00364 }
00365 
00366 /*  -------------------------------------------------------------------------*/
00367 
00368 /*  LoadAccelerator --*/
00369 /* */
00370 /*  This package can make use of a number of compiled extensions to*/
00371 /*  accelerate the digest computation. This procedure manages the*/
00372 /*  use of these extensions within the package. During normal usage*/
00373 /*  this should not be called, but the test package manipulates the*/
00374 /*  list of enabled accelerators.*/
00375 /* */
00376 ret  ::md4::LoadAccelerator (type name) {
00377     variable accel
00378     set r 0
00379     switch -exact -- $name {
00380         critcl {
00381             if {![catch {package require tcllibc}]
00382                 || ![catch {package require md4c}]} {
00383                 set r [expr {[info command ::md4::md4c] != {}}]
00384             }
00385         }
00386         cryptkit {
00387             if {![catch {package require cryptkit}]} {
00388                 set r [expr {![catch {cryptkit::cryptInit}]}]
00389             }
00390         }
00391         #trf {
00392         #    if {![catch {package require Trf}]} {
00393         #        set r [expr {![catch {::md4 aa} msg]}]
00394         #    }
00395         #}
00396         default {
00397             return -code error "invalid accelerator package:\
00398                 must be one of [join [array names accel] {, }]"
00399         }
00400     }
00401     set accel($name) $r
00402 }
00403 
00404 /*  -------------------------------------------------------------------------*/
00405 
00406 /*  Description:*/
00407 /*   Pop the nth element off a list. Used in options processing.*/
00408 /* */
00409 ret  ::md4::Pop (type varname , optional nth =0) {
00410     upvar $varname args
00411     set r [lindex $args $nth]
00412     set args [lreplace $args $nth $nth]
00413     return $r
00414 }
00415 
00416 /*  -------------------------------------------------------------------------*/
00417 
00418 /*  fileevent handler for chunked file hashing.*/
00419 /* */
00420 ret  ::md4::Chunk (type token , type channel , optional chunksize =4096) {
00421     # FRINK: nocheck
00422     variable $token
00423     upvar 0 $token state
00424     
00425     if {[eof $channel]} {
00426         fileevent $channel readable {}
00427         set state(reading) 0
00428     }
00429         
00430     MD4Update $token [read $channel $chunksize]
00431 }
00432 
00433 /*  -------------------------------------------------------------------------*/
00434 
00435 ret  ::md4::md4 (type args) {
00436     array set opts {-hex 0 -filename {} -channel {} -chunksize 4096}
00437     while {[string match -* [set option [lindex $args 0]]]} {
00438         switch -glob -- $option {
00439             -hex       { set opts(-hex) 1 }
00440             -file*     { set opts(-filename) [Pop args 1] }
00441             -channel   { set opts(-channel) [Pop args 1] }
00442             -chunksize { set opts(-chunksize) [Pop args 1] }
00443             default {
00444                 if {[llength $args] == 1} { break }
00445                 if {[string compare $option "--"] == 0 } { Pop args; break }
00446                 set err [join [lsort [array names opts]] ", "]
00447                 return -code error "bad option $option:\
00448                     must be one of $err"
00449             }
00450         }
00451         Pop args
00452     }
00453 
00454     if {$opts(-filename) != {}} {
00455         set opts(-channel) [open $opts(-filename) r]
00456         fconfigure $opts(-channel) -translation binary
00457     }
00458 
00459     if {$opts(-channel) == {}} {
00460 
00461         if {[llength $args] != 1} {
00462             return -code error "wrong # args:\
00463                 should be \"md4 ?-hex? -filename file | string\""
00464         }
00465         set tok [MD4Init]
00466         MD4Update $tok [lindex $args 0]
00467         set r [MD4Final $tok]
00468 
00469     } else {
00470 
00471         set tok [MD4Init]
00472         # FRINK: nocheck
00473         set [subst $tok](reading) 1
00474         fileevent $opts(-channel) readable \
00475             [list [namespace origin Chunk] \
00476                  $tok $opts(-channel) $opts(-chunksize)]
00477         vwait [subst $tok](reading)
00478         set r [MD4Final $tok]
00479 
00480         # If we opened the channel - we should close it too.
00481         if {$opts(-filename) != {}} {
00482             close $opts(-channel)
00483         }
00484     }
00485     
00486     if {$opts(-hex)} {
00487         set r [Hex $r]
00488     }
00489     return $r
00490 }
00491 
00492 /*  -------------------------------------------------------------------------*/
00493 
00494 ret  ::md4::hmac (type args) {
00495     array set opts {-hex 0 -filename {} -channel {} -chunksize 4096}
00496     while {[string match -* [set option [lindex $args 0]]]} {
00497         switch -glob -- $option {
00498             -key       { set opts(-key) [Pop args 1] }
00499             -hex       { set opts(-hex) 1 }
00500             -file*     { set opts(-filename) [Pop args 1] }
00501             -channel   { set opts(-channel) [Pop args 1] }
00502             -chunksize { set opts(-chunksize) [Pop args 1] }
00503             default {
00504                 if {[llength $args] == 1} { break }
00505                 if {[string compare $option "--"] == 0 } { Pop args; break }
00506                 set err [join [lsort [array names opts]] ", "]
00507                 return -code error "bad option $option:\
00508                     must be one of $err"
00509             }
00510         }
00511         Pop args
00512     }
00513 
00514     if {![info exists opts(-key)]} {
00515         return -code error "wrong # args:\
00516             should be \"hmac ?-hex? -key key -filename file | string\""
00517     }
00518 
00519     if {$opts(-filename) != {}} {
00520         set opts(-channel) [open $opts(-filename) r]
00521         fconfigure $opts(-channel) -translation binary
00522     }
00523 
00524     if {$opts(-channel) == {}} {
00525 
00526         if {[llength $args] != 1} {
00527             return -code error "wrong # args:\
00528                 should be \"hmac ?-hex? -key key -filename file | string\""
00529         }
00530         set tok [HMACInit $opts(-key)]
00531         HMACUpdate $tok [lindex $args 0]
00532         set r [HMACFinal $tok]
00533 
00534     } else {
00535 
00536         set tok [HMACInit $opts(-key)]
00537         # FRINK: nocheck
00538         set [subst $tok](reading) 1
00539         fileevent $opts(-channel) readable \
00540             [list [namespace origin Chunk] \
00541                  $tok $opts(-channel) $opts(-chunksize)]
00542         vwait [subst $tok](reading)
00543         set r [HMACFinal $tok]
00544 
00545         # If we opened the channel - we should close it too.
00546         if {$opts(-filename) != {}} {
00547             close $opts(-channel)
00548         }
00549     }
00550     
00551     if {$opts(-hex)} {
00552         set r [Hex $r]
00553     }
00554     return $r
00555 }
00556 
00557 /*  -------------------------------------------------------------------------*/
00558 
00559 /*  Try and load a compiled extension to help.*/
00560 namespace ::md4 {
00561     foreach e {critcl cryptkit} { if {[LoadAccelerator $e]} { break } }
00562 }
00563 
00564 package provide md4 $::md4::version
00565 
00566 /*  -------------------------------------------------------------------------*/
00567 /*  Local Variables:*/
00568 /*    mode: tcl*/
00569 /*    indent-tabs-mode: nil*/
00570 /*  End:*/
00571 
00572 
00573 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1