sha256.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
00022
00023
00024
00025
00026
00027 package require Tcl 8.2;
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
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
00072
00073
00074
00075
00076
00077
00078
00079
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
00105
00106
00107
00108
00109
00110
00111
00112
00113
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
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
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
00149
00150
00151
00152
00153
00154
00155
00156
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
00209
00210
00211
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
00245
00246
00247
00248
00249
00250
00251
00252
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
00281
00282
00283
00284
00285
00286
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
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
00390
00391
00392
00393
00394
00395
00396
00397
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
00433
00434
00435
00436 ret ::sha2::HMACUpdate (type token , type data) {
00437 SHA256Update $token $data
00438 return
00439 }
00440
00441
00442
00443
00444
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
00457
00458
00459
00460 ::sha2 = ::SHA256Transform_body {
00461 variable K
00462 upvar
00463
00464
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
00471
00472
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
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
00495
00496
00497
00498
00499
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
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
00532 ret ::sha2::Ch (type x , type y , type z) {
00533 return [expr {($x & $y) ^ (~$x & $z)}]
00534 }
00535
00536
00537 ret ::sha2::Maj (type x , type y , type z) {
00538 return [expr {($x & $y) ^ ($x & $z) ^ ($y & $z)}]
00539 }
00540
00541
00542
00543 ret ::sha2::SIGMA0 (type x) {
00544 return [expr {[>>> $x 2] ^ [>>> $x 13] ^ [>>> $x 22]}]
00545 }
00546
00547
00548
00549 ret ::sha2::SIGMA1 (type x) {
00550 return [expr {[>>> $x 6] ^ [>>> $x 11] ^ [>>> $x 25]}]
00551 }
00552
00553
00554
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
00563
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
00572 ret ::sha2::>>> (type v , type n) {
00573 return [expr {(($v << (32 - $n)) \
00574 | (($v >> $n) & (0x7FFFFFFF >> ($n - 1)))) \
00575 & 0xFFFFFFFF}]
00576 }
00577
00578
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
00588
00589
00590
00591
00592 regsub -all -line \
00593 {\[Ch (\$[ABCDEFGH]) (\$[ABCDEFGH]) (\$[ABCDEFGH])\]} \
00594 $::sha2::SHA256Transform_body \
00595 {((\1 \& \2) ^ ((~\1) \& \3))} \
00596 ::sha2::SHA256Transform_body
00597
00598
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
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
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
00651
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
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
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
00835
00836
00837
00838