gost_magma 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 GostMagma
2
+ class MagmaCbc < Magma
3
+ def initialize(key, iv)
4
+ @key = key.dup.force_encoding('BINARY')
5
+ @keys = []
6
+ (0...8).each do |i|
7
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
8
+ end
9
+
10
+ @ctxR = iv.dup.force_encoding('BINARY')
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, @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, @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,146 @@
1
+ module GostMagma
2
+ class MagmaCfb < Magma
3
+ def initialize(key, iv, gamma_s)
4
+ @key = key.dup.force_encoding('BINARY')
5
+ @keys = []
6
+ (0...8).each do |i|
7
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
8
+ end
9
+
10
+ @gamma_s = gamma_s
11
+ @ctxR = iv.dup.force_encoding('BINARY')
12
+ tmp_block = @ctxR[0...BlockLengthInBytes]
13
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
14
+ @incomplete_block = ''
15
+ @incomplete_block_len = 0
16
+ end
17
+
18
+ def encrypt(data)
19
+ data_len = data.length
20
+ left_data_len = data_len
21
+ outdata = ''
22
+ if @incomplete_block_len > 0 then
23
+ # use old @gamma_block
24
+ if data_len < @gamma_s - @incomplete_block_len then
25
+ # incomplete block yet
26
+ encr_data = data.dup
27
+ (0...data_len).each do |j|
28
+ encr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
29
+ end
30
+ @incomplete_block_len += data_len
31
+ @incomplete_block += encr_data
32
+ return encr_data
33
+ else
34
+ encr_data = data[0...(@gamma_s - @incomplete_block_len)]
35
+ (0...encr_data.length).each do |j|
36
+ encr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
37
+ end
38
+ outdata += encr_data
39
+ # complete block - gamma update
40
+ @incomplete_block += encr_data
41
+ left_data_len -= encr_data.length
42
+ @ctxR = @ctxR[@gamma_s..-1] + @incomplete_block
43
+ tmp_block = @ctxR[0...BlockLengthInBytes]
44
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
45
+ @incomplete_block = ''
46
+ end
47
+ end
48
+
49
+ (0...(left_data_len / @gamma_s)).each do |i|
50
+ if @incomplete_block_len > 0 then
51
+ encr_data = data[((i + 1) * @gamma_s - @incomplete_block_len)...((i + 2) * @gamma_s - @incomplete_block_len)]
52
+ else
53
+ encr_data = data[(i * @gamma_s)...((i + 1) * @gamma_s)]
54
+ end
55
+ (0...@gamma_s).each do |j|
56
+ encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
57
+ end
58
+ outdata += encr_data
59
+ # complete block - gamma update
60
+ @ctxR = @ctxR[@gamma_s..-1] + encr_data
61
+ tmp_block = @ctxR[0...BlockLengthInBytes]
62
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
63
+ end
64
+
65
+ left_data_len %= @gamma_s
66
+ if left_data_len > 0 then
67
+ # incomplete block start
68
+ encr_data = data[-left_data_len..-1]
69
+ (0...left_data_len).each do |j|
70
+ encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
71
+ end
72
+ outdata += encr_data
73
+ @incomplete_block_len = left_data_len
74
+ @incomplete_block = encr_data
75
+ end
76
+ outdata
77
+ end
78
+
79
+ # Use input encrypted text to gamma update
80
+ def decrypt(data)
81
+ data_len = data.length
82
+ left_data_len = data_len
83
+ outdata = ''
84
+ if @incomplete_block_len > 0 then
85
+ # use old @gamma_block
86
+ if data_len < @gamma_s - @incomplete_block_len then
87
+ # incomplete block yet
88
+ encr_data = data.dup
89
+ decr_data = data.dup
90
+ (0...data_len).each do |j|
91
+ decr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
92
+ end
93
+ @incomplete_block_len += data_len
94
+ @incomplete_block += encr_data
95
+ return decr_data
96
+ else
97
+ encr_data = data[0...(@gamma_s - @incomplete_block_len)]
98
+ decr_data = encr_data.dup
99
+ (0...encr_data.length).each do |j|
100
+ decr_data[j] = (@gamma_block[@incomplete_block_len + j].ord ^ encr_data[j].ord).chr
101
+ end
102
+ outdata += decr_data
103
+ # complete block - gamma update
104
+ @incomplete_block += encr_data
105
+ left_data_len -= encr_data.length
106
+ @ctxR = @ctxR[@gamma_s..-1] + @incomplete_block
107
+ tmp_block = @ctxR[0...BlockLengthInBytes]
108
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
109
+ @incomplete_block = ''
110
+ end
111
+ end
112
+
113
+ (0...(left_data_len / @gamma_s)).each do |i|
114
+ if @incomplete_block_len > 0 then
115
+ encr_data = data[((i + 1) * @gamma_s - @incomplete_block_len)...((i + 2) * @gamma_s - @incomplete_block_len)]
116
+ else
117
+ encr_data = data[(i * @gamma_s)...((i + 1) * @gamma_s)]
118
+ end
119
+ decr_data = encr_data.dup
120
+ (0...@gamma_s).each do |j|
121
+ decr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
122
+ end
123
+ outdata += decr_data
124
+ # complete block - gamma update
125
+ @ctxR = @ctxR[@gamma_s..-1] + encr_data
126
+ tmp_block = @ctxR[0...BlockLengthInBytes]
127
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
128
+ end
129
+
130
+ left_data_len %= @gamma_s
131
+ if left_data_len > 0 then
132
+ # incomplete block start
133
+ encr_data = data[-left_data_len..-1]
134
+ decr_data = encr_data.dup
135
+ (0...left_data_len).each do |j|
136
+ decr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
137
+ end
138
+ outdata += decr_data
139
+ @incomplete_block_len = left_data_len
140
+ @incomplete_block = encr_data
141
+ end
142
+ outdata
143
+ end
144
+
145
+ end
146
+ end
@@ -0,0 +1,73 @@
1
+ module GostMagma
2
+ class MagmaCtr < Magma
3
+ def initialize(key, iv, gamma_s)
4
+ @key = key.dup.force_encoding('BINARY')
5
+ @keys = []
6
+ (0...8).each do |i|
7
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
8
+ end
9
+
10
+ @gamma_s = gamma_s
11
+ @iv = iv.dup.force_encoding('BINARY')
12
+ @prev_len = 0
13
+ @bytes_count = 0
14
+ @tmp_block = self.class.zeroBlock
15
+ if @iv.length < BlockLengthInBytes/2 then
16
+ @iv += self.class.zeroBytes(BlockLengthInBytes/2 - @iv.length)
17
+ end
18
+ @counter = @iv[0...(BlockLengthInBytes/2)]
19
+ @counter += self.class.zeroBytes(BlockLengthInBytes/2)
20
+ end
21
+
22
+ def encrypt(indata)
23
+ data_len = indata.length
24
+ outdata = self.class.zeroBytes(data_len)
25
+ data_index = 0
26
+ if @prev_len > 0 then
27
+ if data_len < (@gamma_s - @prev_len) then
28
+ (0...data_len).each do |j|
29
+ outdata[j] = (indata[j].ord ^ @tmp_block[j + @prev_len].ord).chr
30
+ end
31
+ @prev_len += data_len
32
+ @bytes_count += data_len
33
+ return outdata
34
+ else
35
+ (0...(@gamma_s - @prev_len)).each do |j|
36
+ outdata[j] = (indata[j].ord ^ @tmp_block[j + @prev_len].ord).chr
37
+ end
38
+ data_index += @gamma_s - @prev_len
39
+ @bytes_count += @gamma_s - @prev_len
40
+ data_len -= @gamma_s - @prev_len
41
+ self.class.incrementModulo(@counter, BlockLengthInBytes)
42
+ @prev_len = 0
43
+ end
44
+ end
45
+ (0...(data_len / @gamma_s)).each do |i|
46
+ @tmp_block = self.class.encryptBlock(@counter, @keys)
47
+ (0...@gamma_s).each do |j|
48
+ outdata[data_index + j] = (indata[data_index + j].ord ^ @tmp_block[j].ord).chr
49
+ end
50
+ data_index += @gamma_s
51
+ @bytes_count += @gamma_s
52
+ data_len -= @gamma_s
53
+ self.class.incrementModulo(@counter, BlockLengthInBytes)
54
+ @prev_len = 0
55
+ end
56
+ if data_len > 0 then
57
+ @tmp_block = self.class.encryptBlock(@counter, @keys)
58
+ (0...data_len).each do |j|
59
+ outdata[data_index + j] = (indata[data_index + j].ord ^ @tmp_block[j].ord).chr
60
+ end
61
+ @bytes_count += data_len
62
+ @prev_len = data_len
63
+ end
64
+ return outdata
65
+ end
66
+
67
+ def decrypt(data)
68
+ encrypt(data)
69
+ end
70
+
71
+ end
72
+ end
73
+
@@ -0,0 +1,91 @@
1
+ module GostMagma
2
+ class MagmaCtrAcpkm < Magma
3
+ def initialize(key, iv, gamma_s, section_N)
4
+ @key = key.dup.force_encoding('BINARY')
5
+ @keys = []
6
+ (0...8).each do |i|
7
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
8
+ end
9
+
10
+ @iv = iv.dup.force_encoding('BINARY')
11
+ @gamma_s = gamma_s
12
+ @section_N = section_N
13
+ @gamma_bytes = 0
14
+ @section_bytes = 0
15
+ @block_bytes = 0
16
+ @bytes_count = 0
17
+ if @iv.length < BlockLengthInBytes/2 then
18
+ @iv += 0.chr * (BlockLengthInBytes/2 - @iv.length)
19
+ end
20
+ @counter = @iv[0...(BlockLengthInBytes/2)]
21
+ @counter += 0.chr * (BlockLengthInBytes/2)
22
+ @gamma = self.class.encryptBlock(@counter, @keys)
23
+ self.class.incrementModulo(@counter, BlockLengthInBytes)
24
+ end
25
+
26
+ def encrypt(indata)
27
+ data_len = indata.length
28
+ if data_len > 0 then
29
+ outdata = self.class.zeroBytes(data_len)
30
+ (0...data_len).each do |i|
31
+ if @section_bytes == @section_N then
32
+ acpkmCtrKey
33
+ @gamma = self.class.encryptBlock(@counter, @keys)
34
+ self.class.incrementModulo(@counter, BlockLengthInBytes)
35
+ @section_bytes = 0
36
+ @block_bytes = 0
37
+ @gamma_bytes = 0
38
+ else
39
+ if @gamma_bytes == @gamma_s then
40
+ @gamma = self.class.encryptBlock(@counter, @keys)
41
+ self.class.incrementModulo(@counter, BlockLengthInBytes)
42
+ @gamma_bytes = 0
43
+ end
44
+ if @block_bytes == BlockLengthInBytes then
45
+ @block_bytes = 0
46
+ end
47
+ end
48
+ outdata[i] = (indata[i].ord ^ @gamma[@gamma_bytes].ord).chr
49
+ @gamma_bytes += 1
50
+ @block_bytes += 1
51
+ @section_bytes += 1
52
+ @bytes_count += 1
53
+ end
54
+ return outdata
55
+ else
56
+ return ''
57
+ end
58
+ end
59
+
60
+ def decrypt(indata)
61
+ encrypt(indata)
62
+ end
63
+
64
+ protected
65
+
66
+ W1 = [
67
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87
68
+ ].pack('C*').freeze
69
+ W2 = [
70
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f
71
+ ].pack('C*').freeze
72
+ W3 = [
73
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97
74
+ ].pack('C*').freeze
75
+ W4 = [
76
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f
77
+ ].pack('C*').freeze
78
+
79
+ def acpkmCtrKey
80
+ @key = self.class.encryptBlock(W1, @keys) +
81
+ self.class.encryptBlock(W2, @keys) +
82
+ self.class.encryptBlock(W3, @keys) +
83
+ self.class.encryptBlock(W4, @keys)
84
+ @keys = []
85
+ (0...8).each do |i|
86
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
87
+ end
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,47 @@
1
+ module GostMagma
2
+ class MagmaEcb < Magma
3
+ # key = 32-byte string
4
+ def initialize(key)
5
+ @key = key.dup.force_encoding('BINARY')
6
+ @keys = []
7
+ (0...8).each do |i|
8
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
9
+ end
10
+ end
11
+
12
+ # returns encrypted text string
13
+ def encrypt(plain_text)
14
+ len = plain_text.length
15
+ if (len == 0) || (len % BlockLengthInBytes > 0) then
16
+ puts "(plain_text.length == 0) || (plain_text.length % BlockLengthInBytes > 0)"
17
+ return nil
18
+ end
19
+ blocks = plain_text.scan(/.{8}/m)
20
+ encrypted_blocks = []
21
+ blocks.each do |block|
22
+ encryptedBlock = self.class.encryptBlock(block, @keys)
23
+ encrypted_blocks << encryptedBlock
24
+ end
25
+ output = encrypted_blocks.join
26
+ return output
27
+ end
28
+
29
+ # returns decrypted text string
30
+ def decrypt(encrypted_text)
31
+ len = encrypted_text.length
32
+ if (len == 0) || (len % BlockLengthInBytes > 0) then
33
+ puts "(encrypted_text.length == 0) || (encrypted_text.length % BlockLengthInBytes > 0)"
34
+ return nil
35
+ end
36
+ blocks = encrypted_text.scan(/.{8}/m)
37
+ decrypted_blocks = []
38
+ blocks.each do |block|
39
+ decryptedBlock = self.class.decryptBlock(block, @keys)
40
+ decrypted_blocks << decryptedBlock
41
+ end
42
+ output = decrypted_blocks.join
43
+ return output
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,22 @@
1
+ module GostMagma
2
+ class MagmaKeyExpImp < Magma
3
+ def self.export(key, key_mac, key_enc, iv)
4
+ mac = MagmaOmac.new(key_mac, BlockLengthInBytes).update(iv+key).final
5
+ ctr = MagmaCtr.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 = MagmaCtr.new(key_enc, iv, BlockLengthInBytes).decrypt(encr_key)
13
+ decr_key = buf[0...-BlockLengthInBytes]
14
+ decr_mac = buf[decr_key.length..-1]
15
+ mac = MagmaOmac.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,79 @@
1
+ module GostMagma
2
+ class MagmaOfb < Magma
3
+ def initialize(key, iv, gamma_s)
4
+ @key = key.dup.force_encoding('BINARY')
5
+ @keys = []
6
+ (0...8).each do |i|
7
+ @keys << self.class.uint8ToUint32(@key[i*4...(i+1)*4].reverse)
8
+ end
9
+
10
+ @gamma_s = gamma_s
11
+ @ctxR = iv.dup.force_encoding('BINARY')
12
+ tmp_block = @ctxR[0...BlockLengthInBytes]
13
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
14
+ @ctxR = @ctxR[BlockLengthInBytes..-1] + @gamma_block
15
+ @incomplete_block_len = 0
16
+ end
17
+
18
+ def encrypt(data)
19
+ data_len = data.length
20
+ outdata = ''
21
+ left_data_len = data_len
22
+ if @incomplete_block_len > 0 then
23
+ # use old @gamma_block
24
+ if data_len < @gamma_s - @incomplete_block_len then
25
+ # incomplete block yet
26
+ outdata = data.dup
27
+ (0...data_len).each do |j|
28
+ outdata[j] = (@gamma_block[@incomplete_block_len + j].ord ^ outdata[j].ord).chr
29
+ end
30
+ @incomplete_block_len += data_len
31
+ return outdata
32
+ else
33
+ outdata = data[0...(@gamma_s - @incomplete_block_len)]
34
+ (0...outdata.length).each do |j|
35
+ outdata[j] = (@gamma_block[@incomplete_block_len + j].ord ^ outdata[j].ord).chr
36
+ end
37
+ # complete block - update gamma block
38
+ tmp_block = @ctxR[0...BlockLengthInBytes]
39
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
40
+ @ctxR = @ctxR[BlockLengthInBytes..-1] + @gamma_block
41
+ left_data_len -= outdata.length
42
+ end
43
+ end
44
+
45
+ (0...(left_data_len / @gamma_s)).each do |i|
46
+ if @incomplete_block_len > 0 then
47
+ encr_data = data[((i + 1) * @gamma_s - @incomplete_block_len)...((i + 2) * @gamma_s - @incomplete_block_len)]
48
+ else
49
+ encr_data = data[(i * @gamma_s)...((i + 1) * @gamma_s)]
50
+ end
51
+ (0...@gamma_s).each do |j|
52
+ encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
53
+ end
54
+ outdata += encr_data
55
+ # complete block - update gamma block
56
+ tmp_block = @ctxR[0...BlockLengthInBytes]
57
+ @gamma_block = self.class.encryptBlock(tmp_block, @keys)
58
+ @ctxR = @ctxR[BlockLengthInBytes..-1] + @gamma_block
59
+ left_data_len -= @gamma_s
60
+ end
61
+
62
+ if left_data_len > 0 then
63
+ # incomplete block start
64
+ encr_data = data[-left_data_len..-1]
65
+ (0...left_data_len).each do |j|
66
+ encr_data[j] = (@gamma_block[j].ord ^ encr_data[j].ord).chr
67
+ end
68
+ outdata += encr_data
69
+ @incomplete_block_len = left_data_len
70
+ end
71
+ outdata
72
+ end
73
+
74
+ def decrypt(data)
75
+ encrypt(data)
76
+ end
77
+
78
+ end
79
+ end