gost_kuznyechik 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +31 -0
- data/LICENSE.txt +21 -0
- data/README.md +167 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/gost_kuznyechik.gemspec +38 -0
- data/lib/gost_kuznyechik.rb +15 -0
- data/lib/gost_kuznyechik/kuznyechik.rb +249 -0
- data/lib/gost_kuznyechik/kuznyechik_cbc.rb +44 -0
- data/lib/gost_kuznyechik/kuznyechik_cfb.rb +145 -0
- data/lib/gost_kuznyechik/kuznyechik_ctr.rb +72 -0
- data/lib/gost_kuznyechik/kuznyechik_ctr_acpkm.rb +81 -0
- data/lib/gost_kuznyechik/kuznyechik_ecb.rb +50 -0
- data/lib/gost_kuznyechik/kuznyechik_key_exp_imp.rb +22 -0
- data/lib/gost_kuznyechik/kuznyechik_ofb.rb +78 -0
- data/lib/gost_kuznyechik/kuznyechik_omac.rb +141 -0
- data/lib/gost_kuznyechik/kuznyechik_omac_acpkm.rb +123 -0
- data/lib/gost_kuznyechik/kuznyechik_tables.rb +4299 -0
- data/lib/gost_kuznyechik/version.rb +3 -0
- metadata +111 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikCbc < Kuznyechik
|
3
|
+
def initialize(key, iv)
|
4
|
+
@key = key.dup.force_encoding('BINARY')
|
5
|
+
# @inkey => [4] uint_64, native-endian
|
6
|
+
@inkey = self.class.keyToNumbers(@key)
|
7
|
+
@ctxR = iv.dup.force_encoding('BINARY')
|
8
|
+
# @keys => [10*2] uint_64, native-endian
|
9
|
+
@encrypt_keys = self.class.expandEncryptKeys(@inkey)
|
10
|
+
@decrypt_keys = self.class.expandDecryptKeys(@inkey)
|
11
|
+
end
|
12
|
+
|
13
|
+
def encrypt(data)
|
14
|
+
data_len = data.length
|
15
|
+
outdata = ''
|
16
|
+
(0...(data_len / BlockLengthInBytes)).each do |i|
|
17
|
+
encr_block = data[(i * BlockLengthInBytes)...((i+1) * BlockLengthInBytes)]
|
18
|
+
(0...BlockLengthInBytes).each do |j|
|
19
|
+
encr_block[j] = (@ctxR[j].ord ^ data[i * BlockLengthInBytes + j].ord).chr
|
20
|
+
end
|
21
|
+
encr_block = self.class.encryptBlock(encr_block, @encrypt_keys)
|
22
|
+
outdata += encr_block
|
23
|
+
@ctxR = @ctxR[BlockLengthInBytes..-1] + encr_block
|
24
|
+
end
|
25
|
+
outdata
|
26
|
+
end
|
27
|
+
|
28
|
+
def decrypt(data)
|
29
|
+
data_len = data.length
|
30
|
+
outdata = ''
|
31
|
+
(0...(data_len / BlockLengthInBytes)).each do |i|
|
32
|
+
encr_block = data[(i * BlockLengthInBytes)...((i+1) * BlockLengthInBytes)]
|
33
|
+
decr_block = self.class.decryptBlock(encr_block, @decrypt_keys)
|
34
|
+
(0...BlockLengthInBytes).each do |j|
|
35
|
+
decr_block[j] = (@ctxR[j].ord ^ decr_block[j].ord).chr
|
36
|
+
end
|
37
|
+
outdata += decr_block
|
38
|
+
@ctxR = @ctxR[BlockLengthInBytes..-1] + encr_block
|
39
|
+
end
|
40
|
+
outdata
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikCfb < Kuznyechik
|
3
|
+
def initialize(key, iv, gamma_s)
|
4
|
+
@key = key.dup.force_encoding('BINARY')
|
5
|
+
# @inkey => [4] uint_64, native-endian
|
6
|
+
@inkey = self.class.keyToNumbers(@key)
|
7
|
+
@gamma_s = gamma_s
|
8
|
+
@ctxR = iv.dup.force_encoding('BINARY')
|
9
|
+
# keys and gamma initialization
|
10
|
+
@keys = self.class.expandEncryptKeys(@inkey)
|
11
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
12
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
13
|
+
@incomplete_block = ''
|
14
|
+
@incomplete_block_len = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def encrypt(data)
|
18
|
+
data_len = data.length
|
19
|
+
left_data_len = data_len
|
20
|
+
outdata = ''
|
21
|
+
if @incomplete_block_len > 0 then
|
22
|
+
# use old @gamma_block
|
23
|
+
if data_len < @gamma_s - @incomplete_block_len then
|
24
|
+
# incomplete block yet
|
25
|
+
encr_data = data.dup
|
26
|
+
(0...data_len).each do |j|
|
27
|
+
encr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
|
28
|
+
end
|
29
|
+
@incomplete_block_len += data_len
|
30
|
+
@incomplete_block += encr_data
|
31
|
+
return encr_data
|
32
|
+
else
|
33
|
+
encr_data = data[0...(@gamma_s - @incomplete_block_len)]
|
34
|
+
(0...encr_data.length).each do |j|
|
35
|
+
encr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
|
36
|
+
end
|
37
|
+
outdata += encr_data
|
38
|
+
# complete block - gamma update
|
39
|
+
@incomplete_block += encr_data
|
40
|
+
left_data_len -= encr_data.length
|
41
|
+
@ctxR = @ctxR[@gamma_s..-1] + @incomplete_block
|
42
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
43
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
44
|
+
@incomplete_block = ''
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
(0...(left_data_len / @gamma_s)).each do |i|
|
49
|
+
if @incomplete_block_len > 0 then
|
50
|
+
encr_data = data[((i + 1) * @gamma_s - @incomplete_block_len)...((i + 2) * @gamma_s - @incomplete_block_len)]
|
51
|
+
else
|
52
|
+
encr_data = data[(i * @gamma_s)...((i + 1) * @gamma_s)]
|
53
|
+
end
|
54
|
+
(0...@gamma_s).each do |j|
|
55
|
+
encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
|
56
|
+
end
|
57
|
+
outdata += encr_data
|
58
|
+
# complete block - gamma update
|
59
|
+
@ctxR = @ctxR[@gamma_s..-1] + encr_data
|
60
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
61
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
62
|
+
end
|
63
|
+
|
64
|
+
left_data_len %= @gamma_s
|
65
|
+
if left_data_len > 0 then
|
66
|
+
# incomplete block start
|
67
|
+
encr_data = data[-left_data_len..-1]
|
68
|
+
(0...left_data_len).each do |j|
|
69
|
+
encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
|
70
|
+
end
|
71
|
+
outdata += encr_data
|
72
|
+
@incomplete_block_len = left_data_len
|
73
|
+
@incomplete_block = encr_data
|
74
|
+
end
|
75
|
+
outdata
|
76
|
+
end
|
77
|
+
|
78
|
+
# Use input encrypted text to gamma update
|
79
|
+
def decrypt(data)
|
80
|
+
data_len = data.length
|
81
|
+
left_data_len = data_len
|
82
|
+
outdata = ''
|
83
|
+
if @incomplete_block_len > 0 then
|
84
|
+
# use old @gamma_block
|
85
|
+
if data_len < @gamma_s - @incomplete_block_len then
|
86
|
+
# incomplete block yet
|
87
|
+
encr_data = data.dup
|
88
|
+
decr_data = data.dup
|
89
|
+
(0...data_len).each do |j|
|
90
|
+
decr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
|
91
|
+
end
|
92
|
+
@incomplete_block_len += data_len
|
93
|
+
@incomplete_block += encr_data
|
94
|
+
return decr_data
|
95
|
+
else
|
96
|
+
encr_data = data[0...(@gamma_s - @incomplete_block_len)]
|
97
|
+
decr_data = encr_data.dup
|
98
|
+
(0...encr_data.length).each do |j|
|
99
|
+
decr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
|
100
|
+
end
|
101
|
+
outdata += decr_data
|
102
|
+
# complete block - gamma update
|
103
|
+
@incomplete_block += encr_data
|
104
|
+
left_data_len -= encr_data.length
|
105
|
+
@ctxR = @ctxR[@gamma_s..-1] + @incomplete_block
|
106
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
107
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
108
|
+
@incomplete_block = ''
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
(0...(left_data_len / @gamma_s)).each do |i|
|
113
|
+
if @incomplete_block_len > 0 then
|
114
|
+
encr_data = data[((i + 1) * @gamma_s - @incomplete_block_len)...((i + 2) * @gamma_s - @incomplete_block_len)]
|
115
|
+
else
|
116
|
+
encr_data = data[(i * @gamma_s)...((i + 1) * @gamma_s)]
|
117
|
+
end
|
118
|
+
decr_data = encr_data.dup
|
119
|
+
(0...@gamma_s).each do |j|
|
120
|
+
decr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
|
121
|
+
end
|
122
|
+
outdata += decr_data
|
123
|
+
# complete block - gamma update
|
124
|
+
@ctxR = @ctxR[@gamma_s..-1] + encr_data
|
125
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
126
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
127
|
+
end
|
128
|
+
|
129
|
+
left_data_len %= @gamma_s
|
130
|
+
if left_data_len > 0 then
|
131
|
+
# incomplete block start
|
132
|
+
encr_data = data[-left_data_len..-1]
|
133
|
+
decr_data = encr_data.dup
|
134
|
+
(0...left_data_len).each do |j|
|
135
|
+
decr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
|
136
|
+
end
|
137
|
+
outdata += decr_data
|
138
|
+
@incomplete_block_len = left_data_len
|
139
|
+
@incomplete_block = encr_data
|
140
|
+
end
|
141
|
+
outdata
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikCtr < Kuznyechik
|
3
|
+
def initialize(key, iv, gamma_s)
|
4
|
+
@key = key.dup.force_encoding('BINARY')
|
5
|
+
# @inkey => [4] uint_64, native-endian
|
6
|
+
@inkey = self.class.keyToNumbers(@key)
|
7
|
+
|
8
|
+
@keys = self.class.expandEncryptKeys(@inkey)
|
9
|
+
@gamma_s = gamma_s
|
10
|
+
@iv = iv.dup.force_encoding('BINARY')
|
11
|
+
@prev_len = 0
|
12
|
+
@bytes_count = 0
|
13
|
+
@tmp_block = self.class.zeroBlock
|
14
|
+
if @iv.length < BlockLengthInBytes/2 then
|
15
|
+
@iv += self.class.zeroBytes(BlockLengthInBytes/2 - @iv.length)
|
16
|
+
end
|
17
|
+
@counter = @iv[0...(BlockLengthInBytes/2)]
|
18
|
+
@counter += self.class.zeroBytes(BlockLengthInBytes/2)
|
19
|
+
end
|
20
|
+
|
21
|
+
def encrypt(indata)
|
22
|
+
data_len = indata.length
|
23
|
+
outdata = self.class.zeroBytes(data_len)
|
24
|
+
data_index = 0
|
25
|
+
if @prev_len > 0 then
|
26
|
+
if data_len < (@gamma_s - @prev_len) then
|
27
|
+
(0...data_len).each do |j|
|
28
|
+
outdata[j] = (indata[j].ord ^ @tmp_block[j + @prev_len].ord).chr
|
29
|
+
end
|
30
|
+
@prev_len += data_len
|
31
|
+
@bytes_count += data_len
|
32
|
+
return outdata
|
33
|
+
else
|
34
|
+
(0...(@gamma_s - @prev_len)).each do |j|
|
35
|
+
outdata[j] = (indata[j].ord ^ @tmp_block[j + @prev_len].ord).chr
|
36
|
+
end
|
37
|
+
data_index += @gamma_s - @prev_len
|
38
|
+
@bytes_count += @gamma_s - @prev_len
|
39
|
+
data_len -= @gamma_s - @prev_len
|
40
|
+
self.class.incrementModulo(@counter, BlockLengthInBytes)
|
41
|
+
@prev_len = 0
|
42
|
+
end
|
43
|
+
end
|
44
|
+
(0...(data_len / @gamma_s)).each do |i|
|
45
|
+
@tmp_block = self.class.encryptBlock(@counter, @keys)
|
46
|
+
(0...@gamma_s).each do |j|
|
47
|
+
outdata[data_index + j] = (indata[data_index + j].ord ^ @tmp_block[j].ord).chr
|
48
|
+
end
|
49
|
+
data_index += @gamma_s
|
50
|
+
@bytes_count += @gamma_s
|
51
|
+
data_len -= @gamma_s
|
52
|
+
self.class.incrementModulo(@counter, BlockLengthInBytes)
|
53
|
+
@prev_len = 0
|
54
|
+
end
|
55
|
+
if data_len > 0 then
|
56
|
+
@tmp_block = self.class.encryptBlock(@counter, @keys)
|
57
|
+
(0...data_len).each do |j|
|
58
|
+
outdata[data_index + j] = (indata[data_index + j].ord ^ @tmp_block[j].ord).chr
|
59
|
+
end
|
60
|
+
@bytes_count += data_len
|
61
|
+
@prev_len = data_len
|
62
|
+
end
|
63
|
+
return outdata
|
64
|
+
end
|
65
|
+
|
66
|
+
def decrypt(data)
|
67
|
+
encrypt(data)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikCtrAcpkm < Kuznyechik
|
3
|
+
def initialize(key, iv, gamma_s, section_N)
|
4
|
+
@key = key.dup.force_encoding('BINARY')
|
5
|
+
# @inkey => [4] uint_64, native-endian
|
6
|
+
@inkey = self.class.keyToNumbers(@key)
|
7
|
+
@keys = self.class.expandEncryptKeys(@inkey)
|
8
|
+
@iv = iv.dup.force_encoding('BINARY')
|
9
|
+
@gamma_s = gamma_s
|
10
|
+
@section_N = section_N
|
11
|
+
@gamma_bytes = 0
|
12
|
+
@section_bytes = 0
|
13
|
+
@block_bytes = 0
|
14
|
+
@bytes_count = 0
|
15
|
+
if @iv.length < BlockLengthInBytes/2 then
|
16
|
+
@iv += 0.chr * (BlockLengthInBytes/2 - @iv.length)
|
17
|
+
end
|
18
|
+
@counter = @iv[0...(BlockLengthInBytes/2)]
|
19
|
+
@counter += 0.chr * (BlockLengthInBytes/2)
|
20
|
+
@gamma = self.class.encryptBlock(@counter, @keys)
|
21
|
+
self.class.incrementModulo(@counter, BlockLengthInBytes)
|
22
|
+
end
|
23
|
+
|
24
|
+
def encrypt(indata)
|
25
|
+
data_len = indata.length
|
26
|
+
if data_len > 0 then
|
27
|
+
outdata = self.class.zeroBytes(data_len)
|
28
|
+
(0...data_len).each do |i|
|
29
|
+
if @section_bytes == @section_N then
|
30
|
+
acpkmCtrKey
|
31
|
+
@keys = self.class.expandEncryptKeys(@inkey)
|
32
|
+
@gamma = self.class.encryptBlock(@counter, @keys)
|
33
|
+
self.class.incrementModulo(@counter, BlockLengthInBytes)
|
34
|
+
@section_bytes = 0
|
35
|
+
@block_bytes = 0
|
36
|
+
@gamma_bytes = 0
|
37
|
+
else
|
38
|
+
if @gamma_bytes == @gamma_s then
|
39
|
+
@gamma = self.class.encryptBlock(@counter, @keys)
|
40
|
+
self.class.incrementModulo(@counter, BlockLengthInBytes)
|
41
|
+
@gamma_bytes = 0
|
42
|
+
end
|
43
|
+
if @block_bytes == BlockLengthInBytes then
|
44
|
+
@block_bytes = 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
outdata[i] = (indata[i].ord ^ @gamma[@gamma_bytes].ord).chr
|
48
|
+
@gamma_bytes += 1
|
49
|
+
@block_bytes += 1
|
50
|
+
@section_bytes += 1
|
51
|
+
@bytes_count += 1
|
52
|
+
end
|
53
|
+
return outdata
|
54
|
+
else
|
55
|
+
return ''
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def decrypt(indata)
|
60
|
+
encrypt(indata)
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
W5 = [
|
66
|
+
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
67
|
+
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f
|
68
|
+
].pack('C*').freeze
|
69
|
+
W6 = [
|
70
|
+
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
71
|
+
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
|
72
|
+
].pack('C*').freeze
|
73
|
+
|
74
|
+
def acpkmCtrKey
|
75
|
+
@key = self.class.encryptBlock(W5, @keys) + self.class.encryptBlock(W6, @keys)
|
76
|
+
# Recalculate @inkey array in base object
|
77
|
+
@inkey = self.class.keyToNumbers(@key)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikEcb < Kuznyechik
|
3
|
+
# key = 32-byte string
|
4
|
+
def initialize(key)
|
5
|
+
@key = key.dup.force_encoding('BINARY')
|
6
|
+
# @inkey => [4] uint_64, native-endian
|
7
|
+
@inkey = self.class.keyToNumbers(@key)
|
8
|
+
|
9
|
+
# @keys => [10*2] uint_64, native-endian
|
10
|
+
@encrypt_keys = self.class.expandEncryptKeys(@inkey)
|
11
|
+
@decrypt_keys = self.class.expandDecryptKeys(@inkey)
|
12
|
+
return self
|
13
|
+
end
|
14
|
+
|
15
|
+
# returns encrypted text string
|
16
|
+
def encrypt(plain_text)
|
17
|
+
len = plain_text.length
|
18
|
+
if (len == 0) || (len % BlockLengthInBytes > 0) then
|
19
|
+
puts "(plain_text.length == 0) || (plain_text.length % BlockLengthInBytes > 0)"
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
blocks = plain_text.scan(/.{16}/m)
|
23
|
+
encrypted_blocks = []
|
24
|
+
blocks.each do |block|
|
25
|
+
encryptedBlock = self.class.encryptBlock(block, @encrypt_keys)
|
26
|
+
encrypted_blocks << encryptedBlock
|
27
|
+
end
|
28
|
+
output = encrypted_blocks.join
|
29
|
+
return output
|
30
|
+
end
|
31
|
+
|
32
|
+
# returns decrypted text string
|
33
|
+
def decrypt(encrypted_text)
|
34
|
+
len = encrypted_text.length
|
35
|
+
if (len == 0) || (len % BlockLengthInBytes > 0) then
|
36
|
+
puts "(encrypted_text.length == 0) || (encrypted_text.length % BlockLengthInBytes > 0)"
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
blocks = encrypted_text.scan(/.{16}/m)
|
40
|
+
decrypted_blocks = []
|
41
|
+
blocks.each do |block|
|
42
|
+
decryptedBlock = self.class.decryptBlock(block, @decrypt_keys)
|
43
|
+
decrypted_blocks << decryptedBlock
|
44
|
+
end
|
45
|
+
output = decrypted_blocks.join
|
46
|
+
return output
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikKeyExpImp < Kuznyechik
|
3
|
+
def self.export(key, key_mac, key_enc, iv)
|
4
|
+
mac = KuznyechikOmac.new(key_mac, BlockLengthInBytes).update(iv+key).final
|
5
|
+
ctr = KuznyechikCtr.new(key_enc, iv, BlockLengthInBytes)
|
6
|
+
encr_key = ctr.encrypt(key)
|
7
|
+
encr_mac = ctr.encrypt(mac)
|
8
|
+
encr_key += encr_mac
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.import(encr_key, key_mac, key_enc, iv)
|
12
|
+
buf = KuznyechikCtr.new(key_enc, iv, BlockLengthInBytes).decrypt(encr_key)
|
13
|
+
decr_key = buf[0...-BlockLengthInBytes]
|
14
|
+
decr_mac = buf[decr_key.length..-1]
|
15
|
+
mac = KuznyechikOmac.new(key_mac, BlockLengthInBytes).update(iv+decr_key).final
|
16
|
+
if mac != decr_mac then
|
17
|
+
decr_key = nil
|
18
|
+
end
|
19
|
+
decr_key
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module GostKuznyechik
|
2
|
+
class KuznyechikOfb < Kuznyechik
|
3
|
+
def initialize(key, iv, gamma_s)
|
4
|
+
@key = key.dup.force_encoding('BINARY')
|
5
|
+
# @inkey => [4] uint_64, native-endian
|
6
|
+
@inkey = self.class.keyToNumbers(@key)
|
7
|
+
@gamma_s = gamma_s
|
8
|
+
@ctxR = iv.dup.force_encoding('BINARY')
|
9
|
+
# keys and gamma initialization
|
10
|
+
@keys = self.class.expandEncryptKeys(@inkey)
|
11
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
12
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
13
|
+
@ctxR = @ctxR[BlockLengthInBytes..-1] + @gamma_block
|
14
|
+
@incomplete_block_len = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def encrypt(data)
|
18
|
+
data_len = data.length
|
19
|
+
outdata = ''
|
20
|
+
left_data_len = data_len
|
21
|
+
if @incomplete_block_len > 0 then
|
22
|
+
# use old @gamma_block
|
23
|
+
if data_len < @gamma_s - @incomplete_block_len then
|
24
|
+
# incomplete block yet
|
25
|
+
outdata = data.dup
|
26
|
+
(0...data_len).each do |j|
|
27
|
+
outdata[j] = (@gamma_block[@incomplete_block_len + j].ord ^ outdata[j].ord).chr
|
28
|
+
end
|
29
|
+
@incomplete_block_len += data_len
|
30
|
+
return outdata
|
31
|
+
else
|
32
|
+
outdata = data[0...(@gamma_s - @incomplete_block_len)]
|
33
|
+
(0...outdata.length).each do |j|
|
34
|
+
outdata[j] = (@gamma_block[@incomplete_block_len + j].ord ^ outdata[j].ord).chr
|
35
|
+
end
|
36
|
+
# complete block - update gamma block
|
37
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
38
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
39
|
+
@ctxR = @ctxR[BlockLengthInBytes..-1] + @gamma_block
|
40
|
+
left_data_len -= outdata.length
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
(0...(left_data_len / @gamma_s)).each do |i|
|
45
|
+
if @incomplete_block_len > 0 then
|
46
|
+
encr_data = data[((i + 1) * @gamma_s - @incomplete_block_len)...((i + 2) * @gamma_s - @incomplete_block_len)]
|
47
|
+
else
|
48
|
+
encr_data = data[(i * @gamma_s)...((i + 1) * @gamma_s)]
|
49
|
+
end
|
50
|
+
(0...@gamma_s).each do |j|
|
51
|
+
encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
|
52
|
+
end
|
53
|
+
outdata += encr_data
|
54
|
+
# complete block - update gamma block
|
55
|
+
tmp_block = @ctxR[0...BlockLengthInBytes]
|
56
|
+
@gamma_block = self.class.encryptBlock(tmp_block, @keys)
|
57
|
+
@ctxR = @ctxR[BlockLengthInBytes..-1] + @gamma_block
|
58
|
+
left_data_len -= @gamma_s
|
59
|
+
end
|
60
|
+
|
61
|
+
if left_data_len > 0 then
|
62
|
+
# incomplete block start
|
63
|
+
encr_data = data[-left_data_len..-1]
|
64
|
+
(0...left_data_len).each do |j|
|
65
|
+
encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
|
66
|
+
end
|
67
|
+
outdata += encr_data
|
68
|
+
@incomplete_block_len = left_data_len
|
69
|
+
end
|
70
|
+
outdata
|
71
|
+
end
|
72
|
+
|
73
|
+
def decrypt(data)
|
74
|
+
encrypt(data)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|