root/ruby/rc4.rb

Revision 74, 3.6 kB (checked in by andrew.pennebak..@gmail.com, 1 year ago)

RC4 uuencodes each 1024 byte block.
RC4 includes original filename as first uuencoded line.

  • Property svn:executable set to *
Line 
1 #!/usr/bin/env ruby
2
3 # Author:: Andrew Pennebaker
4 # Copyright:: Copyright 2007 Andrew Pennebaker
5 # License:: GPL
6 #
7 # == Usage
8 # rc4 [OPTIONS]
9 #
10 # --help, -h:
11 #    shows usage help
12 #
13 # --encrypt, -e <file1> <file2> <file3> ...:
14 #    encrypts infile to outfile (default mode)
15 #
16 # --decrypt, -d <file1> <file2> <file3> ...:
17 #    decrypts infile to outfile
18 #
19 # --key, -k <uuencoded key>:
20 #    specifies key for encryption/decryption
21 #
22 # --gen-key, -g [<length>]:
23 #    generates key (default length 8)
24
25 require "base64"
26
27 require "getoptlong"
28 require "rdoc/usage"
29
30 class SBox
31         def initialize(key=[0])
32                 @s=(0..255).to_a
33
34                 keypos=0
35                 index=0
36
37                 0.upto(255) { |counter|
38                         index=(key[keypos%key.length]+counter+index)%256
39                         swap(@s, counter, index)
40                         keypos+=1
41                 }
42
43                 @x, @y=0, 0
44         end
45
46         def swap(items, a, b)
47                 items[a], items[b]=items[b], items[a]
48         end
49
50         def next_byte
51                 @x=(@x+1)%256
52                 @y=(@s[@x]+@y)%256
53
54                 swap(@s, @x, @y)
55
56                 return @s[(@x+@y)%256]
57         end
58 end
59
60 class RC4
61         def set_key(key)
62                 @sbox=SBox.new(key)
63         end
64
65         def gen_key(length=8)
66                 raise "Key length must be >= 1" unless length>=1
67
68                 key=[]
69                 0.upto(length) { |i|
70                         key.push((rand()*256).to_i)
71                 }
72
73                 return key
74         end
75
76         def encrypt(b)
77                 return b^@sbox.next_byte
78         end
79
80         def decrypt(b)
81                 return encrypt(b)               
82         end
83
84         def format_bytes(bytes)
85                 return Base64.encode64(bytes.join("")).chomp()
86         end
87
88         def unformat_bytes(line)
89                 bytes=[]
90                 Base64.decode64(line).each_byte { |e|
91                         bytes.push(e)
92                 }
93
94                 return bytes
95         end
96
97         def format_key(key)
98                 return format_bytes(key)
99         end
100
101         def unformat_key(key)
102                 return unformat_bytes(key)
103         end
104 end
105
106 def encrypt(filename, cipher, key)
107         cipher.set_key(cipher.unformat_key(key))
108
109         infile=open(filename, "rb")
110         outfile=open("#{filename}.rc4", "wb")
111
112         # include original filename as first line in outfile
113         bytes=[]
114         filename.each_byte { |b|
115                 bytes.push(cipher.encrypt(b).chr)
116         }
117         outfile.write(cipher.format_bytes(bytes))
118         outfile.write("\n")
119
120         line=""
121         while not infile.eof?
122                 line=infile.read(1024, line)
123                 bytes=[]
124                 line.each_byte { |b|
125                         bytes.push(cipher.encrypt(b).chr)
126                 }
127                 outfile.write(cipher.format_bytes(bytes))
128                 outfile.write("\n")
129         end
130
131         infile.close()
132         outfile.close()
133 end
134
135 def decrypt(filename, cipher, key)
136         cipher.set_key(cipher.unformat_key(key))
137
138         infile=open(filename, "rb")
139
140         # original filename is included as first line in infile
141         bytes=[]
142         cipher.unformat_bytes(infile.readline).each { |b|
143                 bytes.push(cipher.decrypt(b).chr)
144         }
145         original_filename=bytes.join("")
146
147         outfile=open(original_filename, "wb")
148
149         infile.each { |line|
150                 bytes=[]
151                 cipher.unformat_bytes(line).each { |b|
152                         bytes.push(cipher.encrypt(b).chr)
153                 }
154                 outfile.write(bytes)
155         }
156
157         infile.close()
158         outfile.close()
159 end
160
161 def main
162         mode = :encrypt
163         key = ""
164         length = 8
165
166         opts=GetoptLong.new(
167                 ["--help", "-h", GetoptLong::NO_ARGUMENT],
168                 ["--encrypt", "-e", GetoptLong::NO_ARGUMENT],
169                 ["--decrypt", "-d", GetoptLong::NO_ARGUMENT],
170                 ["--key", "-k", GetoptLong::REQUIRED_ARGUMENT],
171                 ["--gen-key", "-g", GetoptLong::OPTIONAL_ARGUMENT]
172         )
173
174         opts.each { |option, value|
175                 case option
176                         when "--help"
177                                 RDoc::usage("Usage")
178                         when "--encrypt"
179                                 mode = :encrypt
180                         when "--decrypt"
181                                 mode = :decrypt
182                         when "--key"
183                                 key = value
184                         when "--gen-key"
185                                 mode = :gen_key
186                                 length=value.to_i
187                                 length=8 unless length>=1
188                 end
189         }
190
191         cipher=RC4.new()
192
193         case mode
194                 when :gen_key
195                         puts cipher.format_key(cipher.gen_key(length))
196                 when :encrypt
197                         ARGV.each { |filename|
198                                 encrypt(filename, cipher, key)
199                         }
200                 when :decrypt
201                         ARGV.each { |filename|
202                                 decrypt(filename, cipher, key)
203                         }
204         end
205 end
206
207 if __FILE__==$0
208         begin
209                 main
210         rescue Interrupt => e
211                 nil
212         rescue RuntimeError => e
213                 puts e.message
214         end
215 end
Note: See TracBrowser for help on using the browser.