sha256.tcl

Go to the documentation of this file.
00001 /*  sha256.tcl - Copyright (C) 2005 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00002 /* */
00003 /*  SHA1 defined by FIPS 180-2, "The Secure Hash Standard"*/
00004 /*  HMAC defined by RFC 2104, "Keyed-Hashing for Message Authentication"*/
00005 /* */
00006 /*  This is an implementation of the secure hash algorithms specified in the*/
00007 /*  FIPS 180-2 document.*/
00008 /* */
00009 /*  This implementation permits incremental updating of the hash and */
00010 /*  provides support for external compiled implementations using critcl.*/
00011 /* */
00012 /*  This implementation permits incremental updating of the hash and */
00013 /*  provides support for external compiled implementations either using*/
00014 /*  critcl (sha256c).*/
00015 /* */
00016 /*  Ref: http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf*/
00017 /*       http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf*/
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 
00025 /*  @mdgen EXCLUDE: sha256c.tcl*/
00026 
00027 package require Tcl 8.2;                /*  tcl minimum version*/
00028 
00029 namespace ::sha2 {
00030     variable version 1.0.2
00031     variable rcsid {$Id: sha256.tcl,v 1.6 2007/05/03 21:41:10 andreas_kupries Exp $}
00032 
00033     variable  accel
00034     array  accel =  {tcl 0 critcl 0}
00035     variable  
00036 
00037     namespace export sha256 hmac \
00038             SHA256Init SHA256Update SHA256Final
00039 
00040     variable uid
00041     if {![info exists uid]} {
00042          uid =  0
00043     }
00044 
00045     variable K
00046     if {![info exists K]} {
00047         /*  FIPS 180-2: 4.2.2 SHA-256 constants*/
00048          K =  [list \
00049                    0x428a2f98 0x71374491 0xb5c0fbcf 0xe9b5dba5 \
00050                    0x3956c25b 0x59f111f1 0x923f82a4 0xab1c5ed5 \
00051                    0xd807aa98 0x12835b01 0x243185be 0x550c7dc3 \
00052                    0x72be5d74 0x80deb1fe 0x9bdc06a7 0xc19bf174 \
00053                    0xe49b69c1 0xefbe4786 0x0fc19dc6 0x240ca1cc \
00054                    0x2de92c6f 0x4a7484aa 0x5cb0a9dc 0x76f988da \
00055                    0x983e5152 0xa831c66d 0xb00327c8 0xbf597fc7 \
00056                    0xc6e00bf3 0xd5a79147 0x06ca6351 0x14292967 \
00057                    0x27b70a85 0x2e1b2138 0x4d2c6dfc 0x53380d13 \
00058                    0x650a7354 0x766a0abb 0x81c2c92e 0x92722c85 \
00059                    0xa2bfe8a1 0xa81a664b 0xc24b8b70 0xc76c51a3 \
00060                    0xd192e819 0xd6990624 0xf40e3585 0x106aa070 \
00061                    0x19a4c116 0x1e376c08 0x2748774c 0x34b0bcb5 \
00062                    0x391c0cb3 0x4ed8aa4a 0x5b9cca4f 0x682e6ff3 \
00063                    0x748f82ee 0x78a5636f 0x84c87814 0x8cc70208 \
00064                    0x90befffa 0xa4506ceb 0xbef9a3f7 0xc67178f2 \
00065                   ]
00066     }
00067     
00068 }
00069 
00070 /*  -------------------------------------------------------------------------*/
00071 /*  Management of sha256 implementations.*/
00072 
00073 /*  LoadAccelerator --*/
00074 /* */
00075 /*  This package can make use of a number of compiled extensions to*/
00076 /*  accelerate the digest computation. This procedure manages the*/
00077 /*  use of these extensions within the package. During normal usage*/
00078 /*  this should not be called, but the test package manipulates the*/
00079 /*  list of enabled accelerators.*/
00080 /* */
00081 ret  ::sha2::LoadAccelerator (type name) {
00082     variable accel
00083     set r 0
00084     switch -exact -- $name {
00085         tcl {
00086             # Already present (this file)
00087             set r 1
00088         }
00089         critcl {
00090             if {![catch {package require tcllibc}]
00091                 || ![catch {package require sha256c}]} {
00092                 set r [expr {[info command ::sha2::sha256c_update] != {}}]
00093             }
00094         }
00095         default {
00096             return -code error "invalid accelerator $key:\
00097                 must be one of [join [KnownImplementations] {, }]"
00098         }
00099     }
00100     set accel($name) $r
00101     return $r
00102 }
00103 
00104 /*  ::sha2::Implementations --*/
00105 /* */
00106 /*  Determines which implementations are*/
00107 /*  present, i.e. loaded.*/
00108 /* */
00109 /*  Arguments:*/
00110 /*  None.*/
00111 /* */
00112 /*  Results:*/
00113 /*  A list of implementation keys.*/
00114 
00115 ret  ::sha2::Implementations () {
00116     variable accel
00117     set res {}
00118     foreach n [array names accel] {
00119     if {!$accel($n)} continue
00120     lappend res $n
00121     }
00122     return $res
00123 }
00124 
00125 /*  ::sha2::KnownImplementations --*/
00126 /* */
00127 /*  Determines which implementations are known*/
00128 /*  as possible implementations.*/
00129 /* */
00130 /*  Arguments:*/
00131 /*  None.*/
00132 /* */
00133 /*  Results:*/
00134 /*  A list of implementation keys. In the order*/
00135 /*  of preference, most prefered first.*/
00136 
00137 ret  ::sha2::KnownImplementations () {
00138     return {critcl tcl}
00139 }
00140 
00141 ret  ::sha2::Names () {
00142     return {
00143     critcl   {tcllibc based}
00144     tcl      {pure Tcl}
00145     }
00146 }
00147 
00148 /*  ::sha2::SwitchTo --*/
00149 /* */
00150 /*  Activates a loaded named implementation.*/
00151 /* */
00152 /*  Arguments:*/
00153 /*  key Name of the implementation to activate.*/
00154 /* */
00155 /*  Results:*/
00156 /*  None.*/
00157 
00158 ret  ::sha2::SwitchTo (type key) {
00159     variable accel
00160     variable loaded
00161 
00162     if {[string equal $key $loaded]} {
00163     # No change, nothing to do.
00164     return
00165     } elseif {![string equal $key ""]} {
00166     # Validate the target implementation of the switch.
00167 
00168     if {![info exists accel($key)]} {
00169         return -code error "Unable to activate unknown implementation \"$key\""
00170     } elseif {![info exists accel($key)] || !$accel($key)} {
00171         return -code error "Unable to activate missing implementation \"$key\""
00172     }
00173     }
00174 
00175     # Deactivate the previous implementation, if there was any.
00176 
00177     if {![string equal $loaded ""]} {
00178         foreach c {
00179             SHA256Init   SHA224Init
00180             SHA256Final  SHA224Final
00181             SHA256Update
00182         } {
00183             rename ::sha2::$c ::sha2::${c}-${loaded}
00184         }
00185     }
00186 
00187     # Activate the new implementation, if there is any.
00188 
00189     if {![string equal $key ""]} {
00190         foreach c {
00191             SHA256Init   SHA224Init
00192             SHA256Final  SHA224Final
00193             SHA256Update
00194         } {
00195             rename ::sha2::${c}-${key} ::sha2::$c
00196         }
00197     }
00198 
00199     # Remember the active implementation, for deactivation by future
00200     # switches.
00201 
00202     set loaded $key
00203     return
00204 }
00205 
00206 /*  -------------------------------------------------------------------------*/
00207 
00208 /*  SHA256Init --*/
00209 /* */
00210 /*    Create and initialize an SHA256 state variable. This will be*/
00211 /*    cleaned up when we call SHA256Final*/
00212 /* */
00213 
00214 ret  ::sha2::SHA256Init-tcl () {
00215     variable uid
00216     set token [namespace current]::[incr uid]
00217     upvar #0 $token tok
00218 
00219     # FIPS 180-2: 5.3.2 Setting the initial hash value
00220     array set tok \
00221             [list \
00222             A [expr {int(0x6a09e667)}] \
00223             B [expr {int(0xbb67ae85)}] \
00224             C [expr {int(0x3c6ef372)}] \
00225             D [expr {int(0xa54ff53a)}] \
00226             E [expr {int(0x510e527f)}] \
00227             F [expr {int(0x9b05688c)}] \
00228             G [expr {int(0x1f83d9ab)}] \
00229             H [expr {int(0x5be0cd19)}] \
00230             n 0 i "" v 256]
00231     return $token
00232 }
00233 
00234 ret  ::sha2::SHA256Init-critcl () {
00235     variable uid
00236     set token [namespace current]::[incr uid]
00237     upvar #0 $token tok
00238 
00239     # FIPS 180-2: 5.3.2 Setting the initial hash value
00240     set tok(sha256c) [sha256c_init256]
00241     return $token
00242 }
00243 
00244 /*  SHA256Update --*/
00245 /* */
00246 /*    This is called to add more data into the hash. You may call this*/
00247 /*    as many times as you require. Note that passing in "ABC" is equivalent*/
00248 /*    to passing these letters in as separate calls -- hence this proc */
00249 /*    permits hashing of chunked data*/
00250 /* */
00251 /*    If we have a C-based implementation available, then we will use*/
00252 /*    it here in preference to the pure-Tcl implementation.*/
00253 /* */
00254 
00255 ret  ::sha2::SHA256Update-tcl (type token , type data) {
00256     upvar #0 $token state
00257 
00258     # Update the state values
00259     incr   state(n) [string length $data]
00260     append state(i) $data
00261 
00262     # Calculate the hash for any complete blocks
00263     set len [string length $state(i)]
00264     for {set n 0} {($n + 64) <= $len} {} {
00265         SHA256Transform $token [string range $state(i) $n [incr n 64]]
00266     }
00267 
00268     # Adjust the state for the blocks completed.
00269     set state(i) [string range $state(i) $n end]
00270     return
00271 }
00272 
00273 ret  ::sha2::SHA256Update-critcl (type token , type data) {
00274     upvar #0 $token state
00275 
00276     set state(sha256c) [sha256c_update $data $state(sha256c)]
00277     return
00278 }
00279 
00280 /*  SHA256Final --*/
00281 /* */
00282 /*     This procedure is used to close the current hash and returns the*/
00283 /*     hash data. Once this procedure has been called the hash context*/
00284 /*     is freed and cannot be used again.*/
00285 /* */
00286 /*     Note that the output is 256 bits represented as binary data.*/
00287 /* */
00288 
00289 ret  ::sha2::SHA256Final-tcl (type token) {
00290     upvar #0 $token state
00291     SHA256Penultimate $token
00292     
00293     # Output
00294     set r [bytes $state(A)][bytes $state(B)][bytes $state(C)][bytes $state(D)][bytes $state(E)][bytes $state(F)][bytes $state(G)][bytes $state(H)]
00295     unset state
00296     return $r
00297 }
00298 
00299 ret  ::sha2::SHA256Final-critcl (type token) {
00300     upvar #0 $token state
00301     set r $state(sha256c)
00302     unset  state
00303     return $r
00304 }
00305 
00306 /*  SHA256Penultimate --*/
00307 /* */
00308 /* */
00309 ret  ::sha2::SHA256Penultimate (type token) {
00310     upvar #0 $token state
00311 
00312     # FIPS 180-2: 5.1.1: Padding the message
00313     #
00314     set len [string length $state(i)]
00315     set pad [expr {56 - ($len % 64)}]
00316     if {$len % 64 > 56} {
00317         incr pad 64
00318     }
00319     if {$pad == 0} {
00320         incr pad 64
00321     }
00322     append state(i) [binary format a$pad \x80]
00323 
00324     # Append length in bits as big-endian wide int.
00325     set dlen [expr {8 * $state(n)}]
00326     append state(i) [binary format II 0 $dlen]
00327 
00328     # Calculate the hash for the remaining block.
00329     set len [string length $state(i)]
00330     for {set n 0} {($n + 64) <= $len} {} {
00331         SHA256Transform $token [string range $state(i) $n [incr n 64]]
00332     }
00333 }
00334 
00335 /*  -------------------------------------------------------------------------*/
00336 
00337 ret  ::sha2::SHA224Init-tcl () {
00338     variable uid
00339     set token [namespace current]::[incr uid]
00340     upvar #0 $token tok
00341 
00342     # FIPS 180-2 (change notice 1) (1): SHA-224 initialization values
00343     array set tok \
00344             [list \
00345             A [expr {int(0xc1059ed8)}] \
00346             B [expr {int(0x367cd507)}] \
00347             C [expr {int(0x3070dd17)}] \
00348             D [expr {int(0xf70e5939)}] \
00349             E [expr {int(0xffc00b31)}] \
00350             F [expr {int(0x68581511)}] \
00351             G [expr {int(0x64f98fa7)}] \
00352             H [expr {int(0xbefa4fa4)}] \
00353             n 0 i "" v 224]
00354     return $token
00355 }
00356 
00357 ret  ::sha2::SHA224Init-critcl () {
00358     variable uid
00359     set token [namespace current]::[incr uid]
00360     upvar #0 $token tok
00361 
00362     # FIPS 180-2 (change notice 1) (1): SHA-224 initialization values
00363     set tok(sha256c) [sha256c_init224]
00364     return $token
00365 }
00366 
00367 interp alias {} ::sha2::SHA224Update {} ::sha2::SHA256Update
00368 
00369 ret  ::sha2::SHA224Final-tcl (type token) {
00370     upvar #0 $token state
00371     SHA256Penultimate $token
00372     
00373     # Output
00374     set r [bytes $state(A)][bytes $state(B)][bytes $state(C)][bytes $state(D)][bytes $state(E)][bytes $state(F)][bytes $state(G)]
00375     unset state
00376     return $r
00377 }
00378 
00379 ret  ::sha2::SHA224Final-critcl (type token) {
00380     upvar #0 $token state
00381     # Trim result down to 224 bits (by 4 bytes).
00382     # See output below, A..G, not A..H
00383     set r [string range $state(sha256c) 0 end-4]
00384     unset state
00385     return $r
00386 }
00387 
00388 /*  -------------------------------------------------------------------------*/
00389 /*  HMAC Hashed Message Authentication (RFC 2104)*/
00390 /* */
00391 /*  hmac = H(K xor opad, H(K xor ipad, text))*/
00392 /* */
00393 
00394 /*  HMACInit --*/
00395 /* */
00396 /*     This is equivalent to the SHA1Init procedure except that a key is*/
00397 /*     added into the algorithm*/
00398 /* */
00399 ret  ::sha2::HMACInit (type K) {
00400 
00401     # Key K is adjusted to be 64 bytes long. If K is larger, then use
00402     # the SHA1 digest of K and pad this instead.
00403     set len [string length $K]
00404     if {$len > 64} {
00405         set tok [SHA256Init]
00406         SHA256Update $tok $K
00407         set K [SHA256Final $tok]
00408         set len [string length $K]
00409     }
00410     set pad [expr {64 - $len}]
00411     append K [string repeat \0 $pad]
00412 
00413     # Cacluate the padding buffers.
00414     set Ki {}
00415     set Ko {}
00416     binary scan $K i16 Ks
00417     foreach k $Ks {
00418         append Ki [binary format i [expr {$k ^ 0x36363636}]]
00419         append Ko [binary format i [expr {$k ^ 0x5c5c5c5c}]]
00420     }
00421 
00422     set tok [SHA256Init]
00423     SHA256Update $tok $Ki;                 # initialize with the inner pad
00424     
00425     # preserve the Ko value for the final stage.
00426     # FRINK: nocheck
00427     set [subst $tok](Ko) $Ko
00428 
00429     return $tok
00430 }
00431 
00432 /*  HMACUpdate --*/
00433 /* */
00434 /*     Identical to calling SHA256Update*/
00435 /* */
00436 ret  ::sha2::HMACUpdate (type token , type data) {
00437     SHA256Update $token $data
00438     return
00439 }
00440 
00441 /*  HMACFinal --*/
00442 /* */
00443 /*     This is equivalent to the SHA256Final procedure. The hash context is*/
00444 /*     closed and the binary representation of the hash result is returned.*/
00445 /* */
00446 ret  ::sha2::HMACFinal (type token) {
00447     upvar #0 $token state
00448 
00449     set tok [SHA256Init];                 # init the outer hashing function
00450     SHA256Update $tok $state(Ko);         # prepare with the outer pad.
00451     SHA256Update $tok [SHA256Final $token]; # hash the inner result
00452     return [SHA256Final $tok]
00453 }
00454 
00455 /*  -------------------------------------------------------------------------*/
00456 /*  Description:*/
00457 /*   This is the core SHA1 algorithm. It is a lot like the MD4 algorithm but*/
00458 /*   includes an extra round and a set of constant modifiers throughout.*/
00459 /* */
00460  ::sha2 = ::SHA256Transform_body {
00461     variable K
00462     upvar /* 0 $token state*/
00463 
00464     /*  FIPS 180-2: 6.2.2 SHA-256 Hash computation.*/
00465     binary scan $msg I* blocks
00466      blockLen =  [llength $blocks]
00467     for { i =  0} {$i < $blockLen} {incr i 16} {
00468          W =  [lrange $blocks $i [expr {$i+15}]]
00469 
00470         /*  FIPS 180-2: 6.2.2 (1) Prepare the message schedule*/
00471         /*  For t = 16 to 64 */
00472         /*    let Wt = (sigma1(Wt-2) + Wt-7 + sigma0(Wt-15) + Wt-16)*/
00473          t2 =   13
00474          t7 =    8
00475          t15 =   0
00476          t16 =  -1
00477         for { t =  16} {$t < 64} {incr t} {
00478             lappend W [expr {[sigma1 [lindex $W [incr t2]]] \
00479                                  + [lindex $W [incr t7]] \
00480                                  + [sigma0 [lindex $W [incr t15]]] \
00481                                  + [lindex $W [incr t16]]}]
00482         }
00483         
00484         /*  FIPS 180-2: 6.2.2 (2) Initialise the working variables*/
00485          A =  $state(A)
00486          B =  $state(B)
00487          C =  $state(C)
00488          D =  $state(D)
00489          E =  $state(E)
00490          F =  $state(F)
00491          G =  $state(G)
00492          H =  $state(H)
00493 
00494         /*  FIPS 180-2: 6.2.2 (3) Do permutation rounds*/
00495         /*  For t = 0 to 63 do*/
00496         /*    T1 = h + SIGMA1(e) + Ch(e,f,g) + Kt + Wt*/
00497         /*    T2 = SIGMA0(a) + Maj(a,b,c)*/
00498         /*    h = g; g = f;  f = e;  e = d + T1;  d = c;  c = b; b = a;*/
00499         /*    a = T1 + T2*/
00500         /* */
00501         for { t =  0} {$t < 64} {incr t} {
00502              T1 =  [expr {($H + [SIGMA1 $E] + [Ch $E $F $G] 
00503                           + [lindex $K $t] + [lindex $W $t]) & 0xffffffff}]
00504              T2 =  [expr {([SIGMA0 $A] + [Maj $A $B $C]) & 0xffffffff}]
00505              H =  $G
00506              G =  $F
00507              F =  $E
00508              E =  [expr {($D + $T1) & 0xffffffff}]
00509              D =  $C
00510              C =  $B
00511              B =  $A
00512              A =  [expr {($T1 + $T2) & 0xffffffff}]
00513         }
00514 
00515         /*  FIPS 180-2: 6.2.2 (4) Compute the intermediate hash*/
00516         incr state(A) $A
00517         incr state(B) $B
00518         incr state(C) $C
00519         incr state(D) $D
00520         incr state(E) $E
00521         incr state(F) $F
00522         incr state(G) $G
00523         incr state(H) $H
00524     }
00525 
00526     return
00527 }
00528 
00529 /*  -------------------------------------------------------------------------*/
00530 
00531 /*  FIPS 180-2: 4.1.2 equation 4.2*/
00532 ret  ::sha2::Ch (type x , type y , type z) {
00533     return [expr {($x & $y) ^ (~$x & $z)}]
00534 }
00535 
00536 /*  FIPS 180-2: 4.1.2 equation 4.3*/
00537 ret  ::sha2::Maj (type x , type y , type z) {
00538     return [expr {($x & $y) ^ ($x & $z) ^ ($y & $z)}]
00539 }
00540 
00541 /*  FIPS 180-2: 4.1.2 equation 4.4*/
00542 /*   (x >>> 2) ^ (x >>> 13) ^ (x >>> 22)*/
00543 ret  ::sha2::SIGMA0 (type x) {
00544     return [expr {[>>> $x 2] ^ [>>> $x 13] ^ [>>> $x 22]}]
00545 }
00546 
00547 /*  FIPS 180-2: 4.1.2 equation 4.5*/
00548 /*   (x >>> 6) ^ (x >>> 11) ^ (x >>> 25)*/
00549 ret  ::sha2::SIGMA1 (type x) {
00550     return [expr {[>>> $x 6] ^ [>>> $x 11] ^ [>>> $x 25]}]
00551 }
00552 
00553 /*  FIPS 180-2: 4.1.2 equation 4.6*/
00554 /*   s0 = (x >>> 7)  ^ (x >>> 18) ^ (x >> 3)*/
00555 ret  ::sha2::sigma0 (type x) {
00556     #return [expr {[>>> $x 7] ^ [>>> $x 18] ^ (($x >> 3) & 0x1fffffff)}]
00557     return [expr {((($x<<25) | (($x>>7) & (0x7FFFFFFF>>6))) \
00558                  ^ (($x<<14) | (($x>>18) & (0x7FFFFFFF>>17))) & 0xFFFFFFFF) \
00559                  ^ (($x>>3) & 0x1fffffff)}]
00560 }
00561 
00562 /*  FIPS 180-2: 4.1.2 equation 4.7*/
00563 /*   s1 = (x >>> 17) ^ (x >>> 19) ^ (x >> 10)*/
00564 ret  ::sha2::sigma1 (type x) {
00565     #return [expr {[>>> $x 17] ^ [>>> $x 19] ^ (($x >> 10) & 0x003fffff)}]
00566     return [expr {((($x<<15) | (($x>>17) & (0x7FFFFFFF>>16))) \
00567                  ^ (($x<<13) | (($x>>19) & (0x7FFFFFFF>>18))) & 0xFFFFFFFF) \
00568                  ^ (($x >> 10) & 0x003fffff)}]
00569 }
00570 
00571 /*  32bit rotate-right*/
00572 ret  ::sha2::>>> (type v , type n) {
00573     return [expr {(($v << (32 - $n)) \
00574                        | (($v >> $n) & (0x7FFFFFFF >> ($n - 1)))) \
00575                       & 0xFFFFFFFF}]
00576 }
00577 
00578 /*  32bit rotate-left*/
00579 ret  ::sha2::<<< (type v , type n) {
00580     return [expr {((($v << $n) \
00581                         | (($v >> (32 - $n)) \
00582                                & (0x7FFFFFFF >> (31 - $n))))) \
00583                       & 0xFFFFFFFF}]
00584 }
00585 
00586 /*  -------------------------------------------------------------------------*/
00587 /*  We speed up the SHA256Transform code while maintaining readability in the*/
00588 /*  source code by substituting inline for a number of functions.*/
00589 /*  The idea is to reduce the number of [expr] calls.*/
00590 
00591 /*  Inline the Ch function*/
00592 regsub -all -line \
00593     {\[Ch (\$[ABCDEFGH]) (\$[ABCDEFGH]) (\$[ABCDEFGH])\]} \
00594     $::sha2::SHA256Transform_body \
00595     {((\1 \& \2) ^ ((~\1) \& \3))} \
00596     ::sha2::SHA256Transform_body
00597 
00598 /*  Inline the Maj function*/
00599 regsub -all -line \
00600     {\[Maj (\$[ABCDEFGH]) (\$[ABCDEFGH]) (\$[ABCDEFGH])\]} \
00601     $::sha2::SHA256Transform_body \
00602     {((\1 \& \2) ^ (\1 \& \3) ^ (\2 \& \3))} \
00603     ::sha2::SHA256Transform_body
00604 
00605 
00606 /*  Inline the SIGMA0 function*/
00607 regsub -all -line \
00608     {\[SIGMA0 (\$[ABCDEFGH])\]} \
00609     $::sha2::SHA256Transform_body \
00610     {((((\1<<30) | ((\1>>2) \& (0x7FFFFFFF>>1))) \& 0xFFFFFFFF) \
00611           ^ (((\1<<19) | ((\1>>13) \& (0x7FFFFFFF>>12))) \& 0xFFFFFFFF) \
00612           ^ (((\1<<10) | ((\1>>22) \& (0x7FFFFFFF>>21))) \& 0xFFFFFFFF) \
00613           )} \
00614     ::sha2::SHA256Transform_body
00615 
00616 /*  Inline the SIGMA1 function*/
00617 regsub -all -line \
00618     {\[SIGMA1 (\$[ABCDEFGH])\]} \
00619     $::sha2::SHA256Transform_body \
00620     {((((\1<<26) | ((\1>>6) \& (0x7FFFFFFF>>5))) \& 0xFFFFFFFF) \
00621           ^ (((\1<<21) | ((\1>>11) \& (0x7FFFFFFF>>10))) \& 0xFFFFFFFF) \
00622           ^ (((\1<<7) | ((\1>>25) \& (0x7FFFFFFF>>24))) \& 0xFFFFFFFF) \
00623           )} \
00624     ::sha2::SHA256Transform_body
00625 
00626 ret  ::sha2::SHA256Transform (type token , type msg) $::sha2::SHA256Transform_body
00627 
00628 # -------------------------------------------------------------------------
00629 
00630 # Convert a integer value into a binary string in big-endian order.
00631 proc ::sha2::byte {n v} {expr {((0xFF << (8 * $n)) & $v) >> (8 * $n)}}
00632 ret  ::sha2::bytes (type v) { 
00633     #format %c%c%c%c [byte 3 $v] [byte 2 $v] [byte 1 $v] [byte 0 $v]
00634     format %c%c%c%c \
00635         [expr {((0xFF000000 & $v) >> 24) & 0xFF}] \
00636         [expr {(0xFF0000 & $v) >> 16}] \
00637         [expr {(0xFF00 & $v) >> 8}] \
00638         [expr {0xFF & $v}]
00639 }
00640 
00641 /*  -------------------------------------------------------------------------*/
00642 
00643 ret  ::sha2::Hex (type data) {
00644     binary scan $data H* result
00645     return $result
00646 }
00647 
00648 /*  -------------------------------------------------------------------------*/
00649 
00650 /*  Description:*/
00651 /*   Pop the nth element off a list. Used in options processing.*/
00652 /* */
00653 ret  ::sha2::Pop (type varname , optional nth =0) {
00654     upvar $varname args
00655     set r [lindex $args $nth]
00656     set args [lreplace $args $nth $nth]
00657     return $r
00658 }
00659 
00660 /*  -------------------------------------------------------------------------*/
00661 
00662 /*  fileevent handler for chunked file hashing.*/
00663 /* */
00664 ret  ::sha2::Chunk (type token , type channel , optional chunksize =4096) {
00665     upvar #0 $token state
00666     
00667     if {[eof $channel]} {
00668         fileevent $channel readable {}
00669         set state(reading) 0
00670     }
00671         
00672     SHA256Update $token [read $channel $chunksize]
00673 }
00674 
00675 /*  -------------------------------------------------------------------------*/
00676 
00677 ret  ::sha2::_sha256 (type ver , type args) {
00678     array set opts {-hex 0 -filename {} -channel {} -chunksize 4096}
00679     if {[llength $args] == 1} {
00680         set opts(-hex) 1
00681     } else {
00682         while {[string match -* [set option [lindex $args 0]]]} {
00683             switch -glob -- $option {
00684                 -hex       { set opts(-hex) 1 }
00685                 -bin       { set opts(-hex) 0 }
00686                 -file*     { set opts(-filename) [Pop args 1] }
00687                 -channel   { set opts(-channel) [Pop args 1] }
00688                 -chunksize { set opts(-chunksize) [Pop args 1] }
00689                 default {
00690                     if {[llength $args] == 1} { break }
00691                     if {[string compare $option "--"] == 0} { Pop args; break }
00692                     set err [join [lsort [concat -bin [array names opts]]] ", "]
00693                     return -code error "bad option $option:\
00694                     must be one of $err"
00695                 }
00696             }
00697             Pop args
00698         }
00699     }
00700 
00701     if {$opts(-filename) != {}} {
00702         set opts(-channel) [open $opts(-filename) r]
00703         fconfigure $opts(-channel) -translation binary
00704     }
00705 
00706     if {$opts(-channel) == {}} {
00707 
00708         if {[llength $args] != 1} {
00709             return -code error "wrong # args: should be\
00710                 \"[namespace current]::sha$ver ?-hex|-bin? -filename file\
00711                 | -channel channel | string\""
00712         }
00713         set tok [SHA${ver}Init]
00714         SHA${ver}Update $tok [lindex $args 0]
00715         set r [SHA${ver}Final $tok]
00716 
00717     } else {
00718 
00719         set tok [SHA${ver}Init]
00720         # FRINK: nocheck
00721         set [subst $tok](reading) 1
00722         fileevent $opts(-channel) readable \
00723             [list [namespace origin Chunk] \
00724                  $tok $opts(-channel) $opts(-chunksize)]
00725         # FRINK: nocheck
00726         vwait [subst $tok](reading)
00727         set r [SHA${ver}Final $tok]
00728 
00729         # If we opened the channel - we should close it too.
00730         if {$opts(-filename) != {}} {
00731             close $opts(-channel)
00732         }
00733     }
00734     
00735     if {$opts(-hex)} {
00736         set r [Hex $r]
00737     }
00738     return $r
00739 }
00740 
00741 interp alias {} ::sha2::sha256 {} ::sha2::_sha256 256
00742 interp alias {} ::sha2::sha224 {} ::sha2::_sha256 224
00743 
00744 /*  -------------------------------------------------------------------------*/
00745 
00746 ret  ::sha2::hmac (type args) {
00747     array set opts {-hex 1 -filename {} -channel {} -chunksize 4096}
00748     if {[llength $args] != 2} {
00749         while {[string match -* [set option [lindex $args 0]]]} {
00750             switch -glob -- $option {
00751                 -key       { set opts(-key) [Pop args 1] }
00752                 -hex       { set opts(-hex) 1 }
00753                 -bin       { set opts(-hex) 0 }
00754                 -file*     { set opts(-filename) [Pop args 1] }
00755                 -channel   { set opts(-channel) [Pop args 1] }
00756                 -chunksize { set opts(-chunksize) [Pop args 1] }
00757                 default {
00758                     if {[llength $args] == 1} { break }
00759                     if {[string compare $option "--"] == 0} { Pop args; break }
00760                     set err [join [lsort [array names opts]] ", "]
00761                     return -code error "bad option $option:\
00762                     must be one of $err"
00763                 }
00764             }
00765             Pop args
00766         }
00767     }
00768 
00769     if {[llength $args] == 2} {
00770         set opts(-key) [Pop args]
00771     }
00772 
00773     if {![info exists opts(-key)]} {
00774         return -code error "wrong # args:\
00775             should be \"hmac ?-hex? -key key -filename file | string\""
00776     }
00777 
00778     if {$opts(-filename) != {}} {
00779         set opts(-channel) [open $opts(-filename) r]
00780         fconfigure $opts(-channel) -translation binary
00781     }
00782 
00783     if {$opts(-channel) == {}} {
00784 
00785         if {[llength $args] != 1} {
00786             return -code error "wrong # args:\
00787                 should be \"hmac ?-hex? -key key -filename file | string\""
00788         }
00789         set tok [HMACInit $opts(-key)]
00790         HMACUpdate $tok [lindex $args 0]
00791         set r [HMACFinal $tok]
00792 
00793     } else {
00794 
00795         set tok [HMACInit $opts(-key)]
00796         # FRINK: nocheck
00797         set [subst $tok](reading) 1
00798         fileevent $opts(-channel) readable \
00799             [list [namespace origin Chunk] \
00800                  $tok $opts(-channel) $opts(-chunksize)]
00801         # FRINK: nocheck
00802         vwait [subst $tok](reading)
00803         set r [HMACFinal $tok]
00804 
00805         # If we opened the channel - we should close it too.
00806         if {$opts(-filename) != {}} {
00807             close $opts(-channel)
00808         }
00809     }
00810     
00811     if {$opts(-hex)} {
00812         set r [Hex $r]
00813     }
00814     return $r
00815 }
00816 
00817 /*  -------------------------------------------------------------------------*/
00818 
00819 /*  Try and load a compiled extension to help.*/
00820 namespace ::sha2 {
00821     variable e {}
00822     foreach e [KnownImplementations] {
00823     if {[LoadAccelerator $e]} {
00824         SwitchTo $e
00825         break
00826     }
00827     }
00828     un e = 
00829 }
00830 
00831 package provide sha256 $::sha2::version
00832 
00833 /*  -------------------------------------------------------------------------*/
00834 /*  Local Variables:*/
00835 /*    mode: tcl*/
00836 /*    indent-tabs-mode: nil*/
00837 /*  End:*/
00838 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1