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.
@@ -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