ruby-aes-normal 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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