sha1v1.tcl

Go to the documentation of this file.
00001 /*  sha1.tcl - */
00002 /* */
00003 /*  Copyright (C) 2001 Don Libes <libes@nist.gov>*/
00004 /*  Copyright (C) 2003 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00005 /* */
00006 /*  SHA1 defined by FIPS 180-1, "The SHA1 Message-Digest Algorithm"*/
00007 /*  HMAC defined by RFC 2104, "Keyed-Hashing for Message Authentication"*/
00008 /* */
00009 /*  This is an implementation of SHA1 based upon the example code given in*/
00010 /*  FIPS 180-1 and upon the tcllib MD4 implementation and taking some ideas*/
00011 /*  and methods from the earlier tcllib sha1 version by Don Libes.*/
00012 /* */
00013 /*  This implementation permits incremental updating of the hash and */
00014 /*  provides support for external compiled implementations either using*/
00015 /*  critcl (sha1c) or Trf.*/
00016 /* */
00017 /*  ref: http://www.itl.nist.gov/fipspubs/fip180-1.htm*/
00018 /* */
00019 /*  -------------------------------------------------------------------------*/
00020 /*  See the file "license.terms" for information on usage and redistribution*/
00021 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00022 /*  -------------------------------------------------------------------------*/
00023 /* */
00024 /*  $Id: sha1v1.tcl,v 1.1 2006/03/12 22:46:13 andreas_kupries Exp $*/
00025 
00026 /*  @mdgen EXCLUDE: sha1c.tcl*/
00027 
00028 package require Tcl 8.2;                /*  tcl minimum version*/
00029 
00030 namespace ::sha1 {
00031     variable version 1.1.0
00032     variable rcsid {$Id: sha1v1.tcl,v 1.1 2006/03/12 22:46:13 andreas_kupries Exp $}
00033     variable accel
00034     array  accel =  {critcl 0 cryptkit 0 trf 0}
00035 
00036     namespace export sha1 hmac SHA1Init SHA1Update SHA1Final
00037 
00038     variable uid
00039     if {![info exists uid]} {
00040          uid =  0
00041     }
00042 }
00043 
00044 /*  -------------------------------------------------------------------------*/
00045 
00046 /*  SHA1Init --*/
00047 /* */
00048 /*    Create and initialize an SHA1 state variable. This will be*/
00049 /*    cleaned up when we call SHA1Final*/
00050 /* */
00051 ret  ::sha1::SHA1Init () {
00052     variable accel
00053     variable uid
00054     set token [namespace current]::[incr uid]
00055     upvar #0 $token state
00056 
00057     # FIPS 180-1: 7 - Initialize the hash state
00058     array set state \
00059         [list \
00060              A [expr {int(0x67452301)}] \
00061              B [expr {int(0xEFCDAB89)}] \
00062              C [expr {int(0x98BADCFE)}] \
00063              D [expr {int(0x10325476)}] \
00064              E [expr {int(0xC3D2E1F0)}] \
00065              n 0 i "" ]
00066     if {$accel(cryptkit)} {
00067         cryptkit::cryptCreateContext state(ckctx) CRYPT_UNUSED CRYPT_ALGO_SHA
00068     } elseif {$accel(trf)} {
00069         set s {}
00070         switch -exact -- $::tcl_platform(platform) {
00071             windows { set s [open NUL w] }
00072             unix    { set s [open /dev/null w] }
00073         }
00074         if {$s != {}} {
00075             fconfigure $s -translation binary -buffering none
00076             ::sha1 -attach $s -mode write \
00077                 -read-type variable \
00078                 -read-destination [subst $token](trfread) \
00079                 -write-type variable \
00080                 -write-destination [subst $token](trfwrite)
00081             array set state [list trfread 0 trfwrite 0 trf $s]
00082         }
00083     }
00084     return $token
00085 }
00086 
00087 /*  SHA1Update --*/
00088 /* */
00089 /*    This is called to add more data into the hash. You may call this*/
00090 /*    as many times as you require. Note that passing in "ABC" is equivalent*/
00091 /*    to passing these letters in as separate calls -- hence this proc */
00092 /*    permits hashing of chunked data*/
00093 /* */
00094 /*    If we have a C-based implementation available, then we will use*/
00095 /*    it here in preference to the pure-Tcl implementation.*/
00096 /* */
00097 ret  ::sha1::SHA1Update (type token , type data) {
00098     variable accel
00099     upvar #0 $token state
00100 
00101     if {$accel(critcl)} {
00102         if {[info exists state(sha1c)]} {
00103             set state(sha1c) [sha1c $data $state(sha1c)]
00104         } else {
00105             set state(sha1c) [sha1c $data]
00106         }
00107         return
00108     } elseif {[info exists state(ckctx)]} {
00109         if {[string length $data] > 0} {
00110             cryptkit::cryptEncrypt $state(ckctx) $data
00111         }
00112         return
00113     } elseif {[info exists state(trf)]} {
00114         puts -nonewline $state(trf) $data
00115         return
00116     }
00117 
00118     # Update the state values
00119     incr state(n) [string length $data]
00120     append state(i) $data
00121 
00122     # Calculate the hash for any complete blocks
00123     set len [string length $state(i)]
00124     for {set n 0} {($n + 64) <= $len} {} {
00125         SHA1Transform $token [string range $state(i) $n [incr n 64]]
00126     }
00127 
00128     # Adjust the state for the blocks completed.
00129     set state(i) [string range $state(i) $n end]
00130     return
00131 }
00132 
00133 /*  SHA1Final --*/
00134 /* */
00135 /*     This procedure is used to close the current hash and returns the*/
00136 /*     hash data. Once this procedure has been called the hash context*/
00137 /*     is freed and cannot be used again.*/
00138 /* */
00139 /*     Note that the output is 160 bits represented as binary data.*/
00140 /* */
00141 ret  ::sha1::SHA1Final (type token) {
00142     upvar #0 $token state
00143 
00144     # Check for either of the C-compiled versions.
00145     if {[info exists state(sha1c)]} {
00146         set r $state(sha1c)
00147         unset state
00148         return $r
00149     } elseif {[info exists state(ckctx)]} {
00150         cryptkit::cryptEncrypt $state(ckctx) ""
00151         cryptkit::cryptGetAttributeString $state(ckctx) \
00152             CRYPT_CTXINFO_HASHVALUE r 20
00153         cryptkit::cryptDestroyContext $state(ckctx)
00154         # If nothing was hashed, we get no r variable set!
00155         if {[info exists r]} {
00156             unset state
00157             return $r
00158         }
00159     } elseif {[info exists state(trf)]} {
00160         close $state(trf)
00161         set r $state(trfwrite)
00162         unset state
00163         return $r
00164     }
00165 
00166     # Padding
00167     #
00168     set len [string length $state(i)]
00169     set pad [expr {56 - ($len % 64)}]
00170     if {$len % 64 > 56} {
00171         incr pad 64
00172     }
00173     if {$pad == 0} {
00174         incr pad 64
00175     }
00176     append state(i) [binary format a$pad \x80]
00177 
00178     # Append length in bits as big-endian wide int.
00179     set dlen [expr {8 * $state(n)}]
00180     append state(i) [binary format II 0 $dlen]
00181 
00182     # Calculate the hash for the remaining block.
00183     set len [string length $state(i)]
00184     for {set n 0} {($n + 64) <= $len} {} {
00185         SHA1Transform $token [string range $state(i) $n [incr n 64]]
00186     }
00187 
00188     # Output
00189     set r [bytes $state(A)][bytes $state(B)][bytes $state(C)][bytes $state(D)][bytes $state(E)]
00190     unset state
00191     return $r
00192 }
00193 
00194 /*  -------------------------------------------------------------------------*/
00195 /*  HMAC Hashed Message Authentication (RFC 2104)*/
00196 /* */
00197 /*  hmac = H(K xor opad, H(K xor ipad, text))*/
00198 /* */
00199 
00200 /*  HMACInit --*/
00201 /* */
00202 /*     This is equivalent to the SHA1Init procedure except that a key is*/
00203 /*     added into the algorithm*/
00204 /* */
00205 ret  ::sha1::HMACInit (type K) {
00206 
00207     # Key K is adjusted to be 64 bytes long. If K is larger, then use
00208     # the SHA1 digest of K and pad this instead.
00209     set len [string length $K]
00210     if {$len > 64} {
00211         set tok [SHA1Init]
00212         SHA1Update $tok $K
00213         set K [SHA1Final $tok]
00214         set len [string length $K]
00215     }
00216     set pad [expr {64 - $len}]
00217     append K [string repeat \0 $pad]
00218 
00219     # Cacluate the padding buffers.
00220     set Ki {}
00221     set Ko {}
00222     binary scan $K i16 Ks
00223     foreach k $Ks {
00224         append Ki [binary format i [expr {$k ^ 0x36363636}]]
00225         append Ko [binary format i [expr {$k ^ 0x5c5c5c5c}]]
00226     }
00227 
00228     set tok [SHA1Init]
00229     SHA1Update $tok $Ki;                 # initialize with the inner pad
00230     
00231     # preserve the Ko value for the final stage.
00232     # FRINK: nocheck
00233     set [subst $tok](Ko) $Ko
00234 
00235     return $tok
00236 }
00237 
00238 /*  HMACUpdate --*/
00239 /* */
00240 /*     Identical to calling SHA1Update*/
00241 /* */
00242 ret  ::sha1::HMACUpdate (type token , type data) {
00243     SHA1Update $token $data
00244     return
00245 }
00246 
00247 /*  HMACFinal --*/
00248 /* */
00249 /*     This is equivalent to the SHA1Final procedure. The hash context is*/
00250 /*     closed and the binary representation of the hash result is returned.*/
00251 /* */
00252 ret  ::sha1::HMACFinal (type token) {
00253     upvar #0 $token state
00254 
00255     set tok [SHA1Init];                 # init the outer hashing function
00256     SHA1Update $tok $state(Ko);         # prepare with the outer pad.
00257     SHA1Update $tok [SHA1Final $token]; # hash the inner result
00258     return [SHA1Final $tok]
00259 }
00260 
00261 /*  -------------------------------------------------------------------------*/
00262 /*  Description:*/
00263 /*   This is the core SHA1 algorithm. It is a lot like the MD4 algorithm but*/
00264 /*   includes an extra round and a set of constant modifiers throughout.*/
00265 /* */
00266  ::sha1 = ::SHA1Transform_body {
00267     upvar /* 0 $token state*/
00268 
00269     /*  FIPS 180-1: 7a: Process Message in 16-Word Blocks*/
00270     binary scan $msg I* blocks
00271      blockLen =  [llength $blocks]
00272     for { i =  0} {$i < $blockLen} {incr i 16} {
00273          W =  [lrange $blocks $i [expr {$i+15}]]
00274         
00275         /*  FIPS 180-1: 7b: Expand the input into 80 words*/
00276         /*  For t = 16 to 79 */
00277         /*    let Wt = (Wt-3 ^ Wt-8 ^ Wt-14 ^ Wt-16) <<< 1*/
00278          t3 =   12
00279          t8 =    7
00280          t14 =   1
00281          t16 =  -1
00282         for { t =  16} {$t < 80} {incr t} {
00283              x =  [expr {[lindex $W [incr t3]] ^ [lindex $W [incr t8]] ^ \
00284                              [lindex $W [incr t14]] ^ [lindex $W [incr t16]]}]
00285             lappend W [expr {int(($x << 1) | (($x >> 31) & 1))}]
00286         }
00287         
00288         /*  FIPS 180-1: 7c: Copy hash state.*/
00289          A =  $state(A)
00290          B =  $state(B)
00291          C =  $state(C)
00292          D =  $state(D)
00293          E =  $state(E)
00294 
00295         /*  FIPS 180-1: 7d: Do permutation rounds*/
00296         /*  For t = 0 to 79 do*/
00297         /*    TEMP = (A<<<5) + ft(B,C,D) + E + Wt + Kt;*/
00298         /*    E = D; D = C; C = S30(B); B = A; A = TEMP;*/
00299 
00300         /*  Round 1: ft(B,C,D) = (B & C) | (~B & D) ( 0 <= t <= 19)*/
00301         for { t =  0} {$t < 20} {incr t} {
00302              TEMP =  [F1 $A $B $C $D $E [lindex $W $t]]
00303              E =  $D
00304              D =  $C
00305              C =  [rotl32 $B 30]
00306              B =  $A
00307              A =  $TEMP
00308         }
00309 
00310         /*  Round 2: ft(B,C,D) = (B ^ C ^ D) ( 20 <= t <= 39)*/
00311         for {} {$t < 40} {incr t} {
00312              TEMP =  [F2 $A $B $C $D $E [lindex $W $t]]
00313              E =  $D
00314              D =  $C
00315              C =  [rotl32 $B 30]
00316              B =  $A
00317              A =  $TEMP
00318         }
00319 
00320         /*  Round 3: ft(B,C,D) = ((B & C) | (B & D) | (C & D)) ( 40 <= t <= 59)*/
00321         for {} {$t < 60} {incr t} {
00322              TEMP =  [F3 $A $B $C $D $E [lindex $W $t]]
00323              E =  $D
00324              D =  $C
00325              C =  [rotl32 $B 30]
00326              B =  $A
00327              A =  $TEMP
00328          }
00329 
00330         /*  Round 4: ft(B,C,D) = (B ^ C ^ D) ( 60 <= t <= 79)*/
00331         for {} {$t < 80} {incr t} {
00332              TEMP =  [F4 $A $B $C $D $E [lindex $W $t]]
00333              E =  $D
00334              D =  $C
00335              C =  [rotl32 $B 30]
00336              B =  $A
00337              A =  $TEMP
00338         }
00339 
00340         /*  Then perform the following additions. (That is, increment each*/
00341         /*  of the four registers by the value it had before this block*/
00342         /*  was started.)*/
00343         incr state(A) $A
00344         incr state(B) $B
00345         incr state(C) $C
00346         incr state(D) $D
00347         incr state(E) $E
00348     }
00349 
00350     return
00351 }
00352 
00353 ret  ::sha1::F1 (type A , type B , type C , type D , type E , type W) {
00354     expr {(((($A << 5) & 0xffffffff) | (($A >> 27) & 0x1f)) \
00355                + ($D ^ ($B & ($C ^ $D))) + $E + $W + 0x5a827999) & 0xffffffff}
00356 }
00357 
00358 ret  ::sha1::F2 (type A , type B , type C , type D , type E , type W) {
00359     expr {(((($A << 5) & 0xffffffff) | (($A >> 27) & 0x1f)) \
00360                + ($B ^ $C ^ $D) + $E + $W + 0x6ed9eba1) & 0xffffffff}
00361 }
00362 
00363 ret  ::sha1::F3 (type A , type B , type C , type D , type E , type W) {
00364     expr {(((($A << 5) & 0xffffffff)| (($A >> 27) & 0x1f)) \
00365                + (($B & $C) | ($D & ($B | $C))) + $E + $W + 0x8f1bbcdc) & 0xffffffff}
00366 }
00367 
00368 ret  ::sha1::F4 (type A , type B , type C , type D , type E , type W) {
00369     expr {(((($A << 5) & 0xffffffff)| (($A >> 27) & 0x1f)) \
00370                + ($B ^ $C ^ $D) + $E + $W + 0xca62c1d6) & 0xffffffff}
00371 }
00372 
00373 ret  ::sha1::rotl32 (type v , type n) {
00374     return [expr {((($v << $n) \
00375                         | (($v >> (32 - $n)) \
00376                                & (0x7FFFFFFF >> (31 - $n))))) \
00377                       & 0xFFFFFFFF}]
00378 }
00379 
00380 
00381 /*  -------------------------------------------------------------------------*/
00382 /*  */
00383 /*  In order to get this code to go as fast as possible while leaving*/
00384 /*  the main code readable we can substitute the above function bodies*/
00385 /*  into the transform procedure. This inlines the code for us an avoids*/
00386 /*  a procedure call overhead within the loops.*/
00387 /* */
00388 /*  We can do some minor tweaking to improve speed on Tcl < 8.5 where we*/
00389 /*  know our arithmetic is limited to 64 bits. On > 8.5 we may have */
00390 /*  unconstrained integer arithmetic and must avoid letting it run away.*/
00391 /* */
00392 
00393 regsub -all -line \
00394     {\[F1 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00395     $::sha1::SHA1Transform_body \
00396     {[expr {(rotl32($A,5) + ($D ^ ($B \& ($C ^ $D))) + $E + \1 + 0x5a827999) \& 0xffffffff}]} \
00397     ::sha1::SHA1Transform_body_tmp
00398 
00399 regsub -all -line \
00400     {\[F2 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00401     $::sha1::SHA1Transform_body_tmp \
00402     {[expr {(rotl32($A,5) + ($B ^ $C ^ $D) + $E + \1 + 0x6ed9eba1) \& 0xffffffff}]} \
00403     ::sha1::SHA1Transform_body_tmp
00404 
00405 regsub -all -line \
00406     {\[F3 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00407     $::sha1::SHA1Transform_body_tmp \
00408     {[expr {(rotl32($A,5) + (($B \& $C) | ($D \& ($B | $C))) + $E + \1 + 0x8f1bbcdc) \& 0xffffffff}]} \
00409     ::sha1::SHA1Transform_body_tmp
00410 
00411 regsub -all -line \
00412     {\[F4 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00413     $::sha1::SHA1Transform_body_tmp \
00414     {[expr {(rotl32($A,5) + ($B ^ $C ^ $D) + $E + \1 + 0xca62c1d6) \& 0xffffffff}]} \
00415     ::sha1::SHA1Transform_body_tmp
00416 
00417 regsub -all -line \
00418     {rotl32\(\$A,5\)} \
00419     $::sha1::SHA1Transform_body_tmp \
00420     {((($A << 5) \& 0xffffffff) | (($A >> 27) \& 0x1f))} \
00421     ::sha1::SHA1Transform_body_tmp
00422 
00423 regsub -all -line \
00424     {\[rotl32 \$B 30\]} \
00425     $::sha1::SHA1Transform_body_tmp \
00426     {[expr {int(($B << 30) | (($B >> 2) \& 0x3fffffff))}]} \
00427     ::sha1::SHA1Transform_body_tmp
00428 /* */
00429 /*  Version 2 avoids a few truncations to 32 bits in non-essential places.*/
00430 /* */
00431 regsub -all -line \
00432     {\[F1 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00433     $::sha1::SHA1Transform_body \
00434     {[expr {rotl32($A,5) + ($D ^ ($B \& ($C ^ $D))) + $E + \1 + 0x5a827999}]} \
00435     ::sha1::SHA1Transform_body_tmp2
00436 
00437 regsub -all -line \
00438     {\[F2 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00439     $::sha1::SHA1Transform_body_tmp2 \
00440     {[expr {rotl32($A,5) + ($B ^ $C ^ $D) + $E + \1 + 0x6ed9eba1}]} \
00441     ::sha1::SHA1Transform_body_tmp2
00442 
00443 regsub -all -line \
00444     {\[F3 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00445     $::sha1::SHA1Transform_body_tmp2 \
00446     {[expr {rotl32($A,5) + (($B \& $C) | ($D \& ($B | $C))) + $E + \1 + 0x8f1bbcdc}]} \
00447     ::sha1::SHA1Transform_body_tmp2
00448 
00449 regsub -all -line \
00450     {\[F4 \$A \$B \$C \$D \$E (\[.*?\])\]} \
00451     $::sha1::SHA1Transform_body_tmp2 \
00452     {[expr {rotl32($A,5) + ($B ^ $C ^ $D) + $E + \1 + 0xca62c1d6}]} \
00453     ::sha1::SHA1Transform_body_tmp2
00454 
00455 regsub -all -line \
00456     {rotl32\(\$A,5\)} \
00457     $::sha1::SHA1Transform_body_tmp2 \
00458     {(($A << 5) | (($A >> 27) \& 0x1f))} \
00459     ::sha1::SHA1Transform_body_tmp2
00460 
00461 regsub -all -line \
00462     {\[rotl32 \$B 30\]} \
00463     $::sha1::SHA1Transform_body_tmp2 \
00464     {[expr {($B << 30) | (($B >> 2) \& 0x3fffffff)}]} \
00465     ::sha1::SHA1Transform_body_tmp2
00466 
00467 if {[package vsatisfies [package provide Tcl] 8.5]} {
00468     ret  ::sha1::SHA1Transform (type token , type msg) $::sha1::SHA1Transform_body_tmp
00469 } else {
00470     proc ::sha1::SHA1Transform {token msg} $::sha1::SHA1Transform_body_tmp2
00471 }
00472 
00473 un ::sha1 = ::SHA1Transform_body_tmp
00474 un ::sha1 = ::SHA1Transform_body_tmp2
00475 
00476 /*  -------------------------------------------------------------------------*/
00477 
00478 ret  ::sha1::byte (type n , type v) {expr {((0xFF << (8 * $n)) & $v) >> (8 * $n)}}
00479 ret  ::sha1::bytes (type v) { 
00480     #format %c%c%c%c [byte 0 $v] [byte 1 $v] [byte 2 $v] [byte 3 $v]
00481     format %c%c%c%c \
00482         [expr {((0xFF000000 & $v) >> 24) & 0xFF}] \
00483         [expr {(0xFF0000 & $v) >> 16}] \
00484         [expr {(0xFF00 & $v) >> 8}] \
00485         [expr {0xFF & $v}]
00486 }
00487 
00488 /*  -------------------------------------------------------------------------*/
00489 
00490 ret  ::sha1::Hex (type data) {
00491     binary scan $data H* result
00492     return $result
00493 }
00494 
00495 /*  -------------------------------------------------------------------------*/
00496 
00497 /*  LoadAccelerator --*/
00498 /* */
00499 /*  This package can make use of a number of compiled extensions to*/
00500 /*  accelerate the digest computation. This procedure manages the*/
00501 /*  use of these extensions within the package. During normal usage*/
00502 /*  this should not be called, but the test package manipulates the*/
00503 /*  list of enabled accelerators.*/
00504 /* */
00505 ret  ::sha1::LoadAccelerator (type name) {
00506     variable accel
00507     set r 0
00508     switch -exact -- $name {
00509         critcl {
00510             if {![catch {package require tcllibc}]
00511                 || ![catch {package require sha1c}]} {
00512                 set r [expr {[info command ::sha1::sha1c] != {}}]
00513             }
00514         }
00515         cryptkit {
00516             if {![catch {package require cryptkit}]} {
00517                 set r [expr {![catch {cryptkit::cryptInit}]}]
00518             }
00519         }
00520         trf {
00521             if {![catch {package require Trf}]} {
00522                 set r [expr {![catch {::sha1 aa} msg]}]
00523             }
00524         }
00525         default {
00526             return -code error "invalid accelerator package:\
00527                 must be one of [join [array names accel] {, }]"
00528         }
00529     }
00530     set accel($name) $r
00531 }
00532 
00533 /*  -------------------------------------------------------------------------*/
00534 
00535 /*  Description:*/
00536 /*   Pop the nth element off a list. Used in options processing.*/
00537 /* */
00538 ret  ::sha1::Pop (type varname , optional nth =0) {
00539     upvar $varname args
00540     set r [lindex $args $nth]
00541     set args [lreplace $args $nth $nth]
00542     return $r
00543 }
00544 
00545 /*  -------------------------------------------------------------------------*/
00546 
00547 /*  fileevent handler for chunked file hashing.*/
00548 /* */
00549 ret  ::sha1::Chunk (type token , type channel , optional chunksize =4096) {
00550     upvar #0 $token state
00551     
00552     if {[eof $channel]} {
00553         fileevent $channel readable {}
00554         set state(reading) 0
00555     }
00556         
00557     SHA1Update $token [read $channel $chunksize]
00558 }
00559 
00560 /*  -------------------------------------------------------------------------*/
00561 
00562 ret  ::sha1::sha1 (type args) {
00563     array set opts {-hex 0 -filename {} -channel {} -chunksize 4096}
00564     if {[llength $args] == 1} {
00565         set opts(-hex) 1
00566     } else {
00567         while {[string match -* [set option [lindex $args 0]]]} {
00568             switch -glob -- $option {
00569                 -hex       { set opts(-hex) 1 }
00570                 -bin       { set opts(-hex) 0 }
00571                 -file*     { set opts(-filename) [Pop args 1] }
00572                 -channel   { set opts(-channel) [Pop args 1] }
00573                 -chunksize { set opts(-chunksize) [Pop args 1] }
00574                 default {
00575                     if {[llength $args] == 1} { break }
00576                     if {[string compare $option "--"] == 0} { Pop args; break }
00577                     set err [join [lsort [concat -bin [array names opts]]] ", "]
00578                     return -code error "bad option $option:\
00579                     must be one of $err"
00580                 }
00581             }
00582             Pop args
00583         }
00584     }
00585 
00586     if {$opts(-filename) != {}} {
00587         set opts(-channel) [open $opts(-filename) r]
00588         fconfigure $opts(-channel) -translation binary
00589     }
00590 
00591     if {$opts(-channel) == {}} {
00592 
00593         if {[llength $args] != 1} {
00594             return -code error "wrong # args:\
00595                 should be \"sha1 ?-hex? -filename file | string\""
00596         }
00597         set tok [SHA1Init]
00598         SHA1Update $tok [lindex $args 0]
00599         set r [SHA1Final $tok]
00600 
00601     } else {
00602 
00603         set tok [SHA1Init]
00604         # FRINK: nocheck
00605         set [subst $tok](reading) 1
00606         fileevent $opts(-channel) readable \
00607             [list [namespace origin Chunk] \
00608                  $tok $opts(-channel) $opts(-chunksize)]
00609         # FRINK: nocheck
00610         vwait [subst $tok](reading)
00611         set r [SHA1Final $tok]
00612 
00613         # If we opened the channel - we should close it too.
00614         if {$opts(-filename) != {}} {
00615             close $opts(-channel)
00616         }
00617     }
00618     
00619     if {$opts(-hex)} {
00620         set r [Hex $r]
00621     }
00622     return $r
00623 }
00624 
00625 /*  -------------------------------------------------------------------------*/
00626 
00627 ret  ::sha1::hmac (type args) {
00628     array set opts {-hex 1 -filename {} -channel {} -chunksize 4096}
00629     if {[llength $args] != 2} {
00630         while {[string match -* [set option [lindex $args 0]]]} {
00631             switch -glob -- $option {
00632                 -key       { set opts(-key) [Pop args 1] }
00633                 -hex       { set opts(-hex) 1 }
00634                 -bin       { set opts(-hex) 0 }
00635                 -file*     { set opts(-filename) [Pop args 1] }
00636                 -channel   { set opts(-channel) [Pop args 1] }
00637                 -chunksize { set opts(-chunksize) [Pop args 1] }
00638                 default {
00639                     if {[llength $args] == 1} { break }
00640                     if {[string compare $option "--"] == 0} { Pop args; break }
00641                     set err [join [lsort [array names opts]] ", "]
00642                     return -code error "bad option $option:\
00643                     must be one of $err"
00644                 }
00645             }
00646             Pop args
00647         }
00648     }
00649 
00650     if {[llength $args] == 2} {
00651         set opts(-key) [Pop args]
00652     }
00653 
00654     if {![info exists opts(-key)]} {
00655         return -code error "wrong # args:\
00656             should be \"hmac ?-hex? -key key -filename file | string\""
00657     }
00658 
00659     if {$opts(-filename) != {}} {
00660         set opts(-channel) [open $opts(-filename) r]
00661         fconfigure $opts(-channel) -translation binary
00662     }
00663 
00664     if {$opts(-channel) == {}} {
00665 
00666         if {[llength $args] != 1} {
00667             return -code error "wrong # args:\
00668                 should be \"hmac ?-hex? -key key -filename file | string\""
00669         }
00670         set tok [HMACInit $opts(-key)]
00671         HMACUpdate $tok [lindex $args 0]
00672         set r [HMACFinal $tok]
00673 
00674     } else {
00675 
00676         set tok [HMACInit $opts(-key)]
00677         # FRINK: nocheck
00678         set [subst $tok](reading) 1
00679         fileevent $opts(-channel) readable \
00680             [list [namespace origin Chunk] \
00681                  $tok $opts(-channel) $opts(-chunksize)]
00682         # FRINK: nocheck
00683         vwait [subst $tok](reading)
00684         set r [HMACFinal $tok]
00685 
00686         # If we opened the channel - we should close it too.
00687         if {$opts(-filename) != {}} {
00688             close $opts(-channel)
00689         }
00690     }
00691     
00692     if {$opts(-hex)} {
00693         set r [Hex $r]
00694     }
00695     return $r
00696 }
00697 
00698 /*  -------------------------------------------------------------------------*/
00699 
00700 /*  Try and load a compiled extension to help.*/
00701 namespace ::sha1 {
00702     foreach e {critcl cryptkit trf} { if {[LoadAccelerator $e]} { break } }
00703 }
00704 
00705 package provide sha1 $::sha1::version
00706 
00707 /*  -------------------------------------------------------------------------*/
00708 /*  Local Variables:*/
00709 /*    mode: tcl*/
00710 /*    indent-tabs-mode: nil*/
00711 /*  End:*/
00712 
00713 
00714 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1