encrypted 0.0.1

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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in encrypted.gemspec
4
+ gemspec
@@ -0,0 +1,24 @@
1
+ Copyright 2005-2011 Jim Driscoll.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions
6
+ are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,31 @@
1
+ # Encrypted
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'encrypted'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install encrypted
20
+
21
+ ## Usage
22
+
23
+ TODO: Write usage instructions here
24
+
25
+ ## Contributing
26
+
27
+ 1. Fork it ( https://github.com/getaasciesh/encrypted/fork )
28
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
29
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
30
+ 4. Push to the branch (`git push origin my-new-feature`)
31
+ 5. Create a new Pull Request
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'encrypted/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "encrypted"
8
+ spec.version = Encrypted::VERSION
9
+ spec.authors = ["asish bhattarai"]
10
+ spec.email = ["getaasciesh@hotmail.com"]
11
+ spec.summary = %q{Rijndael encryption with cbc.}
12
+ spec.description = %q{Rijndael encryption with cbc. More Coming soon.}
13
+ spec.homepage = "https://github.com/getaasciesh/encrypted"
14
+ spec.license = "LICENCE.txt"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="CompassSettings">
4
+ <option name="compassSupportEnabled" value="true" />
5
+ </component>
6
+ <component name="FacetManager">
7
+ <facet type="gem" name="Ruby Gem">
8
+ <configuration>
9
+ <option name="GEM_APP_ROOT_PATH" value="$MODULE_DIR$" />
10
+ <option name="GEM_APP_TEST_PATH" value="$MODULE_DIR$/test" />
11
+ <option name="GEM_APP_LIB_PATH" value="$MODULE_DIR$/lib" />
12
+ </configuration>
13
+ </facet>
14
+ </component>
15
+ <component name="NewModuleRootManager" inherit-compiler-output="true">
16
+ <exclude-output />
17
+ <content url="file://$MODULE_DIR$">
18
+ <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
19
+ </content>
20
+ <orderEntry type="jdk" jdkName="ruby-2.0.0-p451" jdkType="RUBY_SDK" />
21
+ <orderEntry type="sourceFolder" forTests="false" />
22
+ <orderEntry type="library" scope="PROVIDED" name="rake (v10.3.2, ruby-2.0.0-p451) [gem]" level="application" />
23
+ </component>
24
+ </module>
25
+
@@ -0,0 +1,6 @@
1
+ require "encrypted/version"
2
+ require "encrypted/rijndael"
3
+ require "encrypted/cbc"
4
+ module Encrypted
5
+
6
+ end
@@ -0,0 +1,71 @@
1
+ module Encrypted
2
+ class ByteStream < String
3
+ =begin rdoc
4
+ A subclass of String with a single purpose: to provide the ^ (XOR) operator, for encryption purposes.
5
+ =end
6
+
7
+ =begin rdoc
8
+ Returned values are still of class Encrypted::ByteStream, and are of the same length as the longer value. Note that this means that:
9
+ a=Encrypted::ByteStream.new("a")
10
+ bb=Encrypted::ByteStream.new("b")
11
+ a^bb^bb
12
+
13
+ ...does not equal "a" but rather "a\000", so this should be used with caution except where you have equal-size strings in mind.
14
+ =end
15
+ def ^(string)
16
+ max_length=if(self.length > string.length)
17
+ self.length
18
+ else
19
+ string.length
20
+ end
21
+ my_bytes=self.unpack("C*")
22
+ other_bytes=string.unpack("C*")
23
+ out_bytes=Array.new
24
+ 0.upto(max_length-1) do
25
+ |i|
26
+ out_bytes[i]=(my_bytes[i]||0)^(other_bytes[i]||0)
27
+ end
28
+ self.class.new(out_bytes.pack("C*"))
29
+ end
30
+ def +(string)
31
+ my_dwords=self.unpack("N*")
32
+ other_dwords=string.unpack("N*")
33
+ max_length=if(my_dwords.length > other_dwords.length)
34
+ my_dwords.length
35
+ else
36
+ other_dwords.length
37
+ end
38
+ out_dwords=Array.new
39
+ 0.upto(max_length-1) do
40
+ |i|
41
+ out_dwords[i]=(my_dwords[i]||0)+(other_dwords[i]||0)&0xffffffff
42
+ end
43
+ self.class.new(out_dwords.pack("N*"))
44
+ end
45
+ Use_getbyte = "".respond_to?(:getbyte)
46
+ def byte_at(position, new_value=nil)
47
+ if(new_value)
48
+ self[position, 1]=[new_value].pack("C")
49
+ elsif(Use_getbyte)
50
+ self.getbyte(position)
51
+ else
52
+ self.slice(position)
53
+ end
54
+ end
55
+ @@strict_mode = false
56
+ def self.strict_mode=(new_mode)
57
+ @@strict_mode=new_mode
58
+ end
59
+ def [](anything, whatever=nil)
60
+ if(whatever)
61
+ super(anything, whatever)
62
+ elsif(not anything.is_a? Numeric)
63
+ super(anything)
64
+ elsif(@@strict_mode)
65
+ raise "Ambiguous, you must use #byte_at instead"
66
+ else
67
+ STDERR.puts "Ambiguous usage of [], please use #byte_at"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,73 @@
1
+ unless(defined? Encrypted::ByteStream)
2
+ require "bytestream"
3
+ end
4
+ module Encrypted
5
+ class CBC
6
+ # YARV (1.9) compat
7
+ Use_getbyte = "".respond_to?(:getbyte)
8
+
9
+ def CBC.pad_pkcs5(string, to_length) #:nodoc:
10
+ diff= to_length - (string.length % to_length)
11
+ string+=[diff].pack("C") * diff
12
+ return string
13
+ end
14
+
15
+ def CBC.unpad_pkcs5(string) #:nodoc:
16
+ return unless string.length > 0
17
+
18
+ if(Use_getbyte) # 1.9 returns a string from []
19
+ pad_len = string.getbyte(-1)
20
+ else
21
+ pad_len = string[-1]
22
+ end
23
+ unless(string.slice!(-pad_len .. -1) == [pad_len].pack("C") * pad_len)
24
+ raise "Unpad failure: trailing junk found"
25
+ end
26
+ return string
27
+ end
28
+
29
+ def initialize(cipher)
30
+ @cipher=cipher
31
+ end
32
+ def encrypt(iv, plaintext)
33
+ block_size=iv.length
34
+
35
+ last_block_e=Encrypted::ByteStream.new(iv)
36
+
37
+ plaintext=CBC.pad_pkcs5(plaintext, iv.length)
38
+ r_data="-" * plaintext.length
39
+
40
+ j=0
41
+ pt_l = plaintext.length
42
+ while(j<pt_l)
43
+ last_block_e[0,block_size]=@cipher.encrypt(last_block_e^plaintext[j, block_size])
44
+ r_data[j, block_size]=last_block_e
45
+ j+=block_size
46
+ end
47
+ return r_data
48
+ end
49
+ def decrypt(iv, ciphertext)
50
+ block_size=iv.length
51
+
52
+ last_block_e=Encrypted::ByteStream.new(iv)
53
+
54
+ unless(ciphertext.length % block_size==0)
55
+ raise "Bad IV: doesn't match ciphertext length"
56
+ end
57
+
58
+ r_data="-" * ciphertext.length
59
+ j=0
60
+ ct_l = ciphertext.length
61
+ current_block = "-" * block_size
62
+ while(j<ct_l)
63
+ current_block=ciphertext[j, block_size]
64
+
65
+ r_data[j, block_size]=last_block_e^@cipher.decrypt(current_block)
66
+ last_block_e[0,block_size]=current_block
67
+ j+=block_size
68
+ end
69
+ r_data=CBC.unpad_pkcs5(r_data)
70
+ return r_data
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,163 @@
1
+ unless(defined? Encrypted::ByteStream)
2
+ require 'bytestream'
3
+ Encrypted::ByteStream.strict_mode = true
4
+ end
5
+ # This is to help testing
6
+ unless(defined? Encrypted::Rijndael::Core)
7
+ require "rijndael/core"
8
+ end
9
+
10
+ module Encrypted
11
+ =begin rdoc
12
+ Encrypted::Rijndael allows you to encrypt single blocks of data using the encrypt() and decrypt() methods
13
+ below.
14
+
15
+ You probably want to use some kind of CBC module with this.
16
+ =end
17
+ class Rijndael
18
+
19
+
20
+
21
+ @@valid_blocksizes_bytes=[16, 24, 32]
22
+ @@valid_keysizes_bytes=[16, 24, 32]
23
+
24
+ =begin rdoc
25
+ The new() function here takes only one argument: the key to use, as a String (or similar). Valid lengths
26
+ are 16, 24 or 32 bytes, and you should ensure that this value is sufficiently random. Most people will
27
+ choose 16-byte (128-bit) keys, but a longer key will take longer to crack if security is of unusually
28
+ high importance for you.
29
+ =end
30
+ def initialize(new_key)
31
+ self.key = new_key
32
+ @current_block_length = nil # This makes it easier to adjust in #block=
33
+ end
34
+
35
+ attr_reader :key
36
+
37
+ # If you want to, you can assign a new key to an existing object.
38
+ def key=(new_key)
39
+ raise "Invalid key length: #{new_key.length}" unless(self.class.key_sizes_supported.find {|size| size==new_key.length})
40
+ @key = new_key
41
+ @key_words=@key.length/4
42
+ @expanded_key = nil
43
+ @round_count = nil
44
+ end
45
+ def expand_key #:nodoc:
46
+ return @expanded_key if(@expanded_key)
47
+ @expanded_key=(@key_words>6)? Core.expand_key_gt6(key, @block_words):
48
+ Core.expand_key_le6(key, @block_words)
49
+ return @expanded_key
50
+ end
51
+ protected :expand_key
52
+
53
+ attr_reader :block
54
+ def block=(new_block) #:nodoc:
55
+ if(new_block.length != @current_block_length) then
56
+ raise "Invalid block size: #{new_block.length}" unless(block_sizes_supported.find { |size| size==new_block.length })
57
+ @current_block_length = new_block.length
58
+ @block_words = @current_block_length / 4
59
+ @expanded_key = nil
60
+ @round_count = nil
61
+ end
62
+ @block = new_block
63
+ end
64
+ protected :block=, :block, :key
65
+
66
+ # If you want to probe for supported block sizes, by all means use this method. It'll raise
67
+ # if the value isn't supported.
68
+ #
69
+ # Don't use this: #block_sizes_supported is better.
70
+ def blocksize=(block_size_bytes)
71
+ self.block = "\x00" * block_size_bytes
72
+ self
73
+ end
74
+
75
+ # This lets you know how big a block is currently being used.
76
+ # There's probably no point using this.
77
+ def blocksize
78
+ return @block_words*4
79
+ end
80
+
81
+ # Provides a list of block sizes (bytes) which are supported
82
+ def self.block_sizes_supported
83
+ @@valid_blocksizes_bytes
84
+ end
85
+
86
+ # Provides a list of key sizes (bytes) which are supported
87
+ def self.key_sizes_supported
88
+ @@valid_keysizes_bytes
89
+ end
90
+
91
+ # This just calls the class' .block_sizes_supported method for you.
92
+ def block_sizes_supported
93
+ self.class.block_sizes_supported
94
+ end
95
+
96
+
97
+ def round_count #:nodoc:
98
+ return @round_count if @round_count
99
+ @round_count = Core.round_count(@block_words, @key_words)
100
+ end
101
+
102
+
103
+ protected :round_count
104
+
105
+ =begin rdoc
106
+ Your main entry point. You must provide an input string of a valid length - if not, it'll +raise+.
107
+ Valid lengths are 16, 24 or 32 bytes, and it will pick the block size based on the length of the input.
108
+
109
+ The output is a Encrypted::ByteStream object, which is to say more-or-less a String.
110
+ =end
111
+ def encrypt(plaintext)
112
+ self.block = plaintext
113
+
114
+ rounds=round_count
115
+ expanded_key=expand_key
116
+
117
+ blockl_b=@block_words*4
118
+ #puts "m #{block.length}"
119
+ tmp_block=Core.round0(block, expanded_key[0])
120
+ tmp_block = Core.roundn_times(tmp_block, expanded_key, rounds, :forward)
121
+ return Core.roundl(tmp_block, expanded_key[rounds])
122
+ end
123
+
124
+ =begin rdoc
125
+ Your other main entry point. You must provide an input string of a valid length - if not, it'll +raise+.
126
+ Valid lengths are 16, 24 or 32 bytes, and it will pick the block size based on the length of the input.
127
+ Of course, if the string to decrypt is of invalid length then you've got other problems...
128
+
129
+ The output is a Encrypted::ByteStream object, which is to say more-or-less a String.
130
+ =end
131
+ def decrypt(ciphertext)
132
+ self.block = ciphertext
133
+ rounds=round_count
134
+ expanded_key=expand_key
135
+
136
+ blockl_b=@block_words*4
137
+ tmp_block=Core.inv_roundl(block, expanded_key[rounds])
138
+ tmp_block = Core.roundn_times(tmp_block, expanded_key, rounds, :reverse)
139
+ decrypted=Core.round0(tmp_block, expanded_key[0])
140
+ #p "decrypted: #{decrypted}" if $VERBOSE
141
+ return decrypted
142
+ end
143
+ end
144
+
145
+ =begin rdoc
146
+ This is exactly the same as Encrypted::Rijndael except that the only allowed block size is 128-bit (16 bytes
147
+ ), which affects possible IV (for CBC and other block-chaining algorithms) and plaintext block lengths.
148
+
149
+ Given the effort that went into standardising on AES, you may well want to use this instead of
150
+ Encrypted::Rijndael for encryption if you're interoperating with another party. Of course, you *can* safely
151
+ use Encrypted::Rijndael for decryption in that circumstance.
152
+
153
+ The spec for this is in an US government standards document named FIPS-197. Google for it.
154
+ =end
155
+ class AES < Rijndael
156
+ AES_BLOCKSIZE_BYTES=16
157
+
158
+ # Only one block size is supported for real AES: 16 bytes.
159
+ def self.block_sizes_supported
160
+ [AES_BLOCKSIZE_BYTES]
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,430 @@
1
+ class Encrypted
2
+ class Rijndael
3
+ class Core
4
+ @@rounds_by_block_size={
5
+ 4=>10,
6
+ 6=>12,
7
+ 8=>14
8
+ }
9
+
10
+ def self.round_count(block_words, key_words) #:nodoc:
11
+ biggest_words=if(block_words > key_words)
12
+ block_words
13
+ else
14
+ key_words
15
+ end
16
+ @@rounds_by_block_size[biggest_words]
17
+ end
18
+ def self.round_constants(block_words, key_words) #:nodoc:
19
+ @@round_constants ||= {}
20
+ @@round_constants[block_words] ||= {}
21
+ unless(@@round_constants[block_words][key_words]) then
22
+ temp_v=1
23
+ p_round_constant=[0,1].map {|i| [i, 0, 0, 0].pack("C*")}
24
+
25
+ p_round_constant+=
26
+ (2 .. (block_words * (round_count(block_words, key_words) + 1)/key_words).to_i).to_a.map {
27
+ #0x1000000<<($_-1)
28
+ [(temp_v=Core.dot(02,temp_v)),0,0,0].pack("C*")
29
+ }
30
+ @@round_constants[block_words][key_words] = p_round_constant
31
+ end
32
+ @@round_constants[block_words][key_words]
33
+ end
34
+ def self.expand_key_le6(key, block_words) #:nodoc
35
+ # For short (128-bit, 192-bit) keys this is used to expand the key to blocklen*(rounds+1) bits
36
+
37
+ #expanded_key=key;
38
+ ek_words=key.unpack("N*").map {|number| Encrypted::ByteStream.new([number].pack("N"))}
39
+
40
+ key_words = key.length / 4
41
+ p_round_constant = round_constants(block_words, key_words)
42
+
43
+ rounds=round_count(block_words, key_words)
44
+
45
+ (key_words .. block_words * (rounds + 1)-1).each do
46
+ |i|
47
+
48
+ p_temp=ek_words[i-1]
49
+
50
+
51
+ if(i % key_words == 0)
52
+
53
+ t_byte=p_temp.byte_at(0)
54
+ p_temp[0 .. 2]=p_temp[1 .. 3]
55
+ p_temp.byte_at(3, t_byte)
56
+
57
+ # tr would be great here again.
58
+ p_temp=Encrypted::ByteStream.new(Core.sbox_block(p_temp))
59
+ p_temp^=p_round_constant[(i/key_words).to_i]
60
+ end
61
+ ek_words[i]=p_temp^ek_words[i-key_words]
62
+ i+=1
63
+ end
64
+ #puts ek_words.to_s
65
+ expanded_key=Array(rounds+1)
66
+ (0 .. rounds).each do
67
+ |round|
68
+ expanded_key[round]=Encrypted::ByteStream.new(ek_words[round*block_words, block_words].join(""))
69
+ end
70
+ return expanded_key;
71
+ end
72
+
73
+ def self.expand_key_gt6(key, block_words) #:nodoc:
74
+ # For long (256-bit) keys this is used to expand the key to blocklen*(rounds+1) bits
75
+
76
+ #expanded_key=key
77
+ ek_words=key.unpack("N*").map {|number| Encrypted::ByteStream.new([number].pack("N"))}
78
+
79
+ key_words = key.length / 4
80
+ p_round_constant = round_constants(block_words, key_words)
81
+
82
+ rounds=round_count(block_words, key_words)
83
+
84
+ (key_words .. block_words * (rounds + 1)-1).each do
85
+ |i|
86
+
87
+ p_temp=ek_words[i-1]
88
+ if(i % key_words == 0)
89
+
90
+ t_byte=p_temp.byte_at(0)
91
+ p_temp[0 .. 2]=p_temp[1 .. 3]
92
+ p_temp.byte_at(3, t_byte)
93
+
94
+ # tr would be great here again.
95
+ p_temp=Encrypted::ByteStream.new(Core.sbox_block(p_temp))
96
+ p_temp^=p_round_constant[(i/key_words).to_i]
97
+
98
+ elsif(i % key_words == 4)
99
+ p_temp=Core.sbox_block(p_temp)
100
+ end
101
+ ek_words[i]=ek_words[i-key_words]^p_temp
102
+ end
103
+ expanded_key=Array(rounds+1)
104
+ (0 .. rounds).each do
105
+ |round|
106
+ expanded_key[round]=Encrypted::ByteStream.new(ek_words[round*block_words, block_words].join(""))
107
+ end
108
+ return expanded_key;
109
+ end
110
+
111
+ def self.roundn_times(block, expanded_key, rounds, direction) #:nodoc:
112
+ case(direction)
113
+ when :forward then
114
+ (1 .. rounds-1).each do
115
+ |current_round|
116
+ block=Core.roundn(block, expanded_key[current_round])
117
+ end
118
+ when :reverse then
119
+ (1 .. rounds-1).to_a.reverse.each do
120
+ |current_round|
121
+ block=Core.inv_roundn(block, expanded_key[current_round])
122
+ end
123
+ else
124
+ raise "Unsupported round direction"
125
+ end
126
+ block
127
+ end
128
+ def self.roundn(input, round_key) #:nodoc:
129
+ block_words = input.length / 4
130
+ row_len=block_words;
131
+
132
+ input=sbox_block(input)
133
+ input=shift_rows(input)
134
+ # Tune this - jim
135
+ input=mix_column(input)
136
+
137
+ return round0(input, round_key)
138
+ end
139
+
140
+ def self.inv_roundn(input, round_key) #:nodoc:
141
+ block_words = input.length / 4
142
+
143
+ input=round0(input, round_key)
144
+ row_len=block_words
145
+ input=inv_mix_column(input)
146
+
147
+
148
+ input=inv_shift_rows(input)
149
+ # convert to use tr for the s-box ?
150
+ input=inv_sbox_block(input)
151
+
152
+ return input
153
+ end
154
+
155
+ def self.roundl(input, round_key) #:nodoc:
156
+ # convert to use tr for the s-box
157
+
158
+ input=sbox_block(input)
159
+ input=shift_rows(input)
160
+ return round0(input, round_key)
161
+ end
162
+
163
+ def self.inv_roundl(input, round_key) #:nodoc:
164
+ # convert to use tr for the s-box
165
+ input=round0(input, round_key)
166
+ input=inv_sbox_block(input)
167
+ input=inv_shift_rows(input)
168
+ #input=bytes_n.pack("C*")
169
+ return input
170
+ end
171
+
172
+
173
+ def self.round0(input, round_key) #:nodoc:
174
+ return round_key^input;
175
+ end
176
+ def self.make_shiftrow_map #:nodoc:
177
+ shift_for_block_len={
178
+ 4=>[0,1,2,3],
179
+ 6=>[0,1,2,3],
180
+ 8=>[0,1,3,4],
181
+ }
182
+ @@inv_shiftrow_map=(0 .. 0xff).map {Array.new}
183
+ @@shiftrow_map=(0 .. 0xff).map {Array.new}
184
+ shift_for_block_len.keys.each do
185
+ |block_len|
186
+ row_len=block_len;
187
+ state_b=(0 .. (row_len*4)-1).to_a;
188
+ col_len=4;
189
+ c=shift_for_block_len[block_len];
190
+ (0 .. c.length-1).each do
191
+ |row_n|
192
+ # Grab the lossage first
193
+ next unless c[row_n] > 0;
194
+ d1=Array.new
195
+ d2=Array.new
196
+ (row_len-c[row_n] .. row_len-1).map {|col| row_n+col_len*col}.each do
197
+ |offset|
198
+ d1+=state_b[offset,1]
199
+ end
200
+ (0 .. row_len-c[row_n]-1).map {|col| row_n+col_len*col}.each do
201
+ |offset|
202
+ d2+=state_b[offset,1]
203
+ end
204
+
205
+ (0 .. row_len-1).map {|col| row_n+col_len*col}.each do
206
+ |offset|
207
+ state_b[offset]=d1.shift||d2.shift
208
+ end
209
+ end
210
+ @@inv_shiftrow_map[block_len]=state_b;
211
+ (0 .. state_b.length-1).each do
212
+ |offset|
213
+ @@shiftrow_map[block_len][state_b[offset]]=offset;
214
+ end
215
+ end
216
+ end
217
+
218
+ make_shiftrow_map
219
+
220
+ def self.shift_rows(state_b) #:nodoc:
221
+ row_len=state_b.length/4
222
+
223
+ state_o=@@shiftrow_map[row_len].map do
224
+ |offset|
225
+ state_b.byte_at(offset)
226
+ end
227
+ return Encrypted::ByteStream.new(state_o.pack("C*"))
228
+ end
229
+
230
+ def self.inv_shift_rows(state_b) #:nodoc:
231
+ col_len=4;
232
+ row_len=state_b.length/4;
233
+
234
+ state_o=@@inv_shiftrow_map[row_len].map do
235
+ |offset|
236
+ state_b.byte_at(offset)
237
+ end
238
+ return Encrypted::ByteStream.new(state_o.pack("C*"))
239
+ end
240
+
241
+
242
+ POLYNOMIAL_SPACE=0x11b
243
+ COLUMN_SIZE=4
244
+
245
+ def self.sbox_block(input)
246
+ return Encrypted::ByteStream.new(input.unpack("C*").map do
247
+ |byte|
248
+ @@sbox[byte]
249
+ end.pack("C*"))
250
+ end
251
+
252
+ def self.inv_sbox_block(input)
253
+ return Encrypted::ByteStream.new(input.unpack("C*").map do
254
+ |byte|
255
+ @@inv_sbox[byte]
256
+ end.pack("C*"))
257
+ end
258
+
259
+ def self.mix_column(col)
260
+ block_words=col.length/COLUMN_SIZE
261
+ r_col=Array.new
262
+ (0 .. (block_words-1)).each {
263
+ |current_word|
264
+ r_col+=[
265
+ (@@dot_cache[02][col.byte_at((current_word*4)+0)] ^
266
+ @@dot_cache[03][col.byte_at((current_word*4)+1)] ^
267
+ col.byte_at((current_word*4)+2) ^
268
+ col.byte_at((current_word*4)+3) ),
269
+ ( col.byte_at((current_word*4)+0) ^
270
+ @@dot_cache[02][col.byte_at((current_word*4)+1)] ^
271
+ @@dot_cache[03][col.byte_at((current_word*4)+2)] ^
272
+ col.byte_at((current_word*4)+3) ),
273
+ ( col.byte_at((current_word*4)+0) ^
274
+ col.byte_at((current_word*4)+1) ^
275
+ @@dot_cache[02][col.byte_at((current_word*4)+2)] ^
276
+ @@dot_cache[03][col.byte_at((current_word*4)+3)]),
277
+ (@@dot_cache[03][col.byte_at((current_word*4)+0)] ^
278
+ col.byte_at((current_word*4)+1) ^
279
+ col.byte_at((current_word*4)+2) ^
280
+ @@dot_cache[02][col.byte_at((current_word*4)+3)])]
281
+ }
282
+ return Encrypted::ByteStream.new(r_col.pack("C*"))
283
+ end
284
+
285
+ # The inverse of the above
286
+
287
+ def self.inv_mix_column(col)
288
+ block_words=col.length/COLUMN_SIZE
289
+ r_col=Array.new
290
+ (0 .. (block_words-1)).each { |current_block|
291
+ r_col+=[
292
+ (@@dot_cache[0x0e][col.byte_at((current_block*4)+0)] ^
293
+ @@dot_cache[0x0b][col.byte_at((current_block*4)+1)] ^
294
+ @@dot_cache[0x0d][col.byte_at((current_block*4)+2)] ^
295
+ @@dot_cache[0x09][col.byte_at((current_block*4)+3)]),
296
+ (@@dot_cache[0x09][col.byte_at((current_block*4)+0)] ^
297
+ @@dot_cache[0x0e][col.byte_at((current_block*4)+1)] ^
298
+ @@dot_cache[0x0b][col.byte_at((current_block*4)+2)] ^
299
+ @@dot_cache[0x0d][col.byte_at((current_block*4)+3)]),
300
+ (@@dot_cache[0x0d][col.byte_at((current_block*4)+0)] ^
301
+ @@dot_cache[0x09][col.byte_at((current_block*4)+1)] ^
302
+ @@dot_cache[0x0e][col.byte_at((current_block*4)+2)] ^
303
+ @@dot_cache[0x0b][col.byte_at((current_block*4)+3)]),
304
+ (@@dot_cache[0x0b][col.byte_at((current_block*4)+0)] ^
305
+ @@dot_cache[0x0d][col.byte_at((current_block*4)+1)] ^
306
+ @@dot_cache[0x09][col.byte_at((current_block*4)+2)] ^
307
+ @@dot_cache[0x0e][col.byte_at((current_block*4)+3)])
308
+ ]}
309
+ return Encrypted::ByteStream.new(r_col.pack("C*"))
310
+ end
311
+
312
+ def self.xtime(a)
313
+ a*=2
314
+ if( a & 0x100 > 0 )
315
+ a^=0x1b
316
+ end
317
+ a&=0xff
318
+ return a
319
+ end
320
+
321
+ def self.dot(a, b)
322
+ return 0 unless(a > 0 and b > 0)
323
+
324
+ result=0
325
+ tv=a
326
+ (0 .. 7).each do
327
+ |i|
328
+ if(b & (1<<i) > 0)
329
+ result^=tv
330
+ end
331
+ tv=xtime(tv)
332
+ end
333
+ return result
334
+ end
335
+
336
+
337
+ # _Not_ the same as dot()
338
+ # Multiplies a by b. In polynomial space. Without capping the value.
339
+ def self.mul(a, b)
340
+ result=0
341
+ tv=a
342
+ (0 .. 7).each do
343
+ |i|
344
+ if(b & (1<<i) > 0)
345
+ result^=tv
346
+ end
347
+ tv<<=1
348
+ end
349
+ return result
350
+ end
351
+
352
+ # The inverse of mul() above.
353
+
354
+ def self.div(a, b)
355
+ acc=a
356
+ tv=b
357
+ result=0
358
+ (0 .. 7).to_a.reverse.each do
359
+ | i |
360
+ tv=b<<i
361
+
362
+ if( (tv&~acc) < acc or (acc^tv) <= (1<<i))
363
+ result|=(1<<i)
364
+ acc^=tv
365
+ end
366
+ end
367
+ return result
368
+ end
369
+
370
+ # 8-bit number in, 8-bit number out
371
+ def self.mult_inverse(num)
372
+ return 0 unless num > 0
373
+ remainder=[POLYNOMIAL_SPACE, num]
374
+ auxiliary=[0,1]
375
+
376
+ if(remainder[1]==1)
377
+ return 1
378
+ end
379
+ i=2
380
+ while remainder[i-1]!=1
381
+ quotient=div(remainder[i-2], remainder[i-1])
382
+ multiplied=mul(remainder[i-1], quotient)
383
+
384
+ remainder[i]=remainder[i-2]^multiplied
385
+ auxiliary[i]=mul(quotient,auxiliary[i-1]) ^ auxiliary[i-2]
386
+ if (i>10)
387
+ raise "BUG: Multiplicative inverse should never exceed 10 iterations"
388
+ end
389
+ i+=1
390
+ end
391
+ return auxiliary[i-1]
392
+ end
393
+
394
+ def self.sbox(b)
395
+ c=0x63
396
+ b=mult_inverse(b)
397
+ result=b
398
+ (1 .. 4).each do
399
+ |i|
400
+ b_t=((b<<i)&0xff)|(b>>(8-i))
401
+ result^=b_t
402
+ end
403
+ return result^c
404
+ end
405
+
406
+ # Startup caching follows
407
+
408
+ unless(defined? @@all_cached)
409
+ @@sbox=(0 .. 255).to_a.map { |input| sbox(input)}
410
+ @@inv_sbox=Array.new(256)
411
+ (0 .. 255).each do
412
+ |input|
413
+ @@inv_sbox[@@sbox[input]]=input
414
+ end
415
+ @@dot_cache=(0 .. 0xf).map {Array.new(256)}
416
+ [0x2, 0x3, 0x9, 0xb, 0xd, 0xe].each do
417
+ # These are the only numbers we need.
418
+ |a|
419
+ (0 .. 0xff).each do
420
+ |b|
421
+ @@dot_cache[a][b]=dot(a, b)
422
+ end
423
+ end
424
+ @@all_cached=1
425
+ end
426
+
427
+ end
428
+
429
+ end
430
+ end