Version 1 of PBKDF2

Updated 2012-11-24 19:37:10 by RLE

Since Google gave no usable hits regarding this topic.. here we go: pure Tcl PBKDF2 with SHA-256 (with timing capability)!

 package require sha256 ;# Courtesy of TCLLIB

 namespace eval ::pbkdf2 {
         variable version 1.0.4
 }

 proc ::pbkdf2::pbkdf2 {password salt count dklen} {
         set hlen 32 ;# 256 bits -> 32 bytes
         if {$dklen > (2**32-1)*$hlen} { error "derived key too long" }

         set l [expr {int(ceil(double($dklen)/$hlen))}]
 #        set r [expr {$dklen-($l-1)*$hlen}]

 #set t1 [clock milliseconds]

         set dkl [list]
         for {set i 1} {$i <= $l} {incr i} {
                 set xsor [debin [set salty [::sha2::hmac -bin -key $password "$salt[binary format I $i]"]]]
                 for {set j 1} {$j < $count} {incr j} { set xsor [xsor $xsor [set salty [::sha2::hmac -bin -key $password $salty]]] }
                 lappend dkl $xsor
         }

 #set t2 [clock milliseconds]
 #puts "[expr {($t2-$t1)/1000.0}] s"

         set dk [list]
         foreach dkp $dkl {
                 set dkhl [list]
                 while {$dkp > 0} {
                         lappend dkhl [binary format Iu* [expr {$dkp & 0xFFFFFFFF}]]
                         set dkp [expr {$dkp >> 32}]
                 }
                 lappend dk [join [lreverse $dkhl] ""]
         }

 #        binary scan [string range [join $dk ""] 0 [incr dklen -1]] H* r
 #        return $r
         return [string range [join $dk ""] 0 [incr dklen -1]]
 }

 proc ::pbkdf2::debin {vat} {
         binary scan $vat Iu* rl
         return [expr {([lindex $rl 0] << 224) + ([lindex $rl 1] << 192) + ([lindex $rl 2] << 160) + ([lindex $rl 3] << 128) + ([lindex $rl 4] << 96) + ([lindex $rl 5] << 64) + ([lindex $rl 6] << 32) + [lindex $rl 7]}]
 #        set sh 224
 #        set rs 0
 #        foreach r $rl {
 #                incr rs [expr {$r << $sh}]
 #                incr sh -32
 #        }
 #        return $rs
 }

 proc ::pbkdf2::xsor {var par} { return [expr {$var ^ [debin $par]}] }

 package provide pbkdf2 $::pbkdf2::version

Feel free to find use for it. And anything (excluding Critcl and friends) making it run faster is highly appreciated. "Password NaCl 80000 64" took 336 seconds for me.