md5x.tcl

Go to the documentation of this file.
00001 /*  md5.tcl - Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00002 /* */
00003 /*  MD5  defined by RFC 1321, "The MD5 Message-Digest Algorithm"*/
00004 /*  HMAC defined by RFC 2104, "Keyed-Hashing for Message Authentication"*/
00005 /* */
00006 /*  This is an implementation of MD5 based upon the example code given in*/
00007 /*  RFC 1321 and upon the tcllib MD4 implementation and taking some ideas*/
00008 /*  from the earlier tcllib md5 version by Don Libes.*/
00009 /* */
00010 /*  This implementation permits incremental updating of the hash and */
00011 /*  provides support for external compiled implementations either using*/
00012 /*  critcl (md5c) or Trf.*/
00013 /* */
00014 /*  -------------------------------------------------------------------------*/
00015 /*  See the file "license.terms" for information on usage and redistribution*/
00016 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00017 /*  -------------------------------------------------------------------------*/
00018 /* */
00019 /*  $Id: md5x.tcl,v 1.17 2006/09/19 23:36:17 andreas_kupries Exp $*/
00020 
00021 package require Tcl 8.2;                /*  tcl minimum version*/
00022 
00023 namespace ::md5 {
00024     variable version 2.0.5
00025     variable rcsid {$Id: md5x.tcl,v 1.17 2006/09/19 23:36:17 andreas_kupries Exp $}
00026     variable accel
00027     array  accel =  {critcl 0 cryptkit 0 trf 0}
00028 
00029     namespace export md5 hmac MD5Init MD5Update MD5Final
00030 
00031     variable uid
00032     if {![info exists uid]} {
00033          uid =  0
00034     }
00035 }
00036 
00037 /*  -------------------------------------------------------------------------*/
00038 
00039 /*  MD5Init --*/
00040 /* */
00041 /*    Create and initialize an MD5 state variable. This will be*/
00042 /*    cleaned up when we call MD5Final*/
00043 /* */
00044 ret  ::md5::MD5Init () {
00045     variable accel
00046     variable uid
00047     set token [namespace current]::[incr uid]
00048     upvar #0 $token state
00049 
00050     # RFC1321:3.3 - Initialize MD5 state structure
00051     array set state \
00052         [list \
00053              A [expr {0x67452301}] \
00054              B [expr {0xefcdab89}] \
00055              C [expr {0x98badcfe}] \
00056              D [expr {0x10325476}] \
00057              n 0 i "" ]
00058     if {$accel(cryptkit)} {
00059         cryptkit::cryptCreateContext state(ckctx) CRYPT_UNUSED CRYPT_ALGO_MD5
00060     } elseif {$accel(trf)} {
00061         set s {}
00062         switch -exact -- $::tcl_platform(platform) {
00063             windows { set s [open NUL w] }
00064             unix    { set s [open /dev/null w] }
00065         }
00066         if {$s != {}} {
00067             fconfigure $s -translation binary -buffering none
00068             ::md5 -attach $s -mode write \
00069                 -read-type variable \
00070                 -read-destination [subst $token](trfread) \
00071                 -write-type variable \
00072                 -write-destination [subst $token](trfwrite)
00073             array set state [list trfread 0 trfwrite 0 trf $s]
00074         }
00075     }
00076     return $token
00077 }
00078 
00079 /*  MD5Update --*/
00080 /* */
00081 /*    This is called to add more data into the hash. You may call this*/
00082 /*    as many times as you require. Note that passing in "ABC" is equivalent*/
00083 /*    to passing these letters in as separate calls -- hence this proc */
00084 /*    permits hashing of chunked data*/
00085 /* */
00086 /*    If we have a C-based implementation available, then we will use*/
00087 /*    it here in preference to the pure-Tcl implementation.*/
00088 /* */
00089 ret  ::md5::MD5Update (type token , type data) {
00090     variable accel
00091     upvar #0 $token state
00092 
00093     if {$accel(critcl)} {
00094         if {[info exists state(md5c)]} {
00095             set state(md5c) [md5c $data $state(md5c)]
00096         } else {
00097             set state(md5c) [md5c $data]
00098         }
00099         return
00100     } elseif {[info exists state(ckctx)]} {
00101         if {[string length $data] > 0} {
00102             cryptkit::cryptEncrypt $state(ckctx) $data
00103         }
00104         return
00105     } elseif {[info exists state(trf)]} {
00106         puts -nonewline $state(trf) $data
00107         return
00108     }
00109 
00110     # Update the state values
00111     incr state(n) [string length $data]
00112     append state(i) $data
00113 
00114     # Calculate the hash for any complete blocks
00115     set len [string length $state(i)]
00116     for {set n 0} {($n + 64) <= $len} {} {
00117         MD5Hash $token [string range $state(i) $n [incr n 64]]
00118     }
00119 
00120     # Adjust the state for the blocks completed.
00121     set state(i) [string range $state(i) $n end]
00122     return
00123 }
00124 
00125 /*  MD5Final --*/
00126 /* */
00127 /*     This procedure is used to close the current hash and returns the*/
00128 /*     hash data. Once this procedure has been called the hash context*/
00129 /*     is freed and cannot be used again.*/
00130 /* */
00131 /*     Note that the output is 128 bits represented as binary data.*/
00132 /* */
00133 ret  ::md5::MD5Final (type token) {
00134     upvar #0 $token state
00135 
00136     # Check for either of the C-compiled versions.
00137     if {[info exists state(md5c)]} {
00138         set r $state(md5c)
00139         unset state
00140         return $r
00141     } elseif {[info exists state(ckctx)]} {
00142         cryptkit::cryptEncrypt $state(ckctx) ""
00143         cryptkit::cryptGetAttributeString $state(ckctx) \
00144             CRYPT_CTXINFO_HASHVALUE r 16
00145         cryptkit::cryptDestroyContext $state(ckctx)
00146         # If nothing was hashed, we get no r variable set!
00147         if {[info exists r]} {
00148             unset state
00149             return $r
00150         }
00151     } elseif {[info exists state(trf)]} {
00152         close $state(trf)
00153         set r $state(trfwrite)
00154         unset state
00155         return $r
00156     }
00157 
00158     # RFC1321:3.1 - Padding
00159     #
00160     set len [string length $state(i)]
00161     set pad [expr {56 - ($len % 64)}]
00162     if {$len % 64 > 56} {
00163         incr pad 64
00164     }
00165     if {$pad == 0} {
00166         incr pad 64
00167     }
00168     append state(i) [binary format a$pad \x80]
00169 
00170     # RFC1321:3.2 - Append length in bits as little-endian wide int.
00171     append state(i) [binary format ii [expr {8 * $state(n)}] 0]
00172 
00173     # Calculate the hash for the remaining block.
00174     set len [string length $state(i)]
00175     for {set n 0} {($n + 64) <= $len} {} {
00176         MD5Hash $token [string range $state(i) $n [incr n 64]]
00177     }
00178 
00179     # RFC1321:3.5 - Output
00180     set r [bytes $state(A)][bytes $state(B)][bytes $state(C)][bytes $state(D)]
00181     unset state
00182     return $r
00183 }
00184 
00185 /*  -------------------------------------------------------------------------*/
00186 /*  HMAC Hashed Message Authentication (RFC 2104)*/
00187 /* */
00188 /*  hmac = H(K xor opad, H(K xor ipad, text))*/
00189 /* */
00190 
00191 /*  HMACInit --*/
00192 /* */
00193 /*     This is equivalent to the MD5Init procedure except that a key is*/
00194 /*     added into the algorithm*/
00195 /* */
00196 ret  ::md5::HMACInit (type K) {
00197 
00198     # Key K is adjusted to be 64 bytes long. If K is larger, then use
00199     # the MD5 digest of K and pad this instead.
00200     set len [string length $K]
00201     if {$len > 64} {
00202         set tok [MD5Init]
00203         MD5Update $tok $K
00204         set K [MD5Final $tok]
00205         set len [string length $K]
00206     }
00207     set pad [expr {64 - $len}]
00208     append K [string repeat \0 $pad]
00209 
00210     # Cacluate the padding buffers.
00211     set Ki {}
00212     set Ko {}
00213     binary scan $K i16 Ks
00214     foreach k $Ks {
00215         append Ki [binary format i [expr {$k ^ 0x36363636}]]
00216         append Ko [binary format i [expr {$k ^ 0x5c5c5c5c}]]
00217     }
00218 
00219     set tok [MD5Init]
00220     MD5Update $tok $Ki;                 # initialize with the inner pad
00221     
00222     # preserve the Ko value for the final stage.
00223     # FRINK: nocheck
00224     set [subst $tok](Ko) $Ko
00225 
00226     return $tok
00227 }
00228 
00229 /*  HMACUpdate --*/
00230 /* */
00231 /*     Identical to calling MD5Update*/
00232 /* */
00233 ret  ::md5::HMACUpdate (type token , type data) {
00234     MD5Update $token $data
00235     return
00236 }
00237 
00238 /*  HMACFinal --*/
00239 /* */
00240 /*     This is equivalent to the MD5Final procedure. The hash context is*/
00241 /*     closed and the binary representation of the hash result is returned.*/
00242 /* */
00243 ret  ::md5::HMACFinal (type token) {
00244     upvar #0 $token state
00245 
00246     set tok [MD5Init];                  # init the outer hashing function
00247     MD5Update $tok $state(Ko);          # prepare with the outer pad.
00248     MD5Update $tok [MD5Final $token];   # hash the inner result
00249     return [MD5Final $tok]
00250 }
00251 
00252 /*  -------------------------------------------------------------------------*/
00253 /*  Description:*/
00254 /*   This is the core MD5 algorithm. It is a lot like the MD4 algorithm but*/
00255 /*   includes an extra round and a set of constant modifiers throughout.*/
00256 /*  */
00257 /*  Note:*/
00258 /*   This function body is substituted later on to inline some of the */
00259 /*   procedures and to make is a bit more comprehensible.*/
00260 /* */
00261  ::md5 = ::MD5Hash_body {
00262     variable $token
00263     upvar 0 $token state
00264 
00265     /*  RFC1321:3.4 - Process Message in 16-Word Blocks*/
00266     binary scan $msg i* blocks
00267     foreach {X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15} $blocks {
00268          A =  $state(A)
00269          B =  $state(B)
00270          C =  $state(C)
00271          D =  $state(D)
00272 
00273         /*  Round 1*/
00274         /*  Let [abcd k s i] denote the operation*/
00275         /*    a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s).*/
00276         /*  Do the following 16 operations.*/
00277         /*  [ABCD  0  7  1]  [DABC  1 12  2]  [CDAB  2 17  3]  [BCDA  3 22  4]*/
00278          A =  [expr {$B + (($A + [F $B $C $D] + $X0 + $T01) <<< 7)}]
00279          D =  [expr {$A + (($D + [F $A $B $C] + $X1 + $T02) <<< 12)}]
00280          C =  [expr {$D + (($C + [F $D $A $B] + $X2 + $T03) <<< 17)}]
00281          B =  [expr {$C + (($B + [F $C $D $A] + $X3 + $T04) <<< 22)}]
00282         /*  [ABCD  4  7  5]  [DABC  5 12  6]  [CDAB  6 17  7]  [BCDA  7 22  8]*/
00283          A =  [expr {$B + (($A + [F $B $C $D] + $X4 + $T05) <<< 7)}]
00284          D =  [expr {$A + (($D + [F $A $B $C] + $X5 + $T06) <<< 12)}]
00285          C =  [expr {$D + (($C + [F $D $A $B] + $X6 + $T07) <<< 17)}]
00286          B =  [expr {$C + (($B + [F $C $D $A] + $X7 + $T08) <<< 22)}]
00287         /*  [ABCD  8  7  9]  [DABC  9 12 10]  [CDAB 10 17 11]  [BCDA 11 22 12]*/
00288          A =  [expr {$B + (($A + [F $B $C $D] + $X8 + $T09) <<< 7)}]
00289          D =  [expr {$A + (($D + [F $A $B $C] + $X9 + $T10) <<< 12)}]
00290          C =  [expr {$D + (($C + [F $D $A $B] + $X10 + $T11) <<< 17)}]
00291          B =  [expr {$C + (($B + [F $C $D $A] + $X11 + $T12) <<< 22)}]
00292         /*  [ABCD 12  7 13]  [DABC 13 12 14]  [CDAB 14 17 15]  [BCDA 15 22 16]*/
00293          A =  [expr {$B + (($A + [F $B $C $D] + $X12 + $T13) <<< 7)}]
00294          D =  [expr {$A + (($D + [F $A $B $C] + $X13 + $T14) <<< 12)}]
00295          C =  [expr {$D + (($C + [F $D $A $B] + $X14 + $T15) <<< 17)}]
00296          B =  [expr {$C + (($B + [F $C $D $A] + $X15 + $T16) <<< 22)}]
00297 
00298         /*  Round 2.*/
00299         /*  Let [abcd k s i] denote the operation*/
00300         /*    a = b + ((a + G(b,c,d) + X[k] + Ti) <<< s)*/
00301         /*  Do the following 16 operations.*/
00302         /*  [ABCD  1  5 17]  [DABC  6  9 18]  [CDAB 11 14 19]  [BCDA  0 20 20]*/
00303          A =  [expr {$B + (($A + [G $B $C $D] + $X1  + $T17) <<<  5)}]
00304          D =  [expr {$A + (($D + [G $A $B $C] + $X6  + $T18) <<<  9)}]
00305          C =  [expr {$D + (($C + [G $D $A $B] + $X11 + $T19) <<< 14)}]
00306          B =  [expr {$C + (($B + [G $C $D $A] + $X0  + $T20) <<< 20)}]
00307         /*  [ABCD  5  5 21]  [DABC 10  9 22]  [CDAB 15 14 23]  [BCDA  4 20 24]*/
00308          A =  [expr {$B + (($A + [G $B $C $D] + $X5  + $T21) <<<  5)}]
00309          D =  [expr {$A + (($D + [G $A $B $C] + $X10 + $T22) <<<  9)}]
00310          C =  [expr {$D + (($C + [G $D $A $B] + $X15 + $T23) <<< 14)}]
00311          B =  [expr {$C + (($B + [G $C $D $A] + $X4  + $T24) <<< 20)}]
00312         /*  [ABCD  9  5 25]  [DABC 14  9 26]  [CDAB  3 14 27]  [BCDA  8 20 28]*/
00313          A =  [expr {$B + (($A + [G $B $C $D] + $X9  + $T25) <<<  5)}]
00314          D =  [expr {$A + (($D + [G $A $B $C] + $X14 + $T26) <<<  9)}]
00315          C =  [expr {$D + (($C + [G $D $A $B] + $X3  + $T27) <<< 14)}]
00316          B =  [expr {$C + (($B + [G $C $D $A] + $X8  + $T28) <<< 20)}]
00317         /*  [ABCD 13  5 29]  [DABC  2  9 30]  [CDAB  7 14 31]  [BCDA 12 20 32]*/
00318          A =  [expr {$B + (($A + [G $B $C $D] + $X13 + $T29) <<<  5)}]
00319          D =  [expr {$A + (($D + [G $A $B $C] + $X2  + $T30) <<<  9)}]
00320          C =  [expr {$D + (($C + [G $D $A $B] + $X7  + $T31) <<< 14)}]
00321          B =  [expr {$C + (($B + [G $C $D $A] + $X12 + $T32) <<< 20)}]
00322         
00323         /*  Round 3.*/
00324         /*  Let [abcd k s i] denote the operation*/
00325         /*    a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s)*/
00326         /*  Do the following 16 operations.*/
00327         /*  [ABCD  5  4 33]  [DABC  8 11 34]  [CDAB 11 16 35]  [BCDA 14 23 36]*/
00328          A =  [expr {$B + (($A + [H $B $C $D] + $X5  + $T33) <<<  4)}]
00329          D =  [expr {$A + (($D + [H $A $B $C] + $X8  + $T34) <<< 11)}]
00330          C =  [expr {$D + (($C + [H $D $A $B] + $X11 + $T35) <<< 16)}]
00331          B =  [expr {$C + (($B + [H $C $D $A] + $X14 + $T36) <<< 23)}]
00332         /*  [ABCD  1  4 37]  [DABC  4 11 38]  [CDAB  7 16 39]  [BCDA 10 23 40]*/
00333          A =  [expr {$B + (($A + [H $B $C $D] + $X1  + $T37) <<<  4)}]
00334          D =  [expr {$A + (($D + [H $A $B $C] + $X4  + $T38) <<< 11)}]
00335          C =  [expr {$D + (($C + [H $D $A $B] + $X7  + $T39) <<< 16)}]
00336          B =  [expr {$C + (($B + [H $C $D $A] + $X10 + $T40) <<< 23)}]
00337         /*  [ABCD 13  4 41]  [DABC  0 11 42]  [CDAB  3 16 43]  [BCDA  6 23 44]*/
00338          A =  [expr {$B + (($A + [H $B $C $D] + $X13 + $T41) <<<  4)}]
00339          D =  [expr {$A + (($D + [H $A $B $C] + $X0  + $T42) <<< 11)}]
00340          C =  [expr {$D + (($C + [H $D $A $B] + $X3  + $T43) <<< 16)}]
00341          B =  [expr {$C + (($B + [H $C $D $A] + $X6  + $T44) <<< 23)}]
00342         /*  [ABCD  9  4 45]  [DABC 12 11 46]  [CDAB 15 16 47]  [BCDA  2 23 48]*/
00343          A =  [expr {$B + (($A + [H $B $C $D] + $X9  + $T45) <<<  4)}]
00344          D =  [expr {$A + (($D + [H $A $B $C] + $X12 + $T46) <<< 11)}]
00345          C =  [expr {$D + (($C + [H $D $A $B] + $X15 + $T47) <<< 16)}]
00346          B =  [expr {$C + (($B + [H $C $D $A] + $X2  + $T48) <<< 23)}]
00347 
00348         /*  Round 4.*/
00349         /*  Let [abcd k s i] denote the operation*/
00350         /*    a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s)*/
00351         /*  Do the following 16 operations.*/
00352         /*  [ABCD  0  6 49]  [DABC  7 10 50]  [CDAB 14 15 51]  [BCDA  5 21 52]*/
00353          A =  [expr {$B + (($A + [I $B $C $D] + $X0  + $T49) <<<  6)}]
00354          D =  [expr {$A + (($D + [I $A $B $C] + $X7  + $T50) <<< 10)}]
00355          C =  [expr {$D + (($C + [I $D $A $B] + $X14 + $T51) <<< 15)}]
00356          B =  [expr {$C + (($B + [I $C $D $A] + $X5  + $T52) <<< 21)}]
00357         /*  [ABCD 12  6 53]  [DABC  3 10 54]  [CDAB 10 15 55]  [BCDA  1 21 56]*/
00358          A =  [expr {$B + (($A + [I $B $C $D] + $X12 + $T53) <<<  6)}]
00359          D =  [expr {$A + (($D + [I $A $B $C] + $X3  + $T54) <<< 10)}]
00360          C =  [expr {$D + (($C + [I $D $A $B] + $X10 + $T55) <<< 15)}]
00361          B =  [expr {$C + (($B + [I $C $D $A] + $X1  + $T56) <<< 21)}]
00362         /*  [ABCD  8  6 57]  [DABC 15 10 58]  [CDAB  6 15 59]  [BCDA 13 21 60]*/
00363          A =  [expr {$B + (($A + [I $B $C $D] + $X8  + $T57) <<<  6)}]
00364          D =  [expr {$A + (($D + [I $A $B $C] + $X15 + $T58) <<< 10)}]
00365          C =  [expr {$D + (($C + [I $D $A $B] + $X6  + $T59) <<< 15)}]
00366          B =  [expr {$C + (($B + [I $C $D $A] + $X13 + $T60) <<< 21)}]
00367         /*  [ABCD  4  6 61]  [DABC 11 10 62]  [CDAB  2 15 63]  [BCDA  9 21 64]*/
00368          A =  [expr {$B + (($A + [I $B $C $D] + $X4  + $T61) <<<  6)}]
00369          D =  [expr {$A + (($D + [I $A $B $C] + $X11 + $T62) <<< 10)}]
00370          C =  [expr {$D + (($C + [I $D $A $B] + $X2  + $T63) <<< 15)}]
00371          B =  [expr {$C + (($B + [I $C $D $A] + $X9  + $T64) <<< 21)}]
00372 
00373         /*  Then perform the following additions. (That is, increment each*/
00374         /*  of the four registers by the value it had before this block*/
00375         /*  was started.)*/
00376         incr state(A) $A
00377         incr state(B) $B
00378         incr state(C) $C
00379         incr state(D) $D
00380     }
00381 
00382     return
00383 }
00384 
00385 ret  ::md5::byte (type n , type v) {expr {((0xFF << (8 * $n)) & $v) >> (8 * $n)}}
00386 ret  ::md5::bytes (type v) { 
00387     #format %c%c%c%c [byte 0 $v] [byte 1 $v] [byte 2 $v] [byte 3 $v]
00388     format %c%c%c%c \
00389         [expr {0xFF & $v}] \
00390         [expr {(0xFF00 & $v) >> 8}] \
00391         [expr {(0xFF0000 & $v) >> 16}] \
00392         [expr {((0xFF000000 & $v) >> 24) & 0xFF}]
00393 }
00394 
00395 /*  32bit rotate-left*/
00396 ret  ::md5::<<< (type v , type n) {
00397     return [expr {((($v << $n) \
00398                         | (($v >> (32 - $n)) \
00399                                & (0x7FFFFFFF >> (31 - $n))))) \
00400                       & 0xFFFFFFFF}]
00401 }
00402 
00403 /*  Convert our <<< pseudo-operator into a procedure call.*/
00404 regsub -all -line \
00405     {\[expr {(\$[ABCD]) \+ \(\((.*)\)\s+<<<\s+(\d+)\)}\]} \
00406     $::md5::MD5Hash_body \
00407     {[expr {int(\1 + [<<< [expr {\2}] \3])}]} \
00408     ::md5::MD5Hash_bodyX
00409 
00410 /*  RFC1321:3.4 - function F*/
00411 ret  ::md5::F (type X , type Y , type Z) {
00412     return [expr {($X & $Y) | ((~$X) & $Z)}]
00413 }
00414 
00415 /*  Inline the F function*/
00416 regsub -all -line \
00417     {\[F (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00418     $::md5::MD5Hash_bodyX \
00419     {( (\1 \& \2) | ((~\1) \& \3) )} \
00420     ::md5::MD5Hash_bodyX
00421     
00422 /*  RFC1321:3.4 - function G*/
00423 ret  ::md5::G (type X , type Y , type Z) {
00424     return [expr {(($X & $Z) | ($Y & (~$Z)))}]
00425 }
00426 
00427 /*  Inline the G function*/
00428 regsub -all -line \
00429     {\[G (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00430     $::md5::MD5Hash_bodyX \
00431     {(((\1 \& \3) | (\2 \& (~\3))))} \
00432     ::md5::MD5Hash_bodyX
00433 
00434 /*  RFC1321:3.4 - function H*/
00435 ret  ::md5::H (type X , type Y , type Z) {
00436     return [expr {$X ^ $Y ^ $Z}]
00437 }
00438 
00439 /*  Inline the H function*/
00440 regsub -all -line \
00441     {\[H (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00442     $::md5::MD5Hash_bodyX \
00443     {(\1 ^ \2 ^ \3)} \
00444     ::md5::MD5Hash_bodyX
00445 
00446 /*  RFC1321:3.4 - function I*/
00447 ret  ::md5::I (type X , type Y , type Z) {
00448     return [expr {$Y ^ ($X | (~$Z))}]
00449 }
00450 
00451 /*  Inline the I function*/
00452 regsub -all -line \
00453     {\[I (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00454     $::md5::MD5Hash_bodyX \
00455     {(\2 ^ (\1 | (~\3)))} \
00456     ::md5::MD5Hash_bodyX
00457 
00458 
00459 /*  RFC 1321:3.4 step 4: inline the set of constant modifiers.*/
00460 namespace md5 {
00461     foreach tName {
00462         T01 T02 T03 T04 T05 T06 T07 T08 T09 T10 
00463         T11 T12 T13 T14 T15 T16 T17 T18 T19 T20 
00464         T21 T22 T23 T24 T25 T26 T27 T28 T29 T30 
00465         T31 T32 T33 T34 T35 T36 T37 T38 T39 T40 
00466         T41 T42 T43 T44 T45 T46 T47 T48 T49 T50 
00467         T51 T52 T53 T54 T55 T56 T57 T58 T59 T60 
00468         T61 T62 T63 T64 
00469     }  tVal {
00470         0xd76aa478 0xe8c7b756 0x242070db 0xc1bdceee
00471         0xf57c0faf 0x4787c62a 0xa8304613 0xfd469501
00472         0x698098d8 0x8b44f7af 0xffff5bb1 0x895cd7be
00473         0x6b901122 0xfd987193 0xa679438e 0x49b40821
00474         
00475         0xf61e2562 0xc040b340 0x265e5a51 0xe9b6c7aa
00476         0xd62f105d 0x2441453  0xd8a1e681 0xe7d3fbc8
00477         0x21e1cde6 0xc33707d6 0xf4d50d87 0x455a14ed
00478         0xa9e3e905 0xfcefa3f8 0x676f02d9 0x8d2a4c8a
00479         
00480         0xfffa3942 0x8771f681 0x6d9d6122 0xfde5380c
00481         0xa4beea44 0x4bdecfa9 0xf6bb4b60 0xbebfbc70
00482         0x289b7ec6 0xeaa127fa 0xd4ef3085 0x4881d05
00483         0xd9d4d039 0xe6db99e5 0x1fa27cf8 0xc4ac5665
00484         
00485         0xf4292244 0x432aff97 0xab9423a7 0xfc93a039
00486         0x655b59c3 0x8f0ccc92 0xffeff47d 0x85845dd1
00487         0x6fa87e4f 0xfe2ce6e0 0xa3014314 0x4e0811a1
00488         0xf7537e82 0xbd3af235 0x2ad7d2bb 0xeb86d391
00489     } {
00490         lappend map \$$tName $tVal
00491     }
00492      ::md5 = ::MD5Hash_bodyX [string map $map $::md5::MD5Hash_bodyX]
00493     un map = 
00494 }
00495 
00496 /*  Define the MD5 hashing procedure with inline functions.*/
00497 ret  ::md5::MD5Hash (type token , type msg) $::md5::MD5Hash_bodyX
00498 
00499 # -------------------------------------------------------------------------
00500 
00501 if {[package provide Trf] != {}} {
00502     interp alias {} ::md5::Hex {} ::hex -mode encode --
00503 } else {
00504     ret  ::md5::Hex (type data) {
00505         binary scan $data H* result
00506         return [string toupper $result]
00507     }
00508 }
00509 
00510 /*  -------------------------------------------------------------------------*/
00511 
00512 /*  LoadAccelerator --*/
00513 /* */
00514 /*  This package can make use of a number of compiled extensions to*/
00515 /*  accelerate the digest computation. This procedure manages the*/
00516 /*  use of these extensions within the package. During normal usage*/
00517 /*  this should not be called, but the test package manipulates the*/
00518 /*  list of enabled accelerators.*/
00519 /* */
00520 ret  ::md5::LoadAccelerator (type name) {
00521     variable accel
00522     set r 0
00523     switch -exact -- $name {
00524         critcl {
00525             if {![catch {package require tcllibc}]
00526                 || ![catch {package require md5c}]} {
00527                 set r [expr {[info command ::md5::md5c] != {}}]
00528             }
00529         }
00530         cryptkit {
00531             if {![catch {package require cryptkit}]} {
00532                 set r [expr {![catch {cryptkit::cryptInit}]}]
00533             }
00534         }
00535         trf {
00536             if {![catch {package require Trf}]} {
00537                 set r [expr {![catch {::md5 aa} msg]}]
00538             }
00539         }
00540         default {
00541             return -code error "invalid accelerator package:\
00542                 must be one of [join [array names accel] {, }]"
00543         }
00544     }
00545     set accel($name) $r
00546 }
00547 
00548 /*  -------------------------------------------------------------------------*/
00549 
00550 /*  Description:*/
00551 /*   Pop the nth element off a list. Used in options processing.*/
00552 /* */
00553 ret  ::md5::Pop (type varname , optional nth =0) {
00554     upvar $varname args
00555     set r [lindex $args $nth]
00556     set args [lreplace $args $nth $nth]
00557     return $r
00558 }
00559 
00560 /*  -------------------------------------------------------------------------*/
00561 
00562 /*  fileevent handler for chunked file hashing.*/
00563 /* */
00564 ret  ::md5::Chunk (type token , type channel , optional chunksize =4096) {
00565     upvar #0 $token state
00566     
00567     if {[eof $channel]} {
00568         fileevent $channel readable {}
00569         set state(reading) 0
00570     }
00571         
00572     MD5Update $token [read $channel $chunksize]
00573 }
00574 
00575 /*  -------------------------------------------------------------------------*/
00576 
00577 ret  ::md5::md5 (type args) {
00578     array set opts {-hex 0 -filename {} -channel {} -chunksize 4096}
00579     while {[string match -* [set option [lindex $args 0]]]} {
00580         switch -glob -- $option {
00581             -hex       { set opts(-hex) 1 }
00582             -file*     { set opts(-filename) [Pop args 1] }
00583             -channel   { set opts(-channel) [Pop args 1] }
00584             -chunksize { set opts(-chunksize) [Pop args 1] }
00585             default {
00586                 if {[llength $args] == 1} { break }
00587                 if {[string compare $option "--"] == 0} { Pop args; break }
00588                 set err [join [lsort [array names opts]] ", "]
00589                 return -code error "bad option $option:\
00590                     must be one of $err\nlen: [llength $args]"
00591             }
00592         }
00593         Pop args
00594     }
00595 
00596     if {$opts(-filename) != {}} {
00597         set opts(-channel) [open $opts(-filename) r]
00598         fconfigure $opts(-channel) -translation binary
00599     }
00600 
00601     if {$opts(-channel) == {}} {
00602 
00603         if {[llength $args] != 1} {
00604             return -code error "wrong # args:\
00605                 should be \"md5 ?-hex? -filename file | string\""
00606         }
00607         set tok [MD5Init]
00608         MD5Update $tok [lindex $args 0]
00609         set r [MD5Final $tok]
00610 
00611     } else {
00612 
00613         set tok [MD5Init]
00614         # FRINK: nocheck
00615         set [subst $tok](reading) 1
00616         fileevent $opts(-channel) readable \
00617             [list [namespace origin Chunk] \
00618                  $tok $opts(-channel) $opts(-chunksize)]
00619         vwait [subst $tok](reading)
00620         set r [MD5Final $tok]
00621 
00622         # If we opened the channel - we should close it too.
00623         if {$opts(-filename) != {}} {
00624             close $opts(-channel)
00625         }
00626     }
00627     
00628     if {$opts(-hex)} {
00629         set r [Hex $r]
00630     }
00631     return $r
00632 }
00633 
00634 /*  -------------------------------------------------------------------------*/
00635 
00636 ret  ::md5::hmac (type args) {
00637     array set opts {-hex 0 -filename {} -channel {} -chunksize 4096}
00638     while {[string match -* [set option [lindex $args 0]]]} {
00639         switch -glob -- $option {
00640             -key       { set opts(-key) [Pop args 1] }
00641             -hex       { set opts(-hex) 1 }
00642             -file*     { set opts(-filename) [Pop args 1] }
00643             -channel   { set opts(-channel) [Pop args 1] }
00644             -chunksize { set opts(-chunksize) [Pop args 1] }
00645             default {
00646                 if {[llength $args] == 1} { break }
00647                 if {[string compare $option "--"] == 0} { Pop args; break }
00648                 set err [join [lsort [array names opts]] ", "]
00649                 return -code error "bad option $option:\
00650                     must be one of $err"
00651             }
00652         }
00653         Pop args
00654     }
00655 
00656     if {![info exists opts(-key)]} {
00657         return -code error "wrong # args:\
00658             should be \"hmac ?-hex? -key key -filename file | string\""
00659     }
00660 
00661     if {$opts(-filename) != {}} {
00662         set opts(-channel) [open $opts(-filename) r]
00663         fconfigure $opts(-channel) -translation binary
00664     }
00665 
00666     if {$opts(-channel) == {}} {
00667 
00668         if {[llength $args] != 1} {
00669             return -code error "wrong # args:\
00670                 should be \"hmac ?-hex? -key key -filename file | string\""
00671         }
00672         set tok [HMACInit $opts(-key)]
00673         HMACUpdate $tok [lindex $args 0]
00674         set r [HMACFinal $tok]
00675 
00676     } else {
00677 
00678         set tok [HMACInit $opts(-key)]
00679         # FRINK: nocheck
00680         set [subst $tok](reading) 1
00681         fileevent $opts(-channel) readable \
00682             [list [namespace origin Chunk] \
00683                  $tok $opts(-channel) $opts(-chunksize)]
00684         vwait [subst $tok](reading)
00685         set r [HMACFinal $tok]
00686 
00687         # If we opened the channel - we should close it too.
00688         if {$opts(-filename) != {}} {
00689             close $opts(-channel)
00690         }
00691     }
00692     
00693     if {$opts(-hex)} {
00694         set r [Hex $r]
00695     }
00696     return $r
00697 }
00698 
00699 /*  -------------------------------------------------------------------------*/
00700 
00701 /*  Try and load a compiled extension to help.*/
00702 namespace ::md5 {
00703     foreach e {critcl cryptkit trf} { if {[LoadAccelerator $e]} { break } }
00704 }
00705 
00706 package provide md5 $::md5::version
00707 
00708 /*  -------------------------------------------------------------------------*/
00709 /*  Local Variables:*/
00710 /*    mode: tcl*/
00711 /*    indent-tabs-mode: nil*/
00712 /*  End:*/
00713 
00714 
00715 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1