des.tcl

Go to the documentation of this file.
00001 /*  des.tcl - Copyright (C) 2005 Pat Thoyts <patthoyts@users.sourceforge.net>*/
00002 /* */
00003 /*  Tcllib wrapper for the DES package. This wrapper provides the same */
00004 /*  programming API that tcllib uses for AES and Blowfish. We require a*/
00005 /*  DES implementation and use either TclDES or TclDESjr to get DES */
00006 /*  and/or 3DES*/
00007 /* */
00008 /*  -------------------------------------------------------------------------*/
00009 /*  See the file "license.terms" for information on usage and redistribution*/
00010 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
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 /*  Backwards compatability - here we re-implement the DES 0.8 procs using the*/
00069 /*  current implementation.*/
00070 /* */
00071 /*  -- DO NOT USE THESE FUNCTIONS IN NEW CODE--*/
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 /*  Local variables:*/
00271 /*    mode: tcl*/
00272 /*    indent-tabs-mode: nil*/
00273 /*  End:*/
00274 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1