ruby-aes-normal 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ruby-aes'
4
+ require 'example_helper'
5
+
6
+ class RubyAES_buffer
7
+
8
+ include RubyAES_helper
9
+
10
+ def initialize
11
+ setup
12
+ puts "Using #{@kl}-#{@mode} encryption/decryption"
13
+ pt = "The quick brown fox jumps over the lazy dog"
14
+ puts "Plaintext is: '#{pt}'"
15
+ puts "(a buffer will be padded so that its length will be a multiple of 16)"
16
+ ct = Aes.encrypt_buffer(@kl, @mode, @keys[@kl], @iv, pt)
17
+ puts "Ciphertext (unpacked) is: #{ct.unpack("H*").first}"
18
+ npt = Aes.decrypt_buffer(@kl, @mode, @keys[@kl], @iv, ct)
19
+ puts "Decrypted ciphertext is: '#{npt}'"
20
+ puts "(should be: '#{pt}')"
21
+ end
22
+
23
+ end
24
+ RubyAES_buffer.new
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ruby-aes'
4
+ require 'example_helper'
5
+ require 'fileutils'
6
+
7
+ class RubyAES_stream
8
+
9
+ include RubyAES_helper
10
+
11
+ def initialize
12
+ setup
13
+ puts "Using #{@kl}-#{@mode} encryption/decryption"
14
+ file = "_ruby-aes_encrypt_stream_"
15
+
16
+ sin = File.open(file, "w+b")
17
+ sin.puts "The quick brown fox jumps over the lazy dog"
18
+ sin.rewind
19
+ sout = File.open("#{file}.aes", "w+b")
20
+ Aes.encrypt_stream(@kl, @mode, @keys[@kl], @iv, sin, sout)
21
+ sin.close
22
+ sout.close
23
+
24
+ sin = File.open("#{file}.aes", "rb")
25
+ sout = File.open("#{file}.plain", "w+b")
26
+ Aes.decrypt_stream(@kl, @mode, @keys[@kl], @iv, sin, sout)
27
+ sin.close
28
+ sout.close
29
+
30
+ if IO.read(file) == IO.read("#{file}.plain")
31
+ puts "The decrypted file is exactly the same as the original one"
32
+ else
33
+ puts "The decrypted file differs from the orginal one"
34
+ end
35
+ FileUtils.rm_f [ file, "#{file}.aes", "#{file}.plain" ]
36
+ end
37
+
38
+ end
39
+ RubyAES_stream.new
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module RubyAES_helper
4
+
5
+ KEY_LENGTH = [128,192,256].freeze
6
+ MODES = ['ECB','CBC','OFB','CFB'].freeze
7
+
8
+ def random_fill(n, buffer)
9
+ n.times do
10
+ buffer << rand(256).chr
11
+ end
12
+ end
13
+
14
+ def setup
15
+ @keys = {}
16
+ KEY_LENGTH.each do |kl|
17
+ @keys[kl] = ""
18
+ random_fill(kl/8, @keys[kl])
19
+ end
20
+
21
+ @iv = ""; random_fill(16, @iv)
22
+ @pt = ""; random_fill(64, @pt)
23
+ @kl = KEY_LENGTH[(rand * KEY_LENGTH.length).to_i]
24
+ @mode = MODES[(rand * MODES.length).to_i]
25
+ end
26
+
27
+ end
data/lib/ruby-aes.rb ADDED
@@ -0,0 +1,162 @@
1
+ =begin
2
+ This file is a part of ruby-aes <http://rubyforge.org/projects/ruby-aes>
3
+ Written by Alex Boussinet <alex.boussinet@gmail.com>
4
+
5
+ ==Valid modes are:
6
+ * ECB (Electronic Code Book)
7
+ * CBC (Cipher Block Chaining)
8
+ * OFB (Output Feedback)
9
+ * CFB (Cipher Feedback)
10
+
11
+ ==Valid key length:
12
+ * 128 bits
13
+ * 192 bits
14
+ * 256 bits
15
+
16
+ ==API calls:
17
+ Default key_length: 128
18
+ Default mode: 'ECB'
19
+ Default IV: 16 null chars ("00" * 16 in hex format)
20
+ Default key: 16 null chars ("00" * 16 in hex format)
21
+ Default input text: "PLAINTEXT"
22
+
23
+ Aes.check_key(key_string, key_length)
24
+ Aes.check_iv(iv_string)
25
+ Aes.check_kl(key_length)
26
+ Aes.check_mode(mode)
27
+ Aes.init(key_length, mode, key, iv)
28
+ Aes.encrypt_block(key_length, mode, key, iv, block) # no padding
29
+ Aes.decrypt_block(key_length, mode, key, iv, block) # no padding
30
+ Aes.encrypt_buffer(key_length, mode, key, iv, block) # padding
31
+ Aes.decrypt_buffer(key_length, mode, key, iv, block) # padding
32
+ Aes.encrypt_stream(key_length, mode, key, iv, sin, sout)
33
+ Aes.decrypt_stream(key_length, mode, key, iv, sin, sout)
34
+ Aes.bs() # block size for read operations (stream)
35
+ Aes.bs=(bs)
36
+ =end
37
+
38
+ module Aes
39
+
40
+ require 'ruby-aes/aes_alg'
41
+
42
+ @@aes = nil
43
+ @@bs = 4096
44
+
45
+ def Aes.bs(); return @@bs end
46
+ def Aes.bs=(bs); @@bs = bs.to_i; @@bs==0 ? 4096 : @@bs = @@bs - @@bs%16 end
47
+
48
+ def Aes.check_key(key_string, kl = 128)
49
+ kl = Aes.check_kl(kl)
50
+ k = key_string.length
51
+ raise "Bad key string or bad key length" if (k != kl/8) && (k != kl/4)
52
+ hex = (key_string =~ /[a-f0-9A-F]{#{k}}/) == 0 && (k == kl/4)
53
+ bin = ! hex
54
+ if ! (([32, 48, 64].include?(k) && hex) ||
55
+ ([16, 24, 32].include?(k) && bin))
56
+ raise "Bad key string"
57
+ end
58
+ hex ? [key_string].pack("H*") : key_string
59
+ end
60
+
61
+ def Aes.check_iv(iv_string)
62
+ k = iv_string.length
63
+ hex = (iv_string =~ /[a-f0-9A-F]{#{k}}/) == 0
64
+ bin = ! hex
65
+ if k == 32 && hex
66
+ return [iv_string].pack("H*")
67
+ elsif k == 16 && bin
68
+ return iv_string
69
+ else
70
+ raise "Bad IV string"
71
+ end
72
+ end
73
+
74
+ def Aes.check_mode (mode)
75
+ case mode
76
+ when 'ECB', 'CBC', 'OFB', 'CFB'
77
+ else raise "Bad cipher mode"
78
+ end
79
+ mode
80
+ end
81
+
82
+ def Aes.check_kl(key_length)
83
+ case key_length
84
+ when 128, 192, 256
85
+ else raise "Bad key length"
86
+ end
87
+ key_length
88
+ end
89
+
90
+ def Aes.init(keyl, mode, key, iv)
91
+ unless @@aes
92
+ @@aes = AesAlg.new(Aes.check_kl(keyl), Aes.check_mode(mode),
93
+ Aes.check_key(key, keyl), iv ? Aes.check_iv(iv) : nil)
94
+ else
95
+ @@aes.init(Aes.check_kl(keyl), Aes.check_mode(mode),
96
+ Aes.check_key(key, keyl), iv ? Aes.check_iv(iv) : nil)
97
+ end
98
+ end
99
+
100
+ def Aes.encrypt_block(keyl, mode, key, iv, block = "DEFAULT PLAINTXT")
101
+ raise "Bad Block size" if block.length < 16 || block.length > 16
102
+ Aes.init(keyl, mode, key, iv)
103
+ @@aes.encrypt_block(block)
104
+ end
105
+
106
+ def Aes.decrypt_block(keyl, mode, key, iv, block = "DEFAULT PLAINTXT")
107
+ Aes.init(keyl, mode, key, iv)
108
+ @@aes.decrypt_block(block)
109
+ end
110
+
111
+ def Aes.encrypt_buffer(keyl, mode, key, iv, buffer = "PLAINTEXT")
112
+ Aes.init(keyl, mode, key, iv)
113
+ @@aes.encrypt_buffer(buffer)
114
+ end
115
+
116
+ def Aes.decrypt_buffer(keyl, mode, key, iv, buffer = "DEFAULT PLAINTXT")
117
+ raise "Bad Block size" if buffer.length < 16
118
+ Aes.init(keyl, mode, key, iv)
119
+ @@aes.decrypt_buffer(buffer)
120
+ end
121
+
122
+ def Aes.encrypt_stream(keyl, mode, key, iv, sin = STDIN, sout = STDOUT)
123
+ Aes.init(keyl, mode, key, iv)
124
+ case sout
125
+ when String, Array, IO
126
+ else
127
+ raise "Bad output stream (String, Array, IO)"
128
+ end
129
+ case sin
130
+ when String
131
+ sout << @@aes.encrypt_buffer(sin)
132
+ when IO
133
+ while buf = sin.read(@@bs)
134
+ sout << ((buf.length % 16).zero? ? @@aes.encrypt_blocks(buf) :
135
+ @@aes.encrypt_buffer(buf))
136
+ end
137
+ else
138
+ raise "Bad input stream (String, IO)"
139
+ end
140
+ end
141
+
142
+ def Aes.decrypt_stream(keyl, mode, key, iv, sin = STDIN, sout = STDOUT)
143
+ Aes.init(keyl, mode, key, iv)
144
+ case sout
145
+ when String, Array, IO
146
+ else
147
+ raise "Bad output stream (String, Array, IO)"
148
+ end
149
+ case sin
150
+ when String
151
+ sout << @@aes.decrypt_buffer(sin)
152
+ when IO
153
+ while buf = sin.read(@@bs)
154
+ sout << (sin.eof? ? @@aes.decrypt_buffer(buf) :
155
+ @@aes.decrypt_blocks(buf))
156
+ end
157
+ else
158
+ raise "Bad input stream (String, IO)"
159
+ end
160
+ end
161
+
162
+ end # end Aes
@@ -0,0 +1,277 @@
1
+ =begin
2
+ This file is a part of ruby-aes <http://rubyforge.org/projects/ruby-aes>
3
+ Written by Alex Boussinet <alex.boussinet@gmail.com>
4
+
5
+ ruby-aes (non-optimized version)
6
+ Adapted from the Rijndael Specifications (dfips-AES.pdf)
7
+ =end
8
+
9
+ require 'ruby-aes/aes_cons'
10
+
11
+ class AesAlg
12
+ include AesCons
13
+
14
+ def subBytes
15
+ i = 0
16
+ @state.each_byte do |b|
17
+ @state[i] = S_BOX[b]
18
+ i+=1
19
+ end
20
+ end
21
+ protected :subBytes
22
+
23
+ def isubBytes
24
+ i = 0
25
+ @state.each_byte do |b|
26
+ @state[i] = IS_BOX[b]
27
+ i+=1
28
+ end
29
+ end
30
+ protected :isubBytes
31
+
32
+ def shiftRows
33
+ @state[1], @state[5], @state[9], @state[13] =
34
+ @state[5], @state[9], @state[13], @state[1]
35
+ @state[2], @state[6], @state[10], @state[14] =
36
+ @state[10], @state[14], @state[2], @state[6]
37
+ @state[3], @state[7], @state[11], @state[15] =
38
+ @state[15], @state[3], @state[7], @state[11]
39
+ end
40
+ protected :shiftRows
41
+
42
+ def ishiftRows
43
+ @state[1], @state[5], @state[9], @state[13] =
44
+ @state[13], @state[1], @state[5], @state[9]
45
+ @state[2], @state[6], @state[10], @state[14] =
46
+ @state[10], @state[14], @state[2], @state[6]
47
+ @state[3], @state[7], @state[11], @state[15] =
48
+ @state[7], @state[11], @state[15], @state[3]
49
+ end
50
+ protected :ishiftRows
51
+
52
+ def mixColumns
53
+ t = "\000" * 16
54
+ 4.times do |c|
55
+ t[c*4] = G2X.at(@state[c*4]) ^ G3X.at(@state[1+c*4]) ^
56
+ @state[2+c*4] ^ @state[3+c*4]
57
+ t[1+c*4] = @state[c*4] ^ G2X.at(@state[1+c*4]) ^
58
+ G3X.at(@state[2+c*4]) ^ @state[3+c*4]
59
+ t[2+c*4] = @state[c*4] ^ @state[1+c*4] ^
60
+ G2X.at(@state[2+c*4]) ^ G3X.at(@state[3+c*4])
61
+ t[3+c*4] = G3X.at(@state[c*4]) ^ @state[1+c*4] ^
62
+ @state[2+c*4] ^ G2X.at(@state[3+c*4])
63
+ end
64
+ @state = t
65
+ end
66
+ protected :mixColumns
67
+
68
+ def imixColumns
69
+ t = "\000" * 16
70
+ 4.times do |c|
71
+ t[c*4] = GEX.at(@state[c*4]) ^ GBX.at(@state[1+c*4]) ^
72
+ GDX.at(@state[2+c*4]) ^ G9X.at(@state[3+c*4])
73
+ t[1+c*4] = G9X.at(@state[c*4]) ^ GEX.at(@state[1+c*4]) ^
74
+ GBX.at(@state[2+c*4]) ^ GDX.at(@state[3+c*4])
75
+ t[2+c*4] = GDX.at(@state[c*4]) ^ G9X.at(@state[1+c*4]) ^
76
+ GEX.at(@state[2+c*4]) ^ GBX.at(@state[3+c*4])
77
+ t[3+c*4] = GBX.at(@state[c*4]) ^ GDX.at(@state[1+c*4]) ^
78
+ G9X.at(@state[2+c*4]) ^ GEX.at(@state[3+c*4])
79
+ end
80
+ @state = t
81
+ end
82
+ protected :imixColumns
83
+
84
+ def addRoundKey(n)
85
+ j = n*16
86
+ 16.times do |i|
87
+ @state[i] ^= @w[i+j]
88
+ end
89
+ end
90
+ protected :addRoundKey
91
+
92
+ def key_expansion(key)
93
+ 0.upto(@nk*4-1) do |i|
94
+ @w[i] = key[i]
95
+ end
96
+ @nk.upto(@nb*(@nr+1)-1) do |i|
97
+ j = i*4
98
+ k = j-(@nk*4)
99
+ t0, t1, t2, t3 = @w[j-4], @w[j-3], @w[j-2], @w[j-1]
100
+ if (i % @nk == 0)
101
+ t0, t1, t2, t3 =
102
+ S_BOX[t1] ^ RCON[i/@nk - 1], S_BOX[t2], S_BOX[t3], S_BOX[t0]
103
+ elsif (@nk > 6) && (i % @nk == 4)
104
+ t0, t1, t2, t3 = S_BOX[t0], S_BOX[t1], S_BOX[t2], S_BOX[t3]
105
+ end
106
+ @w[j], @w[j+1], @w[j+2], @w[j+3] =
107
+ @w[k] ^ t0, @w[k+1] ^ t1, @w[k+2] ^ t2, @w[k+3] ^ t3
108
+ end
109
+ end
110
+ protected :key_expansion
111
+
112
+ def _encrypt_block
113
+ addRoundKey 0
114
+ 1.upto(@nr) do |n|
115
+ subBytes
116
+ shiftRows
117
+ mixColumns unless n == @nr
118
+ addRoundKey n
119
+ end
120
+ @state
121
+ end
122
+ protected :_encrypt_block
123
+
124
+ def _decrypt_block
125
+ addRoundKey @nr
126
+ (@nr-1).downto(0) do |n|
127
+ ishiftRows
128
+ isubBytes
129
+ addRoundKey n
130
+ imixColumns unless n == 0
131
+ end
132
+ @state
133
+ end
134
+ protected :_decrypt_block
135
+
136
+ def xor(a,b)
137
+ c = ""
138
+ 16.times do |i|
139
+ c << (a[i] ^ b[i]).chr
140
+ end
141
+ c
142
+ end
143
+ protected :xor
144
+
145
+ def encrypt_block(block)
146
+ @state = block.dup
147
+ case @mode
148
+ when 'ECB'
149
+ _encrypt_block
150
+ when 'CBC'
151
+ @state = xor(block, @iv)
152
+ @iv = _encrypt_block
153
+ when 'OFB'
154
+ @state = @iv.dup
155
+ @iv = _encrypt_block
156
+ xor(@iv, block)
157
+ when 'CFB'
158
+ @state = @iv.dup
159
+ @iv = xor(_encrypt_block, block)
160
+ end
161
+ end
162
+
163
+ def decrypt_block(block)
164
+ @state = block.dup
165
+ case @mode
166
+ when 'ECB'
167
+ _decrypt_block
168
+ when 'CBC'
169
+ o = xor(_decrypt_block, @iv)
170
+ @iv = block
171
+ o
172
+ when 'OFB'
173
+ @state = @iv.dup
174
+ @iv = _encrypt_block
175
+ xor(@iv, block)
176
+ when 'CFB'
177
+ @state = @iv.dup
178
+ o = xor(_encrypt_block, block)
179
+ @iv = block
180
+ o
181
+ end
182
+ end
183
+
184
+ def encrypt_blocks(buffer)
185
+ raise "Bad block length" unless (buffer.length % 16).zero?
186
+ ct = ""
187
+ block = ""
188
+ buffer.each_byte do |char|
189
+ block << char
190
+ if block.length == 16
191
+ ct << encrypt_block(block)
192
+ block = ""
193
+ end
194
+ end
195
+ end
196
+
197
+ def decrypt_blocks(buffer)
198
+ raise "Bad block length" unless (buffer.length % 16).zero?
199
+ pt = ""
200
+ block = ""
201
+ buffer.each_byte do |char|
202
+ block << char
203
+ if block.length == 16
204
+ pt << decrypt_block(block)
205
+ block = ""
206
+ end
207
+ end
208
+ end
209
+
210
+ def encrypt_buffer(buffer)
211
+ ct = ""
212
+ block = ""
213
+ buffer.each_byte do |char|
214
+ block << char
215
+ if block.length == 16
216
+ ct << encrypt_block(block)
217
+ block = ""
218
+ end
219
+ end
220
+ m = 16 - block.length % 16
221
+ ct << (m == 16 ? 0 : encrypt_block(block << m.chr * m))
222
+ end
223
+
224
+ def decrypt_buffer(buffer)
225
+ pt = ""
226
+ block = ""
227
+ buffer.each_byte do |char|
228
+ block << char
229
+ if block.length == 16
230
+ pt << decrypt_block(block)
231
+ block = ""
232
+ end
233
+ end
234
+ if block.length == 0
235
+ c = pt[-1]
236
+ c.chr * c == pt[-c..-1] ? pt[0..-(c+1)] : (raise "Bad Block Padding")
237
+ else
238
+ pt
239
+ end
240
+ end
241
+
242
+ def init(key_length, mode, key, iv = nil)
243
+ @iv = "\000" * 16
244
+ @iv = iv if iv
245
+ @nb = 4
246
+ @nk = 4
247
+ @nr = 10
248
+ @mode = 'ECB'
249
+ @state = nil
250
+ @w = []
251
+ case key_length
252
+ when 128
253
+ @nk = 4
254
+ @nr = 10
255
+ when 192
256
+ @nk = 6
257
+ @nr = 12
258
+ when 256
259
+ @nk = 8
260
+ @nr = 14
261
+ else
262
+ raise 'Bad Key length'
263
+ end
264
+ case mode
265
+ when 'ECB', 'CBC', 'OFB', 'CFB'
266
+ @mode = mode
267
+ else
268
+ raise 'Bad AES mode'
269
+ end
270
+ key_expansion key
271
+ end
272
+
273
+ def initialize(key_length, mode, key, iv = nil)
274
+ init(key_length, mode, key, iv)
275
+ end
276
+
277
+ end # class aes