md5x.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 package require Tcl 8.2;
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
00040
00041
00042
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
00080
00081
00082
00083
00084
00085
00086
00087
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
00126
00127
00128
00129
00130
00131
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
00187
00188
00189
00190
00191
00192
00193
00194
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
00230
00231
00232
00233 ret ::md5::HMACUpdate (type token , type data) {
00234 MD5Update $token $data
00235 return
00236 }
00237
00238
00239
00240
00241
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
00254
00255
00256
00257
00258
00259
00260
00261 ::md5 = ::MD5Hash_body {
00262 variable $token
00263 upvar 0 $token state
00264
00265
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
00274
00275
00276
00277
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
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
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
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
00299
00300
00301
00302
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
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
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
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
00324
00325
00326
00327
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
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
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
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
00349
00350
00351
00352
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
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
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
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
00374
00375
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
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
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
00411 ret ::md5::F (type X , type Y , type Z) {
00412 return [expr {($X & $Y) | ((~$X) & $Z)}]
00413 }
00414
00415
00416 regsub -all -line \
00417 {\[F (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00418 $::md5::MD5Hash_bodyX \
00419 {( (\1 \& \2) | ((~\1) \& \3) )} \
00420 ::md5::MD5Hash_bodyX
00421
00422
00423 ret ::md5::G (type X , type Y , type Z) {
00424 return [expr {(($X & $Z) | ($Y & (~$Z)))}]
00425 }
00426
00427
00428 regsub -all -line \
00429 {\[G (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00430 $::md5::MD5Hash_bodyX \
00431 {(((\1 \& \3) | (\2 \& (~\3))))} \
00432 ::md5::MD5Hash_bodyX
00433
00434
00435 ret ::md5::H (type X , type Y , type Z) {
00436 return [expr {$X ^ $Y ^ $Z}]
00437 }
00438
00439
00440 regsub -all -line \
00441 {\[H (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00442 $::md5::MD5Hash_bodyX \
00443 {(\1 ^ \2 ^ \3)} \
00444 ::md5::MD5Hash_bodyX
00445
00446
00447 ret ::md5::I (type X , type Y , type Z) {
00448 return [expr {$Y ^ ($X | (~$Z))}]
00449 }
00450
00451
00452 regsub -all -line \
00453 {\[I (\$[ABCD]) (\$[ABCD]) (\$[ABCD])\]} \
00454 $::md5::MD5Hash_bodyX \
00455 {(\2 ^ (\1 | (~\3)))} \
00456 ::md5::MD5Hash_bodyX
00457
00458
00459
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
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
00513
00514
00515
00516
00517
00518
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
00551
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
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
00702 namespace ::md5 {
00703 foreach e {critcl cryptkit trf} { if {[LoadAccelerator $e]} { break } }
00704 }
00705
00706 package provide md5 $::md5::version
00707
00708
00709
00710
00711
00712
00713
00714
00715