naoki 1.0.21 → 1.0.22
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.
- data/config/data_secure.yml +14 -0
- data/lib/data_secure_wrapper.rb +2 -0
- data/lib/naoki/data_secure.rb +176 -109
- data/naoki.gemspec +1 -1
- data/test/helper.rb +1 -20
- data/test/test_data_secure.rb +53 -0
- metadata +7 -4
- data/test/test_data_secure_wrapper.rb +0 -53
@@ -0,0 +1,14 @@
|
|
1
|
+
data_secure_enabled: false
|
2
|
+
properties_file: IngrianNAE.properties
|
3
|
+
|
4
|
+
credentials:
|
5
|
+
document_store:
|
6
|
+
username: username
|
7
|
+
password: password
|
8
|
+
initialization_vector: "1234567890123456"
|
9
|
+
key_name: stg-new-test-key
|
10
|
+
account_number:
|
11
|
+
username: username
|
12
|
+
password: password
|
13
|
+
initialization_vector: "1234567890123456"
|
14
|
+
key_name: stg-new-test-key
|
data/lib/data_secure_wrapper.rb
CHANGED
data/lib/naoki/data_secure.rb
CHANGED
@@ -3,34 +3,10 @@
|
|
3
3
|
# NB: this class is not thread-safe. Create an instance for each thread.
|
4
4
|
module Naoki
|
5
5
|
class DataSecure
|
6
|
-
@enabled = if File.exist?("config/data_secure.yml")
|
7
|
-
YAML.load(File.read("config/data_secure.yml"))['data_secure_enabled']
|
8
|
-
end
|
9
|
-
|
10
|
-
if !(`uname -s`.strip =~ /Linux/ && @enabled)
|
11
|
-
|
12
|
-
def self.init(file); end
|
13
|
-
def close; end
|
14
|
-
|
15
|
-
def encrypt_stream(input, out)
|
16
|
-
out.write("ENC")
|
17
|
-
count = 0
|
18
|
-
while block = input.read(4096)
|
19
|
-
count += block.size
|
20
|
-
out.write(block)
|
21
|
-
end
|
22
|
-
[count, count + 3]
|
23
|
-
end
|
24
|
-
|
25
|
-
def decrypt_stream(input, out)
|
26
|
-
val = input.read(3)
|
27
|
-
raise ArgumentError, "Invalid encrypted data (#{val})" if val != 'ENC'
|
28
|
-
count = IO.copy_stream(input, out)
|
29
|
-
[count + 3, count]
|
30
|
-
end
|
31
6
|
|
32
|
-
|
7
|
+
@Linux = `uname -s`.strip =~ /linux/i
|
33
8
|
|
9
|
+
if @Linux
|
34
10
|
require 'ffi'
|
35
11
|
extend FFI::Library
|
36
12
|
LIB_ICAPI_FILE = `uname -m`.match(/x86_64/) ? 'libICAPI_64.so' : 'libICAPI_32.so'
|
@@ -60,115 +36,206 @@ module Naoki
|
|
60
36
|
attach_function 'I_C_CryptFinal', [:pointer,:pointer,:pointer,:pointer], :int
|
61
37
|
@blocking = true
|
62
38
|
attach_function 'I_C_CryptUpdate', [:pointer, :pointer, :pointer, :uint, :pointer, :pointer], :int
|
39
|
+
end
|
40
|
+
|
41
|
+
DEFAULTS = {
|
42
|
+
'algorithm' => 'AES/CBC/PKCS5Padding',
|
43
|
+
}
|
44
|
+
|
45
|
+
MAX_SAFENET_BLOCK_SIZE = 31000
|
46
|
+
MAX_OUTPUT_BLOCK_SIZE = 32000
|
63
47
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
}
|
48
|
+
def initialize(credential_to_use, data_secure_yml)
|
49
|
+
options = data_secure_yml
|
50
|
+
credential_to_use = credential_to_use.to_s
|
51
|
+
@live = self.class.init(options['data_secure_enabled'], options['properties_file'])
|
69
52
|
|
70
|
-
|
71
|
-
|
53
|
+
if live?
|
54
|
+
@options = DEFAULTS.merge(data_secure_yml['credentials'][credential_to_use])
|
72
55
|
|
73
|
-
def initialize(key_to_use = :account_number, options={})
|
74
|
-
@options = DEFAULTS.merge(options.symbolize_keys)
|
75
|
-
#check { I_C_Initialize(I_T_Init_File, @options[:properties_file]) }
|
76
56
|
@session_pointer = FFI::MemoryPointer.new :pointer
|
77
|
-
check { I_C_OpenSession(@session_pointer, I_T_Auth_Password, @options[
|
57
|
+
check { I_C_OpenSession(@session_pointer, I_T_Auth_Password, @options['username'], @options['password']) }
|
78
58
|
@cipherspec_pointer = FFI::MemoryPointer.new :pointer
|
79
|
-
check { I_C_CreateCipherSpec(@options[
|
59
|
+
check { I_C_CreateCipherSpec(@options['algorithm'], @options['key_name'], @cipherspec_pointer) }
|
80
60
|
end
|
61
|
+
end
|
81
62
|
|
82
|
-
|
83
|
-
|
84
|
-
|
63
|
+
def self.init(enabled, file)
|
64
|
+
return false unless file && enabled && @Linux
|
65
|
+
return true if @initialized
|
66
|
+
check { I_C_Initialize(I_T_Init_File, file) }
|
67
|
+
@initialized = true
|
68
|
+
true
|
69
|
+
end
|
85
70
|
|
86
|
-
|
87
|
-
|
88
|
-
|
71
|
+
def close
|
72
|
+
return unless live?
|
73
|
+
check { I_C_DeleteCipherSpec(@cipherspec_pointer.get_pointer(0)) } if @cipherspec_pointer
|
74
|
+
@cipherspec_pointer = nil
|
75
|
+
I_C_CloseSession(@session_pointer.get_pointer(0)) if @session_pointer
|
76
|
+
@session_pointer = nil
|
77
|
+
end
|
89
78
|
|
90
|
-
|
91
|
-
|
92
|
-
|
79
|
+
def encrypt_stream(input_io, output_io)
|
80
|
+
return dummy_encrypt_stream(input_io, output_io) unless live?
|
81
|
+
transform_stream(I_T_Operation_Encrypt, input_io, output_io)
|
82
|
+
end
|
93
83
|
|
94
|
-
|
95
|
-
|
96
|
-
|
84
|
+
def decrypt_stream(input_io, output_io)
|
85
|
+
return dummy_decrypt_stream(input_io, output_io) unless live?
|
86
|
+
transform_stream(I_T_Operation_Decrypt, input_io, output_io)
|
87
|
+
end
|
97
88
|
|
98
|
-
|
89
|
+
def encrypt(plain_text)
|
90
|
+
return dummy_encrypt(plain_text) unless live?
|
91
|
+
transform(I_T_Operation_Encrypt, plain_text) do |transform_data_length_pointer|
|
92
|
+
check do
|
93
|
+
I_C_CalculateEncipheredSizeForKey(
|
94
|
+
@session_pointer.get_pointer(0),
|
95
|
+
@cipherspec_pointer.get_pointer(0),
|
96
|
+
I_T_Operation_Encrypt,
|
97
|
+
plain_text.length,
|
98
|
+
transform_data_length_pointer)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
99
102
|
|
100
|
-
|
101
|
-
|
103
|
+
def decrypt(text)
|
104
|
+
return dummy_decrypt(text) unless live?
|
105
|
+
transform(I_T_Operation_Decrypt, text) do |transform_data_length_pointer|
|
102
106
|
check do
|
103
|
-
|
107
|
+
I_C_CalculateOutputSizeForKey(
|
104
108
|
@session_pointer.get_pointer(0),
|
105
109
|
@cipherspec_pointer.get_pointer(0),
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
current_state)
|
110
|
+
I_T_Operation_Decrypt,
|
111
|
+
text.length,
|
112
|
+
transform_data_length_pointer)
|
110
113
|
end
|
114
|
+
end
|
115
|
+
end
|
111
116
|
|
112
|
-
|
113
|
-
read_size = 0
|
114
|
-
wrote_size = 0
|
115
|
-
output_data = FFI::MemoryPointer.new :pointer, MAX_OUTPUT_BLOCK_SIZE
|
116
|
-
output_data_length_pointer = FFI::MemoryPointer.new :pointer
|
117
|
-
|
118
|
-
loop do
|
119
|
-
output_data_length_pointer.write_uint(MAX_OUTPUT_BLOCK_SIZE)
|
120
|
-
|
121
|
-
data = input_io.read(MAX_SAFENET_BLOCK_SIZE)
|
122
|
-
if !data || data.size == 0
|
123
|
-
|
124
|
-
check do
|
125
|
-
I_C_CryptFinal(
|
126
|
-
@session_pointer.get_pointer(0),
|
127
|
-
current_state.get_pointer(0),
|
128
|
-
output_data,
|
129
|
-
output_data_length_pointer)
|
130
|
-
end
|
131
|
-
done = true
|
132
|
-
|
133
|
-
elsif data.size <= MAX_SAFENET_BLOCK_SIZE
|
134
|
-
read_size += data.size
|
135
|
-
check do
|
136
|
-
I_C_CryptUpdate(
|
137
|
-
@session_pointer.get_pointer(0),
|
138
|
-
current_state.get_pointer(0),
|
139
|
-
data,
|
140
|
-
data.size,
|
141
|
-
output_data,
|
142
|
-
output_data_length_pointer)
|
143
|
-
end
|
144
|
-
|
145
|
-
else
|
146
|
-
raise "DataSecure, how did we get here? #{data}"
|
147
|
-
end
|
117
|
+
private
|
148
118
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
119
|
+
def live?
|
120
|
+
@live
|
121
|
+
end
|
122
|
+
|
123
|
+
def dummy_encrypt(input)
|
124
|
+
"encrypted string"
|
125
|
+
end
|
126
|
+
|
127
|
+
def dummy_decrypt(input)
|
128
|
+
"decrypted string"
|
129
|
+
end
|
130
|
+
|
131
|
+
def dummy_encrypt_stream(input, out)
|
132
|
+
out.write("ENC")
|
133
|
+
count = 0
|
134
|
+
while block = input.read(4096)
|
135
|
+
count += block.size
|
136
|
+
out.write(block)
|
137
|
+
end
|
138
|
+
[count, count + 3]
|
139
|
+
end
|
140
|
+
|
141
|
+
def dummy_decrypt_stream(input, out)
|
142
|
+
val = input.read(3)
|
143
|
+
raise ArgumentError, "Invalid encrypted data (#{val})" if val != 'ENC'
|
144
|
+
count = IO.copy_stream(input, out)
|
145
|
+
[count + 3, count]
|
146
|
+
end
|
147
|
+
|
148
|
+
def transform(op, text)
|
149
|
+
yield(transform_data_length_pointer = FFI::MemoryPointer.new(:uint))
|
150
|
+
|
151
|
+
transform_data = FFI::MemoryPointer.new :char, transform_data_length_pointer.read_uint
|
154
152
|
|
155
|
-
|
153
|
+
check { I_C_Crypt(
|
154
|
+
@session_pointer.get_pointer(0),
|
155
|
+
@cipherspec_pointer.get_pointer(0),
|
156
|
+
op,
|
157
|
+
@options['initialization_vector'],
|
158
|
+
@options['initialization_vector'].length,
|
159
|
+
text,
|
160
|
+
text.length,
|
161
|
+
transform_data,
|
162
|
+
transform_data_length_pointer
|
163
|
+
) }
|
164
|
+
|
165
|
+
transform_data.read_string(transform_data_length_pointer.read_uint)
|
166
|
+
end
|
167
|
+
|
168
|
+
def transform_stream(op, input_io, output_io)
|
169
|
+
current_state = FFI::MemoryPointer.new :pointer
|
170
|
+
check do
|
171
|
+
I_C_CryptInit(
|
172
|
+
@session_pointer.get_pointer(0),
|
173
|
+
@cipherspec_pointer.get_pointer(0),
|
174
|
+
op,
|
175
|
+
@options['initialization_vector'],
|
176
|
+
@options['initialization_vector'].length,
|
177
|
+
current_state)
|
156
178
|
end
|
157
179
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
180
|
+
done = false
|
181
|
+
read_size = 0
|
182
|
+
wrote_size = 0
|
183
|
+
output_data = FFI::MemoryPointer.new :pointer, MAX_OUTPUT_BLOCK_SIZE
|
184
|
+
output_data_length_pointer = FFI::MemoryPointer.new :pointer
|
185
|
+
|
186
|
+
loop do
|
187
|
+
output_data_length_pointer.write_uint(MAX_OUTPUT_BLOCK_SIZE)
|
188
|
+
|
189
|
+
data = input_io.read(MAX_SAFENET_BLOCK_SIZE)
|
190
|
+
if !data || data.size == 0
|
191
|
+
|
192
|
+
check do
|
193
|
+
I_C_CryptFinal(
|
194
|
+
@session_pointer.get_pointer(0),
|
195
|
+
current_state.get_pointer(0),
|
196
|
+
output_data,
|
197
|
+
output_data_length_pointer)
|
198
|
+
end
|
199
|
+
done = true
|
200
|
+
|
201
|
+
elsif data.size <= MAX_SAFENET_BLOCK_SIZE
|
202
|
+
read_size += data.size
|
203
|
+
check do
|
204
|
+
I_C_CryptUpdate(
|
205
|
+
@session_pointer.get_pointer(0),
|
206
|
+
current_state.get_pointer(0),
|
207
|
+
data,
|
208
|
+
data.size,
|
209
|
+
output_data,
|
210
|
+
output_data_length_pointer)
|
211
|
+
end
|
212
|
+
|
213
|
+
else
|
214
|
+
raise "DataSecure, how did we get here? #{data}"
|
164
215
|
end
|
216
|
+
|
217
|
+
outsize = output_data_length_pointer.read_uint
|
218
|
+
enc_data = output_data.get_bytes(0, outsize)
|
219
|
+
wrote_size += output_io.write(enc_data)
|
220
|
+
break if done
|
165
221
|
end
|
166
222
|
|
167
|
-
|
168
|
-
|
169
|
-
|
223
|
+
[read_size, wrote_size]
|
224
|
+
end
|
225
|
+
|
226
|
+
def check
|
227
|
+
return_code = yield
|
228
|
+
if return_code != I_E_OK
|
229
|
+
I_C_DeleteCipherSpec(@cipherspec_pointer.get_pointer(0)) if @cipherspec_pointer
|
230
|
+
@cipherspec_pointer = nil
|
231
|
+
raise I_C_GetErrorString(return_code)
|
170
232
|
end
|
233
|
+
end
|
171
234
|
|
235
|
+
def self.check(&block)
|
236
|
+
return_code = yield
|
237
|
+
raise I_C_GetErrorString(return_code) if return_code != I_E_OK
|
172
238
|
end
|
239
|
+
|
173
240
|
end
|
174
241
|
end
|
data/naoki.gemspec
CHANGED
data/test/helper.rb
CHANGED
@@ -1,23 +1,4 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
require 'minitest/unit'
|
2
3
|
require 'naoki'
|
3
|
-
require '~/naoki_config'
|
4
|
-
|
5
|
-
def one_time_setup
|
6
|
-
user_name = SAFENET_CONFIG[:username]
|
7
|
-
password = SAFENET_CONFIG[:password]
|
8
|
-
algorithm = SAFENET_CONFIG[:algorithm]
|
9
|
-
key_name = SAFENET_CONFIG[:key_name] # versioned key
|
10
|
-
initialization_vector = SAFENET_CONFIG[:initialization_vector]
|
11
|
-
|
12
|
-
properties_file = 'IngrianNAE.properties'
|
13
|
-
|
14
|
-
DataSecureWrapper.configure(properties_file)
|
15
|
-
DataSecureWrapper.open(user_name, password)
|
16
|
-
|
17
|
-
at_exit do
|
18
|
-
DataSecureWrapper.close
|
19
|
-
end
|
20
|
-
end
|
21
|
-
one_time_setup
|
22
|
-
|
23
4
|
require 'minitest/autorun'
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
class TestDataSecure < MiniTest::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@data_secure = Naoki::DataSecure.new(:account_number, config_file)
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
@data_secure.close
|
11
|
+
@data_secure = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_hello_world
|
15
|
+
expected = 'hello world!'
|
16
|
+
encrypted_data = @data_secure.encrypt(expected)
|
17
|
+
decrypted_data = @data_secure.decrypt(encrypted_data)
|
18
|
+
assert(expected == decrypted_data || "decrypted string" == decrypted_data)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_documents
|
22
|
+
13.times do |idx|
|
23
|
+
str = '01234567'*(1 << idx)
|
24
|
+
encrypt_and_decrypt(str.size, StringIO.new(str))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def encrypt_and_decrypt(size, unencrypted)
|
31
|
+
encrypted = StringIO.new
|
32
|
+
unencrypted_size = unencrypted.size
|
33
|
+
|
34
|
+
(read_bytes, written_bytes) = @data_secure.encrypt_stream(unencrypted, encrypted)
|
35
|
+
|
36
|
+
assert_equal unencrypted_size, read_bytes
|
37
|
+
assert(read_bytes < written_bytes)
|
38
|
+
|
39
|
+
encrypted.rewind
|
40
|
+
|
41
|
+
decrypted = StringIO.new
|
42
|
+
(read_bytes, written_bytes) = @data_secure.decrypt_stream(encrypted, decrypted)
|
43
|
+
|
44
|
+
unencrypted.rewind
|
45
|
+
decrypted.rewind
|
46
|
+
assert(read_bytes > written_bytes)
|
47
|
+
assert_equal(unencrypted.read, decrypted.read)
|
48
|
+
end
|
49
|
+
|
50
|
+
def config_file
|
51
|
+
YAML.load(File.read('config/data_secure.yml'))
|
52
|
+
end
|
53
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: naoki
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.0.
|
5
|
+
version: 1.0.22
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Chris Apolzon
|
@@ -11,7 +11,8 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-06-21 00:00:00
|
14
|
+
date: 2011-06-21 00:00:00 -07:00
|
15
|
+
default_executable:
|
15
16
|
dependencies:
|
16
17
|
- !ruby/object:Gem::Dependency
|
17
18
|
name: ffi
|
@@ -38,6 +39,7 @@ files:
|
|
38
39
|
- .rvmrc
|
39
40
|
- Gemfile
|
40
41
|
- Rakefile
|
42
|
+
- config/data_secure.yml
|
41
43
|
- lib/data_secure_wrapper.rb
|
42
44
|
- lib/libICAPI_32.so
|
43
45
|
- lib/libICAPI_64.so
|
@@ -46,7 +48,8 @@ files:
|
|
46
48
|
- naoki.gemspec
|
47
49
|
- sample.rb
|
48
50
|
- test/helper.rb
|
49
|
-
- test/
|
51
|
+
- test/test_data_secure.rb
|
52
|
+
has_rdoc: true
|
50
53
|
homepage: ""
|
51
54
|
licenses: []
|
52
55
|
|
@@ -70,7 +73,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
73
|
requirements: []
|
71
74
|
|
72
75
|
rubyforge_project:
|
73
|
-
rubygems_version: 1.
|
76
|
+
rubygems_version: 1.5.2
|
74
77
|
signing_key:
|
75
78
|
specification_version: 3
|
76
79
|
summary: C bindings for SafeNet DataSecure ICAPI
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'stringio'
|
3
|
-
|
4
|
-
class TestDataSecureWrapper < MiniTest::Unit::TestCase
|
5
|
-
|
6
|
-
def test_hello_world
|
7
|
-
expected = 'hello world!'
|
8
|
-
encrypted_data = encrypt(expected)
|
9
|
-
decrypted_data = decrypt(encrypted_data)
|
10
|
-
assert(expected == decrypted_data || "decrypted_string" == decrypted_data)
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_documents
|
14
|
-
ds = Naoki::DataSecure.new(:document_store, SAFENET_CONFIG)
|
15
|
-
|
16
|
-
15.times do |idx|
|
17
|
-
str = '01234567'*(1 << idx)
|
18
|
-
encrypt_and_decrypt(ds, str.size, StringIO.new(str))
|
19
|
-
end
|
20
|
-
ensure
|
21
|
-
ds.close
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def encrypt_and_decrypt(ds, size, unencrypted)
|
27
|
-
encrypted = StringIO.new
|
28
|
-
unencrypted_size = unencrypted.size
|
29
|
-
|
30
|
-
(read_bytes, written_bytes) = ds.encrypt_stream(unencrypted, encrypted)
|
31
|
-
|
32
|
-
assert_equal unencrypted_size, read_bytes
|
33
|
-
assert(read_bytes < written_bytes)
|
34
|
-
|
35
|
-
encrypted.rewind
|
36
|
-
|
37
|
-
decrypted = StringIO.new
|
38
|
-
(read_bytes, written_bytes) = ds.decrypt_stream(encrypted, decrypted)
|
39
|
-
|
40
|
-
unencrypted.rewind
|
41
|
-
decrypted.rewind
|
42
|
-
assert(read_bytes > written_bytes)
|
43
|
-
assert_equal(unencrypted.read, decrypted.read)
|
44
|
-
end
|
45
|
-
|
46
|
-
def decrypt(data)
|
47
|
-
DataSecureWrapper.decrypt(SAFENET_CONFIG[:algorithm], SAFENET_CONFIG[:key_name], SAFENET_CONFIG[:initialization_vector], data)
|
48
|
-
end
|
49
|
-
|
50
|
-
def encrypt(data)
|
51
|
-
DataSecureWrapper.encrypt(SAFENET_CONFIG[:algorithm], SAFENET_CONFIG[:key_name], SAFENET_CONFIG[:initialization_vector], data)
|
52
|
-
end
|
53
|
-
end
|