des.tcl
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 package require Tcl 8.2
00014
00015 if {[catch {package require tclDES 1.0.0}]} {
00016 package require tclDESjr 1.0.0
00017 }
00018
00019 namespace DES {
00020 variable version 1.1.0
00021 variable rcsid {$Id: des.tcl,v 1.14 2007/08/20 19:58:54 andreas_kupries Exp $}
00022 variable uid ; if {![info exists uid]} { uid = 0 }
00023 }
00024
00025 ret ::DES::Init (type mode , type key , type iv , optional weak =0) {
00026 variable uid
00027 set Key [namespace current]::[incr uid]
00028 upvar #0 $Key state
00029 if {[string length $key] % 8 != 0} {
00030 return -code error "invalid key length of\
00031 [expr {[string length $key] * 8}] bits:\
00032 DES requires 64 bit keys (56 bits plus parity bits)"
00033 }
00034 array set state [list M $mode I $iv K [des::keyset create $key $weak]]
00035 return $Key
00036 }
00037
00038 ret ::DES::Encrypt (type Key , type data) {
00039 upvar #0 $Key state
00040 set iv $state(I)
00041 set r [des::encrypt $state(K) $data $state(M) iv]
00042 set state(I) $iv
00043 return $r
00044 }
00045
00046 ret ::DES::Decrypt (type Key , type data) {
00047 upvar #0 $Key state
00048 set iv $state(I)
00049 set r [des::decrypt $state(K) $data $state(M) iv]
00050 set state(I) $iv
00051 return $r
00052 }
00053
00054 ret ::DES::Reset (type Key , type iv) {
00055 upvar #0 $Key state
00056 set state(I) $iv
00057 return
00058 }
00059
00060 ret ::DES::Final (type Key) {
00061 upvar #0 $Key state
00062 des::keyset destroy $state(K)
00063 # FRINK: nocheck
00064 unset $Key
00065 }
00066
00067
00068
00069
00070
00071
00072
00073 ret ::DES::GetKey (type mode , type keydata , type keyvarname) {
00074 set weak 1
00075 switch -exact -- $mode {
00076 -encrypt { set dir encrypt ; set vnc 0 }
00077 -encryptVNC { set dir encrypt ; set vnc 1 }
00078 -decrypt { set dir decrypt ; set vnc 0 }
00079 -decryptVNC { set dir decrypt ; set vnc 1 }
00080 default {
00081 return -code error "invalid mode \"$mode\":\
00082 must be one of -encrypt, -decrypt, -encryptVNC or -decryptVNC"
00083 }
00084 }
00085 if {$vnc} { set keydata [ReverseBytes $keydata] }
00086 upvar $keyvarname Key
00087 set Key [Init ecb $keydata [string repeat \0 8] $weak]
00088 upvar $Key state
00089 array set state [list dir $dir]
00090 return
00091 }
00092
00093 ret ::DES::DesBlock (type data , type keyvarname) {
00094 upvar $keyvarname Key
00095 upvar #0 $Key state
00096 if {[string equal $state(dir) "encrypt"]} {
00097 set r [Encrypt $Key $data]
00098 } else {
00099 set r [Decrypt $Key $data]
00100 }
00101 return $r
00102 }
00103
00104 ret ::DES::ReverseBytes (type data) {
00105 binary scan $data b* bin
00106 return [binary format B* $bin]
00107 }
00108
00109
00110
00111 ret ::DES::SetOneOf (type lst , type item) {
00112 set ndx [lsearch -glob $lst "${item}*"]
00113 if {$ndx == -1} {
00114 set err [join $lst ", "]
00115 return -code error "invalid mode \"$item\": must be one of $err"
00116 }
00117 return [lindex $lst $ndx]
00118 }
00119
00120 ret ::DES::CheckSize (type what , type size , type thing) {
00121 if {[string length $thing] != $size} {
00122 return -code error "invalid value for $what: must be $size bytes long"
00123 }
00124 return $thing
00125 }
00126
00127 ret ::DES::Pad (type data , type blocksize , optional fill =\0) {
00128 set len [string length $data]
00129 if {$len == 0} {
00130 set data [string repeat $fill $blocksize]
00131 } elseif {($len % $blocksize) != 0} {
00132 set pad [expr {$blocksize - ($len % $blocksize)}]
00133 append data [string repeat $fill $pad]
00134 }
00135 return $data
00136 }
00137
00138 ret ::DES::Pop (type varname , optional nth =0) {
00139 upvar $varname args
00140 set r [lindex $args $nth]
00141 set args [lreplace $args $nth $nth]
00142 return $r
00143 }
00144
00145 ret ::DES::Hex (type data) {
00146 binary scan $data H* r
00147 return $r
00148 }
00149
00150 ret ::DES::des (type args) {
00151 array set opts {
00152 -dir encrypt -mode cbc -key {} -in {} -out {} -chunksize 4096 -hex 0 -weak 0 old 0
00153 }
00154 set blocksize 8
00155 set opts(-iv) [string repeat \0 $blocksize]
00156 set modes {ecb cbc cfb ofb}
00157 set dirs {encrypt decrypt}
00158 while {[string match -* [set option [lindex $args 0]]]} {
00159 switch -exact -- $option {
00160 -mode {
00161 set M [Pop args 1]
00162 if {[catch {set mode [SetOneOf $modes $M]} err]} {
00163 if {[catch {SetOneOf {encode decode} $M}]} {
00164 return -code error $err
00165 } else {
00166 # someone is using the old interface, therefore ecb
00167 set mode ecb
00168 set opts(-weak) 1
00169 set opts(old) 1
00170 set opts(-dir) [expr {[string match en* $M] ? "encrypt" : "decrypt"}]
00171 }
00172 }
00173 set opts(-mode) $mode
00174 }
00175 -dir { set opts(-dir) [SetOneOf $dirs [Pop args 1]] }
00176 -iv { set opts(-iv) [Pop args 1] }
00177 -key { set opts(-key) [Pop args 1] }
00178 -in { set opts(-in) [Pop args 1] }
00179 -out { set opts(-out) [Pop args 1] }
00180 -chunksize { set opts(-chunksize) [Pop args 1] }
00181 -hex { set opts(-hex) 1 }
00182 -weak { set opts(-weak) 1 }
00183 -- { Pop args ; break }
00184 default {
00185 set err [join [lsort [array names opts -*]] ", "]
00186 return -code error "bad option \"$option\":\
00187 must be one of $err"
00188 }
00189 }
00190 Pop args
00191 }
00192
00193 if {$opts(-key) == {}} {
00194 return -code error "no key provided: the -key option is required"
00195 }
00196
00197 # pad the key if backwards compat required
00198 if {$opts(old)} {
00199 set pad [expr {8 - ([string length $opts(-key)] % 8)}]
00200 if {$pad != 8} {
00201 append opts(-key) [string repeat \0 $pad]
00202 }
00203 }
00204
00205 set r {}
00206 if {$opts(-in) == {}} {
00207
00208 if {[llength $args] != 1} {
00209 return -code error "wrong \# args:\
00210 should be \"des ?options...? -key keydata plaintext\""
00211 }
00212
00213 set data [Pad [lindex $args 0] $blocksize]
00214 set Key [Init $opts(-mode) $opts(-key) $opts(-iv) $opts(-weak)]
00215 if {[string equal $opts(-dir) "encrypt"]} {
00216 set r [Encrypt $Key $data]
00217 } else {
00218 set r [Decrypt $Key $data]
00219 }
00220
00221 if {$opts(-out) != {}} {
00222 puts -nonewline $opts(-out) $r
00223 set r {}
00224 }
00225 Final $Key
00226
00227 } else {
00228
00229 if {[llength $args] != 0} {
00230 return -code error "wrong \# args:\
00231 should be \"des ?options...? -key keydata -in channel\""
00232 }
00233
00234 set Key [Init $opts(-mode) $opts(-key) $opts(-iv) $opts(-weak)]
00235 upvar $Key state
00236 set state(reading) 1
00237 if {[string equal $opts(-dir) "encrypt"]} {
00238 set state(cmd) Encrypt
00239 } else {
00240 set state(cmd) Decrypt
00241 }
00242 set state(output) ""
00243 fileevent $opts(-in) readable \
00244 [list [namespace origin Chunk] \
00245 $Key $opts(-in) $opts(-out) $opts(-chunksize)]
00246 if {[info commands ::tkwait] != {}} {
00247 tkwait variable [subst $Key](reading)
00248 } else {
00249 vwait [subst $Key](reading)
00250 }
00251 if {$opts(-out) == {}} {
00252 set r $state(output)
00253 }
00254 Final $Key
00255
00256 }
00257
00258 if {$opts(-hex)} {
00259 set r [Hex $r]
00260 }
00261 return $r
00262 }
00263
00264
00265
00266 package provide des $DES::version
00267
00268
00269
00270
00271
00272
00273
00274