crypt19-rb 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +18 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +16 -0
- data/LICENSE +44 -0
- data/README.md +54 -0
- data/Rakefile +10 -0
- data/VERSION +1 -0
- data/crypt19.gemspec +21 -0
- data/lib/crypt/blowfish-tables.rb +187 -0
- data/lib/crypt/blowfish.rb +109 -0
- data/lib/crypt/bytes-compat.rb +15 -0
- data/lib/crypt/cbc.rb +119 -0
- data/lib/crypt/gost.rb +138 -0
- data/lib/crypt/idea.rb +190 -0
- data/lib/crypt/noise.rb +92 -0
- data/lib/crypt/rc6.rb +73 -0
- data/lib/crypt/rijndael-tables.rb +115 -0
- data/lib/crypt/rijndael.rb +267 -0
- data/lib/crypt/stringxor.rb +23 -0
- data/lib/crypt/version.rb +3 -0
- data/test/blowfish_test.rb +84 -0
- data/test/gost_test.rb +69 -0
- data/test/idea_test.rb +70 -0
- data/test/rc6_test.rb +72 -0
- data/test/rijndael_test.rb +61 -0
- metadata +91 -0
data/lib/crypt/noise.rb
ADDED
@@ -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
|
data/lib/crypt/rc6.rb
ADDED
@@ -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
|