crypt19-rb 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,92 @@
1
+ # add_noise - take a message and intersperse noise to make a new noisy message of given byte-length
2
+ # remove_noise - take a noisy message and extract the message
3
+
4
+ module Crypt
5
+ module Noise
6
+
7
+ def add_noise(new_length)
8
+ message = self
9
+ usable_noisy_message_length = new_length / 9 * 8
10
+ bitmap_size = new_length / 9
11
+ remaining_bytes = new_length - usable_noisy_message_length - bitmap_size
12
+ if (message.length > usable_noisy_message_length)
13
+ minimumnew_length = (message.length / 8.0).ceil * 9
14
+ puts "For a clear text of #{message.length} bytes, the minimum obscured length"
15
+ puts "is #{minimumnew_length} bytes which allows for no noise in the message."
16
+ puts "You should choose an obscured length of at least double the clear text"
17
+ puts "length, such as #{message.length / 8 * 32} bytes"
18
+ raise "Insufficient length for noisy message"
19
+ end
20
+ bitmap = []
21
+ usable_noisy_message_length.times { bitmap << false }
22
+ srand(Time.now.to_i)
23
+ positions_selected = 0
24
+ while (positions_selected < message.length)
25
+ position_taken = rand(usable_noisy_message_length)
26
+ if bitmap[position_taken]
27
+ next
28
+ else
29
+ bitmap[position_taken] = true
30
+ positions_selected = positions_selected.next
31
+ end
32
+ end
33
+
34
+ noisy_message = ""
35
+ 0.upto(bitmap_size-1) { |byte|
36
+ c = 0
37
+ 0.upto(7) { |bit|
38
+ c = c + (1<<bit) if bitmap[byte * 8 + bit]
39
+ }
40
+ noisy_message << c.chr
41
+ }
42
+ pos_in_message = 0
43
+ 0.upto(usable_noisy_message_length-1) { |pos|
44
+ if bitmap[pos]
45
+ meaningful_byte = message[pos_in_message]
46
+ noisy_message << meaningful_byte
47
+ pos_in_message = pos_in_message.next
48
+ else
49
+ noise_byte = rand(256).chr
50
+ noisy_message << noise_byte
51
+ end
52
+ }
53
+ remaining_bytes.times {
54
+ noise_byte = rand(256).chr
55
+ noisy_message << noise_byte
56
+ }
57
+ return(noisy_message)
58
+ end
59
+
60
+
61
+ def remove_noise
62
+ noisy_message = self
63
+ bitmap_size = noisy_message.length / 9
64
+ actual_message_length = bitmap_size * 8
65
+
66
+ actual_message_start = bitmap_size
67
+ actual_message_finish = bitmap_size + actual_message_length - 1
68
+ actual_message = noisy_message[actual_message_start..actual_message_finish]
69
+
70
+ bitmap = []
71
+ 0.upto(bitmap_size - 1) { |byte|
72
+ c = noisy_message[byte]
73
+ 0.upto(7) { |bit|
74
+ bitmap[byte * 8 + bit] = (c[bit] == 1)
75
+ }
76
+ }
77
+ clear_message = ""
78
+ 0.upto(actual_message_length) { |pos|
79
+ meaningful = bitmap[pos]
80
+ if meaningful
81
+ clear_message << actual_message[pos]
82
+ end
83
+ }
84
+ return(clear_message)
85
+ end
86
+
87
+ end
88
+ end
89
+
90
+ class String
91
+ include Crypt::Noise
92
+ end
@@ -0,0 +1,73 @@
1
+ # RC6 symmetric key block cipher
2
+ # RC6 is a patented encryption algorithm (U.S. Patent 5,724,428 and U.S. Patent 5,835,600)
3
+ # Ported by Alexey Lapitsky <lex.public@gmail.com> (2009)
4
+
5
+ require 'crypt/cbc'
6
+
7
+ module Crypt
8
+ class RC6
9
+ include Crypt::CBC
10
+
11
+ def block_size
12
+ return 16
13
+ end
14
+
15
+ def lrotate(d,s)
16
+ d = d & 0xffffffff
17
+ ((d)<<(s&(31))) | ((d)>>(32-(s&(31))))
18
+ end
19
+ def rrotate(d,s)
20
+ d = d & 0xffffffff
21
+ ((d)>>(s&(31))) | ((d)<<(32-(s&(31))))
22
+ end
23
+
24
+ def initialize(key)
25
+ @rounds, @sbox, @key = 20, [0xB7E15163], []
26
+ key = key.bytes.to_a if key.class == String
27
+ raise("Wrong key length") unless [32,24,16].include?(key.size)
28
+ (key.size-1).downto(0){|i| @key[i/4] = ((@key[i/4]||0) << 8) + key[i]}
29
+
30
+ (@rounds * 2 + 3).times{|i| @sbox << (@sbox.last + 0x9E3779B9 & 0xffffffff)}
31
+ a = b = i = j = 0
32
+ (3 * (2 * @rounds + 4)).times do
33
+ a = @sbox[i] = lrotate(@sbox[i] + a + b, 3)
34
+ b = @key[j] = lrotate(@key[j] + a + b, a + b)
35
+ i = (i + 1).divmod(2 * @rounds + 4).last
36
+ j = (j + 1).divmod(@key.size).last
37
+ end
38
+ end
39
+
40
+ def encrypt_block(data)
41
+ a, b, c, d = *data.unpack('N*')
42
+ b += @sbox[0]
43
+ d += @sbox[1]
44
+ 1.upto @rounds do |i|
45
+ t = lrotate((b * (2 * b + 1)), 5)
46
+ u = lrotate((d * (2 * d + 1)), 5)
47
+ a = lrotate((a ^ t), u) + @sbox[2 * i]
48
+ c = lrotate((c ^ u), t) + @sbox[2 * i + 1]
49
+ a, b, c, d = b, c, d, a
50
+ end
51
+ a += @sbox[2 * @rounds + 2]
52
+ c += @sbox[2 * @rounds + 3]
53
+ [a, b, c, d].map{|i| i & 0xffffffff}.pack('N*')
54
+ end
55
+
56
+ def decrypt_block(data)
57
+ a, b, c, d = *data.unpack('N*')
58
+ c -= @sbox[2 * @rounds + 3]
59
+ a -= @sbox[2 * @rounds + 2]
60
+ @rounds.downto 1 do |i|
61
+ a, b, c, d = d, a, b, c
62
+ u = lrotate((d * (2 * d + 1)), 5)
63
+ t = lrotate((b * (2 * b + 1)), 5)
64
+ c = rrotate((c - @sbox[2 * i + 1]), t) ^ u
65
+ a = rrotate((a - @sbox[2 * i]), u) ^ t
66
+ end
67
+ d -= @sbox[1]
68
+ b -= @sbox[0]
69
+ [a, b, c, d].map{|i| i & 0xffffffff}.pack('N*')
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,115 @@
1
+ module Crypt
2
+ module RijndaelTables
3
+
4
+ LogTable = [
5
+ 0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3,
6
+ 100, 4, 224, 14, 52, 141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193,
7
+ 125, 194, 29, 181, 249, 185, 39, 106, 77, 228, 166, 114, 154, 201, 9, 120,
8
+ 101, 47, 138, 5, 33, 15, 225, 36, 18, 240, 130, 69, 53, 147, 218, 142,
9
+ 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241, 64, 70, 131, 56,
10
+ 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145, 16,
11
+ 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186,
12
+ 43, 121, 10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87,
13
+ 175, 88, 168, 80, 244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232,
14
+ 44, 215, 117, 122, 235, 22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160,
15
+ 127, 12, 246, 111, 23, 196, 73, 236, 216, 67, 31, 45, 164, 118, 123, 183,
16
+ 204, 187, 62, 90, 251, 96, 177, 134, 59, 82, 161, 108, 170, 85, 41, 157,
17
+ 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207, 205, 55, 63, 91, 209,
18
+ 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242, 211, 171,
19
+ 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165,
20
+ 103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7
21
+ ]
22
+
23
+ AlogTable = [
24
+ 1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53,
25
+ 95, 225, 56, 72, 216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170,
26
+ 229, 52, 92, 228, 55, 89, 235, 38, 106, 190, 217, 112, 144, 171, 230, 49,
27
+ 83, 245, 4, 12, 20, 60, 68, 204, 79, 209, 104, 184, 211, 110, 178, 205,
28
+ 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8, 24, 40, 120, 136,
29
+ 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73, 219, 118, 154,
30
+ 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97, 163,
31
+ 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160,
32
+ 251, 22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65,
33
+ 195, 94, 226, 61, 71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117,
34
+ 159, 186, 213, 100, 172, 239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
35
+ 155, 182, 193, 88, 232, 35, 101, 175, 234, 37, 111, 177, 200, 67, 197, 84,
36
+ 252, 31, 33, 99, 165, 244, 7, 9, 27, 45, 119, 153, 176, 203, 70, 202,
37
+ 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66, 198, 81, 243, 14,
38
+ 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242, 13, 23,
39
+ 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1
40
+ ]
41
+
42
+ S = [
43
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118,
44
+ 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
45
+ 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21,
46
+ 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117,
47
+ 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132,
48
+ 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207,
49
+ 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168,
50
+ 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210,
51
+ 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115,
52
+ 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219,
53
+ 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121,
54
+ 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8,
55
+ 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138,
56
+ 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158,
57
+ 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
58
+ 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22
59
+ ]
60
+
61
+ Si = [
62
+ 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251,
63
+ 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203,
64
+ 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66, 250, 195, 78,
65
+ 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73, 109, 139, 209, 37,
66
+ 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92, 204, 93, 101, 182, 146,
67
+ 108, 112, 72, 80, 253, 237, 185, 218, 94, 21, 70, 87, 167, 141, 157, 132,
68
+ 144, 216, 171, 0, 140, 188, 211, 10, 247, 228, 88, 5, 184, 179, 69, 6,
69
+ 208, 44, 30, 143, 202, 63, 15, 2, 193, 175, 189, 3, 1, 19, 138, 107,
70
+ 58, 145, 17, 65, 79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
71
+ 150, 172, 116, 34, 231, 173, 53, 133, 226, 249, 55, 232, 28, 117, 223, 110,
72
+ 71, 241, 26, 113, 29, 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27,
73
+ 252, 86, 62, 75, 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244,
74
+ 31, 221, 168, 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95,
75
+ 96, 81, 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239,
76
+ 160, 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
77
+ 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12, 125,
78
+ ]
79
+
80
+ IG = [
81
+ [0x0e, 0x09, 0x0d, 0x0b],
82
+ [0x0b, 0x0e, 0x09, 0x0d],
83
+ [0x0d, 0x0b, 0x0e, 0x09],
84
+ [0x09, 0x0d, 0x0b, 0x0e]
85
+ ]
86
+
87
+ Rcon = [
88
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20,
89
+ 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8,
90
+ 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc,
91
+ 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4,
92
+ 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
93
+ ]
94
+
95
+ Shifts = [
96
+ [
97
+ [0, 0],
98
+ [1, 3],
99
+ [2, 2],
100
+ [3, 1]
101
+ ], [
102
+ [0, 0],
103
+ [1, 5],
104
+ [2, 4],
105
+ [3, 3]
106
+ ], [
107
+ [0, 0],
108
+ [1, 7],
109
+ [3, 5],
110
+ [4, 4]
111
+ ]
112
+ ]
113
+
114
+ end
115
+ end
@@ -0,0 +1,267 @@
1
+ # Adapted from the reference C implementation:
2
+ # rijndael-alg-ref.c v2.2 March 2002
3
+ # Reference ANSI C code by Paulo Barreto and Vincent Rijmen
4
+
5
+ require 'crypt/cbc'
6
+ require 'crypt/rijndael-tables'
7
+ require 'crypt/bytes-compat'
8
+
9
+ module Crypt
10
+ class Rijndael
11
+
12
+ include Crypt::CBC
13
+ include Crypt::RijndaelTables
14
+
15
+
16
+ def initialize(user_key, key_bits = 256, block_bits = 128)
17
+ case key_bits
18
+ when 128
19
+ @key_words = 4
20
+ when 192
21
+ @key_words = 6
22
+ when 256
23
+ @key_words = 8
24
+ else raise "The key must be 128, 192, or 256 bits long."
25
+ end
26
+
27
+ case (key_bits >= block_bits) ? key_bits : block_bits
28
+ when 128
29
+ @rounds = 10
30
+ when 192
31
+ @rounds = 12
32
+ when 256
33
+ @rounds = 14
34
+ else raise "The key and block sizes must be 128, 192, or 256 bits long."
35
+ end
36
+
37
+ case block_bits
38
+ when 128
39
+ @block_size = 16
40
+ @block_words = 4
41
+ @shift_index = 0
42
+ when 192
43
+ @block_size = 24
44
+ @block_words = 6
45
+ @shift_index = 1
46
+ when 256
47
+ @block_size = 32
48
+ @block_words = 8
49
+ @shift_index = 2
50
+ else raise "The block size must be 128, 192, or 256 bits long."
51
+ end
52
+
53
+ uk = user_key.unpack('C'*user_key.length)
54
+ max_useful_size_of_user_key = (key_bits/8)
55
+ uk = uk[0..max_useful_size_of_user_key-1] # truncate
56
+ padding = 0
57
+ if (user_key.length < key_bits/8)
58
+ shortfall_in_user_key = (key_bits/8 - user_key.length)
59
+ shortfall_in_user_key.times { uk << padding }
60
+ end
61
+ @key = [[], [], [], []]
62
+ 0.upto(uk.length-1) { |pos|
63
+ @key[pos % 4][pos / 4] = uk[pos]
64
+ }
65
+ @round_keys = generate_key_schedule(@key, key_bits, block_bits)
66
+ end
67
+
68
+
69
+ def block_size
70
+ return(@block_size) # needed for CBC
71
+ end
72
+
73
+
74
+ def mul(a, b)
75
+ if ((a ==0) | (b == 0))
76
+ result = 0
77
+ else
78
+ result = AlogTable[(LogTable[a] + LogTable[b]) % 255]
79
+ end
80
+ return(result)
81
+ end
82
+
83
+
84
+ def add_round_key(block_array, round_key)
85
+ 0.upto(3) { |i|
86
+ 0.upto(@block_words) { |j|
87
+ block_array[i][j] ^= round_key[i][j]
88
+ }
89
+ }
90
+ return(block_array)
91
+ end
92
+
93
+
94
+ def shift_rows(block_array, direction)
95
+ tmp = []
96
+ 1.upto(3) { |i| # row zero remains unchanged
97
+ 0.upto(@block_words-1) { |j|
98
+ tmp[j] = block_array[i][(j + Shifts[@shift_index][i][direction]) % @block_words]
99
+ }
100
+ 0.upto(@block_words-1) { |j|
101
+ block_array[i][j] = tmp[j]
102
+ }
103
+ }
104
+ return(block_array)
105
+ end
106
+
107
+
108
+ def substitution(block_array, sBox)
109
+ # replace every byte of the input with the byte at that position in the S-box
110
+ 0.upto(3) { |i|
111
+ 0.upto(@block_words-1) { |j|
112
+ block_array[i][j] = sBox[block_array[i][j]]
113
+ }
114
+ }
115
+ return(block_array)
116
+ end
117
+
118
+
119
+ def mix_columns(block_array)
120
+ mixed = [[], [], [], []]
121
+ 0.upto(@block_words-1) { |j|
122
+ 0.upto(3) { |i|
123
+ mixed[i][j] = mul(2,block_array[i][j]) ^
124
+ mul(3,block_array[(i + 1) % 4][j]) ^
125
+ block_array[(i + 2) % 4][j] ^
126
+ block_array[(i + 3) % 4][j]
127
+ }
128
+ }
129
+ return(mixed)
130
+ end
131
+
132
+
133
+ def inverse_mix_columns(block_array)
134
+ unmixed = [[], [], [], []]
135
+ 0.upto(@block_words-1) { |j|
136
+ 0.upto(3) { |i|
137
+ unmixed[i][j] = mul(0xe, block_array[i][j]) ^
138
+ mul(0xb, block_array[(i + 1) % 4][j]) ^
139
+ mul(0xd, block_array[(i + 2) % 4][j]) ^
140
+ mul(0x9, block_array[(i + 3) % 4][j])
141
+ }
142
+ }
143
+ return(unmixed)
144
+ end
145
+
146
+
147
+ def generate_key_schedule(k, key_bits, block_bits)
148
+ tk = k[0..3][0..@key_words-1] # using slice to get a copy instead of a reference
149
+ key_sched = []
150
+ (@rounds + 1).times { key_sched << [[], [], [], []] }
151
+ t = 0
152
+ j = 0
153
+ while ((j < @key_words) && (t < (@rounds+1)*@block_words))
154
+ 0.upto(3) { |i|
155
+ key_sched[t / @block_words][i][t % @block_words] = tk[i][j]
156
+ }
157
+ j += 1
158
+ t += 1
159
+ end
160
+ # while not enough round key material collected, calculate new values
161
+ rcon_index = 0
162
+ while (t < (@rounds+1)*@block_words)
163
+ 0.upto(3) { |i|
164
+ tk[i][0] ^= S[tk[(i + 1) % 4][@key_words - 1]]
165
+ }
166
+ tk[0][0] ^= Rcon[rcon_index]
167
+ rcon_index = rcon_index.next
168
+ if (@key_words != 8)
169
+ 1.upto(@key_words - 1) { |j|
170
+ 0.upto(3) { |i|
171
+ tk[i][j] ^= tk[i][j-1];
172
+ }
173
+ }
174
+ else
175
+ 1.upto(@key_words/2 - 1) { |j|
176
+ 0.upto(3) { |i|
177
+ tk[i][j] ^= tk[i][j-1]
178
+ }
179
+ }
180
+ 0.upto(3) { |i|
181
+ tk[i][@key_words/2] ^= S[tk[i][@key_words/2 - 1]]
182
+ }
183
+ (@key_words/2 + 1).upto(@key_words - 1) { |j|
184
+ 0.upto(3) { |i|
185
+ tk[i][j] ^= tk[i][j-1]
186
+ }
187
+ }
188
+ end
189
+ j = 0
190
+ while ((j < @key_words) && (t < (@rounds+1) * @block_words))
191
+ 0.upto(3) { |i|
192
+ key_sched[t / @block_words][i][t % @block_words] = tk[i][j]
193
+ }
194
+ j += 1
195
+ t += 1
196
+ end
197
+ end
198
+ return(key_sched)
199
+ end
200
+
201
+
202
+ def encrypt_byte_array(block_array)
203
+ block_array = add_round_key(block_array, @round_keys[0])
204
+ 1.upto(@rounds - 1) { |round|
205
+ block_array = substitution(block_array, S)
206
+ block_array = shift_rows(block_array, 0)
207
+ block_array = mix_columns(block_array)
208
+ block_array = add_round_key(block_array, @round_keys[round])
209
+ }
210
+ # special round without mix_columns
211
+ block_array = substitution(block_array,S)
212
+ block_array = shift_rows(block_array,0)
213
+ block_array = add_round_key(block_array, @round_keys[@rounds])
214
+ return(block_array)
215
+ end
216
+
217
+
218
+ def encrypt_block(block)
219
+ raise "block must be #{@block_size} bytes long" if (block.length() != @block_size)
220
+ block_array = [[], [], [], []]
221
+ block_bytes = block.bytes.to_a
222
+ 0.upto(@block_size - 1) { |pos|
223
+ block_array[pos % 4][pos / 4] = block_bytes[pos]
224
+ }
225
+ encrypted_block = encrypt_byte_array(block_array)
226
+ encrypted = ""
227
+ 0.upto(@block_size - 1) { |pos|
228
+ encrypted << encrypted_block[pos % 4][pos / 4]
229
+ }
230
+ return(encrypted)
231
+ end
232
+
233
+
234
+ def decrypt_byte_array(block_array)
235
+ # first special round without inverse_mix_columns
236
+ # add_round_key is an involution - applying it a second time returns the original result
237
+ block_array = add_round_key(block_array, @round_keys[@rounds])
238
+ block_array = substitution(block_array,Si) # using inverse S-box
239
+ block_array = shift_rows(block_array,1)
240
+ (@rounds-1).downto(1) { |round|
241
+ block_array = add_round_key(block_array, @round_keys[round])
242
+ block_array = inverse_mix_columns(block_array)
243
+ block_array = substitution(block_array, Si)
244
+ block_array = shift_rows(block_array, 1)
245
+ }
246
+ block_array = add_round_key(block_array, @round_keys[0])
247
+ return(block_array)
248
+ end
249
+
250
+
251
+ def decrypt_block(block)
252
+ raise "block must be #{@block_size} bytes long" if (block.length() != @block_size)
253
+ block_array = [[], [], [], []]
254
+ block_bytes = block.bytes.to_a
255
+ 0.upto(@block_size - 1) { |pos|
256
+ block_array[pos % 4][pos / 4] = block_bytes[pos]
257
+ }
258
+ decrypted_block = decrypt_byte_array(block_array)
259
+ decrypted = ""
260
+ 0.upto(@block_size - 1) { |pos|
261
+ decrypted << decrypted_block[pos % 4][pos / 4]
262
+ }
263
+ return(decrypted)
264
+ end
265
+
266
+ end
267
+ end