RC4 is a symmetric stream cipher developed by Ron Rivest of RSA Data Security Inc. The algorithm was a trade secret of RSA but was reverse engineered and published to the internet in 1994. The algorithm is a pseudo-random number generator with the output of the PRNG being xored with the plaintext stream. Decryption is done by feeding the ciphertext as input with the same key. Here is a pure Tcl version. e.g: set src [open $filename r] set dst [open ${filename}.rc4 w] rc4::rc4 -key Secret -in $src -out $dst close $src close $dst or just set crypt [rc4::rc4 -key Secret "Hello, World!"] ---- # rc4.tcl - Copyright (C) 2004 Pat Thoyts # # This could probably do with some optimization. # # $Id: 11888,v 1.1 2004-07-01 06:01:06 jcw Exp $ package require Tcl 8.2 namespace eval ::rc4 { variable version 1.0.0 variable rcsid {$Id: 11888,v 1.1 2004-07-01 06:01:06 jcw Exp $} namespace export rc4 variable uid if {![info exists uid]} { set uid 0 } } # RC4Init - create and initialize the RC4 state. # proc ::rc4::RC4Init {keystr} { variable uid binary scan $keystr c* key set keylen [llength $key] set Key [namespace current]::key[incr uid] variable $Key upvar #0 $Key state catch {unset state} set state(x) 0 set state(y) 0 for {set cn 0} {$cn < 256} {incr cn} { set state(s,$cn) $cn } set i 0 set j 0 for {set cn 0} {$cn < 256} {incr cn} { set j [expr {([lindex $key $i] + $state(s,$cn) + $j) % 256}] set t $state(s,$cn) set state(s,$cn) $state(s,$j) set state(s,$j) $t set i [expr {($i + 1) % $keylen}] } return $Key } proc ::rc4::RC4 {Key datastr} { # FRINK: nocheck variable $Key upvar #0 $Key state set res {} binary scan $datastr c* data set datalen [llength $data] set x $state(x) set y $state(y) for {set cn 0} {$cn < $datalen} {incr cn} { set x [expr {($x + 1) % 256}] set y [expr {($state(s,$x) + $y) % 256}] set t $state(s,$y) set state(s,$y) $state(s,$x) set state(s,$x) $t set i [expr {($state(s,$x) + $state(s,$y)) % 256}] lappend res [expr {([lindex $data $cn] ^ $state(s,$i)) & 0xFF}] } set state(x) $x set state(y) $y return [binary format c* $res] } proc ::rc4::RC4Final {Key} { # FRINK: nocheck variable $Key upvar #0 $Key state catch {unset state} return {} } # ------------------------------------------------------------------------- # Helper to turn binary data into hex format. # if {[package provide Trf] != {}} { interp alias {} ::rc4::Hex {} ::hex -mode encode -- } else { proc ::rc4::Hex {data} { set result {} binary scan $data c* r foreach c $r { append result [format "%02X" [expr {$c & 0xff}]] } return $result } } # ------------------------------------------------------------------------- # Description: # Pop the nth element off a list. Used in options processing. # proc ::rc4::Pop {varname {nth 0}} { upvar $varname args set r [lindex $args $nth] set args [lreplace $args $nth $nth] return $r } # ------------------------------------------------------------------------- # Fileevent handler for chunked file hashing. # proc ::rc4::Chunk {Key in {out {}} {chunksize 4096}} { # FRINK: nocheck variable $Key upvar #0 $Key state if {[eof $in]} { fileevent $in readable {} set state(reading) 0 } if {$out == {}} { append state(output) [RC4 $Key [read $in $chunksize]] } else { puts -nonewline $out [RC4 $Key [read $in $chunksize]] } } # ------------------------------------------------------------------------- proc ::rc4::rc4 {args} { array set opts {-hex 0 -infile {} -in {} -out {} -chunksize 4096 -key {}} while {[string match -* [set option [lindex $args 0]]]} { switch -exact -- $option { -key { set opts(-key) [Pop args 1] } -hex { set opts(-hex) 1} -infile { set opts(-infile) [Pop args 1] } -in { set opts(-in) [Pop args 1] } -out { set opts(-out) [Pop args 1] } -chunksize { set opts(-chunksize) [Pop args 1] } -- { Pop args; break } default { set err [join [lsort [array names opts]] ", "] return -code error "bad option $option:\ must be one of $err" } } Pop args } if {$opts(-key) == {}} { return -code error "wrong # args:\ should be \"rc4 ?-hex? -key key -in channel | string\"" } if {$opts(-infile) != {}} { set opts(-in) [open $opts(-infile) r] fconfigure $opts(-in) -translation binary } set r {} if {$opts(-in) == {}} { if {[llength $args] != 1} { return -code error "wrong # args:\ should be \"rc4 ?-hex? -key key -in channel | string\"" } set Key [RC4Init $opts(-key)] set r [RC4 $Key [lindex $args 0]] if {$opts(-out) != {}} { puts -nonewline $opts(-out) $r set r {} } RC4Final $Key } else { set Key [RC4Init $opts(-key)] variable $Key upvar #0 $Key state set state(reading) 1 set state(output) "" fileevent $opts(-in) readable \ [list [namespace origin Chunk] \ $Key $opts(-in) $opts(-out) $opts(-chunksize)] vwait [subst $Key](reading) if {$opts(-out) == {}} { set r $state(output) } RC4Final $Key # If we opened the channel then we should close it too. if {$opts(-infile) != {}} { close $opts(-in) } } if {$opts(-hex)} { set r [Hex $r] } return $r } # ------------------------------------------------------------------------- package provide rc4 $::rc4::version # ------------------------------------------------------------------------- # Local variables: # mode: tcl # indent-tabs-mode: nil # End: ---- [[ [Category Cryptography] ]]