home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / sha1 / sha1.tcl < prev   
Encoding:
Text File  |  2001-08-17  |  8.6 KB  |  332 lines

  1. ##################################################
  2. #
  3. # sha1.tcl - SHA1 in Tcl
  4. # Author: Don Libes <libes@nist.gov>, May 2001
  5. # Version 1.0.0
  6. #
  7. # SHA1 defined by FIPS 180-1, "The SHA1 Message-Digest Algorithm",
  8. #          http://www.itl.nist.gov/fipspubs/fip180-1.htm
  9. # HMAC defined by RFC 2104, "Keyed-Hashing for Message Authentication"
  10. #
  11. # Some of the comments below come right out of FIPS 180-1; That's why
  12. # they have such peculiar numbers.  In addition, I have retained
  13. # original syntax, etc. from the FIPS.  All remaining bugs are mine.
  14. #
  15. # HMAC implementation by D. J. Hagberg <dhagberg@millibits.com> and
  16. # is based on C code in FIPS 2104.
  17. #
  18. # For more info, see: http://expect.nist.gov/sha1pure
  19. #
  20. # - Don
  21. ##################################################
  22.  
  23. ### Code speedups by Donal Fellows <fellowsd@cs.man.ac.uk> who may well
  24. ### have added some extra bugs of his own...  :^)
  25.  
  26. ### Changed the code to use Trf if this package is present on the
  27. ### system requiring the sha1 package. Analogous to md5.
  28.  
  29. package require Tcl 8.2
  30. namespace eval ::sha1 {
  31. }
  32.  
  33. if {![catch {package require Trf 2.0}]} {
  34.     # Trf is available, so implement the functionality provided here
  35.     # in terms of calls to Trf for speed.
  36.  
  37.     proc ::sha1::sha1 {msg} {
  38.     string tolower [::hex -mode encode [::sha1 $msg]]
  39.     }
  40.  
  41.     # hmac: hash for message authentication
  42.  
  43.     # SHA1 of Trf and SHA1 as defined by this package have slightly
  44.     # different results. Trf returns the digest in binary, here we get
  45.     # it as hex-string. In the computation of the HMAC the latter
  46.     # requires back conversion into binary in some places. With Trf we
  47.     # can use omit these. (Not all, the first place must not the changed,
  48.     # see [x]
  49.  
  50.     proc ::sha1::hmac {key text} {
  51.     # if key is longer than 64 bytes, reset it to SHA1(key).  If shorter, 
  52.     # pad it out with null (\x00) chars.
  53.     set keyLen [string length $key]
  54.     if {$keyLen > 64} {
  55.         set key [binary format H32 [sha1 $key]]
  56.         # [x] set key [::sha1 $key]
  57.         set keyLen [string length $key]
  58.     }
  59.     
  60.     # ensure the key is padded out to 64 chars with nulls.
  61.     set padLen [expr {64 - $keyLen}]
  62.     append key [binary format "a$padLen" {}]
  63.  
  64.     # Split apart the key into a list of 16 little-endian words
  65.     binary scan $key i16 blocks
  66.  
  67.     # XOR key with ipad and opad values
  68.     set k_ipad {}
  69.     set k_opad {}
  70.     foreach i $blocks {
  71.         append k_ipad [binary format i [expr {$i ^ 0x36363636}]]
  72.         append k_opad [binary format i [expr {$i ^ 0x5c5c5c5c}]]
  73.     }
  74.     
  75.     # Perform inner sha1, appending its results to the outer key
  76.     append k_ipad $text
  77.     #append k_opad [binary format H* [sha1 $k_ipad]]
  78.     append k_opad [::sha1 $k_ipad]
  79.  
  80.     # Perform outer sha1
  81.     #sha1 $k_opad
  82.     string tolower [::hex -mode encode [::sha1 $k_opad]]
  83.     }
  84.  
  85. } else {
  86.     # Without Trf use the all-tcl implementation by Don Libes.
  87.  
  88.     namespace eval sha1 {
  89.     variable K
  90.  
  91.     proc initK {} {
  92.         variable K {}
  93.         foreach t {
  94.         0x5A827999
  95.         0x6ED9EBA1
  96.         0x8F1BBCDC
  97.         0xCA62C1D6
  98.         } {
  99.         for {set i 0} {$i < 20} {incr i} {
  100.             lappend K $t
  101.         }
  102.         }
  103.     }
  104.     initK
  105.     }
  106.  
  107.     # test sha1
  108.     #
  109.     # This proc is not necessary during runtime and may be omitted if you
  110.     # are simply inserting this file into a production program.
  111.     #
  112.     proc sha1::test {} {
  113.     foreach {msg expected} {
  114.         "abc"
  115.         "a9993e364706816aba3e25717850c26c9cd0d89d"
  116.         "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
  117.         "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
  118.         "[string repeat a 1000000]"
  119.         "34aa973cd4c4daa4f61eeb2bdbad27316534016f"
  120.     } {
  121.         puts "testing: sha1 \"$msg\""
  122.         set msg [subst $msg]
  123.         set msgLen [string length $msg]
  124.         if {$msgLen > 10000} {
  125.         puts "warning: msg length = $msgLen; this may take a while . . ."
  126.         }
  127.         set computed [sha1 $msg]
  128.         puts "expected: $expected"
  129.         puts "computed: $computed"
  130.         if {0 != [string compare $computed $expected]} {
  131.         puts "FAILED"
  132.         } else {
  133.         puts "SUCCEEDED"
  134.         }
  135.     }
  136.     }
  137.  
  138.     # time sha1
  139.     #
  140.     # This proc is not necessary during runtime and may be omitted if you
  141.     # are simply inserting this file into a production program.
  142.     #
  143.     proc sha1::time {} {
  144.     foreach len {10 50 100 500 1000 5000 10000} {
  145.         set time [::time {sha1 [format %$len.0s ""]} 10]
  146.         regexp -- "\[0-9]*" $time msec
  147.         puts "input length $len: [expr {$msec/1000}] milliseconds per interation"
  148.     }
  149.     }
  150.  
  151.     proc sha1::sha1 {msg} {
  152.     variable K
  153.  
  154.     #
  155.     # 4. MESSAGE PADDING
  156.     #
  157.  
  158.     # pad to 512 bits (512/8 = 64 bytes)
  159.  
  160.     set msgLen [string length $msg]
  161.  
  162.     # last 8 bytes are reserved for msgLen
  163.     # plus 1 for "1"
  164.  
  165.     set padLen [expr {56 - $msgLen%64}]
  166.     if {$msgLen % 64 >= 56} {
  167.         incr padLen 64
  168.     }
  169.  
  170.     # 4a. and b. append single 1b followed by 0b's
  171.     append msg [binary format "a$padLen" \200]
  172.  
  173.     # 4c. append 64-bit length
  174.     # Our implementation obviously limits string length to 32bits.
  175.     append msg \0\0\0\0[binary format "I" [expr {8*$msgLen}]]
  176.     
  177.     #
  178.     # 7. COMPUTING THE MESSAGE DIGEST
  179.     #
  180.  
  181.     # initial H buffer
  182.  
  183.     set H0 0x67452301
  184.     set H1 0xEFCDAB89
  185.     set H2 0x98BADCFE
  186.     set H3 0x10325476
  187.     set H4 0xC3D2E1F0
  188.  
  189.     #
  190.     # process message in 16-word blocks (64-byte blocks)
  191.     #
  192.  
  193.     # convert message to array of 32-bit integers
  194.     # each block of 16-words is stored in M($i,0-16)
  195.  
  196.     binary scan $msg I* words
  197.     set blockLen [llength $words]
  198.  
  199.     for {set i 0} {$i < $blockLen} {incr i 16} {
  200.         # 7a. Divide M[i] into 16 words W[0], W[1], ...
  201.         set W [lrange $words $i [expr {$i+15}]]
  202.  
  203.         # 7b. For t = 16 to 79 let W[t] = ....
  204.         set t   16
  205.         set t3  12
  206.         set t8   7
  207.         set t14  1
  208.         set t16 -1
  209.         for {} {$t < 80} {incr t} {
  210.         set x [expr {[lindex $W [incr t3]] ^ [lindex $W [incr t8]] ^ \
  211.             [lindex $W [incr t14]] ^ [lindex $W [incr t16]]}]
  212.         lappend W [expr {($x << 1) | (($x >> 31) & 1)}]
  213.         }
  214.  
  215.         # 7c. Let A = H[0] ....
  216.         set A $H0
  217.         set B $H1
  218.         set C $H2
  219.         set D $H3
  220.         set E $H4
  221.  
  222.         # 7d. For t = 0 to 79 do
  223.         for {set t 0} {$t < 20} {incr t} {
  224.         set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \
  225.             (($B & $C) | ((~$B) & $D)) \
  226.             + $E + [lindex $W $t] + [lindex $K $t]}]
  227.         set E $D
  228.         set D $C
  229.         set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}]
  230.         set B $A
  231.         set A $TEMP
  232.         }
  233.         for {} {$t<40} {incr t} {
  234.         set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \
  235.             ($B ^ $C ^ $D) \
  236.             + $E + [lindex $W $t] + [lindex $K $t]}]
  237.         set E $D
  238.         set D $C
  239.         set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}]
  240.         set B $A
  241.         set A $TEMP
  242.         }
  243.         for {} {$t<60} {incr t} {
  244.         set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \
  245.             (($B & $C) | ($B & $D) | ($C & $D)) \
  246.             + $E + [lindex $W $t] + [lindex $K $t]}]
  247.         set E $D
  248.         set D $C
  249.         set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}]
  250.         set B $A
  251.         set A $TEMP
  252.         }
  253.         for {} {$t<80} {incr t} {
  254.         set TEMP [expr {(($A << 5) | (($A >> 27) & 0x1f)) + \
  255.             ($B ^ $C ^ $D) \
  256.             + $E + [lindex $W $t] + [lindex $K $t]}]
  257.         set E $D
  258.         set D $C
  259.         set C [expr {($B << 30) | (($B >> 2) & 0x3fffffff)}]
  260.         set B $A
  261.         set A $TEMP
  262.         }
  263.  
  264.         incr H0 $A
  265.         incr H1 $B
  266.         incr H2 $C
  267.         incr H3 $D
  268.         incr H4 $E
  269.     }
  270.  
  271.     return [format %0.8x%0.8x%0.8x%0.8x%0.8x $H0 $H1 $H2 $H3 $H4]
  272.     }
  273.  
  274.     ### These procedures are either inlined or replaced with a normal [format]!
  275.     #
  276.     #proc sha1::f {t B C D} {
  277.     #    switch [expr {$t/20}] {
  278.     #     0 {
  279.     #         expr {($B & $C) | ((~$B) & $D)}
  280.     #     } 1 - 3 {
  281.     #         expr {$B ^ $C ^ $D}
  282.     #     } 2 {
  283.     #         expr {($B & $C) | ($B & $D) | ($C & $D)}
  284.     #     }
  285.     #    }
  286.     #}
  287.     #
  288.     #proc sha1::byte0 {i} {expr {0xff & $i}}
  289.     #proc sha1::byte1 {i} {expr {(0xff00 & $i) >> 8}}
  290.     #proc sha1::byte2 {i} {expr {(0xff0000 & $i) >> 16}}
  291.     #proc sha1::byte3 {i} {expr {((0xff000000 & $i) >> 24) & 0xff}}
  292.     #
  293.     #proc sha1::bytes {i} {
  294.     #    format %0.2x%0.2x%0.2x%0.2x [byte3 $i] [byte2 $i] [byte1 $i] [byte0 $i]
  295.     #}
  296.  
  297.     # hmac: hash for message authentication
  298.     proc sha1::hmac {key text} {
  299.     # if key is longer than 64 bytes, reset it to SHA1(key).  If shorter, 
  300.     # pad it out with null (\x00) chars.
  301.     set keyLen [string length $key]
  302.     if {$keyLen > 64} {
  303.         set key [binary format H32 [sha1 $key]]
  304.         set keyLen [string length $key]
  305.     }
  306.  
  307.     # ensure the key is padded out to 64 chars with nulls.
  308.     set padLen [expr {64 - $keyLen}]
  309.     append key [binary format "a$padLen" {}]
  310.  
  311.     # Split apart the key into a list of 16 little-endian words
  312.     binary scan $key i16 blocks
  313.  
  314.     # XOR key with ipad and opad values
  315.     set k_ipad {}
  316.     set k_opad {}
  317.     foreach i $blocks {
  318.         append k_ipad [binary format i [expr {$i ^ 0x36363636}]]
  319.         append k_opad [binary format i [expr {$i ^ 0x5c5c5c5c}]]
  320.     }
  321.     
  322.     # Perform inner sha1, appending its results to the outer key
  323.     append k_ipad $text
  324.     append k_opad [binary format H* [sha1 $k_ipad]]
  325.  
  326.     # Perform outer sha1
  327.     sha1 $k_opad
  328.     }
  329. }
  330.  
  331. package provide sha1 1.0
  332.