ruby-aes-optimized 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.
- data/CHANGELOG +6 -0
- data/COPYING +20 -0
- data/README +77 -0
- data/Rakefile +154 -0
- data/doc/rdoc/classes/Aes.html +494 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/CHANGELOG.html +117 -0
- data/doc/rdoc/files/COPYING.html +129 -0
- data/doc/rdoc/files/README.html +235 -0
- data/doc/rdoc/files/lib/ruby-aes_rb.html +108 -0
- data/doc/rdoc/fr_class_index.html +29 -0
- data/doc/rdoc/fr_file_index.html +32 -0
- data/doc/rdoc/fr_method_index.html +57 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/examples/encrypt_block.rb +22 -0
- data/examples/encrypt_buffer.rb +24 -0
- data/examples/encrypt_stream.rb +39 -0
- data/examples/example_helper.rb +27 -0
- data/lib/ruby-aes/aes_alg.rb +280 -0
- data/lib/ruby-aes/aes_cons.rb +216 -0
- data/lib/ruby-aes.rb +162 -0
- data/test/KAT_MCT/aes_kat_mct.rb +386 -0
- data/test/KAT_MCT/rijndael-vals.zip +0 -0
- data/test/KAT_MCT/table.128 +128 -0
- data/test/KAT_MCT/table.192 +128 -0
- data/test/KAT_MCT/table.256 +128 -0
- data/test/test_helper.rb +14 -0
- data/test/test_ruby-aes.rb +113 -0
- metadata +93 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'ruby-aes'
|
4
|
+
require 'example_helper'
|
5
|
+
|
6
|
+
class RubyAES_block
|
7
|
+
|
8
|
+
include RubyAES_helper
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
setup
|
12
|
+
pt = "0123467890ABCDEF"
|
13
|
+
puts "Using #{@kl}-#{@mode} encryption/decryption"
|
14
|
+
puts "Plaintext is: #{pt} (a block should be 16 octets)"
|
15
|
+
ct = Aes.encrypt_block(@kl, @mode, @keys[@kl], @iv, pt)
|
16
|
+
puts "Ciphertext (unpacked) is: #{ct.unpack("H*").first}"
|
17
|
+
npt = Aes.decrypt_block(@kl, @mode, @keys[@kl], @iv, ct)
|
18
|
+
puts "Decrypted ciphertext is: #{npt} (should be: #{pt})"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
RubyAES_block.new
|
@@ -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
|
@@ -0,0 +1,280 @@
|
|
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 (optimized version)
|
6
|
+
Based on "Normal" code
|
7
|
+
Adapted from the Rijndael Specifications (dfips-AES.pdf)
|
8
|
+
=end
|
9
|
+
|
10
|
+
require 'ruby-aes/aes_cons'
|
11
|
+
|
12
|
+
class AesAlg
|
13
|
+
include AesCons
|
14
|
+
|
15
|
+
def mixColumns
|
16
|
+
t = ""
|
17
|
+
4.times do |j| i = j*4
|
18
|
+
t << (G2X[@state[i]] ^ G3X[@state[i+1]] ^ @state[i+2] ^ @state[i+3])
|
19
|
+
t << (@state[i] ^ G2X[@state[i+1]] ^ G3X[@state[i+2]] ^ @state[i+3])
|
20
|
+
t << (@state[i] ^ @state[i+1] ^ G2X[@state[i+2]] ^ G3X[@state[i+3]])
|
21
|
+
t << (G3X[@state[i]] ^ @state[i+1] ^ @state[i+2] ^ G2X[@state[i+3]])
|
22
|
+
end
|
23
|
+
@state = t
|
24
|
+
end
|
25
|
+
protected :mixColumns
|
26
|
+
|
27
|
+
def imixColumns
|
28
|
+
t = ""
|
29
|
+
4.times do |j| i = j*4
|
30
|
+
t << (GEX[@state[i]] ^ GBX[@state[i+1]] ^ GDX[@state[i+2]] ^ G9X[@state[i+3]])
|
31
|
+
t << (G9X[@state[i]] ^ GEX[@state[i+1]] ^ GBX[@state[i+2]] ^ GDX[@state[i+3]])
|
32
|
+
t << (GDX[@state[i]] ^ G9X[@state[i+1]] ^ GEX[@state[i+2]] ^ GBX[@state[i+3]])
|
33
|
+
t << (GBX[@state[i]] ^ GDX[@state[i+1]] ^ G9X[@state[i+2]] ^ GEX[@state[i+3]])
|
34
|
+
end
|
35
|
+
@state = t
|
36
|
+
end
|
37
|
+
protected :imixColumns
|
38
|
+
|
39
|
+
# Combine -- shiftRows, subBytes -- as one method
|
40
|
+
def subShiftRows
|
41
|
+
@state[0], @state[4], @state[8], @state[12] =
|
42
|
+
S_BOX[@state[0]], S_BOX[@state[4]], S_BOX[@state[8]], S_BOX[@state[12]]
|
43
|
+
@state[1], @state[5], @state[9], @state[13] =
|
44
|
+
S_BOX[@state[5]], S_BOX[@state[9]], S_BOX[@state[13]], S_BOX[@state[1]]
|
45
|
+
@state[2], @state[6], @state[10], @state[14] =
|
46
|
+
S_BOX[@state[10]], S_BOX[@state[14]], S_BOX[@state[2]], S_BOX[@state[6]]
|
47
|
+
@state[3], @state[7], @state[11], @state[15] =
|
48
|
+
S_BOX[@state[15]], S_BOX[@state[3]], S_BOX[@state[7]], S_BOX[@state[11]]
|
49
|
+
end
|
50
|
+
protected :subShiftRows
|
51
|
+
|
52
|
+
# Combine -- shiftRows, subBytes, addRoundkey -- as one method
|
53
|
+
def lastEncryptRound
|
54
|
+
i = 16*@nr
|
55
|
+
@state[0], @state[4], @state[8], @state[12] =
|
56
|
+
S_BOX[@state[0]] ^ @w[i], S_BOX[@state[4]] ^ @w[i+4],
|
57
|
+
S_BOX[@state[8]] ^ @w[i+8], S_BOX[@state[12]] ^ @w[i+12]
|
58
|
+
@state[1], @state[5], @state[9], @state[13] =
|
59
|
+
S_BOX[@state[5]] ^ @w[i+1], S_BOX[@state[9]] ^ @w[i+5],
|
60
|
+
S_BOX[@state[13]] ^ @w[i+9], S_BOX[@state[1]] ^ @w[i+13]
|
61
|
+
@state[2], @state[6], @state[10], @state[14] =
|
62
|
+
S_BOX[@state[10]] ^ @w[i+2], S_BOX[@state[14]] ^ @w[i+6],
|
63
|
+
S_BOX[@state[2]] ^ @w[i+10], S_BOX[@state[6]] ^ @w[i+14]
|
64
|
+
@state[3], @state[7], @state[11], @state[15] =
|
65
|
+
S_BOX[@state[15]] ^ @w[i+3], S_BOX[@state[3]] ^ @w[i+7],
|
66
|
+
S_BOX[@state[7]] ^ @w[i+11], S_BOX[@state[11]] ^ @w[i+15]
|
67
|
+
end
|
68
|
+
protected :lastEncryptRound
|
69
|
+
|
70
|
+
# Combine -- ishiftRows, isubBytes, addRoundkey -- as one method
|
71
|
+
def decryptSubRound(n)
|
72
|
+
i = 16*n
|
73
|
+
@state[0], @state[4], @state[8], @state[12] =
|
74
|
+
IS_BOX[@state[0]] ^ @w[i], IS_BOX[@state[4]] ^ @w[i+4],
|
75
|
+
IS_BOX[@state[8]] ^ @w[i+8], IS_BOX[@state[12]] ^ @w[i+12]
|
76
|
+
@state[1], @state[5], @state[9], @state[13] =
|
77
|
+
IS_BOX[@state[13]] ^ @w[i+1], IS_BOX[@state[1]] ^ @w[i+5],
|
78
|
+
IS_BOX[@state[5]] ^ @w[i+9], IS_BOX[@state[9]] ^ @w[i+13]
|
79
|
+
@state[2], @state[6], @state[10], @state[14] =
|
80
|
+
IS_BOX[@state[10]] ^ @w[i+2], IS_BOX[@state[14]] ^ @w[i+6],
|
81
|
+
IS_BOX[@state[2]] ^ @w[i+10], IS_BOX[@state[6]] ^ @w[i+14]
|
82
|
+
@state[3], @state[7], @state[11], @state[15] =
|
83
|
+
IS_BOX[@state[7]] ^ @w[i+3], IS_BOX[@state[11]] ^ @w[i+7],
|
84
|
+
IS_BOX[@state[15]] ^ @w[i+11], IS_BOX[@state[3]] ^@w[i+15]
|
85
|
+
end
|
86
|
+
protected :decryptSubRound
|
87
|
+
|
88
|
+
def addRoundKey(n)
|
89
|
+
j = n*16
|
90
|
+
16.times do |i|
|
91
|
+
@state[i] ^= @w[i+j]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
protected :addRoundKey
|
95
|
+
|
96
|
+
def key_expansion(key)
|
97
|
+
0.upto(@nk*4-1) do
|
98
|
+
|i| @w[i] = key[i]
|
99
|
+
end
|
100
|
+
@nk.upto(@nb*(@nr+1)-1) do |i|
|
101
|
+
j = i*4
|
102
|
+
k = j-(@nk*4)
|
103
|
+
t0, t1, t2, t3 = @w[j-4], @w[j-3], @w[j-2], @w[j-1]
|
104
|
+
if (i % @nk == 0)
|
105
|
+
t0, t1, t2, t3 =
|
106
|
+
S_BOX[t1] ^ RCON[i/@nk - 1], S_BOX[t2], S_BOX[t3], S_BOX[t0]
|
107
|
+
elsif (@nk > 6) && (i % @nk == 4)
|
108
|
+
t0, t1, t2, t3 = S_BOX[t0], S_BOX[t1], S_BOX[t2], S_BOX[t3]
|
109
|
+
end
|
110
|
+
@w[j], @w[j+1], @w[j+2], @w[j+3] =
|
111
|
+
@w[k] ^ t0, @w[k+1] ^ t1, @w[k+2] ^ t2, @w[k+3] ^ t3
|
112
|
+
end
|
113
|
+
end
|
114
|
+
protected :key_expansion
|
115
|
+
|
116
|
+
def _encrypt_block
|
117
|
+
addRoundKey 0
|
118
|
+
1.upto(@nr-1) do |n|
|
119
|
+
subShiftRows
|
120
|
+
mixColumns
|
121
|
+
addRoundKey n
|
122
|
+
end
|
123
|
+
lastEncryptRound
|
124
|
+
@state
|
125
|
+
end
|
126
|
+
protected :_encrypt_block
|
127
|
+
|
128
|
+
def _decrypt_block
|
129
|
+
addRoundKey @nr
|
130
|
+
(@nr-1).downto(1) do |n|
|
131
|
+
decryptSubRound n
|
132
|
+
imixColumns
|
133
|
+
end
|
134
|
+
decryptSubRound 0
|
135
|
+
@state
|
136
|
+
end
|
137
|
+
protected :_decrypt_block
|
138
|
+
|
139
|
+
def xor(a,b)
|
140
|
+
c = ""
|
141
|
+
16.times do |i|
|
142
|
+
c << (a[i] ^ b[i]).chr
|
143
|
+
end
|
144
|
+
c
|
145
|
+
end
|
146
|
+
protected :xor
|
147
|
+
|
148
|
+
def encrypt_block(block)
|
149
|
+
@state = block.dup
|
150
|
+
case @mode
|
151
|
+
when 'ECB'
|
152
|
+
_encrypt_block
|
153
|
+
when 'CBC'
|
154
|
+
@state = xor(block, @iv)
|
155
|
+
@iv = _encrypt_block
|
156
|
+
when 'OFB'
|
157
|
+
@state = @iv.dup
|
158
|
+
@iv = _encrypt_block
|
159
|
+
xor(@iv, block)
|
160
|
+
when 'CFB'
|
161
|
+
@state = @iv.dup
|
162
|
+
@iv = xor(_encrypt_block, block)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def decrypt_block(block)
|
167
|
+
@state = block.dup
|
168
|
+
case @mode
|
169
|
+
when 'ECB'
|
170
|
+
_decrypt_block
|
171
|
+
when 'CBC'
|
172
|
+
o = xor(_decrypt_block, @iv)
|
173
|
+
@iv = block
|
174
|
+
o
|
175
|
+
when 'OFB'
|
176
|
+
@state = @iv.dup
|
177
|
+
@iv = _encrypt_block
|
178
|
+
xor(@iv, block)
|
179
|
+
when 'CFB'
|
180
|
+
@state = @iv.dup
|
181
|
+
o = xor(_encrypt_block, block)
|
182
|
+
@iv = block
|
183
|
+
o
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def encrypt_blocks(buffer)
|
188
|
+
raise "Bad block length" unless (buffer.length % 16).zero?
|
189
|
+
ct = ""
|
190
|
+
block = ""
|
191
|
+
buffer.each_byte do |char|
|
192
|
+
block << char
|
193
|
+
if block.length == 16
|
194
|
+
ct << encrypt_block(block)
|
195
|
+
block = ""
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def decrypt_blocks(buffer)
|
201
|
+
raise "Bad block length" unless (buffer.length % 16).zero?
|
202
|
+
pt = ""
|
203
|
+
block = ""
|
204
|
+
buffer.each_byte do |char|
|
205
|
+
block << char
|
206
|
+
if block.length == 16
|
207
|
+
pt << decrypt_block(block)
|
208
|
+
block = ""
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def encrypt_buffer(buffer)
|
214
|
+
ct = ""
|
215
|
+
block = ""
|
216
|
+
buffer.each_byte do |char|
|
217
|
+
block << char
|
218
|
+
if block.length == 16
|
219
|
+
ct << encrypt_block(block)
|
220
|
+
block = ""
|
221
|
+
end
|
222
|
+
end
|
223
|
+
m = 16 - block.length % 16
|
224
|
+
ct << (m == 16 ? 0 : encrypt_block(block << m.chr * m))
|
225
|
+
end
|
226
|
+
|
227
|
+
def decrypt_buffer(buffer)
|
228
|
+
pt = ""
|
229
|
+
block = ""
|
230
|
+
buffer.each_byte do |char|
|
231
|
+
block << char
|
232
|
+
if block.length == 16
|
233
|
+
pt << decrypt_block(block)
|
234
|
+
block = ""
|
235
|
+
end
|
236
|
+
end
|
237
|
+
if block.length == 0
|
238
|
+
c = pt[-1]
|
239
|
+
c.chr * c == pt[-c..-1] ? pt[0..-(c+1)] : (raise "Bad Block Padding")
|
240
|
+
else
|
241
|
+
pt
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def init(key_length, mode, key, iv = nil)
|
246
|
+
@iv = "\000" * 16
|
247
|
+
@iv = iv if iv
|
248
|
+
@nb = 4
|
249
|
+
@nk = 4
|
250
|
+
@nr = 10
|
251
|
+
@mode = 'ECB'
|
252
|
+
@state = nil
|
253
|
+
@w = []
|
254
|
+
case key_length
|
255
|
+
when 128
|
256
|
+
@nk = 4
|
257
|
+
@nr = 10
|
258
|
+
when 192
|
259
|
+
@nk = 6
|
260
|
+
@nr = 12
|
261
|
+
when 256
|
262
|
+
@nk = 8
|
263
|
+
@nr = 14
|
264
|
+
else
|
265
|
+
raise 'Bad Key length'
|
266
|
+
end
|
267
|
+
case mode
|
268
|
+
when 'ECB', 'CBC', 'OFB', 'CFB'
|
269
|
+
@mode = mode
|
270
|
+
else
|
271
|
+
raise 'Bad AES mode'
|
272
|
+
end
|
273
|
+
key_expansion key
|
274
|
+
end
|
275
|
+
|
276
|
+
def initialize(key_length, mode, key, iv = nil)
|
277
|
+
init(key_length, mode, key, iv)
|
278
|
+
end
|
279
|
+
|
280
|
+
end # class aes
|