Updated 2016-02-26 00:27:41 by mistachkin

PBKDF2 (Password-Based Key Derivation Function 2) is, according to Wikipedia [1], a "key derivation function that is part of RSA Laboratories' Public-Key Cryptography Standards (PKCS) series, specifically PKCS #5 v2.0, also published as Internet Engineering Task Force's RFC 2898." Basically, using passwords as cryptographic keys isn't considered good enough, so "Password-Based Key Derivation" is used to turn your password into a cryptographic key that is good enough.

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

JJM 2016-02-25: It seems like an implementation of this algorithm should be included in tcllib?
 package require sha256

 namespace eval ::pbkdf2 {
         variable version 1.0.5
 }

 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 [expr {$xsor ^ [debin [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
 }

 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 331 seconds for me.