symmetric-encryption 3.9.1 → 4.0.0.beta3
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 +4 -4
- data/README.md +72 -0
- data/bin/symmetric-encryption +5 -0
- data/lib/symmetric_encryption/cipher.rb +162 -419
- data/lib/symmetric_encryption/cli.rb +343 -0
- data/lib/symmetric_encryption/coerce.rb +5 -20
- data/lib/symmetric_encryption/config.rb +128 -50
- data/lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb +2 -2
- data/lib/symmetric_encryption/generator.rb +3 -2
- data/lib/symmetric_encryption/header.rb +260 -0
- data/lib/symmetric_encryption/key.rb +106 -0
- data/lib/symmetric_encryption/keystore/environment.rb +90 -0
- data/lib/symmetric_encryption/keystore/file.rb +102 -0
- data/lib/symmetric_encryption/keystore/memory.rb +53 -0
- data/lib/symmetric_encryption/keystore.rb +124 -0
- data/lib/symmetric_encryption/railtie.rb +5 -7
- data/lib/symmetric_encryption/reader.rb +74 -55
- data/lib/symmetric_encryption/rsa_key.rb +24 -0
- data/lib/symmetric_encryption/symmetric_encryption.rb +64 -102
- data/lib/symmetric_encryption/utils/re_encrypt_files.rb +140 -0
- data/lib/symmetric_encryption/version.rb +1 -1
- data/lib/symmetric_encryption/writer.rb +104 -117
- data/lib/symmetric_encryption.rb +9 -4
- data/test/active_record_test.rb +61 -40
- data/test/cipher_test.rb +179 -236
- data/test/config/symmetric-encryption.yml +140 -82
- data/test/header_test.rb +218 -0
- data/test/key_test.rb +231 -0
- data/test/keystore/environment_test.rb +119 -0
- data/test/keystore/file_test.rb +125 -0
- data/test/keystore_test.rb +59 -0
- data/test/mongoid_test.rb +13 -13
- data/test/reader_test.rb +52 -53
- data/test/symmetric_encryption_test.rb +50 -135
- data/test/test_db.sqlite3 +0 -0
- data/test/writer_test.rb +52 -31
- metadata +26 -14
- data/examples/symmetric-encryption.yml +0 -108
- data/lib/rails/generators/symmetric_encryption/config/config_generator.rb +0 -22
- data/lib/rails/generators/symmetric_encryption/config/templates/symmetric-encryption.yml +0 -50
- data/lib/rails/generators/symmetric_encryption/heroku_config/heroku_config_generator.rb +0 -20
- data/lib/rails/generators/symmetric_encryption/heroku_config/templates/symmetric-encryption.yml +0 -78
- data/lib/rails/generators/symmetric_encryption/new_keys/new_keys_generator.rb +0 -14
- data/lib/symmetric_encryption/key_encryption_key.rb +0 -32
- data/lib/symmetric_encryption/railties/symmetric_encryption.rake +0 -84
- data/lib/symmetric_encryption/utils/re_encrypt_config_files.rb +0 -82
data/test/cipher_test.rb
CHANGED
@@ -1,267 +1,210 @@
|
|
1
1
|
require_relative 'test_helper'
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
3
|
+
# Tests for SymmetricEncryption::Cipher
|
5
4
|
class CipherTest < Minitest::Test
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'not require an iv' do
|
19
|
-
cipher = SymmetricEncryption::Cipher.new(
|
20
|
-
key: '1234567890ABCDEF1234567890ABCDEF',
|
21
|
-
encoding: :none
|
22
|
-
)
|
23
|
-
result = "\302<\351\227oj\372\3331\310\260V\001\v'\346"
|
24
|
-
# Note: This test fails on JRuby 1.7 RC1 since it's OpenSSL
|
25
|
-
# behaves differently when no IV is supplied.
|
26
|
-
# It instead encrypts to the following value:
|
27
|
-
# result = "0h\x92\x88\xA1\xFE\x8D\xF5\xF3v\x82\xAF(P\x83Y"
|
28
|
-
result.force_encoding('binary') if defined?(Encoding)
|
29
|
-
assert_equal result, cipher.encrypt('Hello World')
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'throw an exception on bad data' do
|
33
|
-
cipher = SymmetricEncryption::Cipher.new(
|
34
|
-
cipher_name: 'aes-128-cbc',
|
35
|
-
key: '1234567890ABCDEF',
|
36
|
-
iv: '1234567890ABCDEF',
|
37
|
-
encoding: :none
|
38
|
-
)
|
39
|
-
assert_raises OpenSSL::Cipher::CipherError do
|
40
|
-
cipher.decrypt('bad data')
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
[false, true].each do |always_add_header|
|
47
|
-
[:none, :base64, :base64strict, :base16].each do |encoding|
|
48
|
-
describe "encoding: #{encoding} with#{'out' unless always_add_header} header" do
|
49
|
-
before do
|
50
|
-
@social_security_number = '987654321'
|
51
|
-
@social_security_number_encrypted =
|
52
|
-
case encoding
|
53
|
-
when :base64
|
54
|
-
always_add_header ? "QEVuQwAAyTeLjsHTa8ykoO95K0KQmg==\n" : "yTeLjsHTa8ykoO95K0KQmg==\n"
|
55
|
-
when :base64strict
|
56
|
-
always_add_header ? 'QEVuQwAAyTeLjsHTa8ykoO95K0KQmg==' : 'yTeLjsHTa8ykoO95K0KQmg=='
|
57
|
-
when :base16
|
58
|
-
always_add_header ? '40456e430000c9378b8ec1d36bcca4a0ef792b42909a' : 'c9378b8ec1d36bcca4a0ef792b42909a'
|
59
|
-
when :none
|
60
|
-
bin = always_add_header ? "@EnC\x00\x00\xC97\x8B\x8E\xC1\xD3k\xCC\xA4\xA0\xEFy+B\x90\x9A" : "\xC97\x8B\x8E\xC1\xD3k\xCC\xA4\xA0\xEFy+B\x90\x9A"
|
61
|
-
bin.force_encoding(Encoding.find('binary'))
|
62
|
-
else
|
63
|
-
raise "Add test for encoding: #{encoding}"
|
64
|
-
end
|
65
|
-
@social_security_number_encrypted_with_secondary_1 = "D1UCu38pqJ3jc0GvwJHiow==\n"
|
66
|
-
@non_utf8 = "\xc2".force_encoding('binary')
|
67
|
-
@cipher = SymmetricEncryption::Cipher.new(
|
68
|
-
key: 'ABCDEF1234567890',
|
69
|
-
iv: 'ABCDEF1234567890',
|
70
|
-
cipher_name: 'aes-128-cbc',
|
71
|
-
encoding: encoding,
|
72
|
-
always_add_header: always_add_header
|
5
|
+
['aes-128-cbc'].each do |cipher_name|
|
6
|
+
#['aes-128-cbc', 'aes-128-gcm'].each do |cipher_name|
|
7
|
+
describe "Cipher: #{cipher_name}" do
|
8
|
+
describe 'standalone' do
|
9
|
+
it 'allows setting the cipher_name' do
|
10
|
+
cipher = SymmetricEncryption::Cipher.new(
|
11
|
+
cipher_name: cipher_name,
|
12
|
+
key: '1234567890ABCDEF',
|
13
|
+
iv: '1234567890ABCDEF',
|
14
|
+
encoding: :none
|
73
15
|
)
|
16
|
+
assert_equal cipher_name, cipher.cipher_name
|
74
17
|
end
|
75
18
|
|
76
|
-
it '
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
it 'return BINARY encoding for non-UTF-8 encrypted data' do
|
87
|
-
assert_equal Encoding.find('binary'), @non_utf8.encoding
|
88
|
-
assert_equal true, @non_utf8.valid_encoding?
|
89
|
-
assert encrypted = @cipher.encrypt(@non_utf8)
|
90
|
-
assert decrypted = @cipher.decrypt(encrypted)
|
91
|
-
assert_equal true, decrypted.valid_encoding?
|
92
|
-
assert_equal Encoding.find('binary'), decrypted.encoding, decrypted
|
93
|
-
assert_equal @non_utf8, decrypted
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'return nil when encrypting nil' do
|
97
|
-
assert_nil @cipher.encrypt(nil)
|
98
|
-
end
|
99
|
-
|
100
|
-
it "return '' when encrypting ''" do
|
101
|
-
assert_equal '', @cipher.encrypt('')
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'return nil when decrypting nil' do
|
105
|
-
assert_nil @cipher.decrypt(nil)
|
19
|
+
it 'does not require an iv' do
|
20
|
+
cipher = SymmetricEncryption::Cipher.new(
|
21
|
+
key: '1234567890ABCDEF',
|
22
|
+
cipher_name: cipher_name,
|
23
|
+
encoding: :none,
|
24
|
+
always_add_header: false
|
25
|
+
)
|
26
|
+
assert result = cipher.encrypt('Hello World')
|
27
|
+
assert_equal 'Hello World', cipher.decrypt(result)
|
106
28
|
end
|
107
29
|
|
108
|
-
it
|
109
|
-
|
30
|
+
it 'throw an exception on bad data' do
|
31
|
+
cipher = SymmetricEncryption::Cipher.new(
|
32
|
+
cipher_name: cipher_name,
|
33
|
+
key: '1234567890ABCDEF',
|
34
|
+
iv: '1234567890ABCDEF',
|
35
|
+
encoding: :none
|
36
|
+
)
|
37
|
+
assert_raises OpenSSL::Cipher::CipherError do
|
38
|
+
cipher.decrypt('bad data')
|
39
|
+
end
|
110
40
|
end
|
111
41
|
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
describe 'with configuration' do
|
116
|
-
before do
|
117
|
-
@cipher = SymmetricEncryption::Cipher.new(
|
118
|
-
key: '1234567890ABCDEF1234567890ABCDEF',
|
119
|
-
iv: '1234567890ABCDEF',
|
120
|
-
encoding: :none
|
121
|
-
)
|
122
|
-
@social_security_number = '987654321'
|
123
42
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
43
|
+
[false, true].each do |always_add_header|
|
44
|
+
[:none, :base64, :base64strict, :base16].each do |encoding|
|
45
|
+
describe "encoding: #{encoding} with#{'out' unless always_add_header} header" do
|
46
|
+
before do
|
47
|
+
@social_security_number = '987654321'
|
48
|
+
@encrypted_values = {
|
49
|
+
'aes-128-cbc' => {
|
50
|
+
base64: {
|
51
|
+
header: "QEVuQwAAyTeLjsHTa8ykoO95K0KQmg==\n",
|
52
|
+
no_header: "yTeLjsHTa8ykoO95K0KQmg==\n"
|
53
|
+
},
|
54
|
+
base64strict: {
|
55
|
+
header: 'QEVuQwAAyTeLjsHTa8ykoO95K0KQmg==',
|
56
|
+
no_header: 'yTeLjsHTa8ykoO95K0KQmg=='
|
57
|
+
},
|
58
|
+
base16: {
|
59
|
+
header: '40456e430000c9378b8ec1d36bcca4a0ef792b42909a',
|
60
|
+
no_header: 'c9378b8ec1d36bcca4a0ef792b42909a'
|
61
|
+
},
|
62
|
+
none: {
|
63
|
+
header: "@EnC\x00\x00\xC97\x8B\x8E\xC1\xD3k\xCC\xA4\xA0\xEFy+B\x90\x9A",
|
64
|
+
no_header: "\xC97\x8B\x8E\xC1\xD3k\xCC\xA4\xA0\xEFy+B\x90\x9A"
|
65
|
+
},
|
66
|
+
},
|
67
|
+
# 'aes-128-gcm' => {
|
68
|
+
# base64: {
|
69
|
+
# header: "QEVuQwAAOcqz9UDbd1Sn\n",
|
70
|
+
# no_header: "Ocqz9UDbd1Sn\n"
|
71
|
+
# },
|
72
|
+
# base64strict: {
|
73
|
+
# header: 'QEVuQwAAOcqz9UDbd1Sn',
|
74
|
+
# no_header: 'Ocqz9UDbd1Sn'
|
75
|
+
# },
|
76
|
+
# base16: {
|
77
|
+
# header: '40456e43000039cab3f540db7754a7',
|
78
|
+
# no_header: '39cab3f540db7754a7'
|
79
|
+
# },
|
80
|
+
# none: {
|
81
|
+
# header: "@EnC\x00\x009\xCA\xB3\xF5@\xDBwT\xA7",
|
82
|
+
# no_header: "9\xCA\xB3\xF5@\xDBwT\xA7"
|
83
|
+
# },
|
84
|
+
# }
|
85
|
+
}
|
86
|
+
|
87
|
+
@non_utf8 = "\xc2".force_encoding('binary')
|
88
|
+
@cipher = SymmetricEncryption::Cipher.new(
|
89
|
+
key: 'ABCDEF1234567890',
|
90
|
+
iv: 'ABCDEF1234567890',
|
91
|
+
cipher_name: cipher_name,
|
92
|
+
encoding: encoding,
|
93
|
+
always_add_header: always_add_header
|
94
|
+
)
|
95
|
+
|
96
|
+
h = @encrypted_values[cipher_name][encoding] if @encrypted_values[cipher_name]
|
97
|
+
skip "Add @encrypted_values for cipher_name: #{cipher_name} and encoding: #{encoding}, value: #{@cipher.encrypt(@social_security_number).inspect}" unless h
|
98
|
+
@social_security_number_encrypted = h[always_add_header ? :header : :no_header]
|
99
|
+
|
100
|
+
@social_security_number_encrypted.force_encoding(Encoding.find('binary')) if encoding == :none
|
101
|
+
end
|
140
102
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
assert_equal true, header.compressed
|
146
|
-
assert random_cipher = SymmetricEncryption::Cipher.new(random_key_pair)
|
147
|
-
assert_equal random_cipher.cipher_name, header.cipher_name, 'Ciphers differ'
|
148
|
-
assert_equal random_cipher.send(:key), header.key, 'Keys differ'
|
149
|
-
assert_equal random_cipher.send(:iv), header.iv, 'IVs differ'
|
103
|
+
it 'encrypt simple string' do
|
104
|
+
assert encrypted = @cipher.encrypt(@social_security_number)
|
105
|
+
assert_equal @social_security_number_encrypted, encrypted
|
106
|
+
end
|
150
107
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
108
|
+
it 'decrypt string' do
|
109
|
+
assert decrypted = @cipher.decrypt(@social_security_number_encrypted)
|
110
|
+
assert_equal @social_security_number, decrypted
|
111
|
+
assert_equal Encoding.find('utf-8'), decrypted.encoding, decrypted
|
112
|
+
end
|
156
113
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
114
|
+
it 'encrypt and decrypt string' do
|
115
|
+
assert encrypted = @cipher.encrypt(@social_security_number)
|
116
|
+
assert_equal @social_security_number_encrypted, encrypted
|
117
|
+
assert decrypted = @cipher.decrypt(encrypted)
|
118
|
+
assert_equal @social_security_number, decrypted
|
119
|
+
assert_equal Encoding.find('utf-8'), decrypted.encoding, decrypted
|
120
|
+
end
|
161
121
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
122
|
+
it 'return BINARY encoding for non-UTF-8 encrypted data' do
|
123
|
+
assert_equal Encoding.find('binary'), @non_utf8.encoding
|
124
|
+
assert_equal true, @non_utf8.valid_encoding?
|
125
|
+
assert encrypted = @cipher.encrypt(@non_utf8)
|
126
|
+
assert decrypted = @cipher.decrypt(encrypted)
|
127
|
+
assert_equal true, decrypted.valid_encoding?
|
128
|
+
assert_equal Encoding.find('binary'), decrypted.encoding, decrypted
|
129
|
+
assert_equal @non_utf8, decrypted
|
130
|
+
end
|
166
131
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
end
|
132
|
+
it 'return nil when encrypting nil' do
|
133
|
+
assert_nil @cipher.encrypt(nil)
|
134
|
+
end
|
171
135
|
|
172
|
-
|
136
|
+
it "return '' when encrypting ''" do
|
137
|
+
assert_equal '', @cipher.encrypt('')
|
138
|
+
end
|
173
139
|
|
174
|
-
|
140
|
+
it 'return nil when decrypting nil' do
|
141
|
+
assert_nil @cipher.decrypt(nil)
|
142
|
+
end
|
175
143
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
SymmetricEncryption::Cipher.generate_random_keys(wrong_params: '')
|
144
|
+
it "return '' when decrypting ''" do
|
145
|
+
assert_equal '', @cipher.decrypt('')
|
146
|
+
end
|
147
|
+
end
|
181
148
|
end
|
182
|
-
|
183
|
-
assert_equal "SymmetricEncryption::Cipher Invalid options {:wrong_params=>\"\"}", error.message
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
describe 'without keys' do
|
188
|
-
it 'creates new keys' do
|
189
|
-
h = SymmetricEncryption::Cipher.generate_random_keys
|
190
|
-
assert_equal 'aes-256-cbc', h[:cipher_name]
|
191
|
-
assert_equal :base64strict, h[:encoding]
|
192
|
-
assert h.has_key?(:key), h
|
193
|
-
assert h.has_key?(:iv), h
|
194
149
|
end
|
195
|
-
end
|
196
150
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
describe 'with encrypted keys' do
|
208
|
-
it 'creates new encrypted keys' do
|
209
|
-
key_encryption_key = SymmetricEncryption::KeyEncryptionKey.generate
|
210
|
-
h = SymmetricEncryption::Cipher.generate_random_keys(
|
211
|
-
encrypted_key: '',
|
212
|
-
encrypted_iv: '',
|
213
|
-
private_rsa_key: key_encryption_key
|
214
|
-
)
|
215
|
-
assert_equal 'aes-256-cbc', h[:cipher_name]
|
216
|
-
assert_equal :base64strict, h[:encoding]
|
217
|
-
assert h.has_key?(:encrypted_key), h
|
218
|
-
assert h.has_key?(:encrypted_iv), h
|
219
|
-
end
|
220
|
-
|
221
|
-
it 'exception on missing rsa key' do
|
222
|
-
assert_raises SymmetricEncryption::ConfigError do
|
223
|
-
SymmetricEncryption::Cipher.generate_random_keys(
|
224
|
-
encrypted_key: '',
|
225
|
-
encrypted_iv: ''
|
151
|
+
describe 'with configuration' do
|
152
|
+
before do
|
153
|
+
@cipher = SymmetricEncryption::Cipher.new(
|
154
|
+
key: '1234567890ABCDEF',
|
155
|
+
iv: '1234567890ABCDEF',
|
156
|
+
cipher_name: 'aes-128-cbc',
|
157
|
+
encoding: :none
|
226
158
|
)
|
227
|
-
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
describe 'with files' do
|
232
|
-
before do
|
233
|
-
@key_filename = 'blah.key'
|
234
|
-
@iv_filename = 'blah.iv'
|
235
|
-
end
|
159
|
+
@social_security_number = '987654321'
|
236
160
|
|
237
|
-
|
238
|
-
|
239
|
-
File.delete(@iv_filename) if File.exist?(@iv_filename)
|
240
|
-
end
|
161
|
+
@social_security_number_encrypted = "A\335*\314\336\250V\340\023%\000S\177\305\372\266"
|
162
|
+
@social_security_number_encrypted.force_encoding('binary')
|
241
163
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
iv_filename: @iv_filename,
|
247
|
-
private_rsa_key: key_encryption_key
|
248
|
-
)
|
249
|
-
assert_equal 'aes-256-cbc', h[:cipher_name]
|
250
|
-
assert_equal :base64strict, h[:encoding]
|
251
|
-
assert h.has_key?(:key_filename), h
|
252
|
-
assert h.has_key?(:iv_filename), h
|
253
|
-
assert File.exist?(@key_filename)
|
254
|
-
assert File.exist?(@iv_filename)
|
255
|
-
end
|
164
|
+
@sample_data = [
|
165
|
+
{text: '555052345', encrypted: ''}
|
166
|
+
]
|
167
|
+
end
|
256
168
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
169
|
+
describe 'with header' do
|
170
|
+
before do
|
171
|
+
@social_security_number = '987654321'
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'build and parse header' do
|
175
|
+
key = SymmetricEncryption::Key.new(cipher_name: 'aes-128-cbc')
|
176
|
+
assert binary_header = SymmetricEncryption::Cipher.build_header(SymmetricEncryption.cipher.version, true, key.iv, key.key, key.cipher_name)
|
177
|
+
header = SymmetricEncryption::Header.new
|
178
|
+
header.parse(binary_header)
|
179
|
+
assert_equal true, header.compressed?
|
180
|
+
assert random_cipher = SymmetricEncryption::Cipher.new(iv: key.iv, key: key.key, cipher_name: key.cipher_name)
|
181
|
+
assert_equal random_cipher.cipher_name, header.cipher_name, 'Ciphers differ'
|
182
|
+
assert_equal random_cipher.send(:key), header.key, 'Keys differ'
|
183
|
+
assert_equal random_cipher.send(:iv), header.iv, 'IVs differ'
|
184
|
+
|
185
|
+
string = 'Hello World'
|
186
|
+
cipher = SymmetricEncryption::Cipher.new(key: header.key, iv: header.iv, cipher_name: header.cipher_name)
|
187
|
+
# Test Encryption
|
188
|
+
assert_equal random_cipher.encrypt(string), cipher.encrypt(string), 'Encrypted values differ'
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'encrypt and then decrypt without a header' do
|
192
|
+
assert encrypted = @cipher.binary_encrypt(@social_security_number, header: false)
|
193
|
+
assert_equal @social_security_number, @cipher.decrypt(encrypted)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'encrypt and then decrypt using random iv' do
|
197
|
+
assert encrypted = @cipher.encrypt(@social_security_number, random_iv: true)
|
198
|
+
assert_equal @social_security_number, @cipher.decrypt(encrypted)
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'encrypt and then decrypt using random iv with compression' do
|
202
|
+
assert encrypted = @cipher.encrypt(@social_security_number, random_iv: true, compress: true)
|
203
|
+
assert_equal @social_security_number, @cipher.decrypt(encrypted)
|
204
|
+
end
|
263
205
|
end
|
264
206
|
end
|
207
|
+
|
265
208
|
end
|
266
209
|
end
|
267
210
|
end
|